"src/harmony-reflect.js",
"src/harmony-spread.js",
"src/harmony-object.js",
- "src/harmony-sharedarraybuffer.js"
+ "src/harmony-sharedarraybuffer.js",
+ "src/harmony-simd.js"
]
outputs = [
"src/runtime/runtime-proxy.cc",
"src/runtime/runtime-regexp.cc",
"src/runtime/runtime-scopes.cc",
+ "src/runtime/runtime-simd.cc",
"src/runtime/runtime-strings.cc",
"src/runtime/runtime-symbol.cc",
"src/runtime/runtime-test.cc",
class Data;
class Date;
class External;
+class Float32x4Object;
class Function;
class FunctionTemplate;
class HeapProfiler;
*/
bool IsSymbolObject() const;
+ /**
+ * Returns true if this value is a Float32x4 object.
+ * This is an experimental feature.
+ */
+ bool IsFloat32x4Object() const;
+
/**
* Returns true if this value is a NativeError.
*/
};
+/**
+ * An instance of Float32x4 constructor.
+ * (ES7 draft http://littledan.github.io/simd.html).
+ * This API is experimental and may change significantly.
+ */
+class V8_EXPORT Float32x4 : public Value {
+ public:
+ static Local<Float32x4> New(Isolate* isolate, float w, float x, float y,
+ float z);
+ V8_INLINE static Float32x4* Cast(Value* obj);
+
+ private:
+ Float32x4();
+ static void CheckCast(Value* obj);
+};
+
+
/**
* An instance of the built-in Date constructor (ECMA-262, 15.9).
*/
};
+/**
+ * A Float32x4 object.
+ * (ES7 draft http://littledan.github.io/simd.html).
+ * This is an experimental feature. Use at your own risk.
+ */
+class V8_EXPORT Float32x4Object : public Object {
+ public:
+ static Local<Value> New(Isolate* isolate, Local<Float32x4> value);
+
+ Local<Float32x4> ValueOf() const;
+
+ V8_INLINE static Float32x4Object* Cast(v8::Value* obj);
+
+ private:
+ static void CheckCast(v8::Value* obj);
+};
+
+
/**
* An instance of the built-in RegExp constructor (ECMA-262, 15.10).
*/
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 = 82;
static const int kFullStringRepresentationMask = 0x07;
static const int kStringEncodingMask = 0x4;
static const int kExternalTwoByteRepresentationTag = 0x02;
}
+Float32x4Object* Float32x4Object::Cast(v8::Value* value) {
+#ifdef V8_ENABLE_CHECKS
+ CheckCast(value);
+#endif
+ return static_cast<Float32x4Object*>(value);
+}
+
+
NumberObject* NumberObject::Cast(v8::Value* value) {
#ifdef V8_ENABLE_CHECKS
CheckCast(value);
// 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);
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.
// 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);
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
__ JumpIfSmi(r0, if_false);
__ CompareObjectType(r0, r0, r1, SYMBOL_TYPE);
Split(eq, if_true, if_false, fall_through);
+ } else if (String::Equals(check, factory->float32x4_string())) {
+ __ JumpIfSmi(r0, if_false);
+ __ CompareObjectType(r0, r0, r1, FLOAT32X4_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);
__ b(eq, instr->TrueLabel(chunk_));
}
+ if (expected.Contains(ToBooleanStub::SIMD_VALUE)) {
+ // SIMD value -> true.
+ __ CompareInstanceType(map, ip, FLOAT32X4_TYPE);
+ __ b(eq, instr->TrueLabel(chunk_));
+ }
+
if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
// heap number -> false iff +0, -0, or NaN.
DwVfpRegister dbl_scratch = double_scratch0();
__ tst(scratch, Operand(1 << Map::kIsUndetectable));
final_branch_condition = eq;
+ } else if (String::Equals(type_name, factory->float32x4_string())) {
+ __ JumpIfSmi(input, false_label);
+ __ CompareObjectType(input, scratch, no_reg, FLOAT32X4_TYPE);
+ final_branch_condition = eq;
+
} else {
__ b(false_label);
}
// Call runtime on identical symbols since we need to throw a TypeError.
__ 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);
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.
// Call runtime on identical symbols since we need to throw a TypeError.
__ 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);
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
__ JumpIfSmi(x0, if_false);
__ CompareObjectType(x0, x0, x1, SYMBOL_TYPE);
Split(eq, if_true, if_false, fall_through);
+ } else if (String::Equals(check, factory->float32x4_string())) {
+ ASM_LOCATION(
+ "FullCodeGenerator::EmitLiteralCompareTypeof float32x4_string");
+ __ JumpIfSmi(x0, if_false);
+ __ CompareObjectType(x0, x0, x1, FLOAT32X4_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);
__ B(eq, true_label);
}
+ if (expected.Contains(ToBooleanStub::SIMD_VALUE)) {
+ // SIMD value -> true.
+ __ CompareInstanceType(map, scratch, FLOAT32X4_TYPE);
+ __ B(eq, true_label);
+ }
+
if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
Label not_heap_number;
__ JumpIfNotRoot(map, Heap::kHeapNumberMapRootIndex, ¬_heap_number);
__ Ldrb(scratch, FieldMemOperand(map, Map::kBitFieldOffset));
EmitTestAndBranch(instr, eq, scratch, 1 << Map::kIsUndetectable);
+ } else if (String::Equals(type_name, factory->float32x4_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, FLOAT32X4_TYPE);
+ EmitBranch(instr, eq);
+
} else {
__ B(false_label);
}
EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_atomics)
EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_new_target)
EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_concat_spreadable)
+EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_simd)
void Genesis::InstallNativeFunctions_harmony_proxies() {
}
+void Genesis::InitializeGlobal_harmony_simd() {
+ Handle<JSGlobalObject> global(
+ JSGlobalObject::cast(native_context()->global_object()));
+ Isolate* isolate = global->GetIsolate();
+ Factory* factory = isolate->factory();
+
+ Handle<String> name = factory->InternalizeUtf8String("SIMD");
+ Handle<JSFunction> cons = factory->NewFunction(name);
+ JSFunction::SetInstancePrototype(
+ cons,
+ Handle<Object>(native_context()->initial_object_prototype(), isolate));
+ cons->SetInstanceClassName(*name);
+ Handle<JSObject> simd_object = factory->NewJSObject(cons, TENURED);
+ 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);
+}
+
+
Handle<JSFunction> Genesis::InstallInternalArray(Handle<JSObject> target,
const char* name,
ElementsKind elements_kind) {
static const char* harmony_new_target_natives[] = {nullptr};
static const char* harmony_concat_spreadable_natives[] = {
"native harmony-concat-spreadable.js", nullptr};
+ static const char* harmony_simd_natives[] = {"native harmony-simd.js",
+ nullptr};
for (int i = ExperimentalNatives::GetDebuggerCount();
i < ExperimentalNatives::GetBuiltinsCount(); i++) {
{ Push(Add<HConstant>(factory->function_string())); }
is_function.Else();
{
- // Is it an undetectable object?
- IfBuilder is_undetectable(this);
- is_undetectable.If<HIsUndetectableAndBranch>(object);
- is_undetectable.Then();
+ IfBuilder is_float32x4(this);
+ is_float32x4.If<HCompareNumericAndBranch>(
+ instance_type, Add<HConstant>(FLOAT32X4_TYPE), Token::EQ);
+ is_float32x4.Then();
+ { Push(Add<HConstant>(factory->float32x4_string())); }
+ is_float32x4.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);
+ // 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);
+ }
}
}
is_function.End();
if (s.Contains(ToBooleanStub::STRING)) p.Add("String");
if (s.Contains(ToBooleanStub::SYMBOL)) p.Add("Symbol");
if (s.Contains(ToBooleanStub::HEAP_NUMBER)) p.Add("HeapNumber");
+ if (s.Contains(ToBooleanStub::SIMD_VALUE)) p.Add("SimdValue");
return os << ")";
}
Add(HEAP_NUMBER);
double value = HeapNumber::cast(*object)->value();
return value != 0 && !std::isnan(value);
+ } else if (object->IsFloat32x4()) {
+ Add(SIMD_VALUE);
+ return true;
} else {
// We should never see an internal object at runtime here!
UNREACHABLE();
bool ToBooleanStub::Types::NeedsMap() const {
- return Contains(ToBooleanStub::SPEC_OBJECT)
- || Contains(ToBooleanStub::STRING)
- || Contains(ToBooleanStub::SYMBOL)
- || Contains(ToBooleanStub::HEAP_NUMBER);
+ return Contains(ToBooleanStub::SPEC_OBJECT) ||
+ Contains(ToBooleanStub::STRING) || Contains(ToBooleanStub::SYMBOL) ||
+ Contains(ToBooleanStub::HEAP_NUMBER) ||
+ Contains(ToBooleanStub::SIMD_VALUE);
}
STRING,
SYMBOL,
HEAP_NUMBER,
+ SIMD_VALUE,
NUMBER_OF_TYPES
};
V(STRING_FUNCTION_INDEX, JSFunction, string_function) \
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(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_INDEX,
STRING_FUNCTION_PROTOTYPE_MAP_INDEX,
SYMBOL_FUNCTION_INDEX,
+ FLOAT32X4_FUNCTION_INDEX,
OBJECT_FUNCTION_INDEX,
JS_OBJECT_STRONG_MAP_INDEX,
INTERNAL_ARRAY_FUNCTION_INDEX,
V(harmony_destructuring, "harmony destructuring") \
V(harmony_sharedarraybuffer, "harmony sharedarraybuffer") \
V(harmony_atomics, "harmony atomics") \
- V(harmony_new_target, "harmony new.target")
+ V(harmony_new_target, "harmony new.target") \
+ V(harmony_simd, "harmony simd")
// Features that are complete (but still behind --harmony/es-staging flag).
#define HARMONY_STAGED(V) \
class Symbol;
class Name;
class Struct;
-class Symbol;
class Variable;
class RelocInfo;
class Deserializer;
--- /dev/null
+// Copyright 2015 the V8 project authors. All rights reserved.
+// 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";
+
+%CheckIsBootstrapping();
+
+// -------------------------------------------------------------------
+// Imports
+
+var GlobalSIMD = global.SIMD;
+var GlobalFloat32x4 = GlobalSIMD.Float32x4;
+
+//-------------------------------------------------------------------
+
+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);
+}
+
+function Float32x4Splat(s) {
+ return %CreateFloat32x4(s, s, s, s);
+}
+
+function Float32x4CheckJS(a) {
+ return %Float32x4Check(a);
+}
+
+function Float32x4ToString() {
+ if (!(IS_FLOAT32X4(this) || IS_FLOAT32X4_WRAPPER(this))) {
+ throw MakeTypeError(kIncompatibleMethodReceiver,
+ "Float32x4.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 "Float32x4(" + w + ", " + x + ", " + y + ", " + z + ")";
+}
+
+function Float32x4ValueOf() {
+ if (!(IS_FLOAT32X4(this) || IS_FLOAT32X4_WRAPPER(this))) {
+ throw MakeTypeError(kIncompatibleMethodReceiver,
+ "Float32x4.prototype.valueOf", this);
+ }
+ return %_ValueOf(this);
+}
+
+//-------------------------------------------------------------------
+
+function Float32x4ExtractLaneJS(value, lane) {
+ return %Float32x4ExtractLane(value, lane);
+}
+
+// -------------------------------------------------------------------
+
+%AddNamedProperty(GlobalSIMD, symbolToStringTag, 'SIMD', READ_ONLY | DONT_ENUM);
+%AddNamedProperty(GlobalSIMD, 'float32x4', GlobalFloat32x4, DONT_ENUM);
+
+%SetCode(GlobalFloat32x4, Float32x4Constructor);
+%FunctionSetPrototype(GlobalFloat32x4, {});
+%AddNamedProperty(
+ GlobalFloat32x4.prototype, 'constructor', GlobalFloat32x4, DONT_ENUM);
+%AddNamedProperty(
+ GlobalFloat32x4, symbolToStringTag, 'Float32x4', DONT_ENUM | READ_ONLY);
+
+utils.InstallFunctions(GlobalFloat32x4.prototype, DONT_ENUM, [
+ 'valueOf', Float32x4ValueOf,
+ 'toString', Float32x4ToString,
+]);
+
+utils.InstallFunctions(GlobalFloat32x4, DONT_ENUM, [
+ 'splat', Float32x4Splat,
+ 'check', Float32x4CheckJS,
+ 'extractLane', Float32x4ExtractLaneJS,
+]);
+
+$float32x4ToString = Float32x4ToString;
+
+})
V(constructor_string, "constructor") \
V(dot_result_string, ".result") \
V(eval_string, "eval") \
+ V(float32x4_string, "float32x4") \
+ V(Float32x4_string, "Float32x4") \
V(function_string, "function") \
V(Function_string, "Function") \
V(length_string, "length") \
if (expected_input_types_.Contains(ToBooleanStub::NULL_TYPE) ||
expected_input_types_.Contains(ToBooleanStub::SPEC_OBJECT) ||
expected_input_types_.Contains(ToBooleanStub::STRING) ||
- expected_input_types_.Contains(ToBooleanStub::SYMBOL)) {
+ expected_input_types_.Contains(ToBooleanStub::SYMBOL) ||
+ expected_input_types_.Contains(ToBooleanStub::SIMD_VALUE)) {
return Representation::Tagged();
}
if (expected_input_types_.Contains(ToBooleanStub::UNDEFINED)) {
}
case SYMBOL_TYPE:
return heap->symbol_string();
+ case FLOAT32X4_TYPE:
+ return heap->float32x4_string();
case JS_FUNCTION_TYPE:
case JS_FUNCTION_PROXY_TYPE:
return heap->function_string();
// Call runtime on identical symbols since we need to throw a TypeError.
__ 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);
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.
__ JumpIfSmi(eax, if_false);
__ CmpObjectType(eax, SYMBOL_TYPE, edx);
Split(equal, if_true, if_false, fall_through);
+ } else if (String::Equals(check, factory->float32x4_string())) {
+ __ JumpIfSmi(eax, if_false);
+ __ CmpObjectType(eax, FLOAT32X4_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);
__ j(equal, instr->TrueLabel(chunk_));
}
+ if (expected.Contains(ToBooleanStub::SIMD_VALUE)) {
+ // SIMD value -> true.
+ __ CmpInstanceType(map, FLOAT32X4_TYPE);
+ __ j(equal, instr->TrueLabel(chunk_));
+ }
+
if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
// heap number -> false iff +0, -0, or NaN.
Label not_heap_number;
1 << Map::kIsUndetectable);
final_branch_condition = zero;
+ } else if (String::Equals(type_name, factory()->float32x4_string())) {
+ __ JumpIfSmi(input, false_label, false_distance);
+ __ CmpObjectType(input, FLOAT32X4_TYPE, input);
+ final_branch_condition = equal;
+
} else {
__ jmp(false_label, false_distance);
}
function_index = Context::SYMBOL_FUNCTION_INDEX;
} else if (map()->instance_type() == HEAP_NUMBER_TYPE) {
function_index = Context::NUMBER_FUNCTION_INDEX;
+ } else if (map()->instance_type() == FLOAT32X4_TYPE) {
+ function_index = Context::FLOAT32X4_FUNCTION_INDEX;
} else if (*map() == isolate()->heap()->boolean_map()) {
function_index = Context::BOOLEAN_FUNCTION_INDEX;
} else {
return native_context->string_function();
} else if (receiver_map->instance_type() == SYMBOL_TYPE) {
return native_context->symbol_function();
+ } else if (receiver_map->instance_type() == FLOAT32X4_TYPE) {
+ return native_context->float32x4_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_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');
"Cannot convert a Symbol wrapper object to a primitive value") \
T(SymbolToNumber, "Cannot convert a Symbol value to a number") \
T(SymbolToString, "Cannot convert a Symbol value to a string") \
+ T(SimdToNumber, "Cannot convert a SIMD value to a number") \
T(UndefinedOrNullToObject, "Cannot convert undefined or null to object") \
T(ValueAndAccessor, \
"Invalid property. A property cannot both have accessors and be " \
return str;
}
if (IS_SYMBOL(obj)) return %_CallFunction(obj, $symbolToString);
+ if (IS_FLOAT32X4(obj)) return %_CallFunction(obj, $float32x4ToString);
if (IS_OBJECT(obj)
&& %GetDataProperty(obj, "toString") === ObjectToString) {
var constructor = %GetDataProperty(obj, "constructor");
__ 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));
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, 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));
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
__ JumpIfSmi(v0, if_false);
__ GetObjectType(v0, v0, a1);
Split(eq, a1, Operand(SYMBOL_TYPE), if_true, if_false, fall_through);
+ } else if (String::Equals(check, factory->float32x4_string())) {
+ __ 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->boolean_string())) {
__ LoadRoot(at, Heap::kTrueValueRootIndex);
__ Branch(if_true, eq, v0, Operand(at));
__ Branch(instr->TrueLabel(chunk_), eq, scratch, Operand(SYMBOL_TYPE));
}
+ if (expected.Contains(ToBooleanStub::SIMD_VALUE)) {
+ // SIMD value -> true.
+ const Register scratch = scratch1();
+ __ lbu(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
+ __ Branch(instr->TrueLabel(chunk_), eq, scratch,
+ Operand(FLOAT32X4_TYPE));
+ }
+
if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
// heap number -> false iff +0, -0, or NaN.
DoubleRegister dbl_scratch = double_scratch0();
*cmp2 = Operand(zero_reg);
final_branch_condition = eq;
+ } else if (String::Equals(type_name, factory->float32x4_string())) {
+ __ JumpIfSmi(input, false_label);
+ __ GetObjectType(input, input, scratch);
+ *cmp1 = scratch;
+ *cmp2 = Operand(FLOAT32X4_TYPE);
+ final_branch_condition = eq;
+
} else {
*cmp1 = at;
*cmp2 = Operand(zero_reg); // Set to valid regs, to avoid caller assertion.
__ 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 have already been ruled out.
__ 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
__ JumpIfSmi(v0, if_false);
__ GetObjectType(v0, v0, a1);
Split(eq, a1, Operand(SYMBOL_TYPE), if_true, if_false, fall_through);
+ } else if (String::Equals(check, factory->float32x4_string())) {
+ __ 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->boolean_string())) {
__ LoadRoot(at, Heap::kTrueValueRootIndex);
__ Branch(if_true, eq, v0, Operand(at));
__ Branch(instr->TrueLabel(chunk_), eq, scratch, Operand(SYMBOL_TYPE));
}
+ if (expected.Contains(ToBooleanStub::SIMD_VALUE)) {
+ // Symbol value -> true.
+ const Register scratch = scratch1();
+ __ lbu(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
+ __ Branch(instr->TrueLabel(chunk_), eq, scratch,
+ Operand(FLOAT32X4_TYPE));
+ }
+
if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
// heap number -> false iff +0, -0, or NaN.
DoubleRegister dbl_scratch = double_scratch0();
void Object::VerifyApiCallResultType() {
#if DEBUG
- if (!(IsSmi() ||
- IsString() ||
- IsSymbol() ||
- IsSpecObject() ||
- IsHeapNumber() ||
- IsUndefined() ||
- IsTrue() ||
- IsFalse() ||
- IsNull())) {
+ if (!(IsSmi() || IsString() || IsSymbol() || IsSpecObject() ||
+ IsHeapNumber() || IsFloat32x4() || IsUndefined() || IsTrue() ||
+ IsFalse() || IsNull())) {
FATAL("API call returned invalid object");
}
#endif // DEBUG
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 {
return MaybeHandle<JSReceiver>();
}
HeapObject* heap_object = HeapObject::cast(this);
- // The object is either a number, a string, a boolean,
+ // The object is either a number, a string, a symbol, a boolean, a SIMD value,
// a real JS object, or a Harmony proxy.
if (heap_object->IsJSReceiver()) {
return heap_object->map();
if (heap_object->IsBoolean()) {
return context->boolean_function()->initial_map();
}
+ if (heap_object->IsFloat32x4()) {
+ return context->float32x4_function()->initial_map();
+ }
return isolate->heap()->null_value()->map();
}
Object* Object::GetSimpleHash() {
// The object is either a Smi, a HeapNumber, a name, an odd-ball,
- // a real JS object, or a Harmony proxy.
+ // a SIMD value type, a real JS object, or a Harmony proxy.
if (IsSmi()) {
uint32_t hash = ComputeIntegerHash(Smi::cast(this)->value(), kZeroHashSeed);
return Smi::FromInt(hash & Smi::kMaxValue);
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);
+ return Smi::FromInt(hash & Smi::kMaxValue);
+ }
DCHECK(IsJSReceiver());
JSReceiver* receiver = JSReceiver::cast(this);
return receiver->GetHeap()->undefined_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));
+ }
return false;
}
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));
+ }
return false;
}
void Float32x4::Float32x4Print(std::ostream& os) { // NOLINT
- os << get_lane(0) << ", " << get_lane(1) << ", " << get_lane(2) << ", "
- << get_lane(3);
+ 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));
}
V(SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE) \
\
V(SYMBOL_TYPE) \
+ V(FLOAT32X4_TYPE) \
\
V(MAP_TYPE) \
V(CODE_TYPE) \
\
V(HEAP_NUMBER_TYPE) \
V(MUTABLE_HEAP_NUMBER_TYPE) \
- V(FLOAT32X4_TYPE) \
V(FOREIGN_TYPE) \
V(BYTE_ARRAY_TYPE) \
V(FREE_SPACE_TYPE) \
#define HEAP_OBJECT_TYPE_LIST(V) \
V(HeapNumber) \
V(MutableHeapNumber) \
+ V(Float32x4) \
V(Name) \
V(UniqueName) \
V(String) \
V(FixedFloat32Array) \
V(FixedFloat64Array) \
V(FixedUint8ClampedArray) \
- V(Float32x4) \
V(ByteArray) \
V(FreeSpace) \
V(JSReceiver) \
// 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);
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.
// 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);
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
__ JumpIfSmi(r3, if_false);
__ CompareObjectType(r3, r3, r4, SYMBOL_TYPE);
Split(eq, if_true, if_false, fall_through);
+ } else if (String::Equals(check, factory->float32x4_string())) {
+ __ JumpIfSmi(r3, if_false);
+ __ CompareObjectType(r3, r3, r4, FLOAT32X4_TYPE);
+ Split(eq, if_true, if_false, fall_through);
} else if (String::Equals(check, factory->boolean_string())) {
__ CompareRoot(r3, Heap::kTrueValueRootIndex);
__ beq(if_true);
__ beq(instr->TrueLabel(chunk_));
}
+ if (expected.Contains(ToBooleanStub::SIMD_VALUE)) {
+ // SIMD value -> true.
+ __ CompareInstanceType(map, ip, FLOAT32X4_TYPE);
+ __ beq(instr->TrueLabel(chunk_));
+ }
+
if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
// heap number -> false iff +0, -0, or NaN.
Label not_heap_number;
__ cmpi(r0, Operand::Zero());
final_branch_condition = eq;
+ } else if (String::Equals(type_name, factory->float32x4_string())) {
+ __ JumpIfSmi(input, false_label);
+ __ CompareObjectType(input, scratch, no_reg, FLOAT32X4_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)) return 1; // not equal
+ if (IS_SYMBOL(y) || IS_FLOAT32X4(y)) return 1; // not equal
if (!IS_SPEC_OBJECT(y)) {
// 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)) return 1; // not equal
+ 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_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)) return 1; // not equal
+ if (IS_SYMBOL(y) || IS_FLOAT32X4(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 {
// x is an object.
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)) return 1; // not equal
+ if (IS_SYMBOL(y) || IS_FLOAT32X4(y)) return 1; // not equal
if (IS_BOOLEAN(y)) y = %$toNumber(y);
x = %$toPrimitive(x, NO_HINT);
}
return %NumberEquals(this, x);
}
+ if (IS_FLOAT32X4(this) && IS_FLOAT32X4(x))
+ return %Float32x4Equals(this, x);
+
// If anything else gets here, we just do simple identity check.
// Objects (including functions), null, undefined and booleans were
// checked in the CompareStub, so there should be nothing left.
// Normal behavior.
if (!IS_SPEC_OBJECT(x)) return x;
if (IS_SYMBOL_WRAPPER(x)) throw MakeTypeError(kSymbolToPrimitive);
+ if (IS_FLOAT32X4(x)) return x;
if (hint == NO_HINT) hint = (IS_DATE(x)) ? STRING_HINT : NUMBER_HINT;
return (hint == NUMBER_HINT) ? DefaultNumber(x) : DefaultString(x);
}
if (IS_BOOLEAN(x)) return x ? 1 : 0;
if (IS_UNDEFINED(x)) return NAN;
if (IS_SYMBOL(x)) throw MakeTypeError(kSymbolToNumber);
+ if (IS_FLOAT32X4(x)) throw MakeTypeError(kSimdToNumber);
return (IS_NULL(x)) ? 0 : ToNumber(DefaultNumber(x));
}
if (IS_BOOLEAN(x)) return x ? 1 : 0;
if (IS_UNDEFINED(x)) return NAN;
if (IS_SYMBOL(x)) throw MakeTypeError(kSymbolToNumber);
+ if (IS_FLOAT32X4(x)) throw MakeTypeError(kSimdToNumber);
return (IS_NULL(x)) ? 0 : ToNumber(DefaultNumber(x));
}
if (IS_NUMBER(x)) return new GlobalNumber(x);
if (IS_BOOLEAN(x)) return new GlobalBoolean(x);
if (IS_SYMBOL(x)) return %NewSymbolWrapper(x);
+ if (IS_FLOAT32X4(x)) return %NewFloat32x4Wrapper(x);
if (IS_NULL_OR_UNDEFINED(x) && !IS_UNDETECTABLE(x)) {
throw MakeTypeError(kUndefinedOrNullToObject);
}
return false;
}
}
+ if (IS_FLOAT32X4(x)) {
+ return %Float32x4SameValue(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);
+ }
return x === y;
}
+
function ConcatIterableToArray(target, iterable) {
var index = target.length;
for (var element of iterable) {
// ECMA-262, section 8.6.2.6, page 28.
function DefaultNumber(x) {
- if (!IS_SYMBOL_WRAPPER(x)) {
+ if (!IS_SYMBOL_WRAPPER(x) && !IS_FLOAT32X4_WRAPPER(x)) {
var valueOf = x.valueOf;
if (IS_SPEC_FUNCTION(valueOf)) {
var v = %_CallFunction(x, valueOf);
--- /dev/null
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/arguments.h"
+#include "src/base/macros.h"
+#include "src/conversions.h"
+#include "src/runtime/runtime-utils.h"
+
+// Implement Single Instruction Multiple Data (SIMD) operations as defined in
+// 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); \
+ 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_WRAPPER_FUNCTION(type) \
+ RUNTIME_FUNCTION(Runtime_New##type##Wrapper) { \
+ HandleScope scope(isolate); \
+ DCHECK(args.length() == 1); \
+ CONVERT_ARG_HANDLE_CHECKED(type, value, 0); \
+ return *Object::ToObject(isolate, value).ToHandleChecked(); \
+ }
+
+#define SIMD_CHECK_FUNCTION(type) \
+ RUNTIME_FUNCTION(Runtime_##type##Check) { \
+ HandleScope scope(isolate); \
+ CONVERT_ARG_HANDLE_CHECKED(type, a, 0); \
+ 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 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 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 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_CREATE_WRAPPER_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());
+}
+
+
+inline bool Equals(float x, float y) { return x == y; }
+
+} // namespace
+
+SIMD4_FUNCTIONS(Float32x4)
+}
+} // namespace v8::internal
F(Arguments, 1, 1)
+#define FOR_EACH_INTRINSIC_SIMD(F) \
+ F(CreateFloat32x4, 4, 1) \
+ F(NewFloat32x4Wrapper, 1, 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_STRINGS(F) \
F(StringReplaceOneCharWithString, 3, 1) \
F(StringIndexOf, 3, 1) \
FOR_EACH_INTRINSIC_PROXY(F) \
FOR_EACH_INTRINSIC_REGEXP(F) \
FOR_EACH_INTRINSIC_SCOPES(F) \
+ FOR_EACH_INTRINSIC_SIMD(F) \
FOR_EACH_INTRINSIC_STRINGS(F) \
FOR_EACH_INTRINSIC_SYMBOL(F) \
FOR_EACH_INTRINSIC_TEST(F) \
obj = cell->value();
}
- if (obj->IsJSFunction() || obj->IsAllocationSite() || obj->IsSymbol()) {
+ if (obj->IsJSFunction() || obj->IsAllocationSite() || obj->IsSymbol() ||
+ obj->IsFloat32x4()) {
return Handle<Object>(obj, isolate());
}
}
case HEAP_NUMBER_TYPE:
return kNumber & kTaggedPointer;
+ case FLOAT32X4_TYPE:
+ // TODO(bbudge): Add type bits for SIMD value types.
+ return kAny;
case JS_VALUE_TYPE:
case JS_DATE_TYPE:
case JS_OBJECT_TYPE:
// Call runtime on identical symbols since we need to throw a TypeError.
__ 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);
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.
__ JumpIfSmi(rax, if_false);
__ CmpObjectType(rax, SYMBOL_TYPE, rdx);
Split(equal, if_true, if_false, fall_through);
+ } else if (String::Equals(check, factory->float32x4_string())) {
+ __ JumpIfSmi(rax, if_false);
+ __ CmpObjectType(rax, FLOAT32X4_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);
__ j(equal, instr->TrueLabel(chunk_));
}
+ if (expected.Contains(ToBooleanStub::SIMD_VALUE)) {
+ // SIMD value -> true.
+ __ CmpInstanceType(map, FLOAT32X4_TYPE);
+ __ j(equal, instr->TrueLabel(chunk_));
+ }
+
if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
// heap number -> false iff +0, -0, or NaN.
Label not_heap_number;
Immediate(1 << Map::kIsUndetectable));
final_branch_condition = zero;
+ } else if (String::Equals(type_name, factory->float32x4_string())) {
+ __ JumpIfSmi(input, false_label, false_distance);
+ __ CmpObjectType(input, FLOAT32X4_TYPE, input);
+ final_branch_condition = equal;
+
} else {
__ jmp(false_label, false_distance);
}
// Call runtime on identical symbols since we need to throw a TypeError.
__ 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);
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.
__ JumpIfSmi(eax, if_false);
__ CmpObjectType(eax, SYMBOL_TYPE, edx);
Split(equal, if_true, if_false, fall_through);
+ } else if (String::Equals(check, factory->float32x4_string())) {
+ __ JumpIfSmi(eax, if_false);
+ __ CmpObjectType(eax, FLOAT32X4_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);
__ j(equal, instr->TrueLabel(chunk_));
}
+ if (expected.Contains(ToBooleanStub::SIMD_VALUE)) {
+ // SIMD value -> true.
+ __ CmpInstanceType(map, FLOAT32X4_TYPE);
+ __ j(equal, instr->TrueLabel(chunk_));
+ }
+
if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
// heap number -> false iff +0, -0, or NaN.
Label not_heap_number;
1 << Map::kIsUndetectable);
final_branch_condition = zero;
+ } else if (String::Equals(type_name, factory()->float32x4_string())) {
+ __ JumpIfSmi(input, false_label, false_distance);
+ __ CmpObjectType(input, FLOAT32X4_TYPE, input);
+ final_branch_condition = equal;
+
} else {
__ jmp(false_label, false_distance);
}
'test-representation.cc',
'test-sampler-api.cc',
'test-serialize.cc',
+ 'test-simd.cc',
'test-spaces.cc',
'test-strings.cc',
'test-symbols.cc',
}
+TEST(HeapSnapshotFloat32x4) {
+ 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");
+ 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);
+}
+
+
TEST(HeapSnapshotWeakCollection) {
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
HandleScope sc(isolate);
- Handle<Object> value = factory->NewFloat32x4(1, 2, 3, 4);
+ Handle<Float32x4> value = factory->NewFloat32x4(1, 2, 3, 4);
CHECK(value->IsFloat32x4());
CHECK(value->BooleanValue()); // SIMD values map to true.
-
- Float32x4* float32x4 = *Handle<Float32x4>::cast(value);
- CheckSimdLanes<Float32x4, float, 4>(float32x4);
-
- // Check ToString for SIMD values.
- // TODO(bbudge): Switch to Check* style function to test ToString().
- value = factory->NewFloat32x4(1, 2, 3, 4);
- float32x4 = *Handle<Float32x4>::cast(value);
- std::ostringstream os;
- float32x4->Float32x4Print(os);
- CHECK_EQ("1, 2, 3, 4", os.str());
-
- // Check unusual lane values.
- float32x4->set_lane(0, 0);
- CHECK_EQ(0, float32x4->get_lane(0));
- float32x4->set_lane(1, -0.0);
- CHECK_EQ(-0.0, float32x4->get_lane(1));
+ 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();
- float32x4->set_lane(2, quiet_NaN);
- CHECK(std::isnan(float32x4->get_lane(2)));
- float32x4->set_lane(3, signaling_NaN);
- CHECK(std::isnan(float32x4->get_lane(3)));
+ 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.
+ {
+ value = factory->NewFloat32x4(1, 2, 3, 4);
+ std::ostringstream os;
+ value->Float32x4Print(os);
+ CHECK_EQ("1, 2, 3, 4", os.str());
+ }
+ {
+ value = factory->NewFloat32x4(0, -0.0, quiet_NaN, signaling_NaN);
+ std::ostringstream os;
+ value->Float32x4Print(os);
+ // Value printing doesn't preserve signed zeroes.
+ CHECK_EQ("0, 0, NaN, NaN", os.str());
+ }
}
--- /dev/null
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/objects.h"
+#include "src/ostreams.h"
+#include "test/cctest/cctest.h"
+
+using namespace v8::internal;
+
+
+TEST(SameValue) {
+ 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);
+ }
+}
--- /dev/null
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-simd --harmony-tostring --harmony-reflect
+// Flags: --allow-natives-syntax --expose-natives-as natives --noalways-opt
+
+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]);
+}
+
+
+function isValidSimdString(string, value, type, lanes) {
+ var simdFn = SIMD[type],
+ parseFn =
+ type.indexOf('float') === 0 ? Number.parseFloat : Number.parseInt,
+ indexOfOpenParen = string.indexOf('(');
+ // Check prefix for correct type name.
+ if (string.substr(0, indexOfOpenParen).toUpperCase() !== type.toUpperCase())
+ return false;
+ // Remove type name and open parenthesis.
+ string = string.substr(indexOfOpenParen + 1);
+ var laneStrings = string.split(',');
+ if (laneStrings.length !== lanes)
+ return false;
+ for (var i = 0; i < lanes; i++) {
+ var fromString = parseFn(laneStrings[i]),
+ fromValue = simdFn.extractLane(value, i);
+ if (Math.abs(fromString - fromValue) > Number.EPSILON)
+ return false;
+ }
+ return true;
+}
+
+
+// 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;
+}
+
+
+// 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]");
+}
+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.
+function TestConstructor(type, lanes) {
+ var simdFn = SIMD[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__)
+ }
+}
+
+
+function TestType(type, lanes) {
+ for (var i in values) {
+ assertEquals(type, typeof values[i])
+ assertTrue(typeof values[i] === type)
+ assertTrue(typeof Object(values[i]) === 'object')
+ assertEquals(null, %_ClassOf(values[i]))
+ assertEquals("Float32x4", %_ClassOf(Object(values[i])))
+ }
+}
+
+
+function TestPrototype(type, lanes) {
+ var simdFn = SIMD[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__)
+ }
+}
+
+
+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])
+ }
+}
+
+
+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])
+ }
+}
+
+
+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();
+ }
+}
+
+
+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))
+ }
+}
+
+
+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)
+ }
+}
+
+
+function TestEquality(type, lanes) {
+ // 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())
+ }
+
+ // 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 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])
+ }
+ }
+}
+
+
+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)));
+}
+
+
+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);
+ }
+}
+
+
+// Test SIMD value wrapping/boxing over non-builtins.
+function TestCall(type, lanes) {
+ var simdFn = SIMD[type];
+ simdFn.prototype.getThisProto = function () {
+ return Object.getPrototypeOf(this);
+ }
+ for (var i in values) {
+ assertTrue(values[i].getThisProto() === simdFn.prototype)
+ }
+}
+
+
+function TestAsSetKey(type, lanes, set) {
+ function test(set, key) {
+ assertFalse(set.has(key));
+ assertFalse(set.delete(key));
+ if (!(set instanceof WeakSet)) {
+ assertSame(set, set.add(key));
+ assertTrue(set.has(key));
+ assertTrue(set.delete(key));
+ } else {
+ // SIMD values can't be used as keys in WeakSets.
+ assertThrows(function() { set.add(key) });
+ }
+ assertFalse(set.has(key));
+ assertFalse(set.delete(key));
+ assertFalse(set.has(key));
+ }
+
+ for (var i in values) {
+ test(set, values[i]);
+ }
+}
+
+
+function TestAsMapKey(type, lanes, map) {
+ function test(map, key, value) {
+ assertFalse(map.has(key));
+ assertSame(undefined, map.get(key));
+ assertFalse(map.delete(key));
+ if (!(map instanceof WeakMap)) {
+ assertSame(map, map.set(key, value));
+ assertSame(value, map.get(key));
+ assertTrue(map.has(key));
+ assertTrue(map.delete(key));
+ } else {
+ // SIMD values can't be used as keys in WeakMaps.
+ assertThrows(function() { map.set(key, value) });
+ }
+ assertFalse(map.has(key));
+ assertSame(undefined, map.get(key));
+ assertFalse(map.delete(key));
+ assertFalse(map.has(key));
+ assertSame(undefined, map.get(key));
+ }
+
+ for (var i in values) {
+ test(map, values[i], {});
+ }
+}
+
+
+// Test SIMD type with Harmony reflect-apply.
+function TestReflectApply(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);
+ }
+}
+
+
+function TestSIMDTypes() {
+ var types = [ 'float32x4' ];
+ for (var i = 0; i < types.length; ++i) {
+ var type = types[i],
+ lanes = lanesForType(type);
+ TestConstructor(type, lanes);
+ TestType(type, lanes);
+ TestPrototype(type, lanes);
+ TestValueOf(type, lanes);
+ TestGet(type, lanes);
+ TestToBoolean(type, lanes);
+ TestToString(type, lanes);
+ TestToNumber(type, lanes);
+ TestEquality(type, lanes);
+ TestSameValue(type, lanes);
+ TestComparison(type, lanes);
+ TestCall(type, lanes);
+ TestAsSetKey(type, lanes, new Set);
+ TestAsSetKey(type, lanes, new WeakSet);
+ TestAsMapKey(type, lanes, new Map);
+ TestAsMapKey(type, lanes, new WeakMap);
+ TestReflectApply(type);
+ }
+}
+TestSIMDTypes();
// found in the LICENSE file.
// Flags: --stack-size=100 --harmony --harmony-reflect --harmony-arrays
-// Flags: --harmony-regexps --strong-mode
+// Flags: --harmony-regexps --harmony-simd --strong-mode
function test(f, expected, type) {
try {
1 + Symbol();
}, "Cannot convert a Symbol value to a number", TypeError);
+// kSimdToNumber
+test(function() {
+ 1 + SIMD.float32x4(1, 2, 3, 4);
+}, "Cannot convert a SIMD value to a number", TypeError);
+
// kUndefinedOrNullToObject
test(function() {
Array.prototype.toString.call(null);
// Flags: --expose-natives-as natives
-// Test the SameValue internal method.
+// Test the SameValue and SameValueZero internal methods.
var obj1 = {x: 10, y: 11, z: "test"};
var obj2 = {x: 10, y: 11, z: "test"};
var sameValue = natives.$sameValue;
+var sameValueZero = natives.$sameValueZero;
-assertTrue(sameValue(0, 0));
-assertTrue(sameValue(+0, +0));
-assertTrue(sameValue(-0, -0));
-assertTrue(sameValue(1, 1));
-assertTrue(sameValue(2, 2));
-assertTrue(sameValue(-1, -1));
-assertTrue(sameValue(0.5, 0.5));
-assertTrue(sameValue(true, true));
-assertTrue(sameValue(false, false));
-assertTrue(sameValue(NaN, NaN));
-assertTrue(sameValue(null, null));
-assertTrue(sameValue("foo", "foo"));
-assertTrue(sameValue(obj1, obj1));
+// Calls SameValue and SameValueZero and checks that their results match.
+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;
+}
+
+assertTrue(sameValueBoth(0, 0));
+assertTrue(sameValueBoth(+0, +0));
+assertTrue(sameValueBoth(-0, -0));
+assertTrue(sameValueBoth(1, 1));
+assertTrue(sameValueBoth(2, 2));
+assertTrue(sameValueBoth(-1, -1));
+assertTrue(sameValueBoth(0.5, 0.5));
+assertTrue(sameValueBoth(true, true));
+assertTrue(sameValueBoth(false, false));
+assertTrue(sameValueBoth(NaN, NaN));
+assertTrue(sameValueBoth(null, null));
+assertTrue(sameValueBoth("foo", "foo"));
+assertTrue(sameValueBoth(obj1, obj1));
// Undefined values.
-assertTrue(sameValue());
-assertTrue(sameValue(undefined, undefined));
-
-assertFalse(sameValue(0,1));
-assertFalse(sameValue("foo", "bar"));
-assertFalse(sameValue(obj1, obj2));
-assertFalse(sameValue(true, false));
-
-assertFalse(sameValue(obj1, true));
-assertFalse(sameValue(obj1, "foo"));
-assertFalse(sameValue(obj1, 1));
-assertFalse(sameValue(obj1, undefined));
-assertFalse(sameValue(obj1, NaN));
-
-assertFalse(sameValue(undefined, true));
-assertFalse(sameValue(undefined, "foo"));
-assertFalse(sameValue(undefined, 1));
-assertFalse(sameValue(undefined, obj1));
-assertFalse(sameValue(undefined, NaN));
-
-assertFalse(sameValue(NaN, true));
-assertFalse(sameValue(NaN, "foo"));
-assertFalse(sameValue(NaN, 1));
-assertFalse(sameValue(NaN, obj1));
-assertFalse(sameValue(NaN, undefined));
-
-assertFalse(sameValue("foo", true));
-assertFalse(sameValue("foo", 1));
-assertFalse(sameValue("foo", obj1));
-assertFalse(sameValue("foo", undefined));
-assertFalse(sameValue("foo", NaN));
-
-assertFalse(sameValue(true, 1));
-assertFalse(sameValue(true, obj1));
-assertFalse(sameValue(true, undefined));
-assertFalse(sameValue(true, NaN));
-assertFalse(sameValue(true, "foo"));
-
-assertFalse(sameValue(1, true));
-assertFalse(sameValue(1, obj1));
-assertFalse(sameValue(1, undefined));
-assertFalse(sameValue(1, NaN));
-assertFalse(sameValue(1, "foo"));
+assertTrue(sameValueBoth());
+assertTrue(sameValueBoth(undefined, undefined));
+
+assertFalse(sameValueBoth(0,1));
+assertFalse(sameValueBoth("foo", "bar"));
+assertFalse(sameValueBoth(obj1, obj2));
+assertFalse(sameValueBoth(true, false));
+
+assertFalse(sameValueBoth(obj1, true));
+assertFalse(sameValueBoth(obj1, "foo"));
+assertFalse(sameValueBoth(obj1, 1));
+assertFalse(sameValueBoth(obj1, undefined));
+assertFalse(sameValueBoth(obj1, NaN));
+
+assertFalse(sameValueBoth(undefined, true));
+assertFalse(sameValueBoth(undefined, "foo"));
+assertFalse(sameValueBoth(undefined, 1));
+assertFalse(sameValueBoth(undefined, obj1));
+assertFalse(sameValueBoth(undefined, NaN));
+
+assertFalse(sameValueBoth(NaN, true));
+assertFalse(sameValueBoth(NaN, "foo"));
+assertFalse(sameValueBoth(NaN, 1));
+assertFalse(sameValueBoth(NaN, obj1));
+assertFalse(sameValueBoth(NaN, undefined));
+
+assertFalse(sameValueBoth("foo", true));
+assertFalse(sameValueBoth("foo", 1));
+assertFalse(sameValueBoth("foo", obj1));
+assertFalse(sameValueBoth("foo", undefined));
+assertFalse(sameValueBoth("foo", NaN));
+
+assertFalse(sameValueBoth(true, 1));
+assertFalse(sameValueBoth(true, obj1));
+assertFalse(sameValueBoth(true, undefined));
+assertFalse(sameValueBoth(true, NaN));
+assertFalse(sameValueBoth(true, "foo"));
+
+assertFalse(sameValueBoth(1, true));
+assertFalse(sameValueBoth(1, obj1));
+assertFalse(sameValueBoth(1, undefined));
+assertFalse(sameValueBoth(1, NaN));
+assertFalse(sameValueBoth(1, "foo"));
// Special string cases.
-assertFalse(sameValue("1", 1));
-assertFalse(sameValue("true", true));
-assertFalse(sameValue("false", false));
-assertFalse(sameValue("undefined", undefined));
-assertFalse(sameValue("NaN", NaN));
-
-// -0 and +0 are should be different
-assertFalse(sameValue(+0, -0));
-assertFalse(sameValue(-0, +0));
+assertFalse(sameValueBoth("1", 1));
+assertFalse(sameValueBoth("true", true));
+assertFalse(sameValueBoth("false", false));
+assertFalse(sameValueBoth("undefined", undefined));
+assertFalse(sameValueBoth("NaN", NaN));
+
+// SameValue considers -0 and +0 to be different; SameValueZero considers
+// -0 and +0 to be the same.
+assertTrue(sameValueZeroOnly(+0, -0));
+assertTrue(sameValueZeroOnly(-0, +0));
load('base.js');
})();
+
+// ecmascript_simd_tests logs errors to the console.
+var console = {
+ log: function(x) { print(x); },
+};
'../../src/runtime/runtime-proxy.cc',
'../../src/runtime/runtime-regexp.cc',
'../../src/runtime/runtime-scopes.cc',
+ '../../src/runtime/runtime-simd.cc',
'../../src/runtime/runtime-strings.cc',
'../../src/runtime/runtime-symbol.cc',
'../../src/runtime/runtime-test.cc',
'../../src/harmony-spread.js',
'../../src/harmony-object.js',
'../../src/harmony-sharedarraybuffer.js',
+ '../../src/harmony-simd.js',
],
'code_stub_library_files': [
'../../src/macros.py',