From: bbudge Date: Mon, 3 Aug 2015 13:02:39 +0000 (-0700) Subject: SIMD.js Add the other SIMD Phase 1 types. X-Git-Tag: upstream/4.7.83~1066 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=7b9670b63b486ba3b6f8a569552d307282dbccfd;p=platform%2Fupstream%2Fv8.git SIMD.js Add the other SIMD Phase 1 types. Adds Int32x4, Bool32x4, Int16x8, Bool16x8, Int8x16, Bool8x16. Adds Simd128Value base heap object class. Changes heap/factory construction pattern to use arrays. Adds replaceLane functions to facilitate testing. NOPRESUBMIT=true (presubmit checks erroneously interpret array declaration in macro definition as variable size array.) LOG=Y BUG=v8:4124 Review URL: https://codereview.chromium.org/1250733005 Cr-Commit-Position: refs/heads/master@{#29974} --- diff --git a/include/v8.h b/include/v8.h index 0bcb311ba..9ac158055 100644 --- a/include/v8.h +++ b/include/v8.h @@ -6913,7 +6913,7 @@ class Internals { static const int kJSObjectHeaderSize = 3 * kApiPointerSize; static const int kFixedArrayHeaderSize = 2 * kApiPointerSize; static const int kContextHeaderSize = 2 * kApiPointerSize; - static const int kContextEmbedderDataIndex = 81; + static const int kContextEmbedderDataIndex = 87; static const int kFullStringRepresentationMask = 0x07; static const int kStringEncodingMask = 0x4; static const int kExternalTwoByteRepresentationTag = 0x02; @@ -6946,10 +6946,10 @@ class Internals { static const int kNodeIsIndependentShift = 3; static const int kNodeIsPartiallyDependentShift = 4; - static const int kJSObjectType = 0xb6; + static const int kJSObjectType = 0xbc; static const int kFirstNonstringType = 0x80; static const int kOddballType = 0x83; - static const int kForeignType = 0x87; + static const int kForeignType = 0x8d; static const int kUndefinedOddballKind = 5; static const int kNullOddballKind = 3; diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc index 80d01a176..d0d09934e 100644 --- a/src/arm/code-stubs-arm.cc +++ b/src/arm/code-stubs-arm.cc @@ -249,6 +249,7 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow, // They are both equal and they are not both Smis so both of them are not // Smis. If it's not a heap number, then return equal. if (cond == lt || cond == gt) { + Label not_simd; // Call runtime on identical JSObjects. __ CompareObjectType(r0, r4, r4, FIRST_SPEC_OBJECT_TYPE); __ b(ge, slow); @@ -256,8 +257,11 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow, __ cmp(r4, Operand(SYMBOL_TYPE)); __ b(eq, slow); // Call runtime on identical SIMD values since we must throw a TypeError. - __ cmp(r4, Operand(FLOAT32X4_TYPE)); - __ b(eq, slow); + __ cmp(r4, Operand(FIRST_SIMD_VALUE_TYPE)); + __ b(lt, ¬_simd); + __ cmp(r4, Operand(LAST_SIMD_VALUE_TYPE)); + __ b(le, slow); + __ bind(¬_simd); if (is_strong(strength)) { // Call the runtime on anything that is converted in the semantics, since // we need to throw a TypeError. Smis have already been ruled out. @@ -271,14 +275,18 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow, __ b(eq, &heap_number); // Comparing JS objects with <=, >= is complicated. if (cond != eq) { + Label not_simd; __ cmp(r4, Operand(FIRST_SPEC_OBJECT_TYPE)); __ b(ge, slow); // Call runtime on identical symbols since we need to throw a TypeError. __ cmp(r4, Operand(SYMBOL_TYPE)); __ b(eq, slow); // Call runtime on identical SIMD values since we must throw a TypeError. - __ cmp(r4, Operand(FLOAT32X4_TYPE)); - __ b(eq, slow); + __ cmp(r4, Operand(FIRST_SIMD_VALUE_TYPE)); + __ b(lt, ¬_simd); + __ cmp(r4, Operand(LAST_SIMD_VALUE_TYPE)); + __ b(le, slow); + __ bind(¬_simd); if (is_strong(strength)) { // Call the runtime on anything that is converted in the semantics, // since we need to throw a TypeError. Smis and heap numbers have diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc index 51d56caef..7af1982ee 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc @@ -2270,8 +2270,12 @@ void LCodeGen::DoBranch(LBranch* instr) { if (expected.Contains(ToBooleanStub::SIMD_VALUE)) { // SIMD value -> true. - __ CompareInstanceType(map, ip, FLOAT32X4_TYPE); - __ b(eq, instr->TrueLabel(chunk_)); + Label not_simd; + __ CompareInstanceType(map, ip, FIRST_SIMD_VALUE_TYPE); + __ b(lt, ¬_simd); + __ CompareInstanceType(map, ip, LAST_SIMD_VALUE_TYPE); + __ b(le, instr->TrueLabel(chunk_)); + __ bind(¬_simd); } if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) { @@ -5707,6 +5711,36 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, __ CompareObjectType(input, scratch, no_reg, FLOAT32X4_TYPE); final_branch_condition = eq; + } else if (String::Equals(type_name, factory->int32x4_string())) { + __ JumpIfSmi(input, false_label); + __ CompareObjectType(input, scratch, no_reg, INT32X4_TYPE); + final_branch_condition = eq; + + } else if (String::Equals(type_name, factory->bool32x4_string())) { + __ JumpIfSmi(input, false_label); + __ CompareObjectType(input, scratch, no_reg, BOOL32X4_TYPE); + final_branch_condition = eq; + + } else if (String::Equals(type_name, factory->int16x8_string())) { + __ JumpIfSmi(input, false_label); + __ CompareObjectType(input, scratch, no_reg, INT16X8_TYPE); + final_branch_condition = eq; + + } else if (String::Equals(type_name, factory->bool16x8_string())) { + __ JumpIfSmi(input, false_label); + __ CompareObjectType(input, scratch, no_reg, BOOL16X8_TYPE); + final_branch_condition = eq; + + } else if (String::Equals(type_name, factory->int8x16_string())) { + __ JumpIfSmi(input, false_label); + __ CompareObjectType(input, scratch, no_reg, INT8X16_TYPE); + final_branch_condition = eq; + + } else if (String::Equals(type_name, factory->bool8x16_string())) { + __ JumpIfSmi(input, false_label); + __ CompareObjectType(input, scratch, no_reg, BOOL8X16_TYPE); + final_branch_condition = eq; + } else { __ b(false_label); } diff --git a/src/arm64/code-stubs-arm64.cc b/src/arm64/code-stubs-arm64.cc index b10364163..f75539d50 100644 --- a/src/arm64/code-stubs-arm64.cc +++ b/src/arm64/code-stubs-arm64.cc @@ -221,6 +221,7 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm, Register left, // Smis. If it's not a heap number, then return equal. Register right_type = scratch; if ((cond == lt) || (cond == gt)) { + Label not_simd; // Call runtime on identical JSObjects. Otherwise return equal. __ JumpIfObjectType(right, right_type, right_type, FIRST_SPEC_OBJECT_TYPE, slow, ge); @@ -228,8 +229,11 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm, Register left, __ Cmp(right_type, SYMBOL_TYPE); __ B(eq, slow); // Call runtime on identical SIMD values since we must throw a TypeError. - __ Cmp(right_type, FLOAT32X4_TYPE); - __ B(eq, slow); + __ Cmp(right_type, FIRST_SIMD_VALUE_TYPE); + __ B(lt, ¬_simd); + __ Cmp(right_type, LAST_SIMD_VALUE_TYPE); + __ B(le, slow); + __ Bind(¬_simd); if (is_strong(strength)) { // Call the runtime on anything that is converted in the semantics, since // we need to throw a TypeError. Smis have already been ruled out. @@ -241,6 +245,7 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm, Register left, } else if (cond == eq) { __ JumpIfHeapNumber(right, &heap_number); } else { + Label not_simd; __ JumpIfObjectType(right, right_type, right_type, HEAP_NUMBER_TYPE, &heap_number); // Comparing JS objects with <=, >= is complicated. @@ -250,8 +255,11 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm, Register left, __ Cmp(right_type, SYMBOL_TYPE); __ B(eq, slow); // Call runtime on identical SIMD values since we must throw a TypeError. - __ Cmp(right_type, FLOAT32X4_TYPE); - __ B(eq, slow); + __ Cmp(right_type, FIRST_SIMD_VALUE_TYPE); + __ B(lt, ¬_simd); + __ Cmp(right_type, LAST_SIMD_VALUE_TYPE); + __ B(le, slow); + __ Bind(¬_simd); if (is_strong(strength)) { // Call the runtime on anything that is converted in the semantics, // since we need to throw a TypeError. Smis and heap numbers have diff --git a/src/arm64/lithium-codegen-arm64.cc b/src/arm64/lithium-codegen-arm64.cc index 6fb1088ef..c4be83277 100644 --- a/src/arm64/lithium-codegen-arm64.cc +++ b/src/arm64/lithium-codegen-arm64.cc @@ -1933,8 +1933,12 @@ void LCodeGen::DoBranch(LBranch* instr) { if (expected.Contains(ToBooleanStub::SIMD_VALUE)) { // SIMD value -> true. - __ CompareInstanceType(map, scratch, FLOAT32X4_TYPE); - __ B(eq, true_label); + Label not_simd; + __ CompareInstanceType(map, scratch, FIRST_SIMD_VALUE_TYPE); + __ B(lt, ¬_simd); + __ CompareInstanceType(map, scratch, LAST_SIMD_VALUE_TYPE); + __ B(le, true_label); + __ Bind(¬_simd); } if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) { @@ -6002,6 +6006,60 @@ void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { __ CompareObjectType(value, map, scratch, FLOAT32X4_TYPE); EmitBranch(instr, eq); + } else if (String::Equals(type_name, factory->int32x4_string())) { + DCHECK((instr->temp1() != NULL) && (instr->temp2() != NULL)); + Register map = ToRegister(instr->temp1()); + Register scratch = ToRegister(instr->temp2()); + + __ JumpIfSmi(value, false_label); + __ CompareObjectType(value, map, scratch, INT32X4_TYPE); + EmitBranch(instr, eq); + + } else if (String::Equals(type_name, factory->bool32x4_string())) { + DCHECK((instr->temp1() != NULL) && (instr->temp2() != NULL)); + Register map = ToRegister(instr->temp1()); + Register scratch = ToRegister(instr->temp2()); + + __ JumpIfSmi(value, false_label); + __ CompareObjectType(value, map, scratch, BOOL32X4_TYPE); + EmitBranch(instr, eq); + + } else if (String::Equals(type_name, factory->int16x8_string())) { + DCHECK((instr->temp1() != NULL) && (instr->temp2() != NULL)); + Register map = ToRegister(instr->temp1()); + Register scratch = ToRegister(instr->temp2()); + + __ JumpIfSmi(value, false_label); + __ CompareObjectType(value, map, scratch, INT16X8_TYPE); + EmitBranch(instr, eq); + + } else if (String::Equals(type_name, factory->bool16x8_string())) { + DCHECK((instr->temp1() != NULL) && (instr->temp2() != NULL)); + Register map = ToRegister(instr->temp1()); + Register scratch = ToRegister(instr->temp2()); + + __ JumpIfSmi(value, false_label); + __ CompareObjectType(value, map, scratch, BOOL16X8_TYPE); + EmitBranch(instr, eq); + + } else if (String::Equals(type_name, factory->int8x16_string())) { + DCHECK((instr->temp1() != NULL) && (instr->temp2() != NULL)); + Register map = ToRegister(instr->temp1()); + Register scratch = ToRegister(instr->temp2()); + + __ JumpIfSmi(value, false_label); + __ CompareObjectType(value, map, scratch, INT8X16_TYPE); + EmitBranch(instr, eq); + + } else if (String::Equals(type_name, factory->bool8x16_string())) { + DCHECK((instr->temp1() != NULL) && (instr->temp2() != NULL)); + Register map = ToRegister(instr->temp1()); + Register scratch = ToRegister(instr->temp2()); + + __ JumpIfSmi(value, false_label); + __ CompareObjectType(value, map, scratch, BOOL8X16_TYPE); + EmitBranch(instr, eq); + } else { __ B(false_label); } diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc index 838510000..ea9edba49 100644 --- a/src/bootstrapper.cc +++ b/src/bootstrapper.cc @@ -1991,13 +1991,16 @@ void Genesis::InitializeGlobal_harmony_simd() { DCHECK(simd_object->IsJSObject()); JSObject::AddProperty(global, name, simd_object, DONT_ENUM); - Handle float32x4_function = - InstallFunction(simd_object, "Float32x4", JS_VALUE_TYPE, JSValue::kSize, - isolate->initial_object_prototype(), Builtins::kIllegal); - // Set the instance class name since InstallFunction only does this when - // we install on the GlobalObject. - float32x4_function->SetInstanceClassName(*factory->Float32x4_string()); - native_context()->set_float32x4_function(*float32x4_function); +// Install SIMD type functions. Set the instance class names since +// InstallFunction only does this when we install on the GlobalObject. +#define SIMD128_INSTALL_FUNCTION(name, type, lane_count, lane_type) \ + Handle type##_function = InstallFunction( \ + simd_object, #name, JS_VALUE_TYPE, JSValue::kSize, \ + isolate->initial_object_prototype(), Builtins::kIllegal); \ + native_context()->set_##type##_function(*type##_function); \ + type##_function->SetInstanceClassName(*factory->name##_string()); + + SIMD128_TYPES(SIMD128_INSTALL_FUNCTION) } diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc index 4afd592ab..b4c74abdd 100644 --- a/src/code-stubs-hydrogen.cc +++ b/src/code-stubs-hydrogen.cc @@ -405,19 +405,72 @@ HValue* CodeStubGraphBuilder::BuildCodeStub() { { Push(Add(factory->float32x4_string())); } is_float32x4.Else(); { - // Is it an undetectable object? - IfBuilder is_undetectable(this); - is_undetectable.If(object); - is_undetectable.Then(); + IfBuilder is_int32x4(this); + is_int32x4.If( + instance_type, Add(INT32X4_TYPE), Token::EQ); + is_int32x4.Then(); + { Push(Add(factory->int32x4_string())); } + is_int32x4.Else(); { - // typeof an undetectable object is 'undefined'. - Push(undefined_string); - } - is_undetectable.Else(); - { - // For any kind of object not handled above, the spec rule for - // host objects gives that it is okay to return "object". - Push(object_string); + IfBuilder is_bool32x4(this); + is_bool32x4.If( + instance_type, Add(BOOL32X4_TYPE), Token::EQ); + is_bool32x4.Then(); + { Push(Add(factory->bool32x4_string())); } + is_bool32x4.Else(); + { + IfBuilder is_int16x8(this); + is_int16x8.If( + instance_type, Add(INT16X8_TYPE), Token::EQ); + is_int16x8.Then(); + { Push(Add(factory->int16x8_string())); } + is_int16x8.Else(); + { + IfBuilder is_bool16x8(this); + is_bool16x8.If( + instance_type, Add(BOOL16X8_TYPE), + Token::EQ); + is_bool16x8.Then(); + { Push(Add(factory->bool16x8_string())); } + is_bool16x8.Else(); + { + IfBuilder is_int8x16(this); + is_int8x16.If( + instance_type, Add(INT8X16_TYPE), + Token::EQ); + is_int8x16.Then(); + { Push(Add(factory->int8x16_string())); } + is_int8x16.Else(); + { + IfBuilder is_bool8x16(this); + is_bool8x16.If( + instance_type, Add(BOOL8X16_TYPE), + Token::EQ); + is_bool8x16.Then(); + { Push(Add(factory->bool8x16_string())); } + is_bool8x16.Else(); + { + // Is it an undetectable object? + IfBuilder is_undetectable(this); + is_undetectable.If( + object); + is_undetectable.Then(); + { + // typeof an undetectable object is 'undefined'. + Push(undefined_string); + } + is_undetectable.Else(); + { + // For any kind of object not handled above, the + // spec rule for host objects gives that it is + // okay to return "object". + Push(object_string); + } + } + } + } + } + } } } } diff --git a/src/code-stubs.cc b/src/code-stubs.cc index cc77389de..c7f4d4b63 100644 --- a/src/code-stubs.cc +++ b/src/code-stubs.cc @@ -994,7 +994,7 @@ bool ToBooleanStub::Types::UpdateStatus(Handle object) { Add(HEAP_NUMBER); double value = HeapNumber::cast(*object)->value(); return value != 0 && !std::isnan(value); - } else if (object->IsFloat32x4()) { + } else if (object->IsSimd128Value()) { Add(SIMD_VALUE); return true; } else { diff --git a/src/contexts.h b/src/contexts.h index 8e8f0b379..0109267dd 100644 --- a/src/contexts.h +++ b/src/contexts.h @@ -82,6 +82,12 @@ enum BindingFlags { V(STRING_FUNCTION_PROTOTYPE_MAP_INDEX, Map, string_function_prototype_map) \ V(SYMBOL_FUNCTION_INDEX, JSFunction, symbol_function) \ V(FLOAT32X4_FUNCTION_INDEX, JSFunction, float32x4_function) \ + V(INT32X4_FUNCTION_INDEX, JSFunction, int32x4_function) \ + V(BOOL32X4_FUNCTION_INDEX, JSFunction, bool32x4_function) \ + V(INT16X8_FUNCTION_INDEX, JSFunction, int16x8_function) \ + V(BOOL16X8_FUNCTION_INDEX, JSFunction, bool16x8_function) \ + V(INT8X16_FUNCTION_INDEX, JSFunction, int8x16_function) \ + V(BOOL8X16_FUNCTION_INDEX, JSFunction, bool8x16_function) \ V(OBJECT_FUNCTION_INDEX, JSFunction, object_function) \ V(JS_OBJECT_STRONG_MAP_INDEX, Map, js_object_strong_map) \ V(INTERNAL_ARRAY_FUNCTION_INDEX, JSFunction, internal_array_function) \ @@ -349,6 +355,12 @@ class Context: public FixedArray { STRING_FUNCTION_PROTOTYPE_MAP_INDEX, SYMBOL_FUNCTION_INDEX, FLOAT32X4_FUNCTION_INDEX, + INT32X4_FUNCTION_INDEX, + BOOL32X4_FUNCTION_INDEX, + INT16X8_FUNCTION_INDEX, + BOOL16X8_FUNCTION_INDEX, + INT8X16_FUNCTION_INDEX, + BOOL8X16_FUNCTION_INDEX, OBJECT_FUNCTION_INDEX, JS_OBJECT_STRONG_MAP_INDEX, INTERNAL_ARRAY_FUNCTION_INDEX, diff --git a/src/factory.cc b/src/factory.cc index 1d594d3eb..2fe185443 100644 --- a/src/factory.cc +++ b/src/factory.cc @@ -1047,11 +1047,50 @@ Handle Factory::NewHeapNumber(double value, } -Handle Factory::NewFloat32x4(float w, float x, float y, float z, +Handle Factory::NewFloat32x4(float lanes[4], PretenureFlag pretenure) { + CALL_HEAP_FUNCTION(isolate(), + isolate()->heap()->AllocateFloat32x4(lanes, pretenure), + Float32x4); +} + + +Handle Factory::NewInt32x4(int32_t lanes[4], PretenureFlag pretenure) { + CALL_HEAP_FUNCTION( + isolate(), isolate()->heap()->AllocateInt32x4(lanes, pretenure), Int32x4); +} + + +Handle Factory::NewBool32x4(bool lanes[4], PretenureFlag pretenure) { + CALL_HEAP_FUNCTION(isolate(), + isolate()->heap()->AllocateBool32x4(lanes, pretenure), + Bool32x4); +} + + +Handle Factory::NewInt16x8(int16_t lanes[8], PretenureFlag pretenure) { CALL_HEAP_FUNCTION( - isolate(), isolate()->heap()->AllocateFloat32x4(w, x, y, z, pretenure), - Float32x4); + isolate(), isolate()->heap()->AllocateInt16x8(lanes, pretenure), Int16x8); +} + + +Handle Factory::NewBool16x8(bool lanes[8], PretenureFlag pretenure) { + CALL_HEAP_FUNCTION(isolate(), + isolate()->heap()->AllocateBool16x8(lanes, pretenure), + Bool16x8); +} + + +Handle Factory::NewInt8x16(int8_t lanes[16], PretenureFlag pretenure) { + CALL_HEAP_FUNCTION( + isolate(), isolate()->heap()->AllocateInt8x16(lanes, pretenure), Int8x16); +} + + +Handle Factory::NewBool8x16(bool lanes[16], PretenureFlag pretenure) { + CALL_HEAP_FUNCTION(isolate(), + isolate()->heap()->AllocateBool8x16(lanes, pretenure), + Bool8x16); } diff --git a/src/factory.h b/src/factory.h index 9d42130ee..9a595c411 100644 --- a/src/factory.h +++ b/src/factory.h @@ -351,8 +351,20 @@ class Factory final { Handle NewHeapNumber(double value, MutableMode mode = IMMUTABLE, PretenureFlag pretenure = NOT_TENURED); - Handle NewFloat32x4(float w, float x, float y, float z, + Handle NewFloat32x4(float lanes[4], PretenureFlag pretenure = NOT_TENURED); + Handle NewInt32x4(int32_t lanes[4], + PretenureFlag pretenure = NOT_TENURED); + Handle NewBool32x4(bool lanes[4], + PretenureFlag pretenure = NOT_TENURED); + Handle NewInt16x8(int16_t lanes[8], + PretenureFlag pretenure = NOT_TENURED); + Handle NewBool16x8(bool lanes[8], + PretenureFlag pretenure = NOT_TENURED); + Handle NewInt8x16(int8_t lanes[16], + PretenureFlag pretenure = NOT_TENURED); + Handle NewBool8x16(bool lanes[16], + PretenureFlag pretenure = NOT_TENURED); // These objects are used by the api to create env-independent data // structures in the heap. diff --git a/src/full-codegen/arm/full-codegen-arm.cc b/src/full-codegen/arm/full-codegen-arm.cc index c07438a2d..724c8d7c4 100644 --- a/src/full-codegen/arm/full-codegen-arm.cc +++ b/src/full-codegen/arm/full-codegen-arm.cc @@ -3431,6 +3431,33 @@ void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) { } +void FullCodeGenerator::EmitIsSimdObject(CallRuntime* expr) { + ZoneList* args = expr->arguments(); + DCHECK(args->length() == 1); + + VisitForAccumulatorValue(args->at(0)); + + Label materialize_true, materialize_false; + Label* if_true = NULL; + Label* if_false = NULL; + Label* fall_through = NULL; + context()->PrepareTest(&materialize_true, &materialize_false, &if_true, + &if_false, &fall_through); + + __ JumpIfSmi(r0, if_false); + Register map = r1; + Register type_reg = r2; + __ ldr(map, FieldMemOperand(r0, HeapObject::kMapOffset)); + __ ldrb(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset)); + __ sub(type_reg, type_reg, Operand(FIRST_SIMD_VALUE_TYPE)); + __ cmp(type_reg, Operand(LAST_SIMD_VALUE_TYPE - FIRST_SIMD_VALUE_TYPE)); + PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); + Split(ls, if_true, if_false, fall_through); + + context()->Plug(if_true, if_false); +} + + void FullCodeGenerator::EmitIsUndetectableObject(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 1); @@ -5076,6 +5103,30 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, __ JumpIfSmi(r0, if_false); __ CompareObjectType(r0, r0, r1, FLOAT32X4_TYPE); Split(eq, if_true, if_false, fall_through); + } else if (String::Equals(check, factory->int32x4_string())) { + __ JumpIfSmi(r0, if_false); + __ CompareObjectType(r0, r0, r1, INT32X4_TYPE); + Split(eq, if_true, if_false, fall_through); + } else if (String::Equals(check, factory->bool32x4_string())) { + __ JumpIfSmi(r0, if_false); + __ CompareObjectType(r0, r0, r1, BOOL32X4_TYPE); + Split(eq, if_true, if_false, fall_through); + } else if (String::Equals(check, factory->int16x8_string())) { + __ JumpIfSmi(r0, if_false); + __ CompareObjectType(r0, r0, r1, INT16X8_TYPE); + Split(eq, if_true, if_false, fall_through); + } else if (String::Equals(check, factory->bool16x8_string())) { + __ JumpIfSmi(r0, if_false); + __ CompareObjectType(r0, r0, r1, BOOL16X8_TYPE); + Split(eq, if_true, if_false, fall_through); + } else if (String::Equals(check, factory->int8x16_string())) { + __ JumpIfSmi(r0, if_false); + __ CompareObjectType(r0, r0, r1, INT8X16_TYPE); + Split(eq, if_true, if_false, fall_through); + } else if (String::Equals(check, factory->bool8x16_string())) { + __ JumpIfSmi(r0, if_false); + __ CompareObjectType(r0, r0, r1, BOOL8X16_TYPE); + Split(eq, if_true, if_false, fall_through); } else if (String::Equals(check, factory->boolean_string())) { __ CompareRoot(r0, Heap::kTrueValueRootIndex); __ b(eq, if_true); diff --git a/src/full-codegen/arm64/full-codegen-arm64.cc b/src/full-codegen/arm64/full-codegen-arm64.cc index 99cf86366..9944d32ef 100644 --- a/src/full-codegen/arm64/full-codegen-arm64.cc +++ b/src/full-codegen/arm64/full-codegen-arm64.cc @@ -3121,6 +3121,33 @@ void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) { } +void FullCodeGenerator::EmitIsSimdObject(CallRuntime* expr) { + ZoneList* args = expr->arguments(); + DCHECK(args->length() == 1); + + VisitForAccumulatorValue(args->at(0)); + + Label materialize_true, materialize_false; + Label* if_true = NULL; + Label* if_false = NULL; + Label* fall_through = NULL; + context()->PrepareTest(&materialize_true, &materialize_false, &if_true, + &if_false, &fall_through); + + __ JumpIfSmi(x0, if_false); + Register map = x10; + Register type_reg = x11; + __ Ldr(map, FieldMemOperand(x0, HeapObject::kMapOffset)); + __ Ldrb(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset)); + __ Sub(type_reg, type_reg, Operand(FIRST_SIMD_VALUE_TYPE)); + __ Cmp(type_reg, Operand(LAST_SIMD_VALUE_TYPE - FIRST_SIMD_VALUE_TYPE)); + PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); + Split(ls, if_true, if_false, fall_through); + + context()->Plug(if_true, if_false); +} + + void FullCodeGenerator::EmitIsUndetectableObject(CallRuntime* expr) { ASM_LOCATION("FullCodeGenerator::EmitIsUndetectableObject"); ZoneList* args = expr->arguments(); @@ -4773,6 +4800,36 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, __ JumpIfSmi(x0, if_false); __ CompareObjectType(x0, x0, x1, FLOAT32X4_TYPE); Split(eq, if_true, if_false, fall_through); + } else if (String::Equals(check, factory->int32x4_string())) { + ASM_LOCATION("FullCodeGenerator::EmitLiteralCompareTypeof int32x4_string"); + __ JumpIfSmi(x0, if_false); + __ CompareObjectType(x0, x0, x1, INT32X4_TYPE); + Split(eq, if_true, if_false, fall_through); + } else if (String::Equals(check, factory->bool32x4_string())) { + ASM_LOCATION("FullCodeGenerator::EmitLiteralCompareTypeof bool32x4_string"); + __ JumpIfSmi(x0, if_false); + __ CompareObjectType(x0, x0, x1, BOOL32X4_TYPE); + Split(eq, if_true, if_false, fall_through); + } else if (String::Equals(check, factory->int16x8_string())) { + ASM_LOCATION("FullCodeGenerator::EmitLiteralCompareTypeof int16x8_string"); + __ JumpIfSmi(x0, if_false); + __ CompareObjectType(x0, x0, x1, INT16X8_TYPE); + Split(eq, if_true, if_false, fall_through); + } else if (String::Equals(check, factory->bool16x8_string())) { + ASM_LOCATION("FullCodeGenerator::EmitLiteralCompareTypeof bool16x8_string"); + __ JumpIfSmi(x0, if_false); + __ CompareObjectType(x0, x0, x1, BOOL16X8_TYPE); + Split(eq, if_true, if_false, fall_through); + } else if (String::Equals(check, factory->int8x16_string())) { + ASM_LOCATION("FullCodeGenerator::EmitLiteralCompareTypeof int8x16_string"); + __ JumpIfSmi(x0, if_false); + __ CompareObjectType(x0, x0, x1, INT8X16_TYPE); + Split(eq, if_true, if_false, fall_through); + } else if (String::Equals(check, factory->bool8x16_string())) { + ASM_LOCATION("FullCodeGenerator::EmitLiteralCompareTypeof bool8x16_string"); + __ JumpIfSmi(x0, if_false); + __ CompareObjectType(x0, x0, x1, BOOL8X16_TYPE); + Split(eq, if_true, if_false, fall_through); } else if (String::Equals(check, factory->boolean_string())) { ASM_LOCATION("FullCodeGenerator::EmitLiteralCompareTypeof boolean_string"); __ JumpIfRoot(x0, Heap::kTrueValueRootIndex, if_true); diff --git a/src/full-codegen/full-codegen.h b/src/full-codegen/full-codegen.h index d83712a56..c3ef66930 100644 --- a/src/full-codegen/full-codegen.h +++ b/src/full-codegen/full-codegen.h @@ -513,6 +513,7 @@ class FullCodeGenerator: public AstVisitor { F(IsFunction) \ F(IsUndetectableObject) \ F(IsSpecObject) \ + F(IsSimdObject) \ F(IsStringWrapperSafeForDefaultValueOf) \ F(MathPow) \ F(IsMinusZero) \ diff --git a/src/full-codegen/ia32/full-codegen-ia32.cc b/src/full-codegen/ia32/full-codegen-ia32.cc index 0d814d618..94d22699a 100644 --- a/src/full-codegen/ia32/full-codegen-ia32.cc +++ b/src/full-codegen/ia32/full-codegen-ia32.cc @@ -3322,6 +3322,32 @@ void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) { } +void FullCodeGenerator::EmitIsSimdObject(CallRuntime* expr) { + ZoneList* args = expr->arguments(); + DCHECK(args->length() == 1); + + VisitForAccumulatorValue(args->at(0)); + + Label materialize_true, materialize_false; + Label* if_true = NULL; + Label* if_false = NULL; + Label* fall_through = NULL; + context()->PrepareTest(&materialize_true, &materialize_false, &if_true, + &if_false, &fall_through); + + __ JumpIfSmi(eax, if_false); + Register map = ebx; + __ mov(map, FieldOperand(eax, HeapObject::kMapOffset)); + __ CmpInstanceType(map, FIRST_SIMD_VALUE_TYPE); + __ j(less, if_false); + __ CmpInstanceType(map, LAST_SIMD_VALUE_TYPE); + PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); + Split(less_equal, if_true, if_false, fall_through); + + context()->Plug(if_true, if_false); +} + + void FullCodeGenerator::EmitIsUndetectableObject(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 1); @@ -5015,6 +5041,30 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, __ JumpIfSmi(eax, if_false); __ CmpObjectType(eax, FLOAT32X4_TYPE, edx); Split(equal, if_true, if_false, fall_through); + } else if (String::Equals(check, factory->int32x4_string())) { + __ JumpIfSmi(eax, if_false); + __ CmpObjectType(eax, INT32X4_TYPE, edx); + Split(equal, if_true, if_false, fall_through); + } else if (String::Equals(check, factory->bool32x4_string())) { + __ JumpIfSmi(eax, if_false); + __ CmpObjectType(eax, BOOL32X4_TYPE, edx); + Split(equal, if_true, if_false, fall_through); + } else if (String::Equals(check, factory->int16x8_string())) { + __ JumpIfSmi(eax, if_false); + __ CmpObjectType(eax, INT16X8_TYPE, edx); + Split(equal, if_true, if_false, fall_through); + } else if (String::Equals(check, factory->bool16x8_string())) { + __ JumpIfSmi(eax, if_false); + __ CmpObjectType(eax, BOOL16X8_TYPE, edx); + Split(equal, if_true, if_false, fall_through); + } else if (String::Equals(check, factory->int8x16_string())) { + __ JumpIfSmi(eax, if_false); + __ CmpObjectType(eax, INT8X16_TYPE, edx); + Split(equal, if_true, if_false, fall_through); + } else if (String::Equals(check, factory->bool8x16_string())) { + __ JumpIfSmi(eax, if_false); + __ CmpObjectType(eax, BOOL8X16_TYPE, edx); + Split(equal, if_true, if_false, fall_through); } else if (String::Equals(check, factory->boolean_string())) { __ cmp(eax, isolate()->factory()->true_value()); __ j(equal, if_true); diff --git a/src/full-codegen/mips/full-codegen-mips.cc b/src/full-codegen/mips/full-codegen-mips.cc index 9e033e2d5..9fe4bbac1 100644 --- a/src/full-codegen/mips/full-codegen-mips.cc +++ b/src/full-codegen/mips/full-codegen-mips.cc @@ -3421,6 +3421,32 @@ void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) { } +void FullCodeGenerator::EmitIsSimdObject(CallRuntime* expr) { + ZoneList* args = expr->arguments(); + DCHECK(args->length() == 1); + + VisitForAccumulatorValue(args->at(0)); + + Label materialize_true, materialize_false; + Label* if_true = NULL; + Label* if_false = NULL; + Label* fall_through = NULL; + context()->PrepareTest(&materialize_true, &materialize_false, &if_true, + &if_false, &fall_through); + + __ JumpIfSmi(v0, if_false); + Register map = a1; + Register type_reg = a2; + __ GetObjectType(v0, map, type_reg); + __ Subu(type_reg, type_reg, Operand(FIRST_SIMD_VALUE_TYPE)); + PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); + Split(ls, type_reg, Operand(LAST_SIMD_VALUE_TYPE - FIRST_SIMD_VALUE_TYPE), + if_true, if_false, fall_through); + + context()->Plug(if_true, if_false); +} + + void FullCodeGenerator::EmitIsUndetectableObject(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 1); @@ -5107,6 +5133,30 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, __ JumpIfSmi(v0, if_false); __ GetObjectType(v0, v0, a1); Split(eq, a1, Operand(FLOAT32X4_TYPE), if_true, if_false, fall_through); + } else if (String::Equals(check, factory->int32x4_string())) { + __ JumpIfSmi(v0, if_false); + __ GetObjectType(v0, v0, a1); + Split(eq, a1, Operand(INT32X4_TYPE), if_true, if_false, fall_through); + } else if (String::Equals(check, factory->bool32x4_string())) { + __ JumpIfSmi(v0, if_false); + __ GetObjectType(v0, v0, a1); + Split(eq, a1, Operand(BOOL32X4_TYPE), if_true, if_false, fall_through); + } else if (String::Equals(check, factory->int16x8_string())) { + __ JumpIfSmi(v0, if_false); + __ GetObjectType(v0, v0, a1); + Split(eq, a1, Operand(INT16X8_TYPE), if_true, if_false, fall_through); + } else if (String::Equals(check, factory->bool16x8_string())) { + __ JumpIfSmi(v0, if_false); + __ GetObjectType(v0, v0, a1); + Split(eq, a1, Operand(BOOL16X8_TYPE), if_true, if_false, fall_through); + } else if (String::Equals(check, factory->int8x16_string())) { + __ JumpIfSmi(v0, if_false); + __ GetObjectType(v0, v0, a1); + Split(eq, a1, Operand(INT8X16_TYPE), if_true, if_false, fall_through); + } else if (String::Equals(check, factory->bool8x16_string())) { + __ JumpIfSmi(v0, if_false); + __ GetObjectType(v0, v0, a1); + Split(eq, a1, Operand(BOOL8X16_TYPE), if_true, if_false, fall_through); } else if (String::Equals(check, factory->boolean_string())) { __ LoadRoot(at, Heap::kTrueValueRootIndex); __ Branch(if_true, eq, v0, Operand(at)); diff --git a/src/full-codegen/mips64/full-codegen-mips64.cc b/src/full-codegen/mips64/full-codegen-mips64.cc index a1d8950fe..ac74e8d3e 100644 --- a/src/full-codegen/mips64/full-codegen-mips64.cc +++ b/src/full-codegen/mips64/full-codegen-mips64.cc @@ -3422,6 +3422,32 @@ void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) { } +void FullCodeGenerator::EmitIsSimdObject(CallRuntime* expr) { + ZoneList* args = expr->arguments(); + DCHECK(args->length() == 1); + + VisitForAccumulatorValue(args->at(0)); + + Label materialize_true, materialize_false; + Label* if_true = NULL; + Label* if_false = NULL; + Label* fall_through = NULL; + context()->PrepareTest(&materialize_true, &materialize_false, &if_true, + &if_false, &fall_through); + + __ JumpIfSmi(v0, if_false); + Register map = a1; + Register type_reg = a2; + __ GetObjectType(v0, map, type_reg); + __ Subu(type_reg, type_reg, Operand(FIRST_SIMD_VALUE_TYPE)); + PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); + Split(ls, type_reg, Operand(LAST_SIMD_VALUE_TYPE - FIRST_SIMD_VALUE_TYPE), + if_true, if_false, fall_through); + + context()->Plug(if_true, if_false); +} + + void FullCodeGenerator::EmitIsUndetectableObject(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 1); @@ -5109,6 +5135,30 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, __ JumpIfSmi(v0, if_false); __ GetObjectType(v0, v0, a1); Split(eq, a1, Operand(FLOAT32X4_TYPE), if_true, if_false, fall_through); + } else if (String::Equals(check, factory->int32x4_string())) { + __ JumpIfSmi(v0, if_false); + __ GetObjectType(v0, v0, a1); + Split(eq, a1, Operand(INT32X4_TYPE), if_true, if_false, fall_through); + } else if (String::Equals(check, factory->bool32x4_string())) { + __ JumpIfSmi(v0, if_false); + __ GetObjectType(v0, v0, a1); + Split(eq, a1, Operand(BOOL32X4_TYPE), if_true, if_false, fall_through); + } else if (String::Equals(check, factory->int16x8_string())) { + __ JumpIfSmi(v0, if_false); + __ GetObjectType(v0, v0, a1); + Split(eq, a1, Operand(INT16X8_TYPE), if_true, if_false, fall_through); + } else if (String::Equals(check, factory->bool16x8_string())) { + __ JumpIfSmi(v0, if_false); + __ GetObjectType(v0, v0, a1); + Split(eq, a1, Operand(BOOL16X8_TYPE), if_true, if_false, fall_through); + } else if (String::Equals(check, factory->int8x16_string())) { + __ JumpIfSmi(v0, if_false); + __ GetObjectType(v0, v0, a1); + Split(eq, a1, Operand(INT8X16_TYPE), if_true, if_false, fall_through); + } else if (String::Equals(check, factory->bool8x16_string())) { + __ JumpIfSmi(v0, if_false); + __ GetObjectType(v0, v0, a1); + Split(eq, a1, Operand(BOOL8X16_TYPE), if_true, if_false, fall_through); } else if (String::Equals(check, factory->boolean_string())) { __ LoadRoot(at, Heap::kTrueValueRootIndex); __ Branch(if_true, eq, v0, Operand(at)); diff --git a/src/full-codegen/ppc/full-codegen-ppc.cc b/src/full-codegen/ppc/full-codegen-ppc.cc index 7234e6abf..9c5c8f32d 100644 --- a/src/full-codegen/ppc/full-codegen-ppc.cc +++ b/src/full-codegen/ppc/full-codegen-ppc.cc @@ -3423,6 +3423,33 @@ void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) { } +void FullCodeGenerator::EmitIsSimdObject(CallRuntime* expr) { + ZoneList* args = expr->arguments(); + DCHECK(args->length() == 1); + + VisitForAccumulatorValue(args->at(0)); + + Label materialize_true, materialize_false; + Label* if_true = NULL; + Label* if_false = NULL; + Label* fall_through = NULL; + context()->PrepareTest(&materialize_true, &materialize_false, &if_true, + &if_false, &fall_through); + + __ JumpIfSmi(r3, if_false); + Register map = r4; + Register type_reg = r5; + __ LoadP(map, FieldMemOperand(r3, HeapObject::kMapOffset)); + __ lbz(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset)); + __ subi(type_reg, type_reg, Operand(FIRST_SIMD_VALUE_TYPE)); + __ cmpli(type_reg, Operand(LAST_SIMD_VALUE_TYPE - FIRST_SIMD_VALUE_TYPE)); + PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); + Split(le, if_true, if_false, fall_through); + + context()->Plug(if_true, if_false); +} + + void FullCodeGenerator::EmitIsUndetectableObject(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 1); @@ -5096,6 +5123,30 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, __ JumpIfSmi(r3, if_false); __ CompareObjectType(r3, r3, r4, FLOAT32X4_TYPE); Split(eq, if_true, if_false, fall_through); + } else if (String::Equals(check, factory->int32x4_string())) { + __ JumpIfSmi(r3, if_false); + __ CompareObjectType(r3, r3, r4, INT32X4_TYPE); + Split(eq, if_true, if_false, fall_through); + } else if (String::Equals(check, factory->bool32x4_string())) { + __ JumpIfSmi(r3, if_false); + __ CompareObjectType(r3, r3, r4, BOOL32X4_TYPE); + Split(eq, if_true, if_false, fall_through); + } else if (String::Equals(check, factory->int16x8_string())) { + __ JumpIfSmi(r3, if_false); + __ CompareObjectType(r3, r3, r4, INT16X8_TYPE); + Split(eq, if_true, if_false, fall_through); + } else if (String::Equals(check, factory->bool16x8_string())) { + __ JumpIfSmi(r3, if_false); + __ CompareObjectType(r3, r3, r4, BOOL16X8_TYPE); + Split(eq, if_true, if_false, fall_through); + } else if (String::Equals(check, factory->int8x16_string())) { + __ JumpIfSmi(r3, if_false); + __ CompareObjectType(r3, r3, r4, INT8X16_TYPE); + Split(eq, if_true, if_false, fall_through); + } else if (String::Equals(check, factory->bool8x16_string())) { + __ JumpIfSmi(r3, if_false); + __ CompareObjectType(r3, r3, r4, BOOL8X16_TYPE); + Split(eq, if_true, if_false, fall_through); } else if (String::Equals(check, factory->boolean_string())) { __ CompareRoot(r3, Heap::kTrueValueRootIndex); __ beq(if_true); diff --git a/src/full-codegen/x64/full-codegen-x64.cc b/src/full-codegen/x64/full-codegen-x64.cc index 377bf67ee..b5dc54eea 100644 --- a/src/full-codegen/x64/full-codegen-x64.cc +++ b/src/full-codegen/x64/full-codegen-x64.cc @@ -3315,6 +3315,32 @@ void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) { } +void FullCodeGenerator::EmitIsSimdObject(CallRuntime* expr) { + ZoneList* args = expr->arguments(); + DCHECK(args->length() == 1); + + VisitForAccumulatorValue(args->at(0)); + + Label materialize_true, materialize_false; + Label* if_true = NULL; + Label* if_false = NULL; + Label* fall_through = NULL; + context()->PrepareTest(&materialize_true, &materialize_false, &if_true, + &if_false, &fall_through); + + __ JumpIfSmi(rax, if_false); + Register map = rbx; + __ movp(map, FieldOperand(rax, HeapObject::kMapOffset)); + __ CmpInstanceType(map, FIRST_SIMD_VALUE_TYPE); + __ j(less, if_false); + __ CmpInstanceType(map, LAST_SIMD_VALUE_TYPE); + PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); + Split(less_equal, if_true, if_false, fall_through); + + context()->Plug(if_true, if_false); +} + + void FullCodeGenerator::EmitIsUndetectableObject(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 1); @@ -5033,6 +5059,30 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, __ JumpIfSmi(rax, if_false); __ CmpObjectType(rax, FLOAT32X4_TYPE, rdx); Split(equal, if_true, if_false, fall_through); + } else if (String::Equals(check, factory->int32x4_string())) { + __ JumpIfSmi(rax, if_false); + __ CmpObjectType(rax, INT32X4_TYPE, rdx); + Split(equal, if_true, if_false, fall_through); + } else if (String::Equals(check, factory->bool32x4_string())) { + __ JumpIfSmi(rax, if_false); + __ CmpObjectType(rax, BOOL32X4_TYPE, rdx); + Split(equal, if_true, if_false, fall_through); + } else if (String::Equals(check, factory->int16x8_string())) { + __ JumpIfSmi(rax, if_false); + __ CmpObjectType(rax, INT16X8_TYPE, rdx); + Split(equal, if_true, if_false, fall_through); + } else if (String::Equals(check, factory->bool16x8_string())) { + __ JumpIfSmi(rax, if_false); + __ CmpObjectType(rax, BOOL16X8_TYPE, rdx); + Split(equal, if_true, if_false, fall_through); + } else if (String::Equals(check, factory->int8x16_string())) { + __ JumpIfSmi(rax, if_false); + __ CmpObjectType(rax, INT8X16_TYPE, rdx); + Split(equal, if_true, if_false, fall_through); + } else if (String::Equals(check, factory->bool8x16_string())) { + __ JumpIfSmi(rax, if_false); + __ CmpObjectType(rax, BOOL8X16_TYPE, rdx); + Split(equal, if_true, if_false, fall_through); } else if (String::Equals(check, factory->boolean_string())) { __ CompareRoot(rax, Heap::kTrueValueRootIndex); __ j(equal, if_true); diff --git a/src/full-codegen/x87/full-codegen-x87.cc b/src/full-codegen/x87/full-codegen-x87.cc index dbe28ae75..198f8616d 100644 --- a/src/full-codegen/x87/full-codegen-x87.cc +++ b/src/full-codegen/x87/full-codegen-x87.cc @@ -3313,6 +3313,32 @@ void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) { } +void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) { + ZoneList* args = expr->arguments(); + DCHECK(args->length() == 1); + + VisitForAccumulatorValue(args->at(0)); + + Label materialize_true, materialize_false; + Label* if_true = NULL; + Label* if_false = NULL; + Label* fall_through = NULL; + context()->PrepareTest(&materialize_true, &materialize_false, &if_true, + &if_false, &fall_through); + + __ JumpIfSmi(eax, if_false); + Register map = ebx; + __ mov(map, FieldOperand(eax, HeapObject::kMapOffset)); + __ CmpInstanceType(map, FIRST_SIMD_VALUE_TYPE); + __ j(less, if_false); + __ CmpInstanceType(map, LAST_SIMD_VALUE_TYPE); + PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); + Split(less_equal, if_true, if_false, fall_through); + + context()->Plug(if_true, if_false); +} + + void FullCodeGenerator::EmitIsUndetectableObject(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 1); @@ -5006,6 +5032,30 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, __ JumpIfSmi(eax, if_false); __ CmpObjectType(eax, FLOAT32X4_TYPE, edx); Split(equal, if_true, if_false, fall_through); + } else if (String::Equals(check, factory->int32x4_string())) { + __ JumpIfSmi(eax, if_false); + __ CmpObjectType(eax, INT32X4_TYPE, edx); + Split(equal, if_true, if_false, fall_through); + } else if (String::Equals(check, factory->bool32x4_string())) { + __ JumpIfSmi(eax, if_false); + __ CmpObjectType(eax, BOOL32X4_TYPE, edx); + Split(equal, if_true, if_false, fall_through); + } else if (String::Equals(check, factory->int16x8_string())) { + __ JumpIfSmi(eax, if_false); + __ CmpObjectType(eax, INT16X8_TYPE, edx); + Split(equal, if_true, if_false, fall_through); + } else if (String::Equals(check, factory->bool16x8_string())) { + __ JumpIfSmi(eax, if_false); + __ CmpObjectType(eax, BOOL16X8_TYPE, edx); + Split(equal, if_true, if_false, fall_through); + } else if (String::Equals(check, factory->int8x16_string())) { + __ JumpIfSmi(eax, if_false); + __ CmpObjectType(eax, INT8X16_TYPE, edx); + Split(equal, if_true, if_false, fall_through); + } else if (String::Equals(check, factory->bool8x16_string())) { + __ JumpIfSmi(eax, if_false); + __ CmpObjectType(eax, BOOL8X16_TYPE, edx); + Split(equal, if_true, if_false, fall_through); } else if (String::Equals(check, factory->boolean_string())) { __ cmp(eax, isolate()->factory()->true_value()); __ j(equal, if_true); diff --git a/src/harmony-simd.js b/src/harmony-simd.js index a4378167d..5119adc92 100644 --- a/src/harmony-simd.js +++ b/src/harmony-simd.js @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -var $float32x4ToString; - (function(global, utils) { "use strict"; @@ -14,90 +12,276 @@ var $float32x4ToString; // Imports var GlobalSIMD = global.SIMD; -var GlobalFloat32x4 = GlobalSIMD.Float32x4; -//------------------------------------------------------------------- +macro SIMD_TYPES(FUNCTION) +FUNCTION(Float32x4, float32x4, 4) +FUNCTION(Int32x4, int32x4, 4) +FUNCTION(Bool32x4, bool32x4, 4) +FUNCTION(Int16x8, int16x8, 8) +FUNCTION(Bool16x8, bool16x8, 8) +FUNCTION(Int8x16, int8x16, 16) +FUNCTION(Bool8x16, bool8x16, 16) +endmacro -function Float32x4Constructor(x, y, z, w) { - if (%_IsConstructCall()) throw MakeTypeError(kNotConstructor, "Float32x4"); - if (!IS_NUMBER(x) || !IS_NUMBER(y) || !IS_NUMBER(z) || !IS_NUMBER(w)) { - throw MakeTypeError(kInvalidArgument); - } - return %CreateFloat32x4(x, y, z, w); -} +macro DECLARE_GLOBALS(NAME, TYPE, LANES) +var GlobalNAME = GlobalSIMD.NAME; +endmacro -function Float32x4Splat(s) { - return %CreateFloat32x4(s, s, s, s); -} +SIMD_TYPES(DECLARE_GLOBALS) -function Float32x4CheckJS(a) { - return %Float32x4Check(a); +macro DECLARE_COMMON_FUNCTIONS(NAME, TYPE, LANES) +function NAMECheckJS(a) { + return %NAMECheck(a); } -function Float32x4ToString() { - if (!(IS_FLOAT32X4(this) || IS_FLOAT32X4_WRAPPER(this))) { +function NAMEToString() { + if (typeof(this) !== 'TYPE' && %_ClassOf(this) !== 'NAME') { throw MakeTypeError(kIncompatibleMethodReceiver, - "Float32x4.prototype.toString", this); + "NAME.prototype.toString", this); } var value = %_ValueOf(this); - var w = GlobalFloat32x4.extractLane(value, 0), - x = GlobalFloat32x4.extractLane(value, 1), - y = GlobalFloat32x4.extractLane(value, 2), - z = GlobalFloat32x4.extractLane(value, 3); - return "SIMD.Float32x4(" + w + ", " + x + ", " + y + ", " + z + ")"; + var str = "SIMD.NAME("; + str += %NAMEExtractLane(value, 0); + for (var i = 1; i < LANES; i++) { + str += ", " + %NAMEExtractLane(value, i); + } + return str + ")"; } -function Float32x4ToLocaleString() { - if (!(IS_FLOAT32X4(this) || IS_FLOAT32X4_WRAPPER(this))) { +function NAMEToLocaleString() { + if (typeof(this) !== 'TYPE' && %_ClassOf(this) !== 'NAME') { throw MakeTypeError(kIncompatibleMethodReceiver, - "Float32x4.prototype.toLocaleString", this); + "NAME.prototype.toLocaleString", this); } var value = %_ValueOf(this); - var w = GlobalFloat32x4.extractLane(value, 0).toLocaleString(), - x = GlobalFloat32x4.extractLane(value, 1).toLocaleString(), - y = GlobalFloat32x4.extractLane(value, 2).toLocaleString(), - z = GlobalFloat32x4.extractLane(value, 3).toLocaleString(); - return "SIMD.Float32x4(" + w + ", " + x + ", " + y + ", " + z + ")"; + var str = "SIMD.NAME("; + str += %NAMEExtractLane(value, 0).toLocaleString(); + for (var i = 1; i < LANES; i++) { + str += ", " + %NAMEExtractLane(value, i).toLocaleString(); + } + return str + ")"; } -function Float32x4ValueOf() { - if (!(IS_FLOAT32X4(this) || IS_FLOAT32X4_WRAPPER(this))) { +function NAMEValueOf() { + if (typeof(this) !== 'TYPE' && %_ClassOf(this) !== 'NAME') { throw MakeTypeError(kIncompatibleMethodReceiver, - "Float32x4.prototype.valueOf", this); + "NAME.prototype.valueOf", this); } return %_ValueOf(this); } +function NAMEExtractLaneJS(instance, lane) { + return %NAMEExtractLane(instance, lane); +} +endmacro + +SIMD_TYPES(DECLARE_COMMON_FUNCTIONS) + +macro SIMD_NUMERIC_TYPES(FUNCTION) +FUNCTION(Float32x4) +FUNCTION(Int32x4) +FUNCTION(Int16x8) +FUNCTION(Int8x16) +endmacro + +macro DECLARE_NUMERIC_FUNCTIONS(NAME) +function NAMEReplaceLaneJS(instance, lane, value) { + return %NAMEReplaceLane(instance, lane, TO_NUMBER_INLINE(value)); +} +endmacro + +SIMD_NUMERIC_TYPES(DECLARE_NUMERIC_FUNCTIONS) + +macro SIMD_BOOL_TYPES(FUNCTION) +FUNCTION(Bool32x4) +FUNCTION(Bool16x8) +FUNCTION(Bool8x16) +endmacro + +macro DECLARE_BOOL_FUNCTIONS(NAME) +function NAMEReplaceLaneJS(instance, lane, value) { + return %NAMEReplaceLane(instance, lane, value); +} +endmacro + +SIMD_BOOL_TYPES(DECLARE_BOOL_FUNCTIONS) + +macro SIMD_UNSIGNED_INT_TYPES(FUNCTION) +FUNCTION(Int16x8) +FUNCTION(Int8x16) +endmacro + +macro DECLARE_UNSIGNED_INT_FUNCTIONS(NAME) +function NAMEUnsignedExtractLaneJS(instance, lane) { + return %NAMEUnsignedExtractLane(instance, lane); +} +endmacro + +SIMD_UNSIGNED_INT_TYPES(DECLARE_UNSIGNED_INT_FUNCTIONS) + //------------------------------------------------------------------- -function Float32x4ExtractLaneJS(value, lane) { - return %Float32x4ExtractLane(value, lane); +function Float32x4Constructor(c0, c1, c2, c3) { + if (%_IsConstructCall()) throw MakeTypeError(kNotConstructor, "Float32x4"); + return %CreateFloat32x4(TO_NUMBER_INLINE(c0), TO_NUMBER_INLINE(c1), + TO_NUMBER_INLINE(c2), TO_NUMBER_INLINE(c3)); +} + + +function Float32x4Splat(s) { + return %CreateFloat32x4(s, s, s, s); +} + + +function Int32x4Constructor(c0, c1, c2, c3) { + if (%_IsConstructCall()) throw MakeTypeError(kNotConstructor, "Int32x4"); + return %CreateInt32x4(TO_NUMBER_INLINE(c0), TO_NUMBER_INLINE(c1), + TO_NUMBER_INLINE(c2), TO_NUMBER_INLINE(c3)); +} + + +function Int32x4Splat(s) { + return %CreateInt32x4(s, s, s, s); +} + + +function Bool32x4Constructor(c0, c1, c2, c3) { + if (%_IsConstructCall()) throw MakeTypeError(kNotConstructor, "Bool32x4"); + return %CreateBool32x4(c0, c1, c2, c3); +} + + +function Bool32x4Splat(s) { + return %CreateBool32x4(s, s, s, s); +} + + +function Int16x8Constructor(c0, c1, c2, c3, c4, c5, c6, c7) { + if (%_IsConstructCall()) throw MakeTypeError(kNotConstructor, "Int16x8"); + return %CreateInt16x8(TO_NUMBER_INLINE(c0), TO_NUMBER_INLINE(c1), + TO_NUMBER_INLINE(c2), TO_NUMBER_INLINE(c3), + TO_NUMBER_INLINE(c4), TO_NUMBER_INLINE(c5), + TO_NUMBER_INLINE(c6), TO_NUMBER_INLINE(c7)); +} + + +function Int16x8Splat(s) { + return %CreateInt16x8(s, s, s, s, s, s, s, s); +} + + +function Bool16x8Constructor(c0, c1, c2, c3, c4, c5, c6, c7) { + if (%_IsConstructCall()) throw MakeTypeError(kNotConstructor, "Bool16x8"); + return %CreateBool16x8(c0, c1, c2, c3, c4, c5, c6, c7); +} + + +function Bool16x8Splat(s) { + return %CreateBool16x8(s, s, s, s, s, s, s, s); +} + + +function Int8x16Constructor(c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, + c12, c13, c14, c15) { + if (%_IsConstructCall()) throw MakeTypeError(kNotConstructor, "Int8x16"); + return %CreateInt8x16(TO_NUMBER_INLINE(c0), TO_NUMBER_INLINE(c1), + TO_NUMBER_INLINE(c2), TO_NUMBER_INLINE(c3), + TO_NUMBER_INLINE(c4), TO_NUMBER_INLINE(c5), + TO_NUMBER_INLINE(c6), TO_NUMBER_INLINE(c7), + TO_NUMBER_INLINE(c8), TO_NUMBER_INLINE(c9), + TO_NUMBER_INLINE(c10), TO_NUMBER_INLINE(c11), + TO_NUMBER_INLINE(c12), TO_NUMBER_INLINE(c13), + TO_NUMBER_INLINE(c14), TO_NUMBER_INLINE(c15)); +} + + +function Int8x16Splat(s) { + return %CreateInt8x16(s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s); +} + + +function Bool8x16Constructor(c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, + c12, c13, c14, c15) { + if (%_IsConstructCall()) throw MakeTypeError(kNotConstructor, "Bool8x16"); + return %CreateBool8x16(c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, + c13, c14, c15); +} + + +function Bool8x16Splat(s) { + return %CreateBool8x16(s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s); } -// ------------------------------------------------------------------- %AddNamedProperty(GlobalSIMD, symbolToStringTag, 'SIMD', READ_ONLY | DONT_ENUM); -%SetCode(GlobalFloat32x4, Float32x4Constructor); -%FunctionSetPrototype(GlobalFloat32x4, {}); -%AddNamedProperty( - GlobalFloat32x4.prototype, 'constructor', GlobalFloat32x4, DONT_ENUM); -%AddNamedProperty( - GlobalFloat32x4.prototype, symbolToStringTag, 'Float32x4', +macro SETUP_SIMD_TYPE(NAME, TYPE, LANES) +%SetCode(GlobalNAME, NAMEConstructor); +%FunctionSetPrototype(GlobalNAME, {}); +%AddNamedProperty(GlobalNAME.prototype, 'constructor', GlobalNAME, + DONT_ENUM); +%AddNamedProperty(GlobalNAME.prototype, symbolToStringTag, 'NAME', DONT_ENUM | READ_ONLY); - -utils.InstallFunctions(GlobalFloat32x4.prototype, DONT_ENUM, [ - 'toLocaleString', Float32x4ToLocaleString, - 'toString', Float32x4ToString, - 'valueOf', Float32x4ValueOf, +utils.InstallFunctions(GlobalNAME.prototype, DONT_ENUM, [ + 'toLocaleString', NAMEToLocaleString, + 'toString', NAMEToString, + 'valueOf', NAMEValueOf, ]); +endmacro + +SIMD_TYPES(SETUP_SIMD_TYPE) + +//------------------------------------------------------------------- utils.InstallFunctions(GlobalFloat32x4, DONT_ENUM, [ 'splat', Float32x4Splat, 'check', Float32x4CheckJS, 'extractLane', Float32x4ExtractLaneJS, + 'replaceLane', Float32x4ReplaceLaneJS, +]); + +utils.InstallFunctions(GlobalInt32x4, DONT_ENUM, [ + 'splat', Int32x4Splat, + 'check', Int32x4CheckJS, + 'extractLane', Int32x4ExtractLaneJS, + 'replaceLane', Int32x4ReplaceLaneJS, +]); + +utils.InstallFunctions(GlobalBool32x4, DONT_ENUM, [ + 'splat', Bool32x4Splat, + 'check', Bool32x4CheckJS, + 'extractLane', Bool32x4ExtractLaneJS, + 'replaceLane', Bool32x4ReplaceLaneJS, +]); + +utils.InstallFunctions(GlobalInt16x8, DONT_ENUM, [ + 'splat', Int16x8Splat, + 'check', Int16x8CheckJS, + 'extractLane', Int16x8ExtractLaneJS, + 'unsignedExtractLane', Int16x8UnsignedExtractLaneJS, + 'replaceLane', Int16x8ReplaceLaneJS, ]); -$float32x4ToString = Float32x4ToString; +utils.InstallFunctions(GlobalBool16x8, DONT_ENUM, [ + 'splat', Bool16x8Splat, + 'check', Bool16x8CheckJS, + 'extractLane', Bool16x8ExtractLaneJS, + 'replaceLane', Bool16x8ReplaceLaneJS, +]); + +utils.InstallFunctions(GlobalInt8x16, DONT_ENUM, [ + 'splat', Int8x16Splat, + 'check', Int8x16CheckJS, + 'extractLane', Int8x16ExtractLaneJS, + 'unsignedExtractLane', Int8x16UnsignedExtractLaneJS, + 'replaceLane', Int8x16ReplaceLaneJS, +]); + +utils.InstallFunctions(GlobalBool8x16, DONT_ENUM, [ + 'splat', Bool8x16Splat, + 'check', Bool8x16CheckJS, + 'extractLane', Bool8x16ExtractLaneJS, + 'replaceLane', Bool8x16ReplaceLaneJS, +]); }) diff --git a/src/heap-snapshot-generator.cc b/src/heap-snapshot-generator.cc index 693361ce0..a4c3f1147 100644 --- a/src/heap-snapshot-generator.cc +++ b/src/heap-snapshot-generator.cc @@ -861,7 +861,7 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object) { return AddEntry(object, HeapEntry::kArray, ""); } else if (object->IsHeapNumber()) { return AddEntry(object, HeapEntry::kHeapNumber, "number"); - } else if (object->IsFloat32x4()) { + } else if (object->IsSimd128Value()) { return AddEntry(object, HeapEntry::kSimdValue, "simd"); } return AddEntry(object, HeapEntry::kHidden, GetSystemEntryName(object)); diff --git a/src/heap/heap.cc b/src/heap/heap.cc index dc82f8a78..4f5a064cc 100644 --- a/src/heap/heap.cc +++ b/src/heap/heap.cc @@ -2974,6 +2974,12 @@ bool Heap::CreateInitialMaps() { ALLOCATE_MAP(MUTABLE_HEAP_NUMBER_TYPE, HeapNumber::kSize, mutable_heap_number) ALLOCATE_MAP(FLOAT32X4_TYPE, Float32x4::kSize, float32x4) + ALLOCATE_MAP(INT32X4_TYPE, Int32x4::kSize, int32x4) + ALLOCATE_MAP(BOOL32X4_TYPE, Bool32x4::kSize, bool32x4) + ALLOCATE_MAP(INT16X8_TYPE, Int16x8::kSize, int16x8) + ALLOCATE_MAP(BOOL16X8_TYPE, Bool16x8::kSize, bool16x8) + ALLOCATE_MAP(INT8X16_TYPE, Int8x16::kSize, int8x16) + ALLOCATE_MAP(BOOL8X16_TYPE, Bool8x16::kSize, bool8x16) ALLOCATE_MAP(SYMBOL_TYPE, Symbol::kSize, symbol) ALLOCATE_MAP(FOREIGN_TYPE, Foreign::kSize, foreign) @@ -3113,31 +3119,30 @@ AllocationResult Heap::AllocateHeapNumber(double value, MutableMode mode, return result; } - -AllocationResult Heap::AllocateFloat32x4(float w, float x, float y, float z, - PretenureFlag pretenure) { - // Statically ensure that it is safe to allocate SIMD values in paged - // spaces. - int size = Float32x4::kSize; - STATIC_ASSERT(Float32x4::kSize <= Page::kMaxRegularHeapObjectSize); - - AllocationSpace space = SelectSpace(size, pretenure); - - HeapObject* result; - { - AllocationResult allocation = - AllocateRaw(size, space, OLD_SPACE, kSimd128Unaligned); - if (!allocation.To(&result)) return allocation; - } - - result->set_map_no_write_barrier(float32x4_map()); - Float32x4* float32x4 = Float32x4::cast(result); - float32x4->set_lane(0, w); - float32x4->set_lane(1, x); - float32x4->set_lane(2, y); - float32x4->set_lane(3, z); - return result; -} +#define SIMD_ALLOCATE_DEFINITION(type, type_name, lane_count, lane_type) \ + AllocationResult Heap::Allocate##type(lane_type lanes[lane_count], \ + PretenureFlag pretenure) { \ + int size = type::kSize; \ + STATIC_ASSERT(type::kSize <= Page::kMaxRegularHeapObjectSize); \ + \ + AllocationSpace space = SelectSpace(size, pretenure); \ + \ + HeapObject* result; \ + { \ + AllocationResult allocation = \ + AllocateRaw(size, space, OLD_SPACE, kSimd128Unaligned); \ + if (!allocation.To(&result)) return allocation; \ + } \ + \ + result->set_map_no_write_barrier(type_name##_map()); \ + type* instance = type::cast(result); \ + for (int i = 0; i < lane_count; i++) { \ + instance->set_lane(i, lanes[i]); \ + } \ + return result; \ + } + +SIMD128_TYPES(SIMD_ALLOCATE_DEFINITION) AllocationResult Heap::AllocateCell(Object* value) { diff --git a/src/heap/heap.h b/src/heap/heap.h index 17e4074b1..089fe7878 100644 --- a/src/heap/heap.h +++ b/src/heap/heap.h @@ -48,6 +48,12 @@ namespace internal { V(Map, heap_number_map, HeapNumberMap) \ V(Map, mutable_heap_number_map, MutableHeapNumberMap) \ V(Map, float32x4_map, Float32x4Map) \ + V(Map, int32x4_map, Int32x4Map) \ + V(Map, bool32x4_map, Bool32x4Map) \ + V(Map, int16x8_map, Int16x8Map) \ + V(Map, bool16x8_map, Bool16x8Map) \ + V(Map, int8x16_map, Int8x16Map) \ + V(Map, bool8x16_map, Bool8x16Map) \ V(Map, native_context_map, NativeContextMap) \ V(Map, fixed_array_map, FixedArrayMap) \ V(Map, code_map, CodeMap) \ @@ -213,6 +219,18 @@ namespace internal { V(eval_string, "eval") \ V(float32x4_string, "float32x4") \ V(Float32x4_string, "Float32x4") \ + V(int32x4_string, "int32x4") \ + V(Int32x4_string, "Int32x4") \ + V(bool32x4_string, "bool32x4") \ + V(Bool32x4_string, "Bool32x4") \ + V(int16x8_string, "int16x8") \ + V(Int16x8_string, "Int16x8") \ + V(bool16x8_string, "bool16x8") \ + V(Bool16x8_string, "Bool16x8") \ + V(int8x16_string, "int8x16") \ + V(Int8x16_string, "Int8x16") \ + V(bool8x16_string, "bool8x16") \ + V(Bool8x16_string, "Bool8x16") \ V(function_string, "function") \ V(Function_string, "Function") \ V(length_string, "length") \ @@ -338,6 +356,12 @@ namespace internal { V(HeapNumberMap) \ V(MutableHeapNumberMap) \ V(Float32x4Map) \ + V(Int32x4Map) \ + V(Bool32x4Map) \ + V(Int16x8Map) \ + V(Bool16x8Map) \ + V(Int8x16Map) \ + V(Bool8x16Map) \ V(NativeContextMap) \ V(FixedArrayMap) \ V(CodeMap) \ @@ -1647,10 +1671,12 @@ class Heap { AllocateHeapNumber(double value, MutableMode mode = IMMUTABLE, PretenureFlag pretenure = NOT_TENURED); - // Allocates a Float32x4 from the given lane values. - MUST_USE_RESULT AllocationResult - AllocateFloat32x4(float w, float x, float y, float z, - PretenureFlag pretenure = NOT_TENURED); +// Allocates SIMD values from the given lane values. +#define SIMD_ALLOCATE_DECLARATION(type, type_name, lane_count, lane_type) \ + AllocationResult Allocate##type(lane_type lanes[lane_count], \ + PretenureFlag pretenure = NOT_TENURED); + + SIMD128_TYPES(SIMD_ALLOCATE_DECLARATION) // Allocates a byte array of the specified length MUST_USE_RESULT AllocationResult diff --git a/src/heap/objects-visiting.cc b/src/heap/objects-visiting.cc index 70f26a504..0e2cba0e2 100644 --- a/src/heap/objects-visiting.cc +++ b/src/heap/objects-visiting.cc @@ -139,6 +139,12 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId( case HEAP_NUMBER_TYPE: case MUTABLE_HEAP_NUMBER_TYPE: case FLOAT32X4_TYPE: + case INT32X4_TYPE: + case BOOL32X4_TYPE: + case INT16X8_TYPE: + case BOOL16X8_TYPE: + case INT8X16_TYPE: + case BOOL8X16_TYPE: return GetVisitorIdForSize(kVisitDataObject, kVisitDataObjectGeneric, instance_size, has_unboxed_fields); diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc index 2586da9be..2e9475542 100644 --- a/src/hydrogen-instructions.cc +++ b/src/hydrogen-instructions.cc @@ -1328,6 +1328,18 @@ static String* TypeOfString(HConstant* constant, Isolate* isolate) { return heap->symbol_string(); case FLOAT32X4_TYPE: return heap->float32x4_string(); + case INT32X4_TYPE: + return heap->int32x4_string(); + case BOOL32X4_TYPE: + return heap->bool32x4_string(); + case INT16X8_TYPE: + return heap->int16x8_string(); + case BOOL16X8_TYPE: + return heap->bool16x8_string(); + case INT8X16_TYPE: + return heap->int8x16_string(); + case BOOL8X16_TYPE: + return heap->bool8x16_string(); case JS_FUNCTION_TYPE: case JS_FUNCTION_PROXY_TYPE: return heap->function_string(); diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc index bf2630b94..026a310b0 100644 --- a/src/ia32/code-stubs-ia32.cc +++ b/src/ia32/code-stubs-ia32.cc @@ -1694,6 +1694,7 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) { Immediate(isolate()->factory()->heap_number_map())); __ j(equal, &generic_heap_number_comparison, Label::kNear); if (cc != equal) { + Label not_simd; __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); // Call runtime on identical JSObjects. Otherwise return equal. @@ -1703,8 +1704,11 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) { __ cmpb(ecx, static_cast(SYMBOL_TYPE)); __ j(equal, &runtime_call, Label::kFar); // Call runtime on identical SIMD values since we must throw a TypeError. - __ cmpb(ecx, static_cast(FLOAT32X4_TYPE)); - __ j(equal, &runtime_call, Label::kFar); + __ cmpb(ecx, static_cast(FIRST_SIMD_VALUE_TYPE)); + __ j(less, ¬_simd, Label::kFar); + __ cmpb(ecx, static_cast(LAST_SIMD_VALUE_TYPE)); + __ j(less_equal, &runtime_call, Label::kFar); + __ bind(¬_simd); if (is_strong(strength())) { // We have already tested for smis and heap numbers, so if both // arguments are not strings we must proceed to the slow case. diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index 8b528d152..ab3426ed9 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc @@ -2170,8 +2170,12 @@ void LCodeGen::DoBranch(LBranch* instr) { if (expected.Contains(ToBooleanStub::SIMD_VALUE)) { // SIMD value -> true. - __ CmpInstanceType(map, FLOAT32X4_TYPE); - __ j(equal, instr->TrueLabel(chunk_)); + Label not_simd; + __ CmpInstanceType(map, FIRST_SIMD_VALUE_TYPE); + __ j(less, ¬_simd, Label::kNear); + __ CmpInstanceType(map, LAST_SIMD_VALUE_TYPE); + __ j(less_equal, instr->TrueLabel(chunk_)); + __ bind(¬_simd); } if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) { @@ -5544,6 +5548,36 @@ Condition LCodeGen::EmitTypeofIs(LTypeofIsAndBranch* instr, Register input) { __ CmpObjectType(input, FLOAT32X4_TYPE, input); final_branch_condition = equal; + } else if (String::Equals(type_name, factory()->int32x4_string())) { + __ JumpIfSmi(input, false_label, false_distance); + __ CmpObjectType(input, INT32X4_TYPE, input); + final_branch_condition = equal; + + } else if (String::Equals(type_name, factory()->bool32x4_string())) { + __ JumpIfSmi(input, false_label, false_distance); + __ CmpObjectType(input, BOOL32X4_TYPE, input); + final_branch_condition = equal; + + } else if (String::Equals(type_name, factory()->int16x8_string())) { + __ JumpIfSmi(input, false_label, false_distance); + __ CmpObjectType(input, INT16X8_TYPE, input); + final_branch_condition = equal; + + } else if (String::Equals(type_name, factory()->bool16x8_string())) { + __ JumpIfSmi(input, false_label, false_distance); + __ CmpObjectType(input, BOOL16X8_TYPE, input); + final_branch_condition = equal; + + } else if (String::Equals(type_name, factory()->int8x16_string())) { + __ JumpIfSmi(input, false_label, false_distance); + __ CmpObjectType(input, INT8X16_TYPE, input); + final_branch_condition = equal; + + } else if (String::Equals(type_name, factory()->bool8x16_string())) { + __ JumpIfSmi(input, false_label, false_distance); + __ CmpObjectType(input, BOOL8X16_TYPE, input); + final_branch_condition = equal; + } else { __ jmp(false_label, false_distance); } diff --git a/src/ic/handler-compiler.cc b/src/ic/handler-compiler.cc index c7220afe1..c37df961d 100644 --- a/src/ic/handler-compiler.cc +++ b/src/ic/handler-compiler.cc @@ -109,6 +109,18 @@ Register NamedLoadHandlerCompiler::FrontendHeader(Register object_reg, function_index = Context::NUMBER_FUNCTION_INDEX; } else if (map()->instance_type() == FLOAT32X4_TYPE) { function_index = Context::FLOAT32X4_FUNCTION_INDEX; + } else if (map()->instance_type() == INT32X4_TYPE) { + function_index = Context::INT32X4_FUNCTION_INDEX; + } else if (map()->instance_type() == BOOL32X4_TYPE) { + function_index = Context::BOOL32X4_FUNCTION_INDEX; + } else if (map()->instance_type() == INT16X8_TYPE) { + function_index = Context::INT16X8_FUNCTION_INDEX; + } else if (map()->instance_type() == BOOL16X8_TYPE) { + function_index = Context::BOOL16X8_FUNCTION_INDEX; + } else if (map()->instance_type() == INT8X16_TYPE) { + function_index = Context::INT8X16_FUNCTION_INDEX; + } else if (map()->instance_type() == BOOL8X16_TYPE) { + function_index = Context::BOOL8X16_FUNCTION_INDEX; } else if (*map() == isolate()->heap()->boolean_map()) { function_index = Context::BOOLEAN_FUNCTION_INDEX; } else { diff --git a/src/ic/ic-inl.h b/src/ic/ic-inl.h index f123595dd..626748a80 100644 --- a/src/ic/ic-inl.h +++ b/src/ic/ic-inl.h @@ -138,6 +138,18 @@ JSFunction* IC::GetRootConstructor(Map* receiver_map, Context* native_context) { return native_context->symbol_function(); } else if (receiver_map->instance_type() == FLOAT32X4_TYPE) { return native_context->float32x4_function(); + } else if (receiver_map->instance_type() == INT32X4_TYPE) { + return native_context->int32x4_function(); + } else if (receiver_map->instance_type() == BOOL32X4_TYPE) { + return native_context->bool32x4_function(); + } else if (receiver_map->instance_type() == INT16X8_TYPE) { + return native_context->int16x8_function(); + } else if (receiver_map->instance_type() == BOOL16X8_TYPE) { + return native_context->bool16x8_function(); + } else if (receiver_map->instance_type() == INT8X16_TYPE) { + return native_context->int8x16_function(); + } else if (receiver_map->instance_type() == BOOL8X16_TYPE) { + return native_context->bool8x16_function(); } else { return NULL; } diff --git a/src/macros.py b/src/macros.py index de5fe8bfa..757d59fc4 100644 --- a/src/macros.py +++ b/src/macros.py @@ -90,7 +90,6 @@ macro IS_NULL(arg) = (arg === null); macro IS_NULL_OR_UNDEFINED(arg) = (arg == null); macro IS_UNDEFINED(arg) = (arg === (void 0)); macro IS_NUMBER(arg) = (typeof(arg) === 'number'); -macro IS_FLOAT32X4(arg) = (typeof(arg) === 'float32x4'); macro IS_STRING(arg) = (typeof(arg) === 'string'); macro IS_BOOLEAN(arg) = (typeof(arg) === 'boolean'); macro IS_SYMBOL(arg) = (typeof(arg) === 'symbol'); @@ -99,12 +98,12 @@ macro IS_ARRAY(arg) = (%_IsArray(arg)); macro IS_DATE(arg) = (%_IsDate(arg)); macro IS_FUNCTION(arg) = (%_IsFunction(arg)); macro IS_REGEXP(arg) = (%_IsRegExp(arg)); +macro IS_SIMD_OBJECT(arg) = (%_IsSimdObject(arg)); macro IS_SET(arg) = (%_ClassOf(arg) === 'Set'); macro IS_MAP(arg) = (%_ClassOf(arg) === 'Map'); macro IS_WEAKMAP(arg) = (%_ClassOf(arg) === 'WeakMap'); macro IS_WEAKSET(arg) = (%_ClassOf(arg) === 'WeakSet'); macro IS_NUMBER_WRAPPER(arg) = (%_ClassOf(arg) === 'Number'); -macro IS_FLOAT32X4_WRAPPER(arg) = (%_ClassOf(arg) === 'Float32x4'); macro IS_STRING_WRAPPER(arg) = (%_ClassOf(arg) === 'String'); macro IS_SYMBOL_WRAPPER(arg) = (%_ClassOf(arg) === 'Symbol'); macro IS_BOOLEAN_WRAPPER(arg) = (%_ClassOf(arg) === 'Boolean'); diff --git a/src/messages.js b/src/messages.js index 3829eda26..2101f79b9 100644 --- a/src/messages.js +++ b/src/messages.js @@ -86,7 +86,17 @@ function NoSideEffectToString(obj) { return str; } if (IS_SYMBOL(obj)) return %_CallFunction(obj, $symbolToString); - if (IS_FLOAT32X4(obj)) return %_CallFunction(obj, $float32x4ToString); + if (IS_SIMD_OBJECT(obj)) { + switch (typeof(obj)) { + case 'float32x4': return %_CallFunction(obj, $float32x4ToString); + case 'int32x4': return %_CallFunction(obj, $int32x4ToString); + case 'bool32x4': return %_CallFunction(obj, $bool32x4ToString); + case 'int16x8': return %_CallFunction(obj, $int16x8ToString); + case 'bool16x8': return %_CallFunction(obj, $bool16x8ToString); + case 'int16x8': return %_CallFunction(obj, $int16x8ToString); + case 'bool16x8': return %_CallFunction(obj, $bool16x8ToString); + } + } if (IS_OBJECT(obj) && %GetDataProperty(obj, "toString") === ObjectToString) { var constructor = %GetDataProperty(obj, "constructor"); diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc index daff32fe9..70df019ca 100644 --- a/src/mips/code-stubs-mips.cc +++ b/src/mips/code-stubs-mips.cc @@ -291,12 +291,15 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow, // Smis. If it's not a heap number, then return equal. __ GetObjectType(a0, t4, t4); if (cc == less || cc == greater) { + Label not_simd; // Call runtime on identical JSObjects. __ Branch(slow, greater, t4, Operand(FIRST_SPEC_OBJECT_TYPE)); // Call runtime on identical symbols since we need to throw a TypeError. __ Branch(slow, eq, t4, Operand(SYMBOL_TYPE)); // Call runtime on identical SIMD values since we must throw a TypeError. - __ Branch(slow, eq, t4, Operand(FLOAT32X4_TYPE)); + __ Branch(¬_simd, lt, t4, Operand(FIRST_SIMD_VALUE_TYPE)); + __ Branch(slow, le, t4, Operand(LAST_SIMD_VALUE_TYPE)); + __ bind(¬_simd); if (is_strong(strength)) { // Call the runtime on anything that is converted in the semantics, since // we need to throw a TypeError. Smis have already been ruled out. @@ -305,6 +308,7 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow, __ Branch(slow, ne, t4, Operand(zero_reg)); } } else { + Label not_simd; __ Branch(&heap_number, eq, t4, Operand(HEAP_NUMBER_TYPE)); // Comparing JS objects with <=, >= is complicated. if (cc != eq) { @@ -312,7 +316,9 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow, // Call runtime on identical symbols since we need to throw a TypeError. __ Branch(slow, eq, t4, Operand(SYMBOL_TYPE)); // Call runtime on identical SIMD values since we must throw a TypeError. - __ Branch(slow, eq, t4, Operand(FLOAT32X4_TYPE)); + __ Branch(¬_simd, lt, t4, Operand(FIRST_SIMD_VALUE_TYPE)); + __ Branch(slow, le, t4, Operand(LAST_SIMD_VALUE_TYPE)); + __ bind(¬_simd); if (is_strong(strength)) { // Call the runtime on anything that is converted in the semantics, // since we need to throw a TypeError. Smis and heap numbers have diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc index d6af3267c..88adcd421 100644 --- a/src/mips/lithium-codegen-mips.cc +++ b/src/mips/lithium-codegen-mips.cc @@ -2183,10 +2183,13 @@ void LCodeGen::DoBranch(LBranch* instr) { if (expected.Contains(ToBooleanStub::SIMD_VALUE)) { // SIMD value -> true. + Label not_simd; const Register scratch = scratch1(); __ lbu(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset)); - __ Branch(instr->TrueLabel(chunk_), eq, scratch, - Operand(FLOAT32X4_TYPE)); + __ Branch(¬_simd, lt, at, Operand(FIRST_SIMD_VALUE_TYPE)); + __ Branch(instr->TrueLabel(chunk_), le, scratch, + Operand(LAST_SIMD_VALUE_TYPE)); + __ bind(¬_simd); } if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) { @@ -5748,6 +5751,48 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, *cmp2 = Operand(FLOAT32X4_TYPE); final_branch_condition = eq; + } else if (String::Equals(type_name, factory->int32x4_string())) { + __ JumpIfSmi(input, false_label); + __ GetObjectType(input, input, scratch); + *cmp1 = scratch; + *cmp2 = Operand(INT32X4_TYPE); + final_branch_condition = eq; + + } else if (String::Equals(type_name, factory->bool32x4_string())) { + __ JumpIfSmi(input, false_label); + __ GetObjectType(input, input, scratch); + *cmp1 = scratch; + *cmp2 = Operand(BOOL32X4_TYPE); + final_branch_condition = eq; + + } else if (String::Equals(type_name, factory->int16x8_string())) { + __ JumpIfSmi(input, false_label); + __ GetObjectType(input, input, scratch); + *cmp1 = scratch; + *cmp2 = Operand(INT16X8_TYPE); + final_branch_condition = eq; + + } else if (String::Equals(type_name, factory->bool16x8_string())) { + __ JumpIfSmi(input, false_label); + __ GetObjectType(input, input, scratch); + *cmp1 = scratch; + *cmp2 = Operand(BOOL16X8_TYPE); + final_branch_condition = eq; + + } else if (String::Equals(type_name, factory->int8x16_string())) { + __ JumpIfSmi(input, false_label); + __ GetObjectType(input, input, scratch); + *cmp1 = scratch; + *cmp2 = Operand(INT8X16_TYPE); + final_branch_condition = eq; + + } else if (String::Equals(type_name, factory->bool8x16_string())) { + __ JumpIfSmi(input, false_label); + __ GetObjectType(input, input, scratch); + *cmp1 = scratch; + *cmp2 = Operand(BOOL8X16_TYPE); + final_branch_condition = eq; + } else { *cmp1 = at; *cmp2 = Operand(zero_reg); // Set to valid regs, to avoid caller assertion. diff --git a/src/mips64/code-stubs-mips64.cc b/src/mips64/code-stubs-mips64.cc index 8b46e4c72..59d36c5fb 100644 --- a/src/mips64/code-stubs-mips64.cc +++ b/src/mips64/code-stubs-mips64.cc @@ -287,12 +287,15 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow, // Smis. If it's not a heap number, then return equal. __ GetObjectType(a0, t0, t0); if (cc == less || cc == greater) { + Label not_simd; // Call runtime on identical JSObjects. __ Branch(slow, greater, t0, Operand(FIRST_SPEC_OBJECT_TYPE)); // Call runtime on identical symbols since we need to throw a TypeError. __ Branch(slow, eq, t0, Operand(SYMBOL_TYPE)); // Call runtime on identical SIMD values since we must throw a TypeError. - __ Branch(slow, eq, t0, Operand(FLOAT32X4_TYPE)); + __ Branch(¬_simd, lt, t0, Operand(FIRST_SIMD_VALUE_TYPE)); + __ Branch(slow, le, t0, Operand(LAST_SIMD_VALUE_TYPE)); + __ bind(¬_simd); if (is_strong(strength)) { // Call the runtime on anything that is converted in the semantics, since // we need to throw a TypeError. Smis have already been ruled out. @@ -304,18 +307,21 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow, __ Branch(&heap_number, eq, t0, Operand(HEAP_NUMBER_TYPE)); // Comparing JS objects with <=, >= is complicated. if (cc != eq) { - __ Branch(slow, greater, t0, Operand(FIRST_SPEC_OBJECT_TYPE)); - // Call runtime on identical symbols since we need to throw a TypeError. - __ Branch(slow, eq, t0, Operand(SYMBOL_TYPE)); - // Call runtime on identical SIMD values since we must throw a TypeError. - __ Branch(slow, eq, t0, Operand(FLOAT32X4_TYPE)); - if (is_strong(strength)) { - // Call the runtime on anything that is converted in the semantics, - // since we need to throw a TypeError. Smis and heap numbers have - // already been ruled out. - __ And(t0, t0, Operand(kIsNotStringMask)); - __ Branch(slow, ne, t0, Operand(zero_reg)); - } + Label not_simd; + __ Branch(slow, greater, t0, Operand(FIRST_SPEC_OBJECT_TYPE)); + // Call runtime on identical symbols since we need to throw a TypeError. + __ Branch(slow, eq, t0, Operand(SYMBOL_TYPE)); + // Call runtime on identical SIMD values since we must throw a TypeError. + __ Branch(¬_simd, lt, t0, Operand(FIRST_SIMD_VALUE_TYPE)); + __ Branch(slow, le, t0, Operand(LAST_SIMD_VALUE_TYPE)); + __ bind(¬_simd); + if (is_strong(strength)) { + // Call the runtime on anything that is converted in the semantics, + // since we need to throw a TypeError. Smis and heap numbers have + // already been ruled out. + __ And(t0, t0, Operand(kIsNotStringMask)); + __ Branch(slow, ne, t0, Operand(zero_reg)); + } // Normally here we fall through to return_equal, but undefined is // special: (undefined == undefined) == true, but // (undefined <= undefined) == false! See ECMAScript 11.8.5. diff --git a/src/mips64/lithium-codegen-mips64.cc b/src/mips64/lithium-codegen-mips64.cc index 15105aa73..fe8ee01ee 100644 --- a/src/mips64/lithium-codegen-mips64.cc +++ b/src/mips64/lithium-codegen-mips64.cc @@ -2283,11 +2283,14 @@ void LCodeGen::DoBranch(LBranch* instr) { } if (expected.Contains(ToBooleanStub::SIMD_VALUE)) { - // Symbol value -> true. + // SIMD value -> true. + Label not_simd; const Register scratch = scratch1(); __ lbu(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset)); - __ Branch(instr->TrueLabel(chunk_), eq, scratch, - Operand(FLOAT32X4_TYPE)); + __ Branch(¬_simd, lt, at, Operand(FIRST_SIMD_VALUE_TYPE)); + __ Branch(instr->TrueLabel(chunk_), le, scratch, + Operand(LAST_SIMD_VALUE_TYPE)); + __ bind(¬_simd); } if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) { @@ -5882,6 +5885,48 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, *cmp2 = Operand(FLOAT32X4_TYPE); final_branch_condition = eq; + } else if (String::Equals(type_name, factory->int32x4_string())) { + __ JumpIfSmi(input, false_label); + __ GetObjectType(input, input, scratch); + *cmp1 = scratch; + *cmp2 = Operand(INT32X4_TYPE); + final_branch_condition = eq; + + } else if (String::Equals(type_name, factory->bool32x4_string())) { + __ JumpIfSmi(input, false_label); + __ GetObjectType(input, input, scratch); + *cmp1 = scratch; + *cmp2 = Operand(BOOL32X4_TYPE); + final_branch_condition = eq; + + } else if (String::Equals(type_name, factory->int16x8_string())) { + __ JumpIfSmi(input, false_label); + __ GetObjectType(input, input, scratch); + *cmp1 = scratch; + *cmp2 = Operand(INT16X8_TYPE); + final_branch_condition = eq; + + } else if (String::Equals(type_name, factory->bool16x8_string())) { + __ JumpIfSmi(input, false_label); + __ GetObjectType(input, input, scratch); + *cmp1 = scratch; + *cmp2 = Operand(BOOL16X8_TYPE); + final_branch_condition = eq; + + } else if (String::Equals(type_name, factory->int8x16_string())) { + __ JumpIfSmi(input, false_label); + __ GetObjectType(input, input, scratch); + *cmp1 = scratch; + *cmp2 = Operand(INT8X16_TYPE); + final_branch_condition = eq; + + } else if (String::Equals(type_name, factory->bool8x16_string())) { + __ JumpIfSmi(input, false_label); + __ GetObjectType(input, input, scratch); + *cmp1 = scratch; + *cmp2 = Operand(BOOL8X16_TYPE); + final_branch_condition = eq; + } else if (String::Equals(type_name, factory->boolean_string())) { __ LoadRoot(at, Heap::kTrueValueRootIndex); __ Branch(USE_DELAY_SLOT, true_label, eq, at, Operand(input)); diff --git a/src/objects-debug.cc b/src/objects-debug.cc index 3a2ec3e55..d2e66189d 100644 --- a/src/objects-debug.cc +++ b/src/objects-debug.cc @@ -61,6 +61,24 @@ void HeapObject::HeapObjectVerify() { case FLOAT32X4_TYPE: Float32x4::cast(this)->Float32x4Verify(); break; + case INT32X4_TYPE: + Int32x4::cast(this)->Int32x4Verify(); + break; + case BOOL32X4_TYPE: + Bool32x4::cast(this)->Bool32x4Verify(); + break; + case INT16X8_TYPE: + Int16x8::cast(this)->Int16x8Verify(); + break; + case BOOL16X8_TYPE: + Bool16x8::cast(this)->Bool16x8Verify(); + break; + case INT8X16_TYPE: + Int8x16::cast(this)->Int8x16Verify(); + break; + case BOOL8X16_TYPE: + Bool8x16::cast(this)->Bool8x16Verify(); + break; case FIXED_ARRAY_TYPE: FixedArray::cast(this)->FixedArrayVerify(); break; @@ -217,6 +235,24 @@ void HeapNumber::HeapNumberVerify() { void Float32x4::Float32x4Verify() { CHECK(IsFloat32x4()); } +void Int32x4::Int32x4Verify() { CHECK(IsInt32x4()); } + + +void Bool32x4::Bool32x4Verify() { CHECK(IsBool32x4()); } + + +void Int16x8::Int16x8Verify() { CHECK(IsInt16x8()); } + + +void Bool16x8::Bool16x8Verify() { CHECK(IsBool16x8()); } + + +void Int8x16::Int8x16Verify() { CHECK(IsInt8x16()); } + + +void Bool8x16::Bool8x16Verify() { CHECK(IsBool8x16()); } + + void ByteArray::ByteArrayVerify() { CHECK(IsByteArray()); } diff --git a/src/objects-inl.h b/src/objects-inl.h index 4929c0d2d..544c66a4c 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -168,10 +168,26 @@ bool Object::IsHeapObject() const { TYPE_CHECKER(HeapNumber, HEAP_NUMBER_TYPE) TYPE_CHECKER(MutableHeapNumber, MUTABLE_HEAP_NUMBER_TYPE) -TYPE_CHECKER(Float32x4, FLOAT32X4_TYPE) TYPE_CHECKER(Symbol, SYMBOL_TYPE) +bool Object::IsSimd128Value() const { + if (!Object::IsHeapObject()) return false; + InstanceType instance_type = HeapObject::cast(this)->map()->instance_type(); + return (instance_type >= FIRST_SIMD_VALUE_TYPE && + instance_type <= LAST_SIMD_VALUE_TYPE); +} + + +TYPE_CHECKER(Float32x4, FLOAT32X4_TYPE) +TYPE_CHECKER(Int32x4, INT32X4_TYPE) +TYPE_CHECKER(Bool32x4, BOOL32X4_TYPE) +TYPE_CHECKER(Int16x8, INT16X8_TYPE) +TYPE_CHECKER(Bool16x8, BOOL16X8_TYPE) +TYPE_CHECKER(Int8x16, INT8X16_TYPE) +TYPE_CHECKER(Bool8x16, BOOL8X16_TYPE) + + bool Object::IsString() const { return Object::IsHeapObject() && HeapObject::cast(this)->map()->instance_type() < FIRST_NONSTRING_TYPE; @@ -1243,6 +1259,18 @@ MaybeHandle Object::GetProperty(Isolate* isolate, Handle object, #define WRITE_INTPTR_FIELD(p, offset, value) \ (*reinterpret_cast(FIELD_ADDR(p, offset)) = value) +#define READ_UINT16_FIELD(p, offset) \ + (*reinterpret_cast(FIELD_ADDR_CONST(p, offset))) + +#define WRITE_UINT16_FIELD(p, offset, value) \ + (*reinterpret_cast(FIELD_ADDR(p, offset)) = value) + +#define READ_INT16_FIELD(p, offset) \ + (*reinterpret_cast(FIELD_ADDR_CONST(p, offset))) + +#define WRITE_INT16_FIELD(p, offset, value) \ + (*reinterpret_cast(FIELD_ADDR(p, offset)) = value) + #define READ_UINT32_FIELD(p, offset) \ (*reinterpret_cast(FIELD_ADDR_CONST(p, offset))) @@ -1273,12 +1301,6 @@ MaybeHandle Object::GetProperty(Isolate* isolate, Handle object, #define WRITE_INT64_FIELD(p, offset, value) \ (*reinterpret_cast(FIELD_ADDR(p, offset)) = value) -#define READ_SHORT_FIELD(p, offset) \ - (*reinterpret_cast(FIELD_ADDR_CONST(p, offset))) - -#define WRITE_SHORT_FIELD(p, offset, value) \ - (*reinterpret_cast(FIELD_ADDR(p, offset)) = value) - #define READ_BYTE_FIELD(p, offset) \ (*reinterpret_cast(FIELD_ADDR_CONST(p, offset))) @@ -1560,6 +1582,162 @@ void Float32x4::set_lane(int lane, float value) { } +int32_t Int32x4::get_lane(int lane) const { + DCHECK(lane < 4 && lane >= 0); +#if defined(V8_TARGET_LITTLE_ENDIAN) + return READ_INT32_FIELD(this, kValueOffset + lane * kInt32Size); +#elif defined(V8_TARGET_BIG_ENDIAN) + return READ_INT32_FIELD(this, kValueOffset + (3 - lane) * kInt32Size); +#else +#error Unknown byte ordering +#endif +} + + +void Int32x4::set_lane(int lane, int32_t value) { + DCHECK(lane < 4 && lane >= 0); +#if defined(V8_TARGET_LITTLE_ENDIAN) + WRITE_INT32_FIELD(this, kValueOffset + lane * kInt32Size, value); +#elif defined(V8_TARGET_BIG_ENDIAN) + WRITE_INT32_FIELD(this, kValueOffset + (3 - lane) * kInt32Size, value); +#else +#error Unknown byte ordering +#endif +} + + +bool Bool32x4::get_lane(int lane) const { + DCHECK(lane < 4 && lane >= 0); + int32_t value; +#if defined(V8_TARGET_LITTLE_ENDIAN) + value = READ_INT32_FIELD(this, kValueOffset + lane * kInt32Size); +#elif defined(V8_TARGET_BIG_ENDIAN) + value = READ_INT32_FIELD(this, kValueOffset + (3 - lane) * kInt32Size); +#else +#error Unknown byte ordering +#endif + DCHECK(value == 0 || value == -1); + return value != 0; +} + + +void Bool32x4::set_lane(int lane, bool value) { + DCHECK(lane < 4 && lane >= 0); + int32_t int_val = value ? -1 : 0; +#if defined(V8_TARGET_LITTLE_ENDIAN) + WRITE_INT32_FIELD(this, kValueOffset + lane * kInt32Size, int_val); +#elif defined(V8_TARGET_BIG_ENDIAN) + WRITE_INT32_FIELD(this, kValueOffset + (3 - lane) * kInt32Size, int_val); +#else +#error Unknown byte ordering +#endif +} + + +int16_t Int16x8::get_lane(int lane) const { + DCHECK(lane < 8 && lane >= 0); +#if defined(V8_TARGET_LITTLE_ENDIAN) + return READ_INT16_FIELD(this, kValueOffset + lane * kShortSize); +#elif defined(V8_TARGET_BIG_ENDIAN) + return READ_INT16_FIELD(this, kValueOffset + (7 - lane) * kShortSize); +#else +#error Unknown byte ordering +#endif +} + + +void Int16x8::set_lane(int lane, int16_t value) { + DCHECK(lane < 8 && lane >= 0); +#if defined(V8_TARGET_LITTLE_ENDIAN) + WRITE_INT16_FIELD(this, kValueOffset + lane * kShortSize, value); +#elif defined(V8_TARGET_BIG_ENDIAN) + WRITE_INT16_FIELD(this, kValueOffset + (7 - lane) * kShortSize, value); +#else +#error Unknown byte ordering +#endif +} + + +bool Bool16x8::get_lane(int lane) const { + DCHECK(lane < 8 && lane >= 0); + int16_t value; +#if defined(V8_TARGET_LITTLE_ENDIAN) + return READ_INT16_FIELD(this, kValueOffset + lane * kShortSize); +#elif defined(V8_TARGET_BIG_ENDIAN) + return READ_INT16_FIELD(this, kValueOffset + (7 - lane) * kShortSize); +#else +#error Unknown byte ordering +#endif + DCHECK(value == 0 || value == -1); + return value != 0; +} + + +void Bool16x8::set_lane(int lane, bool value) { + DCHECK(lane < 8 && lane >= 0); + int16_t int_val = value ? -1 : 0; +#if defined(V8_TARGET_LITTLE_ENDIAN) + WRITE_INT16_FIELD(this, kValueOffset + lane * kShortSize, int_val); +#elif defined(V8_TARGET_BIG_ENDIAN) + WRITE_INT16_FIELD(this, kValueOffset + (7 - lane) * kShortSize, int_val); +#else +#error Unknown byte ordering +#endif +} + + +int8_t Int8x16::get_lane(int lane) const { + DCHECK(lane < 16 && lane >= 0); +#if defined(V8_TARGET_LITTLE_ENDIAN) + return READ_BYTE_FIELD(this, kValueOffset + lane * kCharSize); +#elif defined(V8_TARGET_BIG_ENDIAN) + return READ_BYTE_FIELD(this, kValueOffset + (15 - lane) * kCharSize); +#else +#error Unknown byte ordering +#endif +} + + +void Int8x16::set_lane(int lane, int8_t value) { + DCHECK(lane < 16 && lane >= 0); +#if defined(V8_TARGET_LITTLE_ENDIAN) + WRITE_BYTE_FIELD(this, kValueOffset + lane * kCharSize, value); +#elif defined(V8_TARGET_BIG_ENDIAN) + WRITE_BYTE_FIELD(this, kValueOffset + (15 - lane) * kCharSize, value); +#else +#error Unknown byte ordering +#endif +} + + +bool Bool8x16::get_lane(int lane) const { + DCHECK(lane < 16 && lane >= 0); + int8_t value; +#if defined(V8_TARGET_LITTLE_ENDIAN) + value = READ_BYTE_FIELD(this, kValueOffset + lane * kCharSize); +#elif defined(V8_TARGET_BIG_ENDIAN) + value = READ_BYTE_FIELD(this, kValueOffset + (15 - lane) * kCharSize); +#else +#error Unknown byte ordering +#endif + DCHECK(value == 0 || value == -1); + return value != 0; +} + + +void Bool8x16::set_lane(int lane, bool value) { + DCHECK(lane < 16 && lane >= 0); + int8_t int_val = value ? -1 : 0; +#if defined(V8_TARGET_LITTLE_ENDIAN) + WRITE_BYTE_FIELD(this, kValueOffset + lane * kCharSize, int_val); +#elif defined(V8_TARGET_BIG_ENDIAN) + WRITE_BYTE_FIELD(this, kValueOffset + (15 - lane) * kCharSize, int_val); +#else +#error Unknown byte ordering +#endif +} + + ACCESSORS(JSObject, properties, FixedArray, kPropertiesOffset) @@ -2204,7 +2382,7 @@ bool Object::IsStringObjectWithCharacterAt(uint32_t index) { void Object::VerifyApiCallResultType() { #if DEBUG if (!(IsSmi() || IsString() || IsSymbol() || IsSpecObject() || - IsHeapNumber() || IsFloat32x4() || IsUndefined() || IsTrue() || + IsHeapNumber() || IsSimd128Value() || IsUndefined() || IsTrue() || IsFalse() || IsNull())) { FATAL("API call returned invalid object"); } @@ -2396,7 +2574,7 @@ AllocationAlignment HeapObject::RequiredAlignment() { return kDoubleAligned; } if (IsHeapNumber()) return kDoubleUnaligned; - if (IsFloat32x4()) return kSimd128Unaligned; + if (IsSimd128Value()) return kSimd128Unaligned; #endif // V8_HOST_ARCH_32_BIT return kWordAligned; } @@ -2908,6 +3086,9 @@ void SeededNumberDictionary::set_requires_slow_elements() { CAST_ACCESSOR(AccessorInfo) CAST_ACCESSOR(ArrayList) +CAST_ACCESSOR(Bool16x8) +CAST_ACCESSOR(Bool32x4) +CAST_ACCESSOR(Bool8x16) CAST_ACCESSOR(ByteArray) CAST_ACCESSOR(BytecodeArray) CAST_ACCESSOR(Cell) @@ -2932,6 +3113,9 @@ CAST_ACCESSOR(GlobalDictionary) CAST_ACCESSOR(GlobalObject) CAST_ACCESSOR(HandlerTable) CAST_ACCESSOR(HeapObject) +CAST_ACCESSOR(Int16x8) +CAST_ACCESSOR(Int32x4) +CAST_ACCESSOR(Int8x16) CAST_ACCESSOR(JSArray) CAST_ACCESSOR(JSArrayBuffer) CAST_ACCESSOR(JSArrayBufferView) @@ -2976,6 +3160,7 @@ CAST_ACCESSOR(SeqOneByteString) CAST_ACCESSOR(SeqString) CAST_ACCESSOR(SeqTwoByteString) CAST_ACCESSOR(SharedFunctionInfo) +CAST_ACCESSOR(Simd128Value) CAST_ACCESSOR(SlicedString) CAST_ACCESSOR(Smi) CAST_ACCESSOR(String) @@ -3311,13 +3496,13 @@ uc16* SeqTwoByteString::GetChars() { uint16_t SeqTwoByteString::SeqTwoByteStringGet(int index) { DCHECK(index >= 0 && index < length()); - return READ_SHORT_FIELD(this, kHeaderSize + index * kShortSize); + return READ_UINT16_FIELD(this, kHeaderSize + index * kShortSize); } void SeqTwoByteString::SeqTwoByteStringSet(int index, uint16_t value) { DCHECK(index >= 0 && index < length()); - WRITE_SHORT_FIELD(this, kHeaderSize + index * kShortSize, value); + WRITE_UINT16_FIELD(this, kHeaderSize + index * kShortSize, value); } @@ -7088,10 +7273,20 @@ String::SubStringRange::iterator String::SubStringRange::end() { #undef WRITE_INT_FIELD #undef READ_INTPTR_FIELD #undef WRITE_INTPTR_FIELD +#undef READ_UINT16_FIELD +#undef WRITE_UINT16_FIELD +#undef READ_INT16_FIELD +#undef WRITE_INT16_FIELD #undef READ_UINT32_FIELD #undef WRITE_UINT32_FIELD -#undef READ_SHORT_FIELD -#undef WRITE_SHORT_FIELD +#undef READ_INT32_FIELD +#undef WRITE_INT32_FIELD +#undef READ_FLOAT_FIELD +#undef WRITE_FLOAT_FIELD +#undef READ_UINT64_FIELD +#undef WRITE_UINT64_FIELD +#undef READ_INT64_FIELD +#undef WRITE_INT64_FIELD #undef READ_BYTE_FIELD #undef WRITE_BYTE_FIELD #undef NOBARRIER_READ_BYTE_FIELD diff --git a/src/objects-printer.cc b/src/objects-printer.cc index cb67d6a6e..560419b0d 100644 --- a/src/objects-printer.cc +++ b/src/objects-printer.cc @@ -64,6 +64,24 @@ void HeapObject::HeapObjectPrint(std::ostream& os) { // NOLINT case FLOAT32X4_TYPE: Float32x4::cast(this)->Float32x4Print(os); break; + case INT32X4_TYPE: + Int32x4::cast(this)->Int32x4Print(os); + break; + case BOOL32X4_TYPE: + Bool32x4::cast(this)->Bool32x4Print(os); + break; + case INT16X8_TYPE: + Int16x8::cast(this)->Int16x8Print(os); + break; + case BOOL16X8_TYPE: + Bool16x8::cast(this)->Bool16x8Print(os); + break; + case INT8X16_TYPE: + Int16x8::cast(this)->Int16x8Print(os); + break; + case BOOL8X16_TYPE: + Bool16x8::cast(this)->Bool16x8Print(os); + break; case FIXED_DOUBLE_ARRAY_TYPE: FixedDoubleArray::cast(this)->FixedDoubleArrayPrint(os); break; @@ -192,6 +210,74 @@ void HeapObject::HeapObjectPrint(std::ostream& os) { // NOLINT } +void Float32x4::Float32x4Print(std::ostream& os) { // NOLINT + char arr[100]; + Vector buffer(arr, arraysize(arr)); + os << std::string(DoubleToCString(get_lane(0), buffer)) << ", " + << std::string(DoubleToCString(get_lane(1), buffer)) << ", " + << std::string(DoubleToCString(get_lane(2), buffer)) << ", " + << std::string(DoubleToCString(get_lane(3), buffer)); +} + + +void Int32x4::Int32x4Print(std::ostream& os) { // NOLINT + char arr[100]; + Vector buffer(arr, arraysize(arr)); + os << std::string(IntToCString(get_lane(0), buffer)) << ", " + << std::string(IntToCString(get_lane(1), buffer)) << ", " + << std::string(IntToCString(get_lane(2), buffer)) << ", " + << std::string(IntToCString(get_lane(3), buffer)); +} + + +void Bool32x4::Bool32x4Print(std::ostream& os) { // NOLINT + os << std::string(get_lane(0) ? "true" : "false") << ", " + << std::string(get_lane(1) ? "true" : "false") << ", " + << std::string(get_lane(2) ? "true" : "false") << ", " + << std::string(get_lane(3) ? "true" : "false"); +} + + +void Int16x8::Int16x8Print(std::ostream& os) { // NOLINT + char arr[100]; + Vector buffer(arr, arraysize(arr)); + os << std::string(IntToCString(get_lane(0), buffer)); + for (int i = 1; i < 8; i++) { + os << ", " << std::string(IntToCString(get_lane(i), buffer)); + } +} + + +void Bool16x8::Bool16x8Print(std::ostream& os) { // NOLINT + char arr[100]; + Vector buffer(arr, arraysize(arr)); + os << std::string(get_lane(0) ? "true" : "false"); + for (int i = 1; i < 8; i++) { + os << ", " << std::string(get_lane(i) ? "true" : "false"); + } +} + + +void Int8x16::Int8x16Print(std::ostream& os) { // NOLINT + char arr[100]; + Vector buffer(arr, arraysize(arr)); + os << std::string(IntToCString(get_lane(0), buffer)); + for (int i = 1; i < 16; i++) { + os << ", " << std::string(IntToCString(get_lane(i), buffer)); + } +} + + +void Bool8x16::Bool8x16Print(std::ostream& os) { // NOLINT + char arr[100]; + Vector buffer(arr, arraysize(arr)); + os << std::string(get_lane(0) ? "true" : "false"); + for (int i = 1; i < 16; i++) { + os << ", " << std::string(get_lane(i) ? "true" : "false"); + } +} + + void ByteArray::ByteArrayPrint(std::ostream& os) { // NOLINT os << "byte array, data starts at " << GetDataStartAddress(); } diff --git a/src/objects.cc b/src/objects.cc index 053f7107b..1a0a3683b 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -82,8 +82,24 @@ MaybeHandle Object::ToObject(Isolate* isolate, constructor = handle(native_context->string_function(), isolate); } else if (object->IsSymbol()) { constructor = handle(native_context->symbol_function(), isolate); - } else if (object->IsFloat32x4()) { - constructor = handle(native_context->float32x4_function(), isolate); + } else if (object->IsSimd128Value()) { + if (object->IsFloat32x4()) { + constructor = handle(native_context->float32x4_function(), isolate); + } else if (object->IsInt32x4()) { + constructor = handle(native_context->int32x4_function(), isolate); + } else if (object->IsBool32x4()) { + constructor = handle(native_context->bool32x4_function(), isolate); + } else if (object->IsInt16x8()) { + constructor = handle(native_context->int16x8_function(), isolate); + } else if (object->IsBool16x8()) { + constructor = handle(native_context->bool16x8_function(), isolate); + } else if (object->IsInt8x16()) { + constructor = handle(native_context->int8x16_function(), isolate); + } else if (object->IsBool8x16()) { + constructor = handle(native_context->bool8x16_function(), isolate); + } else { + UNREACHABLE(); + } } else { return MaybeHandle(); } @@ -100,7 +116,7 @@ bool Object::BooleanValue() { if (IsUndetectableObject()) return false; // Undetectable object is false. if (IsString()) return String::cast(this)->length() != 0; if (IsHeapNumber()) return HeapNumber::cast(this)->HeapNumberBooleanValue(); - if (IsFloat32x4()) return true; // Simd value types always evaluate to true. + if (IsSimd128Value()) return true; // Simd value types evaluate to true. return true; } @@ -629,8 +645,24 @@ Map* Object::GetRootMap(Isolate* isolate) { if (heap_object->IsBoolean()) { return context->boolean_function()->initial_map(); } - if (heap_object->IsFloat32x4()) { - return context->float32x4_function()->initial_map(); + if (heap_object->IsSimd128Value()) { + if (heap_object->IsFloat32x4()) { + return context->float32x4_function()->initial_map(); + } else if (heap_object->IsInt32x4()) { + return context->int32x4_function()->initial_map(); + } else if (heap_object->IsBool32x4()) { + return context->bool32x4_function()->initial_map(); + } else if (heap_object->IsInt16x8()) { + return context->int16x8_function()->initial_map(); + } else if (heap_object->IsBool16x8()) { + return context->bool16x8_function()->initial_map(); + } else if (heap_object->IsInt8x16()) { + return context->int8x16_function()->initial_map(); + } else if (heap_object->IsBool8x16()) { + return context->bool8x16_function()->initial_map(); + } else { + UNREACHABLE(); + } } return isolate->heap()->null_value()->map(); } @@ -670,14 +702,8 @@ Object* Object::GetSimpleHash() { uint32_t hash = Oddball::cast(this)->to_string()->Hash(); return Smi::FromInt(hash); } - if (IsFloat32x4()) { - Float32x4* simd = Float32x4::cast(this); - uint32_t seed = v8::internal::kZeroHashSeed; - uint32_t hash; - hash = ComputeIntegerHash(bit_cast(simd->get_lane(0)), seed); - hash = ComputeIntegerHash(bit_cast(simd->get_lane(1)), hash * 31); - hash = ComputeIntegerHash(bit_cast(simd->get_lane(2)), hash * 31); - hash = ComputeIntegerHash(bit_cast(simd->get_lane(3)), hash * 31); + if (IsSimd128Value()) { + uint32_t hash = Simd128Value::cast(this)->Hash(); return Smi::FromInt(hash & Smi::kMaxValue); } DCHECK(IsJSReceiver()); @@ -701,18 +727,37 @@ bool Object::SameValue(Object* other) { // The object is either a number, a name, an odd-ball, // a real JS object, or a Harmony proxy. if (IsNumber() && other->IsNumber()) { - return v8::internal::SameValue(Number(), other->Number()); + double this_value = Number(); + double other_value = other->Number(); + // SameValue(NaN, NaN) is true. + if (this_value != other_value) { + return std::isnan(this_value) && std::isnan(other_value); + } + // SameValue(0.0, -0.0) is false. + return (std::signbit(this_value) == std::signbit(other_value)); } if (IsString() && other->IsString()) { return String::cast(this)->Equals(String::cast(other)); } - if (IsFloat32x4() && other->IsFloat32x4()) { - Float32x4* x = Float32x4::cast(this); - Float32x4* y = Float32x4::cast(other); - return v8::internal::SameValue(x->get_lane(0), y->get_lane(0)) && - v8::internal::SameValue(x->get_lane(1), y->get_lane(1)) && - v8::internal::SameValue(x->get_lane(2), y->get_lane(2)) && - v8::internal::SameValue(x->get_lane(3), y->get_lane(3)); + if (IsSimd128Value() && other->IsSimd128Value()) { + if (IsFloat32x4() && other->IsFloat32x4()) { + Float32x4* a = Float32x4::cast(this); + Float32x4* b = Float32x4::cast(other); + for (int i = 0; i < 4; i++) { + float x = a->get_lane(i); + float y = b->get_lane(i); + // Implements the ES5 SameValue operation for floating point types. + // http://www.ecma-international.org/ecma-262/6.0/#sec-samevalue + if (x != y && !(std::isnan(x) && std::isnan(y))) return false; + if (std::signbit(x) != std::signbit(y)) return false; + } + return true; + } else { + Simd128Value* a = Simd128Value::cast(this); + Simd128Value* b = Simd128Value::cast(other); + return a->map()->instance_type() == b->map()->instance_type() && + a->BitwiseEquals(b); + } } return false; } @@ -724,18 +769,34 @@ bool Object::SameValueZero(Object* other) { // The object is either a number, a name, an odd-ball, // a real JS object, or a Harmony proxy. if (IsNumber() && other->IsNumber()) { - return v8::internal::SameValueZero(Number(), other->Number()); + double this_value = Number(); + double other_value = other->Number(); + // +0 == -0 is true + return this_value == other_value || + (std::isnan(this_value) && std::isnan(other_value)); } if (IsString() && other->IsString()) { return String::cast(this)->Equals(String::cast(other)); } - if (IsFloat32x4() && other->IsFloat32x4()) { - Float32x4* x = Float32x4::cast(this); - Float32x4* y = Float32x4::cast(other); - return v8::internal::SameValueZero(x->get_lane(0), y->get_lane(0)) && - v8::internal::SameValueZero(x->get_lane(1), y->get_lane(1)) && - v8::internal::SameValueZero(x->get_lane(2), y->get_lane(2)) && - v8::internal::SameValueZero(x->get_lane(3), y->get_lane(3)); + if (IsSimd128Value() && other->IsSimd128Value()) { + if (IsFloat32x4() && other->IsFloat32x4()) { + Float32x4* a = Float32x4::cast(this); + Float32x4* b = Float32x4::cast(other); + for (int i = 0; i < 4; i++) { + float x = a->get_lane(i); + float y = b->get_lane(i); + // Implements the ES6 SameValueZero operation for floating point types. + // http://www.ecma-international.org/ecma-262/6.0/#sec-samevaluezero + if (x != y && !(std::isnan(x) && std::isnan(y))) return false; + // SameValueZero doesn't distinguish between 0 and -0. + } + return true; + } else { + Simd128Value* a = Simd128Value::cast(this); + Simd128Value* b = Simd128Value::cast(other); + return a->map()->instance_type() == b->map()->instance_type() && + a->BitwiseEquals(b); + } } return false; } @@ -1347,12 +1408,27 @@ void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT os << '>'; break; } - case FLOAT32X4_TYPE: { - os << "Float32x4Print(os); - os << ">"; + case FLOAT32X4_TYPE: + os << ""; + break; + case INT32X4_TYPE: + os << ""; + break; + case BOOL32X4_TYPE: + os << ""; + break; + case INT16X8_TYPE: + os << ""; + break; + case BOOL16X8_TYPE: + os << ""; + break; + case INT8X16_TYPE: + os << ""; + break; + case BOOL8X16_TYPE: + os << ""; break; - } case JS_PROXY_TYPE: os << ""; break; @@ -1497,6 +1573,12 @@ void HeapObject::IterateBody(InstanceType type, int object_size, case HEAP_NUMBER_TYPE: case MUTABLE_HEAP_NUMBER_TYPE: case FLOAT32X4_TYPE: + case INT32X4_TYPE: + case BOOL32X4_TYPE: + case INT16X8_TYPE: + case BOOL16X8_TYPE: + case INT8X16_TYPE: + case BOOL8X16_TYPE: case FILLER_TYPE: case BYTE_ARRAY_TYPE: case BYTECODE_ARRAY_TYPE: @@ -1545,13 +1627,35 @@ void HeapNumber::HeapNumberPrint(std::ostream& os) { // NOLINT } -void Float32x4::Float32x4Print(std::ostream& os) { // NOLINT - char arr[100]; - Vector buffer(arr, arraysize(arr)); - os << std::string(DoubleToCString(get_lane(0), buffer)) << ", " - << std::string(DoubleToCString(get_lane(1), buffer)) << ", " - << std::string(DoubleToCString(get_lane(2), buffer)) << ", " - << std::string(DoubleToCString(get_lane(3), buffer)); +#define FIELD_ADDR_CONST(p, offset) \ + (reinterpret_cast(p) + offset - kHeapObjectTag) + +#define READ_INT32_FIELD(p, offset) \ + (*reinterpret_cast(FIELD_ADDR_CONST(p, offset))) + +#define READ_INT64_FIELD(p, offset) \ + (*reinterpret_cast(FIELD_ADDR_CONST(p, offset))) + + +bool Simd128Value::BitwiseEquals(const Simd128Value* other) const { + return READ_INT64_FIELD(this, kValueOffset) == + READ_INT64_FIELD(other, kValueOffset) && + READ_INT64_FIELD(this, kValueOffset + kInt64Size) == + READ_INT64_FIELD(other, kValueOffset + kInt64Size); +} + + +uint32_t Simd128Value::Hash() const { + uint32_t seed = v8::internal::kZeroHashSeed; + uint32_t hash; + hash = ComputeIntegerHash(READ_INT32_FIELD(this, kValueOffset), seed); + hash = ComputeIntegerHash( + READ_INT32_FIELD(this, kValueOffset + 1 * kInt32Size), hash * 31); + hash = ComputeIntegerHash( + READ_INT32_FIELD(this, kValueOffset + 2 * kInt32Size), hash * 31); + hash = ComputeIntegerHash( + READ_INT32_FIELD(this, kValueOffset + 3 * kInt32Size), hash * 31); + return hash; } diff --git a/src/objects.h b/src/objects.h index 9663398ad..ee83e3b7a 100644 --- a/src/objects.h +++ b/src/objects.h @@ -113,7 +113,14 @@ // - ExternalTwoByteInternalizedString // - Symbol // - HeapNumber -// - Float32x4 +// - Simd128Value +// - Float32x4 +// - Int32x4 +// - Bool32x4 +// - Int16x8 +// - Bool16x8 +// - Int8x16 +// - Bool8x16 // - Cell // - PropertyCell // - Code @@ -370,6 +377,12 @@ const int kStubMinorKeyBits = kSmiValueSize - kStubMajorKeyBits - 1; \ V(SYMBOL_TYPE) \ V(FLOAT32X4_TYPE) \ + V(INT32X4_TYPE) \ + V(BOOL32X4_TYPE) \ + V(INT16X8_TYPE) \ + V(BOOL16X8_TYPE) \ + V(INT8X16_TYPE) \ + V(BOOL8X16_TYPE) \ \ V(MAP_TYPE) \ V(CODE_TYPE) \ @@ -663,12 +676,18 @@ enum InstanceType { // objects. HEAP_NUMBER_TYPE, MUTABLE_HEAP_NUMBER_TYPE, - FLOAT32X4_TYPE, // FIRST_SIMD_TYPE, LAST_SIMD_TYPE + FLOAT32X4_TYPE, // FIRST_SIMD_VALUE_TYPE + INT32X4_TYPE, + BOOL32X4_TYPE, + INT16X8_TYPE, + BOOL16X8_TYPE, + INT8X16_TYPE, + BOOL8X16_TYPE, // LAST_SIMD_VALUE_TYPE FOREIGN_TYPE, BYTE_ARRAY_TYPE, BYTECODE_ARRAY_TYPE, FREE_SPACE_TYPE, - FIXED_INT8_ARRAY_TYPE, // FIRST_FIXED_TYPED_ARRAY_TYPE + FIXED_INT8_ARRAY_TYPE, // FIRST_FIXED_TYPED_ARRAY_TYPE FIXED_UINT8_ARRAY_TYPE, FIXED_INT16_ARRAY_TYPE, FIXED_UINT16_ARRAY_TYPE, @@ -747,9 +766,9 @@ enum InstanceType { FIRST_UNIQUE_NAME_TYPE = INTERNALIZED_STRING_TYPE, LAST_UNIQUE_NAME_TYPE = SYMBOL_TYPE, FIRST_NONSTRING_TYPE = SYMBOL_TYPE, - // Boundaries for testing for a SIMD type. - FIRST_SIMD_TYPE = FLOAT32X4_TYPE, - LAST_SIMD_TYPE = FLOAT32X4_TYPE, + // Boundaries for testing for a SIMD types. + FIRST_SIMD_VALUE_TYPE = FLOAT32X4_TYPE, + LAST_SIMD_VALUE_TYPE = BOOL8X16_TYPE, // Boundaries for testing for a fixed typed array. FIRST_FIXED_TYPED_ARRAY_TYPE = FIXED_INT8_ARRAY_TYPE, LAST_FIXED_TYPED_ARRAY_TYPE = FIXED_UINT8_CLAMPED_ARRAY_TYPE, @@ -882,7 +901,14 @@ template inline bool Is(Object* obj); #define HEAP_OBJECT_TYPE_LIST(V) \ V(HeapNumber) \ V(MutableHeapNumber) \ + V(Simd128Value) \ V(Float32x4) \ + V(Int32x4) \ + V(Bool32x4) \ + V(Int16x8) \ + V(Bool16x8) \ + V(Int8x16) \ + V(Bool8x16) \ V(Name) \ V(UniqueName) \ V(String) \ @@ -1578,26 +1604,50 @@ class HeapNumber: public HeapObject { }; -// The Float32x4 class describes heap allocated SIMD values holding 4 32-bit -// IEEE floats. -class Float32x4 : public HeapObject { +// The SimdValue128 class describes heap allocated 128 bit SIMD values. +class Simd128Value : public HeapObject { public: - inline float get_lane(int lane) const; - inline void set_lane(int lane, float value); + DECLARE_CAST(Simd128Value) - DECLARE_CAST(Float32x4) - - // Dispatched behavior. - void Float32x4Print(std::ostream& os); // NOLINT - DECLARE_VERIFIER(Float32x4) + // Checks that another instance is bit-wise equal. + bool BitwiseEquals(const Simd128Value* other) const; + // Computes a hash from the 128 bit value, viewed as 4 32-bit integers. + uint32_t Hash() const; // Layout description. static const int kValueOffset = HeapObject::kHeaderSize; static const int kSize = kValueOffset + kSimd128Size; private: - DISALLOW_IMPLICIT_CONSTRUCTORS(Float32x4); -}; + DISALLOW_IMPLICIT_CONSTRUCTORS(Simd128Value); +}; + + +#define SIMD128_TYPES(V) \ + V(Float32x4, float32x4, 4, float) \ + V(Int32x4, int32x4, 4, int32_t) \ + V(Bool32x4, bool32x4, 4, bool) \ + V(Int16x8, int16x8, 8, int16_t) \ + V(Bool16x8, bool16x8, 8, bool) \ + V(Int8x16, int8x16, 16, int8_t) \ + V(Bool8x16, bool8x16, 16, bool) + +#define SIMD128_VALUE_CLASS(name, type, lane_count, lane_type) \ + class name : public Simd128Value { \ + public: \ + inline lane_type get_lane(int lane) const; \ + inline void set_lane(int lane, lane_type value); \ + \ + DECLARE_CAST(name) \ + \ + DECLARE_PRINTER(name) \ + DECLARE_VERIFIER(name) \ + \ + private: \ + DISALLOW_IMPLICIT_CONSTRUCTORS(name); \ + }; + +SIMD128_TYPES(SIMD128_VALUE_CLASS) enum EnsureElementsMode { diff --git a/src/ppc/code-stubs-ppc.cc b/src/ppc/code-stubs-ppc.cc index 59aa8b182..35e9f29fd 100644 --- a/src/ppc/code-stubs-ppc.cc +++ b/src/ppc/code-stubs-ppc.cc @@ -260,6 +260,7 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow, // They are both equal and they are not both Smis so both of them are not // Smis. If it's not a heap number, then return equal. if (cond == lt || cond == gt) { + Label not_simd; // Call runtime on identical JSObjects. __ CompareObjectType(r3, r7, r7, FIRST_SPEC_OBJECT_TYPE); __ bge(slow); @@ -267,8 +268,11 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow, __ cmpi(r7, Operand(SYMBOL_TYPE)); __ beq(slow); // Call runtime on identical SIMD values since we must throw a TypeError. - __ cmpi(r7, Operand(FLOAT32X4_TYPE)); - __ beq(slow); + __ cmpi(r7, Operand(FIRST_SIMD_VALUE_TYPE)); + __ blt(¬_simd); + __ cmpi(r7, Operand(LAST_SIMD_VALUE_TYPE)); + __ ble(slow); + __ bind(¬_simd); if (is_strong(strength)) { // Call the runtime on anything that is converted in the semantics, since // we need to throw a TypeError. Smis have already been ruled out. @@ -282,14 +286,18 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow, __ beq(&heap_number); // Comparing JS objects with <=, >= is complicated. if (cond != eq) { + Label not_simd; __ cmpi(r7, Operand(FIRST_SPEC_OBJECT_TYPE)); __ bge(slow); // Call runtime on identical symbols since we need to throw a TypeError. __ cmpi(r7, Operand(SYMBOL_TYPE)); __ beq(slow); // Call runtime on identical SIMD values since we must throw a TypeError. - __ cmpi(r7, Operand(FLOAT32X4_TYPE)); - __ beq(slow); + __ cmpi(r7, Operand(FIRST_SIMD_VALUE_TYPE)); + __ blt(¬_simd); + __ cmpi(r7, Operand(LAST_SIMD_VALUE_TYPE)); + __ ble(slow); + __ bind(¬_simd); if (is_strong(strength)) { // Call the runtime on anything that is converted in the semantics, // since we need to throw a TypeError. Smis and heap numbers have diff --git a/src/ppc/lithium-codegen-ppc.cc b/src/ppc/lithium-codegen-ppc.cc index e5dd69aa1..caf811654 100644 --- a/src/ppc/lithium-codegen-ppc.cc +++ b/src/ppc/lithium-codegen-ppc.cc @@ -2307,8 +2307,12 @@ void LCodeGen::DoBranch(LBranch* instr) { if (expected.Contains(ToBooleanStub::SIMD_VALUE)) { // SIMD value -> true. - __ CompareInstanceType(map, ip, FLOAT32X4_TYPE); - __ beq(instr->TrueLabel(chunk_)); + Label not_simd; + __ CompareInstanceType(map, ip, FIRST_SIMD_VALUE_TYPE); + __ blt(¬_simd); + __ CompareInstanceType(map, ip, LAST_SIMD_VALUE_TYPE); + __ ble(instr->TrueLabel(chunk_)); + __ bind(¬_simd); } if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) { @@ -5992,6 +5996,36 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, Label* false_label, __ CompareObjectType(input, scratch, no_reg, FLOAT32X4_TYPE); final_branch_condition = eq; + } else if (String::Equals(type_name, factory->int32x4_string())) { + __ JumpIfSmi(input, false_label); + __ CompareObjectType(input, scratch, no_reg, INT32X4_TYPE); + final_branch_condition = eq; + + } else if (String::Equals(type_name, factory->bool32x4_string())) { + __ JumpIfSmi(input, false_label); + __ CompareObjectType(input, scratch, no_reg, BOOL32X4_TYPE); + final_branch_condition = eq; + + } else if (String::Equals(type_name, factory->int16x8_string())) { + __ JumpIfSmi(input, false_label); + __ CompareObjectType(input, scratch, no_reg, INT16X8_TYPE); + final_branch_condition = eq; + + } else if (String::Equals(type_name, factory->bool16x8_string())) { + __ JumpIfSmi(input, false_label); + __ CompareObjectType(input, scratch, no_reg, BOOL16X8_TYPE); + final_branch_condition = eq; + + } else if (String::Equals(type_name, factory->int8x16_string())) { + __ JumpIfSmi(input, false_label); + __ CompareObjectType(input, scratch, no_reg, INT8X16_TYPE); + final_branch_condition = eq; + + } else if (String::Equals(type_name, factory->bool8x16_string())) { + __ JumpIfSmi(input, false_label); + __ CompareObjectType(input, scratch, no_reg, BOOL8X16_TYPE); + final_branch_condition = eq; + } else { __ b(false_label); } diff --git a/src/runtime.js b/src/runtime.js index 000d49756..b4bec8ae8 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -101,8 +101,8 @@ EQUALS = function EQUALS(y) { while (true) { if (IS_NUMBER(y)) return %NumberEquals(x, y); if (IS_NULL_OR_UNDEFINED(y)) return 1; // not equal - if (IS_SYMBOL(y) || IS_FLOAT32X4(y)) return 1; // not equal if (!IS_SPEC_OBJECT(y)) { + if (IS_SYMBOL(y) || IS_SIMD_OBJECT(y)) return 1; // not equal // String or boolean. return %NumberEquals(x, %$toNumber(y)); } @@ -111,10 +111,10 @@ EQUALS = function EQUALS(y) { } else if (IS_STRING(x)) { while (true) { if (IS_STRING(y)) return %StringEquals(x, y); - if (IS_SYMBOL(y) || IS_FLOAT32X4(y)) return 1; // not equal if (IS_NUMBER(y)) return %NumberEquals(%$toNumber(x), y); if (IS_BOOLEAN(y)) return %NumberEquals(%$toNumber(x), %$toNumber(y)); if (IS_NULL_OR_UNDEFINED(y)) return 1; // not equal + if (IS_SYMBOL(y) || IS_SIMD_OBJECT(y)) return 1; // not equal y = %$toPrimitive(y, NO_HINT); } } else if (IS_SYMBOL(x)) { @@ -125,24 +125,23 @@ EQUALS = function EQUALS(y) { if (IS_NULL_OR_UNDEFINED(y)) return 1; if (IS_NUMBER(y)) return %NumberEquals(%$toNumber(x), y); if (IS_STRING(y)) return %NumberEquals(%$toNumber(x), %$toNumber(y)); - if (IS_SYMBOL(y) || IS_FLOAT32X4(y)) return 1; // not equal + if (IS_SYMBOL(y) || IS_SIMD_OBJECT(y)) return 1; // not equal // y is object. x = %$toNumber(x); y = %$toPrimitive(y, NO_HINT); } else if (IS_NULL_OR_UNDEFINED(x)) { return IS_NULL_OR_UNDEFINED(y) ? 0 : 1; - } else if (IS_FLOAT32X4(x)) { - if (IS_FLOAT32X4(y)) - return %Float32x4Equals(x, y); - return 1; // not equal + } else if (IS_SIMD_OBJECT(x)) { + return %SimdEquals(x, y); } else { // x is an object. - if (IS_SPEC_OBJECT(y)) { - return %_ObjectEquals(x, y) ? 0 : 1; - } + if (IS_SPEC_OBJECT(y)) return %_ObjectEquals(x, y) ? 0 : 1; if (IS_NULL_OR_UNDEFINED(y)) return 1; // not equal - if (IS_SYMBOL(y) || IS_FLOAT32X4(y)) return 1; // not equal - if (IS_BOOLEAN(y)) y = %$toNumber(y); + if (IS_BOOLEAN(y)) { + y = %$toNumber(y); + } else if (IS_SYMBOL(y) || IS_SIMD_OBJECT(y)) { + return 1; // not equal + } x = %$toPrimitive(x, NO_HINT); } } @@ -160,8 +159,7 @@ STRICT_EQUALS = function STRICT_EQUALS(x) { return %NumberEquals(this, x); } - if (IS_FLOAT32X4(this) && IS_FLOAT32X4(x)) - return %Float32x4Equals(this, x); + if (IS_SIMD_OBJECT(this)) return %SimdEquals(this, x); // If anything else gets here, we just do simple identity check. // Objects (including functions), null, undefined and booleans were @@ -758,7 +756,7 @@ function ToPrimitive(x, hint) { if (IS_STRING(x)) return x; // Normal behavior. if (!IS_SPEC_OBJECT(x)) return x; - if (IS_FLOAT32X4(x)) return x; + if (IS_SIMD_OBJECT(x)) return x; if (hint == NO_HINT) hint = (IS_DATE(x)) ? STRING_HINT : NUMBER_HINT; return (hint == NUMBER_HINT) ? DefaultNumber(x) : DefaultString(x); } @@ -864,9 +862,7 @@ function SameValue(x, y) { return false; } } - if (IS_FLOAT32X4(x)) { - return %Float32x4SameValue(x, y); - } + if (IS_SIMD_OBJECT(x)) return %SimdSameValue(x, y); return x === y; } @@ -877,9 +873,7 @@ function SameValueZero(x, y) { if (IS_NUMBER(x)) { if (NUMBER_IS_NAN(x) && NUMBER_IS_NAN(y)) return true; } - if (IS_FLOAT32X4(x)) { - return %Float32x4SameValueZero(x, y); - } + if (IS_SIMD_OBJECT(x)) return %SimdSameValueZero(x, y); return x === y; } @@ -923,7 +917,7 @@ function DefaultNumber(x) { if (IS_SPEC_FUNCTION(valueOf)) { var v = %_CallFunction(x, valueOf); if (IS_SYMBOL(v)) throw MakeTypeError(kSymbolToNumber); - if (IS_FLOAT32X4(v)) throw MakeTypeError(kSimdToNumber); + if (IS_SIMD_OBJECT(x)) throw MakeTypeError(kSimdToNumber); if (IsPrimitive(v)) return v; } var toString = x.toString; diff --git a/src/runtime/runtime-simd.cc b/src/runtime/runtime-simd.cc index 12c317147..90f1904f7 100644 --- a/src/runtime/runtime-simd.cc +++ b/src/runtime/runtime-simd.cc @@ -13,24 +13,31 @@ // the SIMD.js draft spec: // http://littledan.github.io/simd.html -#define NumberToFloat32x4Component NumberToFloat - #define CONVERT_SIMD_LANE_ARG_CHECKED(name, index, lanes) \ - RUNTIME_ASSERT(args[index]->IsSmi()); \ - int name = args.smi_at(index); \ + CONVERT_INT32_ARG_CHECKED(name, index); \ RUNTIME_ASSERT(name >= 0 && name < lanes); -#define SIMD4_CREATE_FUNCTION(type) \ - RUNTIME_FUNCTION(Runtime_Create##type) { \ - HandleScope scope(isolate); \ - DCHECK(args.length() == 4); \ - CONVERT_NUMBER_ARG_HANDLE_CHECKED(w, 0); \ - CONVERT_NUMBER_ARG_HANDLE_CHECKED(x, 1); \ - CONVERT_NUMBER_ARG_HANDLE_CHECKED(y, 2); \ - CONVERT_NUMBER_ARG_HANDLE_CHECKED(z, 3); \ - return *isolate->factory()->NewFloat32x4( \ - NumberTo##type##Component(*w), NumberTo##type##Component(*x), \ - NumberTo##type##Component(*y), NumberTo##type##Component(*z)); \ +#define SIMD_CREATE_NUMERIC_FUNCTION(type, lane_type, lane_count) \ + RUNTIME_FUNCTION(Runtime_Create##type) { \ + HandleScope scope(isolate); \ + DCHECK(args.length() == lane_count); \ + lane_type lanes[lane_count]; \ + for (int i = 0; i < lane_count; i++) { \ + CONVERT_NUMBER_ARG_HANDLE_CHECKED(number, i); \ + lanes[i] = ConvertNumber(number->Number()); \ + } \ + return *isolate->factory()->New##type(lanes); \ + } + +#define SIMD_CREATE_BOOLEAN_FUNCTION(type, lane_count) \ + RUNTIME_FUNCTION(Runtime_Create##type) { \ + HandleScope scope(isolate); \ + DCHECK(args.length() == lane_count); \ + bool lanes[lane_count]; \ + for (int i = 0; i < lane_count; i++) { \ + lanes[i] = args[i]->BooleanValue(); \ + } \ + return *isolate->factory()->New##type(lanes); \ } #define SIMD_CHECK_FUNCTION(type) \ @@ -40,82 +47,218 @@ return *a; \ } -#define SIMD_EXTRACT_LANE_FUNCTION(type, lanes) \ - RUNTIME_FUNCTION(Runtime_##type##ExtractLane) { \ - HandleScope scope(isolate); \ - DCHECK(args.length() == 2); \ - CONVERT_ARG_HANDLE_CHECKED(type, a, 0); \ - CONVERT_SIMD_LANE_ARG_CHECKED(lane, 1, lanes); \ - return *isolate->factory()->NewNumber(a->get_lane(lane)); \ +#define SIMD_EXTRACT_LANE_FUNCTION(type, lanes, extract_fn) \ + RUNTIME_FUNCTION(Runtime_##type##ExtractLane) { \ + HandleScope scope(isolate); \ + DCHECK(args.length() == 2); \ + CONVERT_ARG_HANDLE_CHECKED(type, a, 0); \ + CONVERT_SIMD_LANE_ARG_CHECKED(lane, 1, lanes); \ + return *isolate->factory()->extract_fn(a->get_lane(lane)); \ } -#define SIMD4_EQUALS_FUNCTION(type) \ - RUNTIME_FUNCTION(Runtime_##type##Equals) { \ - HandleScope scope(isolate); \ - DCHECK(args.length() == 2); \ - CONVERT_ARG_HANDLE_CHECKED(type, a, 0); \ - CONVERT_ARG_HANDLE_CHECKED(type, b, 1); \ - return Equals(a->get_lane(0), b->get_lane(0)) && \ - Equals(a->get_lane(1), b->get_lane(1)) && \ - Equals(a->get_lane(2), b->get_lane(2)) && \ - Equals(a->get_lane(3), b->get_lane(3)) \ - ? Smi::FromInt(EQUAL) \ - : Smi::FromInt(NOT_EQUAL); \ +#define SIMD_REPLACE_NUMERIC_LANE_FUNCTION(type, lane_type, lane_count) \ + RUNTIME_FUNCTION(Runtime_##type##ReplaceLane) { \ + HandleScope scope(isolate); \ + DCHECK(args.length() == 3); \ + CONVERT_ARG_HANDLE_CHECKED(type, simd, 0); \ + CONVERT_SIMD_LANE_ARG_CHECKED(lane, 1, lane_count); \ + CONVERT_NUMBER_ARG_HANDLE_CHECKED(number, 2); \ + lane_type lanes[lane_count]; \ + for (int i = 0; i < lane_count; i++) { \ + lanes[i] = simd->get_lane(i); \ + } \ + lanes[lane] = ConvertNumber(number->Number()); \ + Handle result = isolate->factory()->New##type(lanes); \ + return *result; \ } -#define SIMD4_SAME_VALUE_FUNCTION(type) \ - RUNTIME_FUNCTION(Runtime_##type##SameValue) { \ - HandleScope scope(isolate); \ - DCHECK(args.length() == 2); \ - CONVERT_ARG_HANDLE_CHECKED(type, a, 0); \ - CONVERT_ARG_HANDLE_CHECKED(type, b, 1); \ - return isolate->heap()->ToBoolean( \ - SameValue(a->get_lane(0), b->get_lane(0)) && \ - SameValue(a->get_lane(1), b->get_lane(1)) && \ - SameValue(a->get_lane(2), b->get_lane(2)) && \ - SameValue(a->get_lane(3), b->get_lane(3))); \ +#define SIMD_REPLACE_BOOLEAN_LANE_FUNCTION(type, lane_count) \ + RUNTIME_FUNCTION(Runtime_##type##ReplaceLane) { \ + HandleScope scope(isolate); \ + DCHECK(args.length() == 3); \ + CONVERT_ARG_HANDLE_CHECKED(type, simd, 0); \ + CONVERT_SIMD_LANE_ARG_CHECKED(lane, 1, lane_count); \ + bool lanes[lane_count]; \ + for (int i = 0; i < lane_count; i++) { \ + lanes[i] = simd->get_lane(i); \ + } \ + lanes[lane] = args[2]->BooleanValue(); \ + Handle result = isolate->factory()->New##type(lanes); \ + return *result; \ } -#define SIMD4_SAME_VALUE_ZERO_FUNCTION(type) \ - RUNTIME_FUNCTION(Runtime_##type##SameValueZero) { \ - HandleScope scope(isolate); \ - DCHECK(args.length() == 2); \ - CONVERT_ARG_HANDLE_CHECKED(type, a, 0); \ - CONVERT_ARG_HANDLE_CHECKED(type, b, 1); \ - return isolate->heap()->ToBoolean( \ - SameValueZero(a->get_lane(0), b->get_lane(0)) && \ - SameValueZero(a->get_lane(1), b->get_lane(1)) && \ - SameValueZero(a->get_lane(2), b->get_lane(2)) && \ - SameValueZero(a->get_lane(3), b->get_lane(3))); \ - } - -#define SIMD4_EXTRACT_LANE_FUNCTION(type) SIMD_EXTRACT_LANE_FUNCTION(type, 4) - -#define SIMD4_FUNCTIONS(type) \ - SIMD4_CREATE_FUNCTION(type) \ - SIMD_CHECK_FUNCTION(type) \ - SIMD4_EXTRACT_LANE_FUNCTION(type) \ - SIMD4_EQUALS_FUNCTION(type) \ - SIMD4_SAME_VALUE_FUNCTION(type) \ - SIMD4_SAME_VALUE_ZERO_FUNCTION(type) - namespace v8 { namespace internal { namespace { -// Convert from Number object to float. -inline float NumberToFloat(Object* number) { - return DoubleToFloat32(number->Number()); +// Functions to convert Numbers to SIMD component types. + +template +static T ConvertNumber(double number); + + +template <> +float ConvertNumber(double number) { + return DoubleToFloat32(number); +} + + +template <> +int32_t ConvertNumber(double number) { + return DoubleToInt32(number); } -inline bool Equals(float x, float y) { return x == y; } +template <> +int16_t ConvertNumber(double number) { + return static_cast(DoubleToInt32(number)); +} + + +template <> +int8_t ConvertNumber(double number) { + return static_cast(DoubleToInt32(number)); +} + + +bool Equals(Float32x4* a, Float32x4* b) { + for (int i = 0; i < 4; i++) { + if (a->get_lane(i) != b->get_lane(i)) return false; + } + return true; +} } // namespace -SIMD4_FUNCTIONS(Float32x4) +RUNTIME_FUNCTION(Runtime_IsSimdObject) { + HandleScope scope(isolate); + DCHECK(args.length() == 1); + return isolate->heap()->ToBoolean(args[0]->IsSimd128Value()); +} + + +RUNTIME_FUNCTION(Runtime_SimdToObject) { + HandleScope scope(isolate); + DCHECK(args.length() == 1); + CONVERT_ARG_HANDLE_CHECKED(Simd128Value, value, 0); + return *Object::ToObject(isolate, value).ToHandleChecked(); +} + + +RUNTIME_FUNCTION(Runtime_SimdEquals) { + HandleScope scope(isolate); + DCHECK(args.length() == 2); + CONVERT_ARG_HANDLE_CHECKED(Simd128Value, a, 0); + bool result = false; + // args[1] is of unknown type. + if (args[1]->IsSimd128Value()) { + Simd128Value* b = Simd128Value::cast(args[1]); + if (a->map()->instance_type() == b->map()->instance_type()) { + if (a->IsFloat32x4()) { + result = Equals(Float32x4::cast(*a), Float32x4::cast(b)); + } else { + result = a->BitwiseEquals(b); + } + } + } + return Smi::FromInt(result ? EQUAL : NOT_EQUAL); +} + + +RUNTIME_FUNCTION(Runtime_SimdSameValue) { + HandleScope scope(isolate); + DCHECK(args.length() == 2); + CONVERT_ARG_HANDLE_CHECKED(Simd128Value, a, 0); + bool result = false; + // args[1] is of unknown type. + if (args[1]->IsSimd128Value()) { + Simd128Value* b = Simd128Value::cast(args[1]); + if (a->map()->instance_type() == b->map()->instance_type()) { + if (a->IsFloat32x4()) { + result = Float32x4::cast(*a)->SameValue(Float32x4::cast(b)); + } else { + result = a->BitwiseEquals(b); + } + } + } + return isolate->heap()->ToBoolean(result); +} + + +RUNTIME_FUNCTION(Runtime_SimdSameValueZero) { + HandleScope scope(isolate); + DCHECK(args.length() == 2); + CONVERT_ARG_HANDLE_CHECKED(Simd128Value, a, 0); + bool result = false; + // args[1] is of unknown type. + if (args[1]->IsSimd128Value()) { + Simd128Value* b = Simd128Value::cast(args[1]); + if (a->map()->instance_type() == b->map()->instance_type()) { + if (a->IsFloat32x4()) { + result = Float32x4::cast(*a)->SameValueZero(Float32x4::cast(b)); + } else { + result = a->BitwiseEquals(b); + } + } + } + return isolate->heap()->ToBoolean(result); +} + + +SIMD_CREATE_NUMERIC_FUNCTION(Float32x4, float, 4) +SIMD_CREATE_NUMERIC_FUNCTION(Int32x4, int32_t, 4) +SIMD_CREATE_BOOLEAN_FUNCTION(Bool32x4, 4) +SIMD_CREATE_NUMERIC_FUNCTION(Int16x8, int16_t, 8) +SIMD_CREATE_BOOLEAN_FUNCTION(Bool16x8, 8) +SIMD_CREATE_NUMERIC_FUNCTION(Int8x16, int8_t, 16) +SIMD_CREATE_BOOLEAN_FUNCTION(Bool8x16, 16) + + +SIMD_CHECK_FUNCTION(Float32x4) +SIMD_CHECK_FUNCTION(Int32x4) +SIMD_CHECK_FUNCTION(Bool32x4) +SIMD_CHECK_FUNCTION(Int16x8) +SIMD_CHECK_FUNCTION(Bool16x8) +SIMD_CHECK_FUNCTION(Int8x16) +SIMD_CHECK_FUNCTION(Bool8x16) + + +SIMD_EXTRACT_LANE_FUNCTION(Float32x4, 4, NewNumber) +SIMD_EXTRACT_LANE_FUNCTION(Int32x4, 4, NewNumber) +SIMD_EXTRACT_LANE_FUNCTION(Bool32x4, 4, ToBoolean) +SIMD_EXTRACT_LANE_FUNCTION(Int16x8, 8, NewNumber) +SIMD_EXTRACT_LANE_FUNCTION(Bool16x8, 8, ToBoolean) +SIMD_EXTRACT_LANE_FUNCTION(Int8x16, 16, NewNumber) +SIMD_EXTRACT_LANE_FUNCTION(Bool8x16, 16, ToBoolean) + + +RUNTIME_FUNCTION(Runtime_Int16x8UnsignedExtractLane) { + HandleScope scope(isolate); + DCHECK(args.length() == 2); + CONVERT_ARG_HANDLE_CHECKED(Int16x8, a, 0); + CONVERT_SIMD_LANE_ARG_CHECKED(lane, 1, 8); + return *isolate->factory()->NewNumber(bit_cast(a->get_lane(lane))); +} + + +RUNTIME_FUNCTION(Runtime_Int8x16UnsignedExtractLane) { + HandleScope scope(isolate); + DCHECK(args.length() == 2); + CONVERT_ARG_HANDLE_CHECKED(Int8x16, a, 0); + CONVERT_SIMD_LANE_ARG_CHECKED(lane, 1, 16); + return *isolate->factory()->NewNumber(bit_cast(a->get_lane(lane))); +} + + +SIMD_REPLACE_NUMERIC_LANE_FUNCTION(Float32x4, float, 4) +SIMD_REPLACE_NUMERIC_LANE_FUNCTION(Int32x4, int32_t, 4) +SIMD_REPLACE_BOOLEAN_LANE_FUNCTION(Bool32x4, 4) +SIMD_REPLACE_NUMERIC_LANE_FUNCTION(Int16x8, int16_t, 8) +SIMD_REPLACE_BOOLEAN_LANE_FUNCTION(Bool16x8, 8) +SIMD_REPLACE_NUMERIC_LANE_FUNCTION(Int8x16, int8_t, 16) +SIMD_REPLACE_BOOLEAN_LANE_FUNCTION(Bool8x16, 16) } // namespace internal } // namespace v8 diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index f89618dac..9c5c0b5f9 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -569,13 +569,42 @@ namespace internal { F(Arguments, 1, 1) -#define FOR_EACH_INTRINSIC_SIMD(F) \ - F(CreateFloat32x4, 4, 1) \ - F(Float32x4Check, 1, 1) \ - F(Float32x4ExtractLane, 2, 1) \ - F(Float32x4Equals, 2, 1) \ - F(Float32x4SameValue, 2, 1) \ - F(Float32x4SameValueZero, 2, 1) +#define FOR_EACH_INTRINSIC_SIMD(F) \ + F(IsSimdObject, 1, 1) \ + F(SimdToObject, 1, 1) \ + F(SimdEquals, 2, 1) \ + F(SimdSameValue, 2, 1) \ + F(SimdSameValueZero, 2, 1) \ + F(CreateFloat32x4, 4, 1) \ + F(CreateInt32x4, 4, 1) \ + F(CreateBool32x4, 4, 1) \ + F(CreateInt16x8, 8, 1) \ + F(CreateBool16x8, 8, 1) \ + F(CreateInt8x16, 16, 1) \ + F(CreateBool8x16, 16, 1) \ + F(Float32x4Check, 1, 1) \ + F(Int32x4Check, 1, 1) \ + F(Bool32x4Check, 1, 1) \ + F(Int16x8Check, 1, 1) \ + F(Bool16x8Check, 1, 1) \ + F(Int8x16Check, 1, 1) \ + F(Bool8x16Check, 1, 1) \ + F(Float32x4ExtractLane, 2, 1) \ + F(Int32x4ExtractLane, 2, 1) \ + F(Bool32x4ExtractLane, 2, 1) \ + F(Int16x8ExtractLane, 2, 1) \ + F(Int16x8UnsignedExtractLane, 2, 1) \ + F(Bool16x8ExtractLane, 2, 1) \ + F(Int8x16ExtractLane, 2, 1) \ + F(Int8x16UnsignedExtractLane, 2, 1) \ + F(Bool8x16ExtractLane, 2, 1) \ + F(Float32x4ReplaceLane, 3, 1) \ + F(Int32x4ReplaceLane, 3, 1) \ + F(Bool32x4ReplaceLane, 3, 1) \ + F(Int16x8ReplaceLane, 3, 1) \ + F(Bool16x8ReplaceLane, 3, 1) \ + F(Int8x16ReplaceLane, 3, 1) \ + F(Bool8x16ReplaceLane, 3, 1) #define FOR_EACH_INTRINSIC_STRINGS(F) \ diff --git a/src/types.cc b/src/types.cc index 302ac0157..0087b9f23 100644 --- a/src/types.cc +++ b/src/types.cc @@ -229,6 +229,12 @@ TypeImpl::BitsetType::Lub(i::Map* map) { case HEAP_NUMBER_TYPE: return kNumber & kTaggedPointer; case FLOAT32X4_TYPE: + case INT32X4_TYPE: + case BOOL32X4_TYPE: + case INT16X8_TYPE: + case BOOL16X8_TYPE: + case INT8X16_TYPE: + case BOOL8X16_TYPE: // TODO(bbudge): Add type bits for SIMD value types. return kAny; case JS_VALUE_TYPE: diff --git a/src/utils.h b/src/utils.h index eeea4da21..582c57699 100644 --- a/src/utils.h +++ b/src/utils.h @@ -200,27 +200,6 @@ inline double Floor(double x) { return std::floor(x); } -// Implements the ES5 SameValue operation for floating point types. -// http://www.ecma-international.org/ecma-262/6.0/#sec-samevalue -template -bool SameValue(T x, T y) { - // SameValue(NaN, NaN) is true. - if (x != y) return std::isnan(x) && std::isnan(y); - // SameValue(0, -0) is false. - if (std::signbit(x) != std::signbit(y)) return false; - return true; -} - - -// Implements the ES6 SameValueZero operation for floating point types. -// http://www.ecma-international.org/ecma-262/6.0/#sec-samevaluezero -template -bool SameValueZero(T x, T y) { - if (x != y) return std::isnan(x) && std::isnan(y); - // SameValueZero doesn't distinguish between 0 and -0. - return true; -} - // TODO(svenpanne) Clean up the whole power-of-2 mess. inline int32_t WhichPowerOf2Abs(int32_t x) { diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc index 3ab60c8d8..4efbc6977 100644 --- a/src/x64/code-stubs-x64.cc +++ b/src/x64/code-stubs-x64.cc @@ -1565,6 +1565,7 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) { factory->heap_number_map()); __ j(equal, &heap_number, Label::kNear); if (cc != equal) { + Label not_simd; __ movp(rcx, FieldOperand(rax, HeapObject::kMapOffset)); __ movzxbl(rcx, FieldOperand(rcx, Map::kInstanceTypeOffset)); // Call runtime on identical objects. Otherwise return equal. @@ -1574,8 +1575,11 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) { __ cmpb(rcx, Immediate(static_cast(SYMBOL_TYPE))); __ j(equal, &runtime_call, Label::kFar); // Call runtime on identical SIMD values since we must throw a TypeError. - __ cmpb(rcx, Immediate(static_cast(FLOAT32X4_TYPE))); - __ j(equal, &runtime_call, Label::kFar); + __ cmpb(rcx, Immediate(static_cast(FIRST_SIMD_VALUE_TYPE))); + __ j(less, ¬_simd, Label::kFar); + __ cmpb(rcx, Immediate(static_cast(LAST_SIMD_VALUE_TYPE))); + __ j(less_equal, &runtime_call, Label::kFar); + __ bind(¬_simd); if (is_strong(strength())) { // We have already tested for smis and heap numbers, so if both // arguments are not strings we must proceed to the slow case. diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc index dea70b5c7..0d875673d 100644 --- a/src/x64/lithium-codegen-x64.cc +++ b/src/x64/lithium-codegen-x64.cc @@ -2215,8 +2215,12 @@ void LCodeGen::DoBranch(LBranch* instr) { if (expected.Contains(ToBooleanStub::SIMD_VALUE)) { // SIMD value -> true. - __ CmpInstanceType(map, FLOAT32X4_TYPE); - __ j(equal, instr->TrueLabel(chunk_)); + Label not_simd; + __ CmpInstanceType(map, FIRST_SIMD_VALUE_TYPE); + __ j(less, ¬_simd, Label::kNear); + __ CmpInstanceType(map, LAST_SIMD_VALUE_TYPE); + __ j(less_equal, instr->TrueLabel(chunk_)); + __ bind(¬_simd); } if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) { @@ -5749,6 +5753,36 @@ Condition LCodeGen::EmitTypeofIs(LTypeofIsAndBranch* instr, Register input) { __ CmpObjectType(input, FLOAT32X4_TYPE, input); final_branch_condition = equal; + } else if (String::Equals(type_name, factory->int32x4_string())) { + __ JumpIfSmi(input, false_label, false_distance); + __ CmpObjectType(input, INT32X4_TYPE, input); + final_branch_condition = equal; + + } else if (String::Equals(type_name, factory->bool32x4_string())) { + __ JumpIfSmi(input, false_label, false_distance); + __ CmpObjectType(input, BOOL32X4_TYPE, input); + final_branch_condition = equal; + + } else if (String::Equals(type_name, factory->int16x8_string())) { + __ JumpIfSmi(input, false_label, false_distance); + __ CmpObjectType(input, INT16X8_TYPE, input); + final_branch_condition = equal; + + } else if (String::Equals(type_name, factory->bool16x8_string())) { + __ JumpIfSmi(input, false_label, false_distance); + __ CmpObjectType(input, BOOL16X8_TYPE, input); + final_branch_condition = equal; + + } else if (String::Equals(type_name, factory->int8x16_string())) { + __ JumpIfSmi(input, false_label, false_distance); + __ CmpObjectType(input, INT8X16_TYPE, input); + final_branch_condition = equal; + + } else if (String::Equals(type_name, factory->bool8x16_string())) { + __ JumpIfSmi(input, false_label, false_distance); + __ CmpObjectType(input, BOOL8X16_TYPE, input); + final_branch_condition = equal; + } else { __ jmp(false_label, false_distance); } diff --git a/src/x87/code-stubs-x87.cc b/src/x87/code-stubs-x87.cc index cdcbaf940..a9a777e49 100644 --- a/src/x87/code-stubs-x87.cc +++ b/src/x87/code-stubs-x87.cc @@ -1389,6 +1389,7 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) { Immediate(isolate()->factory()->heap_number_map())); __ j(equal, &generic_heap_number_comparison, Label::kNear); if (cc != equal) { + Label not_simd; __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); // Call runtime on identical JSObjects. Otherwise return equal. @@ -1398,8 +1399,11 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) { __ cmpb(ecx, static_cast(SYMBOL_TYPE)); __ j(equal, &runtime_call, Label::kFar); // Call runtime on identical SIMD values since we must throw a TypeError. - __ cmpb(ecx, static_cast(FLOAT32X4_TYPE)); - __ j(equal, &runtime_call, Label::kFar); + __ cmpb(ecx, static_cast(FIRST_SIMD_VALUE_TYPE)); + __ j(less, ¬_simd, Label::kFar); + __ cmpb(ecx, static_cast(LAST_SIMD_VALUE_TYPE)); + __ j(less_equal, &runtime_call, Label::kFar); + __ bind(¬_simd); if (is_strong(strength())) { // We have already tested for smis and heap numbers, so if both // arguments are not strings we must proceed to the slow case. diff --git a/src/x87/lithium-codegen-x87.cc b/src/x87/lithium-codegen-x87.cc index b88e29c6c..13ebfc8b6 100644 --- a/src/x87/lithium-codegen-x87.cc +++ b/src/x87/lithium-codegen-x87.cc @@ -2440,8 +2440,12 @@ void LCodeGen::DoBranch(LBranch* instr) { if (expected.Contains(ToBooleanStub::SIMD_VALUE)) { // SIMD value -> true. - __ CmpInstanceType(map, FLOAT32X4_TYPE); - __ j(equal, instr->TrueLabel(chunk_)); + Label not_simd; + __ CmpInstanceType(map, FIRST_SIMD_VALUE_TYPE); + __ j(less, ¬_simd, Label::kNear); + __ CmpInstanceType(map, LAST_SIMD_VALUE_TYPE); + __ j(less_equal, instr->TrueLabel(chunk_)); + __ bind(¬_simd); } if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) { @@ -6155,6 +6159,36 @@ Condition LCodeGen::EmitTypeofIs(LTypeofIsAndBranch* instr, Register input) { __ CmpObjectType(input, FLOAT32X4_TYPE, input); final_branch_condition = equal; + } else if (String::Equals(type_name, factory()->int32x4_string())) { + __ JumpIfSmi(input, false_label, false_distance); + __ CmpObjectType(input, INT32X4_TYPE, input); + final_branch_condition = equal; + + } else if (String::Equals(type_name, factory()->bool32x4_string())) { + __ JumpIfSmi(input, false_label, false_distance); + __ CmpObjectType(input, BOOL32X4_TYPE, input); + final_branch_condition = equal; + + } else if (String::Equals(type_name, factory()->int16x8_string())) { + __ JumpIfSmi(input, false_label, false_distance); + __ CmpObjectType(input, INT16X8_TYPE, input); + final_branch_condition = equal; + + } else if (String::Equals(type_name, factory()->bool16x8_string())) { + __ JumpIfSmi(input, false_label, false_distance); + __ CmpObjectType(input, BOOL16X8_TYPE, input); + final_branch_condition = equal; + + } else if (String::Equals(type_name, factory()->int8x16_string())) { + __ JumpIfSmi(input, false_label, false_distance); + __ CmpObjectType(input, INT8X16_TYPE, input); + final_branch_condition = equal; + + } else if (String::Equals(type_name, factory()->bool8x16_string())) { + __ JumpIfSmi(input, false_label, false_distance); + __ CmpObjectType(input, BOOL8X16_TYPE, input); + final_branch_condition = equal; + } else { __ jmp(false_label, false_distance); } diff --git a/test/cctest/test-heap-profiler.cc b/test/cctest/test-heap-profiler.cc index 4f6813778..1994e9bb8 100644 --- a/test/cctest/test-heap-profiler.cc +++ b/test/cctest/test-heap-profiler.cc @@ -482,20 +482,31 @@ TEST(HeapSnapshotSymbol) { } -TEST(HeapSnapshotFloat32x4) { +void CheckSimdSnapshot(const char* program, const char* var_name) { i::FLAG_harmony_simd = true; LocalContext env; v8::HandleScope scope(env->GetIsolate()); v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); - CompileRun("a = SIMD.Float32x4(1, 2, 3, 4);\n"); + CompileRun(program); const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); - const v8::HeapGraphNode* a = - GetProperty(global, v8::HeapGraphEdge::kProperty, "a"); - CHECK(a); - CHECK_EQ(a->GetType(), v8::HeapGraphNode::kSimdValue); + const v8::HeapGraphNode* var = + GetProperty(global, v8::HeapGraphEdge::kProperty, var_name); + CHECK(var); + CHECK_EQ(var->GetType(), v8::HeapGraphNode::kSimdValue); +} + + +TEST(HeapSnapshotSimd) { + CheckSimdSnapshot("a = SIMD.Float32x4();\n", "a"); + CheckSimdSnapshot("a = SIMD.Int32x4();\n", "a"); + CheckSimdSnapshot("a = SIMD.Bool32x4();\n", "a"); + CheckSimdSnapshot("a = SIMD.Int16x8();\n", "a"); + CheckSimdSnapshot("a = SIMD.Bool16x8();\n", "a"); + CheckSimdSnapshot("a = SIMD.Int8x16();\n", "a"); + CheckSimdSnapshot("a = SIMD.Bool8x16();\n", "a"); } diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc index 87978c0d7..c54d67aee 100644 --- a/test/cctest/test-heap.cc +++ b/test/cctest/test-heap.cc @@ -215,20 +215,24 @@ TEST(HeapObjects) { template -static void CheckSimdLanes(T* value) { - // Get the original values, and check that all lanes can be set to new values - // without disturbing the other lanes. - LANE_TYPE lane_values[LANES]; +static void CheckSimdValue(T* value, LANE_TYPE lane_values[LANES], + LANE_TYPE other_value) { + // Check against lane_values, and check that all lanes can be set to + // other_value without disturbing the other lanes. for (int i = 0; i < LANES; i++) { - lane_values[i] = value->get_lane(i); + CHECK_EQ(lane_values[i], value->get_lane(i)); } for (int i = 0; i < LANES; i++) { - lane_values[i] += 1; - value->set_lane(i, lane_values[i]); + value->set_lane(i, other_value); // change the value for (int j = 0; j < LANES; j++) { - CHECK_EQ(lane_values[j], value->get_lane(j)); + if (i != j) + CHECK_EQ(lane_values[j], value->get_lane(j)); + else + CHECK_EQ(other_value, value->get_lane(j)); } + value->set_lane(i, lane_values[i]); // restore the lane } + CHECK(value->BooleanValue()); // SIMD values are 'true'. } @@ -239,42 +243,131 @@ TEST(SimdObjects) { HandleScope sc(isolate); - Handle value = factory->NewFloat32x4(1, 2, 3, 4); - CHECK(value->IsFloat32x4()); - CHECK(value->BooleanValue()); // SIMD values map to true. - CHECK_EQ(value->get_lane(0), 1); - CHECK_EQ(value->get_lane(1), 2); - CHECK_EQ(value->get_lane(2), 3); - CHECK_EQ(value->get_lane(3), 4); - - CheckSimdLanes(*value); - - // Check all lanes, and special lane values. - value->set_lane(0, 0); - CHECK_EQ(0, value->get_lane(0)); - value->set_lane(1, -0.0); - CHECK_EQ(-0.0, value->get_lane(1)); - CHECK(std::signbit(value->get_lane(1))); // Sign bit is preserved. - float quiet_NaN = std::numeric_limits::quiet_NaN(); - float signaling_NaN = std::numeric_limits::signaling_NaN(); - value->set_lane(2, quiet_NaN); - CHECK(std::isnan(value->get_lane(2))); - value->set_lane(3, signaling_NaN); - CHECK(std::isnan(value->get_lane(3))); - - // Check SIMD value printing. + // Float32x4 { - value = factory->NewFloat32x4(1, 2, 3, 4); + float lanes[4] = {1, 2, 3, 4}; + float quiet_NaN = std::numeric_limits::quiet_NaN(); + float signaling_NaN = std::numeric_limits::signaling_NaN(); + + Handle value = factory->NewFloat32x4(lanes); + CHECK(value->IsFloat32x4()); + CheckSimdValue(*value, lanes, 3.14f); + + // Check special lane values. + value->set_lane(1, -0.0); + CHECK_EQ(-0.0, value->get_lane(1)); + CHECK(std::signbit(value->get_lane(1))); // Sign bit should be preserved. + value->set_lane(2, quiet_NaN); + CHECK(std::isnan(value->get_lane(2))); + value->set_lane(3, signaling_NaN); + CHECK(std::isnan(value->get_lane(3))); + +#ifdef OBJECT_PRINT + // Check value printing. + { + value = factory->NewFloat32x4(lanes); + std::ostringstream os; + value->Float32x4Print(os); + CHECK_EQ("1, 2, 3, 4", os.str()); + } + { + float special_lanes[4] = {0, -0.0, quiet_NaN, signaling_NaN}; + value = factory->NewFloat32x4(special_lanes); + std::ostringstream os; + value->Float32x4Print(os); + // Value printing doesn't preserve signed zeroes. + CHECK_EQ("0, 0, NaN, NaN", os.str()); + } +#endif // OBJECT_PRINT + } + // Int32x4 + { + int32_t lanes[4] = {-1, 0, 1, 2}; + + Handle value = factory->NewInt32x4(lanes); + CHECK(value->IsInt32x4()); + CheckSimdValue(*value, lanes, 3); + +#ifdef OBJECT_PRINT std::ostringstream os; - value->Float32x4Print(os); - CHECK_EQ("1, 2, 3, 4", os.str()); + value->Int32x4Print(os); + CHECK_EQ("-1, 0, 1, 2", os.str()); +#endif // OBJECT_PRINT } + // Bool32x4 { - value = factory->NewFloat32x4(0, -0.0, quiet_NaN, signaling_NaN); + bool lanes[4] = {true, true, true, false}; + + Handle value = factory->NewBool32x4(lanes); + CHECK(value->IsBool32x4()); + CheckSimdValue(*value, lanes, false); + +#ifdef OBJECT_PRINT + std::ostringstream os; + value->Bool32x4Print(os); + CHECK_EQ("true, true, true, false", os.str()); +#endif // OBJECT_PRINT + } + // Int16x8 + { + int16_t lanes[8] = {-1, 0, 1, 2, 3, 4, 5, -32768}; + + Handle value = factory->NewInt16x8(lanes); + CHECK(value->IsInt16x8()); + CheckSimdValue(*value, lanes, 32767); + +#ifdef OBJECT_PRINT std::ostringstream os; - value->Float32x4Print(os); - // Value printing doesn't preserve signed zeroes. - CHECK_EQ("0, 0, NaN, NaN", os.str()); + value->Int16x8Print(os); + CHECK_EQ("-1, 0, 1, 2, 3, 4, 5, -32768", os.str()); +#endif // OBJECT_PRINT + } + // Bool16x8 + { + bool lanes[8] = {true, true, true, true, true, true, true, false}; + + Handle value = factory->NewBool16x8(lanes); + CHECK(value->IsBool16x8()); + CheckSimdValue(*value, lanes, false); + +#ifdef OBJECT_PRINT + std::ostringstream os; + value->Bool16x8Print(os); + CHECK_EQ("true, true, true, true, true, true, true, false", os.str()); +#endif // OBJECT_PRINT + } + // Int8x16 + { + int8_t lanes[16] = {-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, -128}; + + Handle value = factory->NewInt8x16(lanes); + CHECK(value->IsInt8x16()); + CheckSimdValue(*value, lanes, 127); + +#ifdef OBJECT_PRINT + std::ostringstream os; + value->Int8x16Print(os); + CHECK_EQ("-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, -128", + os.str()); +#endif // OBJECT_PRINT + } + // Bool8x16 + { + bool lanes[16] = {true, true, true, true, true, true, true, false, + true, true, true, true, true, true, true, false}; + + Handle value = factory->NewBool8x16(lanes); + CHECK(value->IsBool8x16()); + CheckSimdValue(*value, lanes, false); + +#ifdef OBJECT_PRINT + std::ostringstream os; + value->Bool8x16Print(os); + CHECK_EQ( + "true, true, true, true, true, true, true, false, true, true, true, " + "true, true, true, true, false", + os.str()); +#endif // OBJECT_PRINT } } diff --git a/test/cctest/test-simd.cc b/test/cctest/test-simd.cc index e87032df8..fd72b695e 100644 --- a/test/cctest/test-simd.cc +++ b/test/cctest/test-simd.cc @@ -10,36 +10,108 @@ using namespace v8::internal; +#define FLOAT_TEST(type, lane_count) \ + { \ + float nan = std::numeric_limits::quiet_NaN(); \ + float lanes[lane_count] = {0}; \ + Handle a = factory->New##type(lanes); \ + Handle b = factory->New##type(lanes); \ + CHECK(a->BitwiseEquals(*b)); \ + CHECK(a->SameValue(*b)); \ + CHECK(a->SameValueZero(*b)); \ + CHECK_EQ(a->Hash(), b->Hash()); \ + for (int i = 0; i < lane_count; i++) { \ + a->set_lane(i, -0.0); \ + CHECK(!a->BitwiseEquals(*b)); \ + CHECK_NE(a->Hash(), b->Hash()); \ + CHECK(!a->SameValue(*b)); \ + CHECK(a->SameValueZero(*b)); \ + b->set_lane(i, -0.0); \ + CHECK(a->BitwiseEquals(*b)); \ + CHECK_EQ(a->Hash(), b->Hash()); \ + CHECK(a->SameValue(*b)); \ + CHECK(a->SameValueZero(*b)); \ + a->set_lane(i, nan); \ + CHECK(!a->BitwiseEquals(*b)); \ + CHECK(!a->SameValue(*b)); \ + CHECK(!a->SameValueZero(*b)); \ + CHECK_NE(a->Hash(), b->Hash()); \ + b->set_lane(i, nan); \ + CHECK(a->BitwiseEquals(*b)); \ + CHECK_EQ(a->Hash(), b->Hash()); \ + CHECK(a->SameValue(*b)); \ + CHECK(a->SameValueZero(*b)); \ + } \ + } + +#define INT_TEST(type, lane_count, lane_type) \ + { \ + lane_type lanes[lane_count] = {0}; \ + Handle a = factory->New##type(lanes); \ + Handle b = factory->New##type(lanes); \ + CHECK(a->BitwiseEquals(*b)); \ + CHECK(a->SameValue(*b)); \ + CHECK(a->SameValueZero(*b)); \ + CHECK_EQ(a->Hash(), b->Hash()); \ + for (int i = 0; i < lane_count; i++) { \ + a->set_lane(i, i + 1); \ + CHECK(!a->BitwiseEquals(*b)); \ + CHECK_NE(a->Hash(), b->Hash()); \ + CHECK(!a->SameValue(*b)); \ + CHECK(!a->SameValueZero(*b)); \ + b->set_lane(i, i + 1); \ + CHECK(a->BitwiseEquals(*b)); \ + CHECK_EQ(a->Hash(), b->Hash()); \ + CHECK(a->SameValue(*b)); \ + CHECK(a->SameValueZero(*b)); \ + a->set_lane(i, -(i + 1)); \ + CHECK(!a->BitwiseEquals(*b)); \ + CHECK_NE(a->Hash(), b->Hash()); \ + CHECK(!a->SameValue(*b)); \ + CHECK(!a->SameValueZero(*b)); \ + b->set_lane(i, -(i + 1)); \ + CHECK(a->BitwiseEquals(*b)); \ + CHECK_EQ(a->Hash(), b->Hash()); \ + CHECK(a->SameValue(*b)); \ + CHECK(a->SameValueZero(*b)); \ + } \ + } -TEST(SameValue) { +#define BOOL_TEST(type, lane_count) \ + { \ + bool lanes[lane_count] = {false}; \ + Handle a = factory->New##type(lanes); \ + Handle b = factory->New##type(lanes); \ + CHECK(a->BitwiseEquals(*b)); \ + CHECK(a->SameValue(*b)); \ + CHECK(a->SameValueZero(*b)); \ + CHECK_EQ(a->Hash(), b->Hash()); \ + for (int i = 0; i < lane_count; i++) { \ + a->set_lane(i, true); \ + CHECK(!a->BitwiseEquals(*b)); \ + CHECK_NE(a->Hash(), b->Hash()); \ + CHECK(!a->SameValue(*b)); \ + CHECK(!a->SameValueZero(*b)); \ + b->set_lane(i, true); \ + CHECK(a->BitwiseEquals(*b)); \ + CHECK_EQ(a->Hash(), b->Hash()); \ + CHECK(a->SameValue(*b)); \ + CHECK(a->SameValueZero(*b)); \ + } \ + } + +TEST(SimdTypes) { CcTest::InitializeVM(); Isolate* isolate = CcTest::i_isolate(); Factory* factory = isolate->factory(); HandleScope sc(isolate); - float nan = std::numeric_limits::quiet_NaN(); - - Handle a = factory->NewFloat32x4(0, 0, 0, 0); - Handle b = factory->NewFloat32x4(0, 0, 0, 0); - CHECK(a->SameValue(*b)); - for (int i = 0; i < 4; i++) { - a->set_lane(i, nan); - CHECK(!a->SameValue(*b)); - CHECK(!a->SameValueZero(*b)); - b->set_lane(i, nan); - CHECK(a->SameValue(*b)); - CHECK(a->SameValueZero(*b)); - a->set_lane(i, -0.0); - CHECK(!a->SameValue(*b)); - b->set_lane(i, 0); - CHECK(!a->SameValue(*b)); - CHECK(a->SameValueZero(*b)); - b->set_lane(i, -0.0); - CHECK(a->SameValue(*b)); - CHECK(a->SameValueZero(*b)); - - a->set_lane(i, 0); - b->set_lane(i, 0); - } + FLOAT_TEST(Float32x4, 4) + INT_TEST(Int32x4, 4, int32_t) + BOOL_TEST(Bool32x4, 4) + INT_TEST(Int16x8, 8, int16_t) + BOOL_TEST(Bool16x8, 8) + INT_TEST(Int8x16, 16, int8_t) + BOOL_TEST(Bool8x16, 16) } diff --git a/test/mjsunit/harmony/simd.js b/test/mjsunit/harmony/simd.js index 941eff803..0c5207264 100644 --- a/test/mjsunit/harmony/simd.js +++ b/test/mjsunit/harmony/simd.js @@ -8,7 +8,17 @@ function lanesForType(typeName) { // The lane count follows the first 'x' in the type name, which begins with // 'float', 'int', or 'bool'. - return Number.parseInt(typeName[typeName.indexOf('x') + 1]); + return Number.parseInt(typeName.substr(typeName.indexOf('x') + 1)); +} + + +// Creates an instance that has been zeroed, so it can be used for equality +// testing. +function createInstance(type) { + // Provide enough parameters for the longest type (currently 16). It's + // important that instances be consistent to better test that different SIMD + // types can't be compared and are never equal or the same in any sense. + return SIMD[type](0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); } @@ -35,278 +45,404 @@ function isValidSimdString(string, value, type, lanes) { } -// Test for structural equivalence. -function areEquivalent(type, lanes, a, b) { - var simdFn = SIMD[type]; - for (var i = 0; i < lanes; i++) { - if (simdFn.extractLane(a, i) !== simdFn.extractLane(b, i)) - return false; - } - return true; -} - - -var sameValue = natives.$sameValue; -var sameValueZero = natives.$sameValueZero; - -// Calls SameValue and SameValueZero and checks that their results match. Also -// checks the internal SameValue checks using Object freeze and defineProperty. -function sameValueBoth(a, b) { - var result = sameValue(a, b); - assertTrue(result === sameValueZero(a, b)); - return result; -} - - -// Calls SameValue and SameValueZero and checks that their results don't match. -function sameValueZeroOnly(a, b) { - var result = sameValueZero(a, b); - assertTrue(result && !sameValue(a, b)); - return result; -} +var simdTypeNames = ['Float32x4', 'Int32x4', 'Bool32x4', + 'Int16x8', 'Bool16x8', + 'Int8x16', 'Bool8x16']; +var nonSimdValues = [347, 1.275, NaN, "string", null, undefined, {}, + function() {}]; -// Tests for the global SIMD object. -function TestSIMDObject() { - assertSame(typeof SIMD, 'object'); - assertSame(SIMD.constructor, Object); - assertSame(Object.getPrototypeOf(SIMD), Object.prototype); - assertSame(SIMD + "", "[object SIMD]"); +function checkTypeMatrix(type, fn) { + // Check against non-SIMD types. + nonSimdValues.forEach(fn); + // Check against SIMD values of a different type. + for (var i = 0; i < simdTypeNames.length; i++) { + var otherType = simdTypeNames[i]; + if (type != otherType) fn(createInstance(otherType)); + } } -TestSIMDObject() -// TestConstructor populates this with interesting values for the other tests. -var values; -// Test different forms of constructor calls. This test populates 'values' with -// a variety of SIMD values as a side effect, which are used by other tests. +// Test different forms of constructor calls. function TestConstructor(type, lanes) { var simdFn = SIMD[type]; + var instance = createInstance(type); + assertFalse(Object === simdFn.prototype.constructor) assertFalse(simdFn === Object.prototype.constructor) assertSame(simdFn, simdFn.prototype.constructor) - values = [] - - // The constructor expects values for all lanes. - switch (type) { - case 'Float32x4': - // The constructor expects values for all lanes. - assertThrows(function () { simdFn() }, TypeError) - assertThrows(function () { simdFn(0) }, TypeError) - assertThrows(function () { simdFn(0, 1) }, TypeError) - assertThrows(function () { simdFn(0, 1, 2) }, TypeError) - - values.push(simdFn(1, 2, 3, 4)) - values.push(simdFn(1, 2, 3, 4)) // test structural equivalence - values.push(simdFn(-0, NaN, 0, 0.5)) - values.push(simdFn(-0, NaN, 0, 0.5)) // test structural equivalence - values.push(simdFn(3, 2, 1, 0)) - values.push(simdFn(0, 0, 0, 0)) - break - } - for (var i in values) { - assertSame(simdFn, values[i].__proto__.constructor) - assertSame(simdFn, Object(values[i]).__proto__.constructor) - assertSame(simdFn.prototype, values[i].__proto__) - assertSame(simdFn.prototype, Object(values[i]).__proto__) - } + assertSame(simdFn, instance.__proto__.constructor) + assertSame(simdFn, Object(instance).__proto__.constructor) + assertSame(simdFn.prototype, instance.__proto__) + assertSame(simdFn.prototype, Object(instance).__proto__) } function TestType(type, lanes) { + var simdFn = SIMD[type]; + var instance = createInstance(type); var typeofString = type.charAt(0).toLowerCase() + type.slice(1); - for (var i in values) { - assertEquals(typeofString, typeof values[i]) - assertTrue(typeof values[i] === typeofString) - assertTrue(typeof Object(values[i]) === 'object') - assertEquals(null, %_ClassOf(values[i])) - assertEquals(type, %_ClassOf(Object(values[i]))) - } + + assertEquals(typeofString, typeof instance) + assertTrue(typeof instance === typeofString) + assertTrue(typeof Object(instance) === 'object') + assertEquals(null, %_ClassOf(instance)) + assertEquals(type, %_ClassOf(Object(instance))) } function TestPrototype(type, lanes) { var simdFn = SIMD[type]; + var instance = createInstance(type); + assertSame(Object.prototype, simdFn.prototype.__proto__) - for (var i in values) { - assertSame(simdFn.prototype, values[i].__proto__) - assertSame(simdFn.prototype, Object(values[i]).__proto__) - } + assertSame(simdFn.prototype, instance.__proto__) + assertSame(simdFn.prototype, Object(instance).__proto__) } function TestValueOf(type, lanes) { var simdFn = SIMD[type]; - for (var i in values) { - assertTrue(values[i] === Object(values[i]).valueOf()) - assertTrue(values[i] === values[i].valueOf()) - assertTrue(simdFn.prototype.valueOf.call(Object(values[i])) === values[i]) - assertTrue(simdFn.prototype.valueOf.call(values[i]) === values[i]) - } + var instance = createInstance(type); + + assertTrue(instance === Object(instance).valueOf()) + assertTrue(instance === instance.valueOf()) + assertTrue(simdFn.prototype.valueOf.call(Object(instance)) === instance) + assertTrue(simdFn.prototype.valueOf.call(instance) === instance) } function TestGet(type, lanes) { var simdFn = SIMD[type]; - for (var i in values) { - assertEquals(undefined, values[i].a) - assertEquals(undefined, values[i]["a" + "b"]) - assertEquals(undefined, values[i]["" + "1"]) - assertEquals(undefined, values[i][42]) - } + var instance = createInstance(type); + + assertEquals(undefined, instance.a) + assertEquals(undefined, instance["a" + "b"]) + assertEquals(undefined, instance["" + "1"]) + assertEquals(undefined, instance[42]) } function TestToBoolean(type, lanes) { - for (var i in values) { - assertTrue(Boolean(Object(values[i]))) - assertFalse(!Object(values[i])) - assertTrue(Boolean(values[i]).valueOf()) - assertFalse(!values[i]) - assertTrue(!!values[i]) - assertTrue(values[i] && true) - assertFalse(!values[i] && false) - assertTrue(!values[i] || true) - assertEquals(1, values[i] ? 1 : 2) - assertEquals(2, !values[i] ? 1 : 2) - if (!values[i]) assertUnreachable(); - if (values[i]) {} else assertUnreachable(); - } + var simdFn = SIMD[type]; + var instance = createInstance(type); + + assertTrue(Boolean(Object(instance))) + assertFalse(!Object(instance)) + assertTrue(Boolean(instance).valueOf()) + assertFalse(!instance) + assertTrue(!!instance) + assertTrue(instance && true) + assertFalse(!instance && false) + assertTrue(!instance || true) + assertEquals(1, instance ? 1 : 2) + assertEquals(2, !instance ? 1 : 2) + if (!instance) assertUnreachable(); + if (instance) {} else assertUnreachable(); } function TestToString(type, lanes) { var simdFn = SIMD[type]; - for (var i in values) { - assertEquals(values[i].toString(), String(values[i])) - assertTrue(isValidSimdString(values[i].toString(), values[i], type, lanes)) - assertTrue( - isValidSimdString(Object(values[i]).toString(), values[i], type, lanes)) - assertTrue(isValidSimdString( - simdFn.prototype.toString.call(values[i]), values[i], type, lanes)) - } + var instance = createInstance(type); + + assertEquals(instance.toString(), String(instance)) + assertTrue(isValidSimdString(instance.toString(), instance, type, lanes)) + assertTrue( + isValidSimdString(Object(instance).toString(), instance, type, lanes)) + assertTrue(isValidSimdString( + simdFn.prototype.toString.call(instance), instance, type, lanes)) } function TestToNumber(type, lanes) { - for (var i in values) { - assertThrows(function() { Number(Object(values[i])) }, TypeError) - assertThrows(function() { +Object(values[i]) }, TypeError) - assertThrows(function() { Number(values[i]) }, TypeError) - assertThrows(function() { values[i] + 0 }, TypeError) + var simdFn = SIMD[type]; + var instance = createInstance(type); + + assertThrows(function() { Number(Object(instance)) }, TypeError) + assertThrows(function() { +Object(instance) }, TypeError) + assertThrows(function() { Number(instance) }, TypeError) + assertThrows(function() { instance + 0 }, TypeError) +} + + +function TestCoercions(type, lanes) { + var simdFn = SIMD[type]; + var instance = createInstance(type); + // Test that setting a lane to value 'a' results in a lane with value 'b'. + function test(a, b) { + for (var i = 0; i < lanes; i++) { + var ainstance = simdFn.replaceLane(instance, i, a); + var lane_value = simdFn.extractLane(ainstance, i); + assertSame(b, lane_value); + } + } + + switch (type) { + case 'Float32x4': + test(0, 0); + test(-0, -0); + test(NaN, NaN); + test(null, 0); + test(undefined, NaN); + test("5.25", 5.25); + test(Number.MAX_VALUE, Infinity); + test(-Number.MAX_VALUE, -Infinity); + test(Number.MIN_VALUE, 0); + break; + case 'Int32x4': + test(Infinity, 0); + test(-Infinity, 0); + test(NaN, 0); + test(0, 0); + test(-0, 0); + test(Number.MIN_VALUE, 0); + test(-Number.MIN_VALUE, 0); + test(0.1, 0); + test(-0.1, 0); + test(1, 1); + test(1.1, 1); + test(-1, -1); + test(-1.6, -1); + test(2147483647, 2147483647); + test(2147483648, -2147483648); + test(2147483649, -2147483647); + test(4294967295, -1); + test(4294967296, 0); + test(4294967297, 1); + break; + case 'Int16x8': + test(Infinity, 0); + test(-Infinity, 0); + test(NaN, 0); + test(0, 0); + test(-0, 0); + test(Number.MIN_VALUE, 0); + test(-Number.MIN_VALUE, 0); + test(0.1, 0); + test(-0.1, 0); + test(1, 1); + test(1.1, 1); + test(-1, -1); + test(-1.6, -1); + test(32767, 32767); + test(32768, -32768); + test(32769, -32767); + test(65535, -1); + test(65536, 0); + test(65537, 1); + break; + case 'Int8x16': + test(Infinity, 0); + test(-Infinity, 0); + test(NaN, 0); + test(0, 0); + test(-0, 0); + test(Number.MIN_VALUE, 0); + test(-Number.MIN_VALUE, 0); + test(0.1, 0); + test(-0.1, 0); + test(1, 1); + test(1.1, 1); + test(-1, -1); + test(-1.6, -1); + test(127, 127); + test(128, -128); + test(129, -127); + test(255, -1); + test(256, 0); + test(257, 1); + break; + case 'Bool32x4': + case 'Bool16x8': + case 'Bool8x16': + test(true, true); + test(false, false); + test(0, false); + test(1, true); + test(0.1, true); + test(NaN, false); + test(null, false); + test("", false); + test("false", true); + break; } } function TestEquality(type, lanes) { + var simdFn = SIMD[type]; + var instance = createInstance(type); + // Every SIMD value should equal itself, and non-strictly equal its wrapper. - for (var i in values) { - assertSame(values[i], values[i]) - assertEquals(values[i], values[i]) - assertTrue(Object.is(values[i], values[i])) - assertTrue(values[i] === values[i]) - assertTrue(values[i] == values[i]) - assertFalse(values[i] === Object(values[i])) - assertFalse(Object(values[i]) === values[i]) - assertFalse(values[i] == Object(values[i])) - assertFalse(Object(values[i]) == values[i]) - assertTrue(values[i] === values[i].valueOf()) - assertTrue(values[i].valueOf() === values[i]) - assertTrue(values[i] == values[i].valueOf()) - assertTrue(values[i].valueOf() == values[i]) - assertFalse(Object(values[i]) === Object(values[i])) - assertEquals(Object(values[i]).valueOf(), Object(values[i]).valueOf()) + assertSame(instance, instance) + assertEquals(instance, instance) + assertTrue(Object.is(instance, instance)) + assertTrue(instance === instance) + assertTrue(instance == instance) + assertFalse(instance === Object(instance)) + assertFalse(Object(instance) === instance) + assertFalse(instance == Object(instance)) + assertFalse(Object(instance) == instance) + assertTrue(instance === instance.valueOf()) + assertTrue(instance.valueOf() === instance) + assertTrue(instance == instance.valueOf()) + assertTrue(instance.valueOf() == instance) + assertFalse(Object(instance) === Object(instance)) + assertEquals(Object(instance).valueOf(), Object(instance).valueOf()) + + function notEqual(other) { + assertFalse(instance === other) + assertFalse(other === instance) + assertFalse(instance == other) + assertFalse(other == instance) } - // Test structural equivalence. - for (var i = 0; i < values.length; i++) { - for (var j = i + 1; j < values.length; j++) { - var a = values[i], b = values[j], - equivalent = areEquivalent(type, lanes, a, b); - assertSame(equivalent, a == b); - assertSame(equivalent, a === b); + // SIMD values should not be equal to instances of different types. + checkTypeMatrix(type, function(other) { + assertFalse(instance === other) + assertFalse(other === instance) + assertFalse(instance == other) + assertFalse(other == instance) + }); + + // Test that f(a, b) is the same as f(SIMD(a), SIMD(b)) for equality and + // strict equality, at every lane. + function test(a, b) { + for (var i = 0; i < lanes; i++) { + var aval = simdFn.replaceLane(instance, i, a); + var bval = simdFn.replaceLane(instance, i, b); + assertSame(a == b, aval == bval); + assertSame(a === b, aval === bval); } } - // SIMD values should not be equal to any other kind of object. - var others = [347, 1.275, NaN, "string", null, undefined, {}, function() {}] - for (var i in values) { - for (var j in others) { - assertFalse(values[i] === others[j]) - assertFalse(others[j] === values[i]) - assertFalse(values[i] == others[j]) - assertFalse(others[j] == values[i]) - } + switch (type) { + case 'Float32x4': + test(1, 2.5); + test(1, 1); + test(0, 0); + test(-0, +0); + test(+0, -0); + test(-0, -0); + test(0, NaN); + test(NaN, NaN); + break; + case 'Int32x4': + case 'Int16x8': + case 'Int8x16': + test(1, 2); + test(1, 1); + test(1, -1); + break; + case 'Bool32x4': + case 'Bool16x8': + case 'Bool8x16': + test(true, false); + test(false, true); + break; } } function TestSameValue(type, lanes) { - // SIMD value types. - // All lanes checked. - // TODO(bbudge): use loops to test lanes when replaceLane is defined. - assertTrue(sameValueBoth(SIMD.Float32x4(1, 2, 3, 4), - SIMD.Float32x4(1, 2, 3, 4))); - assertFalse(sameValueBoth(SIMD.Float32x4(1, 2, 3, 4), - SIMD.Float32x4(NaN, 2, 3, 4))); - assertFalse(sameValueBoth(SIMD.Float32x4(1, 2, 3, 4), - SIMD.Float32x4(1, NaN, 3, 4))); - assertFalse(sameValueBoth(SIMD.Float32x4(1, 2, 3, 4), - SIMD.Float32x4(1, 2, NaN, 4))); - assertFalse(sameValueBoth(SIMD.Float32x4(1, 2, 3, 4), - SIMD.Float32x4(1, 2, 3, NaN))); - // Special values. - // TODO(bbudge): use loops to test lanes when replaceLane is defined. - assertTrue(sameValueBoth(SIMD.Float32x4(NaN, 2, 3, 4), - SIMD.Float32x4(NaN, 2, 3, 4))); - assertTrue(sameValueBoth(SIMD.Float32x4(+0, 2, 3, 4), - SIMD.Float32x4(+0, 2, 3, 4))); - assertTrue(sameValueBoth(SIMD.Float32x4(-0, 2, 3, 4), - SIMD.Float32x4(-0, 2, 3, 4))); - assertTrue(sameValueZeroOnly(SIMD.Float32x4(+0, 2, 3, 4), - SIMD.Float32x4(-0, 2, 3, 4))); - assertTrue(sameValueZeroOnly(SIMD.Float32x4(-0, 2, 3, 4), - SIMD.Float32x4(+0, 2, 3, 4))); + var simdFn = SIMD[type]; + var instance = createInstance(type); + var sameValue = natives.$sameValue; + var sameValueZero = natives.$sameValueZero; + + // SIMD values should not be the same as instances of different types. + checkTypeMatrix(type, function(other) { + assertFalse(sameValue(instance, other)); + assertFalse(sameValueZero(instance, other)); + }); + + // Test that f(a, b) is the same as f(SIMD(a), SIMD(b)) for sameValue and + // sameValueZero, at every lane. + function test(a, b) { + for (var i = 0; i < lanes; i++) { + var aval = simdFn.replaceLane(instance, i, a); + var bval = simdFn.replaceLane(instance, i, b); + assertSame(sameValue(a, b), sameValue(aval, bval)); + assertSame(sameValueZero(a, b), sameValueZero(aval, bval)); + } + } + + switch (type) { + case 'Float32x4': + test(1, 2.5); + test(1, 1); + test(0, 0); + test(-0, +0); + test(+0, -0); + test(-0, -0); + test(0, NaN); + test(NaN, NaN); + break; + case 'Int32x4': + case 'Int16x8': + case 'Int8x16': + test(1, 2); + test(1, 1); + test(1, -1); + break; + case 'Bool32x4': + case 'Bool16x8': + case 'Bool8x16': + test(true, false); + test(false, true); + break; + } } function TestComparison(type, lanes) { - var a = values[0], b = values[1]; - - function lt() { a < b; } - function gt() { a > b; } - function le() { a <= b; } - function ge() { a >= b; } - function lt_same() { a < a; } - function gt_same() { a > a; } - function le_same() { a <= a; } - function ge_same() { a >= a; } - - var throwFuncs = [lt, gt, le, ge, lt_same, gt_same, le_same, ge_same]; - - for (var f of throwFuncs) { - assertThrows(f, TypeError); - %OptimizeFunctionOnNextCall(f); - assertThrows(f, TypeError); - assertThrows(f, TypeError); + var simdFn = SIMD[type]; + var a = createInstance(type), b = createInstance(type); + + function compare(other) { + var throwFuncs = [ + function lt() { a < b; }, + function gt() { a > b; }, + function le() { a <= b; }, + function ge() { a >= b; }, + function lt_same() { a < a; }, + function gt_same() { a > a; }, + function le_same() { a <= a; }, + function ge_same() { a >= a; }, + ]; + + for (var f of throwFuncs) { + assertThrows(f, TypeError); + %OptimizeFunctionOnNextCall(f); + assertThrows(f, TypeError); + assertThrows(f, TypeError); + } } + + // Test comparison against the same SIMD type. + compare(b); + // Test comparison against other types. + checkTypeMatrix(type, compare); } // Test SIMD value wrapping/boxing over non-builtins. function TestCall(type, lanes) { var simdFn = SIMD[type]; + var instance = createInstance(type); simdFn.prototype.getThisProto = function () { return Object.getPrototypeOf(this); } - for (var i in values) { - assertTrue(values[i].getThisProto() === simdFn.prototype) - } + assertTrue(instance.getThisProto() === simdFn.prototype) } function TestAsSetKey(type, lanes, set) { + var simdFn = SIMD[type]; + var instance = createInstance(type); + function test(set, key) { assertFalse(set.has(key)); assertFalse(set.delete(key)); @@ -323,13 +459,14 @@ function TestAsSetKey(type, lanes, set) { assertFalse(set.has(key)); } - for (var i in values) { - test(set, values[i]); - } + test(set, instance); } function TestAsMapKey(type, lanes, map) { + var simdFn = SIMD[type]; + var instance = createInstance(type); + function test(map, key, value) { assertFalse(map.has(key)); assertSame(undefined, map.get(key)); @@ -350,42 +487,40 @@ function TestAsMapKey(type, lanes, map) { assertSame(undefined, map.get(key)); } - for (var i in values) { - test(map, values[i], {}); - } + test(map, instance, {}); } // Test SIMD type with Harmony reflect-apply. function TestReflectApply(type) { + var simdFn = SIMD[type]; + var instance = createInstance(type); + function returnThis() { return this; } function returnThisStrict() { 'use strict'; return this; } function noop() {} function noopStrict() { 'use strict'; } var R = void 0; - for (var i in values) { - assertSame(SIMD[type].prototype, - Object.getPrototypeOf( - Reflect.apply(returnThis, values[i], []))); - assertSame(values[i], Reflect.apply(returnThisStrict, values[i], [])); - - assertThrows( - function() { 'use strict'; Reflect.apply(values[i]); }, TypeError); - assertThrows( - function() { Reflect.apply(values[i]); }, TypeError); - assertThrows( - function() { Reflect.apply(noopStrict, R, values[i]); }, TypeError); - assertThrows( - function() { Reflect.apply(noop, R, values[i]); }, TypeError); - } + assertSame(SIMD[type].prototype, + Object.getPrototypeOf( + Reflect.apply(returnThis, instance, []))); + assertSame(instance, Reflect.apply(returnThisStrict, instance, [])); + + assertThrows( + function() { 'use strict'; Reflect.apply(instance); }, TypeError); + assertThrows( + function() { Reflect.apply(instance); }, TypeError); + assertThrows( + function() { Reflect.apply(noopStrict, R, instance); }, TypeError); + assertThrows( + function() { Reflect.apply(noop, R, instance); }, TypeError); } function TestSIMDTypes() { - var types = [ 'Float32x4' ]; - for (var i = 0; i < types.length; ++i) { - var type = types[i], + for (var i = 0; i < simdTypeNames.length; ++i) { + var type = simdTypeNames[i], lanes = lanesForType(type); TestConstructor(type, lanes); TestType(type, lanes); @@ -395,6 +530,7 @@ function TestSIMDTypes() { TestToBoolean(type, lanes); TestToString(type, lanes); TestToNumber(type, lanes); + TestCoercions(type, lanes); TestEquality(type, lanes); TestSameValue(type, lanes); TestComparison(type, lanes); @@ -407,3 +543,18 @@ function TestSIMDTypes() { } } TestSIMDTypes(); + +// Tests for the global SIMD object. +function TestSIMDObject() { + assertSame(typeof SIMD, 'object'); + assertSame(SIMD.constructor, Object); + assertSame(Object.getPrototypeOf(SIMD), Object.prototype); + assertSame(SIMD + "", "[object SIMD]"); + // The SIMD object is mutable. + SIMD.foo = "foo"; + assertSame(SIMD.foo, "foo"); + delete SIMD.foo; + delete SIMD.Bool8x16; + assertSame(SIMD.Bool8x16, undefined); +} +TestSIMDObject() diff --git a/test/simdjs/harness-adapt.js b/test/simdjs/harness-adapt.js index 8941e2fdc..c90d6cc9d 100644 --- a/test/simdjs/harness-adapt.js +++ b/test/simdjs/harness-adapt.js @@ -33,6 +33,7 @@ var console = { log: function(x) { print(x); }, }; -// Disable value type tests for now, since the polyfill can't pass them. -// TODO(bbudge): Drop when polyfill is not needed. + +// Disable value type tests for now. The value semantics tests are incorrect. +// TODO(bbudge): Drop when tests are fixed. var skipValueTests = true;