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;
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;
// 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);
__ 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.
__ 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
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)) {
__ 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);
}
// 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);
__ 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.
} 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.
__ 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
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)) {
__ 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);
}
DCHECK(simd_object->IsJSObject());
JSObject::AddProperty(global, name, simd_object, DONT_ENUM);
- Handle<JSFunction> 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<JSFunction> 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)
}
{ Push(Add<HConstant>(factory->float32x4_string())); }
is_float32x4.Else();
{
- // Is it an undetectable object?
- IfBuilder is_undetectable(this);
- is_undetectable.If<HIsUndetectableAndBranch>(object);
- is_undetectable.Then();
+ IfBuilder is_int32x4(this);
+ is_int32x4.If<HCompareNumericAndBranch>(
+ instance_type, Add<HConstant>(INT32X4_TYPE), Token::EQ);
+ is_int32x4.Then();
+ { Push(Add<HConstant>(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<HCompareNumericAndBranch>(
+ instance_type, Add<HConstant>(BOOL32X4_TYPE), Token::EQ);
+ is_bool32x4.Then();
+ { Push(Add<HConstant>(factory->bool32x4_string())); }
+ is_bool32x4.Else();
+ {
+ IfBuilder is_int16x8(this);
+ is_int16x8.If<HCompareNumericAndBranch>(
+ instance_type, Add<HConstant>(INT16X8_TYPE), Token::EQ);
+ is_int16x8.Then();
+ { Push(Add<HConstant>(factory->int16x8_string())); }
+ is_int16x8.Else();
+ {
+ IfBuilder is_bool16x8(this);
+ is_bool16x8.If<HCompareNumericAndBranch>(
+ instance_type, Add<HConstant>(BOOL16X8_TYPE),
+ Token::EQ);
+ is_bool16x8.Then();
+ { Push(Add<HConstant>(factory->bool16x8_string())); }
+ is_bool16x8.Else();
+ {
+ IfBuilder is_int8x16(this);
+ is_int8x16.If<HCompareNumericAndBranch>(
+ instance_type, Add<HConstant>(INT8X16_TYPE),
+ Token::EQ);
+ is_int8x16.Then();
+ { Push(Add<HConstant>(factory->int8x16_string())); }
+ is_int8x16.Else();
+ {
+ IfBuilder is_bool8x16(this);
+ is_bool8x16.If<HCompareNumericAndBranch>(
+ instance_type, Add<HConstant>(BOOL8X16_TYPE),
+ Token::EQ);
+ is_bool8x16.Then();
+ { Push(Add<HConstant>(factory->bool8x16_string())); }
+ is_bool8x16.Else();
+ {
+ // Is it an undetectable object?
+ IfBuilder is_undetectable(this);
+ is_undetectable.If<HIsUndetectableAndBranch>(
+ 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);
+ }
+ }
+ }
+ }
+ }
+ }
}
}
}
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 {
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) \
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,
}
-Handle<Float32x4> Factory::NewFloat32x4(float w, float x, float y, float z,
+Handle<Float32x4> Factory::NewFloat32x4(float lanes[4],
PretenureFlag pretenure) {
+ CALL_HEAP_FUNCTION(isolate(),
+ isolate()->heap()->AllocateFloat32x4(lanes, pretenure),
+ Float32x4);
+}
+
+
+Handle<Int32x4> Factory::NewInt32x4(int32_t lanes[4], PretenureFlag pretenure) {
+ CALL_HEAP_FUNCTION(
+ isolate(), isolate()->heap()->AllocateInt32x4(lanes, pretenure), Int32x4);
+}
+
+
+Handle<Bool32x4> Factory::NewBool32x4(bool lanes[4], PretenureFlag pretenure) {
+ CALL_HEAP_FUNCTION(isolate(),
+ isolate()->heap()->AllocateBool32x4(lanes, pretenure),
+ Bool32x4);
+}
+
+
+Handle<Int16x8> 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<Bool16x8> Factory::NewBool16x8(bool lanes[8], PretenureFlag pretenure) {
+ CALL_HEAP_FUNCTION(isolate(),
+ isolate()->heap()->AllocateBool16x8(lanes, pretenure),
+ Bool16x8);
+}
+
+
+Handle<Int8x16> Factory::NewInt8x16(int8_t lanes[16], PretenureFlag pretenure) {
+ CALL_HEAP_FUNCTION(
+ isolate(), isolate()->heap()->AllocateInt8x16(lanes, pretenure), Int8x16);
+}
+
+
+Handle<Bool8x16> Factory::NewBool8x16(bool lanes[16], PretenureFlag pretenure) {
+ CALL_HEAP_FUNCTION(isolate(),
+ isolate()->heap()->AllocateBool8x16(lanes, pretenure),
+ Bool8x16);
}
Handle<HeapNumber> NewHeapNumber(double value,
MutableMode mode = IMMUTABLE,
PretenureFlag pretenure = NOT_TENURED);
- Handle<Float32x4> NewFloat32x4(float w, float x, float y, float z,
+ Handle<Float32x4> NewFloat32x4(float lanes[4],
PretenureFlag pretenure = NOT_TENURED);
+ Handle<Int32x4> NewInt32x4(int32_t lanes[4],
+ PretenureFlag pretenure = NOT_TENURED);
+ Handle<Bool32x4> NewBool32x4(bool lanes[4],
+ PretenureFlag pretenure = NOT_TENURED);
+ Handle<Int16x8> NewInt16x8(int16_t lanes[8],
+ PretenureFlag pretenure = NOT_TENURED);
+ Handle<Bool16x8> NewBool16x8(bool lanes[8],
+ PretenureFlag pretenure = NOT_TENURED);
+ Handle<Int8x16> NewInt8x16(int8_t lanes[16],
+ PretenureFlag pretenure = NOT_TENURED);
+ Handle<Bool8x16> NewBool8x16(bool lanes[16],
+ PretenureFlag pretenure = NOT_TENURED);
// These objects are used by the api to create env-independent data
// structures in the heap.
}
+void FullCodeGenerator::EmitIsSimdObject(CallRuntime* expr) {
+ ZoneList<Expression*>* 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<Expression*>* args = expr->arguments();
DCHECK(args->length() == 1);
__ 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);
}
+void FullCodeGenerator::EmitIsSimdObject(CallRuntime* expr) {
+ ZoneList<Expression*>* 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<Expression*>* args = expr->arguments();
__ 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);
F(IsFunction) \
F(IsUndetectableObject) \
F(IsSpecObject) \
+ F(IsSimdObject) \
F(IsStringWrapperSafeForDefaultValueOf) \
F(MathPow) \
F(IsMinusZero) \
}
+void FullCodeGenerator::EmitIsSimdObject(CallRuntime* expr) {
+ ZoneList<Expression*>* 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<Expression*>* args = expr->arguments();
DCHECK(args->length() == 1);
__ 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);
}
+void FullCodeGenerator::EmitIsSimdObject(CallRuntime* expr) {
+ ZoneList<Expression*>* 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<Expression*>* args = expr->arguments();
DCHECK(args->length() == 1);
__ 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));
}
+void FullCodeGenerator::EmitIsSimdObject(CallRuntime* expr) {
+ ZoneList<Expression*>* 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<Expression*>* args = expr->arguments();
DCHECK(args->length() == 1);
__ 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));
}
+void FullCodeGenerator::EmitIsSimdObject(CallRuntime* expr) {
+ ZoneList<Expression*>* 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<Expression*>* args = expr->arguments();
DCHECK(args->length() == 1);
__ 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);
}
+void FullCodeGenerator::EmitIsSimdObject(CallRuntime* expr) {
+ ZoneList<Expression*>* 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<Expression*>* args = expr->arguments();
DCHECK(args->length() == 1);
__ 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);
}
+void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) {
+ ZoneList<Expression*>* 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<Expression*>* args = expr->arguments();
DCHECK(args->length() == 1);
__ 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);
// 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";
// 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,
+]);
})
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));
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)
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) {
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) \
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") \
V(HeapNumberMap) \
V(MutableHeapNumberMap) \
V(Float32x4Map) \
+ V(Int32x4Map) \
+ V(Bool32x4Map) \
+ V(Int16x8Map) \
+ V(Bool16x8Map) \
+ V(Int8x16Map) \
+ V(Bool8x16Map) \
V(NativeContextMap) \
V(FixedArrayMap) \
V(CodeMap) \
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
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);
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();
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.
__ cmpb(ecx, static_cast<uint8_t>(SYMBOL_TYPE));
__ j(equal, &runtime_call, Label::kFar);
// Call runtime on identical SIMD values since we must throw a TypeError.
- __ cmpb(ecx, static_cast<uint8_t>(FLOAT32X4_TYPE));
- __ j(equal, &runtime_call, Label::kFar);
+ __ cmpb(ecx, static_cast<uint8_t>(FIRST_SIMD_VALUE_TYPE));
+ __ j(less, ¬_simd, Label::kFar);
+ __ cmpb(ecx, static_cast<uint8_t>(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.
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)) {
__ 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);
}
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 {
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;
}
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');
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');
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");
// 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.
__ 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) {
// 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
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)) {
*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.
// 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.
__ 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.
}
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)) {
*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));
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;
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());
}
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;
#define WRITE_INTPTR_FIELD(p, offset, value) \
(*reinterpret_cast<intptr_t*>(FIELD_ADDR(p, offset)) = value)
+#define READ_UINT16_FIELD(p, offset) \
+ (*reinterpret_cast<const uint16_t*>(FIELD_ADDR_CONST(p, offset)))
+
+#define WRITE_UINT16_FIELD(p, offset, value) \
+ (*reinterpret_cast<uint16_t*>(FIELD_ADDR(p, offset)) = value)
+
+#define READ_INT16_FIELD(p, offset) \
+ (*reinterpret_cast<const int16_t*>(FIELD_ADDR_CONST(p, offset)))
+
+#define WRITE_INT16_FIELD(p, offset, value) \
+ (*reinterpret_cast<int16_t*>(FIELD_ADDR(p, offset)) = value)
+
#define READ_UINT32_FIELD(p, offset) \
(*reinterpret_cast<const uint32_t*>(FIELD_ADDR_CONST(p, offset)))
#define WRITE_INT64_FIELD(p, offset, value) \
(*reinterpret_cast<int64_t*>(FIELD_ADDR(p, offset)) = value)
-#define READ_SHORT_FIELD(p, offset) \
- (*reinterpret_cast<const uint16_t*>(FIELD_ADDR_CONST(p, offset)))
-
-#define WRITE_SHORT_FIELD(p, offset, value) \
- (*reinterpret_cast<uint16_t*>(FIELD_ADDR(p, offset)) = value)
-
#define READ_BYTE_FIELD(p, offset) \
(*reinterpret_cast<const byte*>(FIELD_ADDR_CONST(p, offset)))
}
+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)
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");
}
return kDoubleAligned;
}
if (IsHeapNumber()) return kDoubleUnaligned;
- if (IsFloat32x4()) return kSimd128Unaligned;
+ if (IsSimd128Value()) return kSimd128Unaligned;
#endif // V8_HOST_ARCH_32_BIT
return kWordAligned;
}
CAST_ACCESSOR(AccessorInfo)
CAST_ACCESSOR(ArrayList)
+CAST_ACCESSOR(Bool16x8)
+CAST_ACCESSOR(Bool32x4)
+CAST_ACCESSOR(Bool8x16)
CAST_ACCESSOR(ByteArray)
CAST_ACCESSOR(BytecodeArray)
CAST_ACCESSOR(Cell)
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)
CAST_ACCESSOR(SeqString)
CAST_ACCESSOR(SeqTwoByteString)
CAST_ACCESSOR(SharedFunctionInfo)
+CAST_ACCESSOR(Simd128Value)
CAST_ACCESSOR(SlicedString)
CAST_ACCESSOR(Smi)
CAST_ACCESSOR(String)
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);
}
#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
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;
}
+void Float32x4::Float32x4Print(std::ostream& os) { // NOLINT
+ char arr[100];
+ Vector<char> 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<char> 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<char> 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<char> 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<char> 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<char> 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();
}
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<JSReceiver>();
}
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;
}
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();
}
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<uint32_t>(simd->get_lane(0)), seed);
- hash = ComputeIntegerHash(bit_cast<uint32_t>(simd->get_lane(1)), hash * 31);
- hash = ComputeIntegerHash(bit_cast<uint32_t>(simd->get_lane(2)), hash * 31);
- hash = ComputeIntegerHash(bit_cast<uint32_t>(simd->get_lane(3)), hash * 31);
+ if (IsSimd128Value()) {
+ uint32_t hash = Simd128Value::cast(this)->Hash();
return Smi::FromInt(hash & Smi::kMaxValue);
}
DCHECK(IsJSReceiver());
// 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;
}
// 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;
}
os << '>';
break;
}
- case FLOAT32X4_TYPE: {
- os << "<Float32x4: ";
- Float32x4::cast(this)->Float32x4Print(os);
- os << ">";
+ case FLOAT32X4_TYPE:
+ os << "<Float32x4>";
+ break;
+ case INT32X4_TYPE:
+ os << "<Int32x4>";
+ break;
+ case BOOL32X4_TYPE:
+ os << "<Bool32x4>";
+ break;
+ case INT16X8_TYPE:
+ os << "<Int16x8>";
+ break;
+ case BOOL16X8_TYPE:
+ os << "<Bool16x8>";
+ break;
+ case INT8X16_TYPE:
+ os << "<Int8x16>";
+ break;
+ case BOOL8X16_TYPE:
+ os << "<Bool8x16>";
break;
- }
case JS_PROXY_TYPE:
os << "<JSProxy>";
break;
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:
}
-void Float32x4::Float32x4Print(std::ostream& os) { // NOLINT
- char arr[100];
- Vector<char> 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<const byte*>(p) + offset - kHeapObjectTag)
+
+#define READ_INT32_FIELD(p, offset) \
+ (*reinterpret_cast<const int32_t*>(FIELD_ADDR_CONST(p, offset)))
+
+#define READ_INT64_FIELD(p, offset) \
+ (*reinterpret_cast<const int64_t*>(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;
}
// - ExternalTwoByteInternalizedString
// - Symbol
// - HeapNumber
-// - Float32x4
+// - Simd128Value
+// - Float32x4
+// - Int32x4
+// - Bool32x4
+// - Int16x8
+// - Bool16x8
+// - Int8x16
+// - Bool8x16
// - Cell
// - PropertyCell
// - Code
\
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) \
// 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,
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,
#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) \
};
-// 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 {
// 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);
__ 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.
__ 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
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)) {
__ 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);
}
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));
}
} 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)) {
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);
}
}
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
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);
}
return false;
}
}
- if (IS_FLOAT32X4(x)) {
- return %Float32x4SameValue(x, y);
- }
+ if (IS_SIMD_OBJECT(x)) return %SimdSameValue(x, y);
return 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;
}
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;
// 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<lane_type>(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) \
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<lane_type>(number->Number()); \
+ Handle<type> 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<type> 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 <typename T>
+static T ConvertNumber(double number);
+
+
+template <>
+float ConvertNumber<float>(double number) {
+ return DoubleToFloat32(number);
+}
+
+
+template <>
+int32_t ConvertNumber<int32_t>(double number) {
+ return DoubleToInt32(number);
}
-inline bool Equals(float x, float y) { return x == y; }
+template <>
+int16_t ConvertNumber<int16_t>(double number) {
+ return static_cast<int16_t>(DoubleToInt32(number));
+}
+
+
+template <>
+int8_t ConvertNumber<int8_t>(double number) {
+ return static_cast<int8_t>(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<uint16_t>(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<uint8_t>(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
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) \
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:
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 <typename T>
-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 <typename T>
-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) {
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.
__ cmpb(rcx, Immediate(static_cast<uint8_t>(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<uint8_t>(FLOAT32X4_TYPE)));
- __ j(equal, &runtime_call, Label::kFar);
+ __ cmpb(rcx, Immediate(static_cast<uint8_t>(FIRST_SIMD_VALUE_TYPE)));
+ __ j(less, ¬_simd, Label::kFar);
+ __ cmpb(rcx, Immediate(static_cast<uint8_t>(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.
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)) {
__ 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);
}
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.
__ cmpb(ecx, static_cast<uint8_t>(SYMBOL_TYPE));
__ j(equal, &runtime_call, Label::kFar);
// Call runtime on identical SIMD values since we must throw a TypeError.
- __ cmpb(ecx, static_cast<uint8_t>(FLOAT32X4_TYPE));
- __ j(equal, &runtime_call, Label::kFar);
+ __ cmpb(ecx, static_cast<uint8_t>(FIRST_SIMD_VALUE_TYPE));
+ __ j(less, ¬_simd, Label::kFar);
+ __ cmpb(ecx, static_cast<uint8_t>(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.
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)) {
__ 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);
}
}
-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");
}
template <typename T, typename LANE_TYPE, int LANES>
-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'.
}
HandleScope sc(isolate);
- Handle<Float32x4> 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<Float32x4, float, 4>(*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<float>::quiet_NaN();
- float signaling_NaN = std::numeric_limits<float>::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<float>::quiet_NaN();
+ float signaling_NaN = std::numeric_limits<float>::signaling_NaN();
+
+ Handle<Float32x4> value = factory->NewFloat32x4(lanes);
+ CHECK(value->IsFloat32x4());
+ CheckSimdValue<Float32x4, float, 4>(*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<Int32x4> value = factory->NewInt32x4(lanes);
+ CHECK(value->IsInt32x4());
+ CheckSimdValue<Int32x4, int32_t, 4>(*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<Bool32x4> value = factory->NewBool32x4(lanes);
+ CHECK(value->IsBool32x4());
+ CheckSimdValue<Bool32x4, bool, 4>(*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<Int16x8> value = factory->NewInt16x8(lanes);
+ CHECK(value->IsInt16x8());
+ CheckSimdValue<Int16x8, int16_t, 8>(*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<Bool16x8> value = factory->NewBool16x8(lanes);
+ CHECK(value->IsBool16x8());
+ CheckSimdValue<Bool16x8, bool, 8>(*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<Int8x16> value = factory->NewInt8x16(lanes);
+ CHECK(value->IsInt8x16());
+ CheckSimdValue<Int8x16, int8_t, 16>(*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<Bool8x16> value = factory->NewBool8x16(lanes);
+ CHECK(value->IsBool8x16());
+ CheckSimdValue<Bool8x16, bool, 16>(*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
}
}
using namespace v8::internal;
+#define FLOAT_TEST(type, lane_count) \
+ { \
+ float nan = std::numeric_limits<float>::quiet_NaN(); \
+ float lanes[lane_count] = {0}; \
+ Handle<type> a = factory->New##type(lanes); \
+ Handle<type> 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<type> a = factory->New##type(lanes); \
+ Handle<type> 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<type> a = factory->New##type(lanes); \
+ Handle<type> 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<float>::quiet_NaN();
-
- Handle<Float32x4> a = factory->NewFloat32x4(0, 0, 0, 0);
- Handle<Float32x4> 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)
}
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);
}
}
-// 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));
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));
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);
TestToBoolean(type, lanes);
TestToString(type, lanes);
TestToNumber(type, lanes);
+ TestCoercions(type, lanes);
TestEquality(type, lanes);
TestSameValue(type, lanes);
TestComparison(type, lanes);
}
}
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()
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;