Expose SIMD.Float32x4 type to Javascript.
This CL exposes the constructor function, defines type related
information, and implements value type semantics.
It also refactors test/mjsunit/samevalue.js to test SameValue and SameValueZero.

TEST=test/mjsunit/harmony/simd.js, test/cctest/test-simd.cc

LOG=Y
BUG=v8:4124

Review URL: https://codereview.chromium.org/1219943002

Cr-Commit-Position: refs/heads/master@{#29689}
diff --git a/BUILD.gn b/BUILD.gn
index f0507fd..65e5101 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -313,7 +313,8 @@
     "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 = [
@@ -1087,6 +1088,7 @@
     "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",
diff --git a/include/v8.h b/include/v8.h
index 560bfb4..222dd2a 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -74,6 +74,7 @@
 class Data;
 class Date;
 class External;
+class Float32x4Object;
 class Function;
 class FunctionTemplate;
 class HeapProfiler;
@@ -1801,6 +1802,12 @@
   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.
    */
   bool IsNativeError() const;
@@ -3845,6 +3852,23 @@
 
 
 /**
+ * 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).
  */
 class V8_EXPORT Date : public Object {
@@ -3948,6 +3972,24 @@
 
 
 /**
+ * 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).
  */
 class V8_EXPORT RegExp : public Object {
@@ -6943,7 +6985,7 @@
   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;
@@ -7860,6 +7902,14 @@
 }
 
 
+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);
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
index 3384479..dff0250 100644
--- a/src/arm/code-stubs-arm.cc
+++ b/src/arm/code-stubs-arm.cc
@@ -255,6 +255,9 @@
     // 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.
@@ -273,6 +276,9 @@
       // 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
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc
index 4b74afd..d15f44a 100644
--- a/src/arm/full-codegen-arm.cc
+++ b/src/arm/full-codegen-arm.cc
@@ -5236,6 +5236,10 @@
     __ 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);
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index 04f6e6d..5b9737e 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -2268,6 +2268,12 @@
         __ 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();
@@ -5681,6 +5687,11 @@
     __ 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);
   }
diff --git a/src/arm64/code-stubs-arm64.cc b/src/arm64/code-stubs-arm64.cc
index 47e789a..2a728c2 100644
--- a/src/arm64/code-stubs-arm64.cc
+++ b/src/arm64/code-stubs-arm64.cc
@@ -227,6 +227,9 @@
     // 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.
@@ -246,6 +249,9 @@
     // 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
diff --git a/src/arm64/full-codegen-arm64.cc b/src/arm64/full-codegen-arm64.cc
index 825eed5..9b31556 100644
--- a/src/arm64/full-codegen-arm64.cc
+++ b/src/arm64/full-codegen-arm64.cc
@@ -4926,6 +4926,12 @@
     __ 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);
diff --git a/src/arm64/lithium-codegen-arm64.cc b/src/arm64/lithium-codegen-arm64.cc
index b7a7aee..a9edbb9 100644
--- a/src/arm64/lithium-codegen-arm64.cc
+++ b/src/arm64/lithium-codegen-arm64.cc
@@ -1926,6 +1926,12 @@
         __ 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, &not_heap_number);
@@ -5962,6 +5968,15 @@
     __ 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);
   }
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index 2df9afc..350e718 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -1877,6 +1877,7 @@
 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() {
@@ -1985,6 +1986,32 @@
 }
 
 
+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) {
@@ -2569,6 +2596,8 @@
   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++) {
diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc
index 2ccf78c..587496f 100644
--- a/src/code-stubs-hydrogen.cc
+++ b/src/code-stubs-hydrogen.cc
@@ -389,19 +389,27 @@
             { 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();
diff --git a/src/code-stubs.cc b/src/code-stubs.cc
index 08fa35a..3b41f9e 100644
--- a/src/code-stubs.cc
+++ b/src/code-stubs.cc
@@ -968,6 +968,7 @@
   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 << ")";
 }
 
@@ -1000,6 +1001,9 @@
     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();
@@ -1009,10 +1013,10 @@
 
 
 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);
 }
 
 
diff --git a/src/code-stubs.h b/src/code-stubs.h
index 812b128..548e54e 100644
--- a/src/code-stubs.h
+++ b/src/code-stubs.h
@@ -2849,6 +2849,7 @@
     STRING,
     SYMBOL,
     HEAP_NUMBER,
+    SIMD_VALUE,
     NUMBER_OF_TYPES
   };
 
diff --git a/src/contexts.h b/src/contexts.h
index 529e1c4..fc29831 100644
--- a/src/contexts.h
+++ b/src/contexts.h
@@ -81,6 +81,7 @@
   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)        \
@@ -358,6 +359,7 @@
     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,
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index b505ce7..27c6e02 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -196,7 +196,8 @@
   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)                                       \
diff --git a/src/globals.h b/src/globals.h
index f85e929..749d6e1 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -466,7 +466,6 @@
 class Symbol;
 class Name;
 class Struct;
-class Symbol;
 class Variable;
 class RelocInfo;
 class Deserializer;
diff --git a/src/harmony-simd.js b/src/harmony-simd.js
new file mode 100644
index 0000000..4a15382
--- /dev/null
+++ b/src/harmony-simd.js
@@ -0,0 +1,89 @@
+// 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;
+
+})
diff --git a/src/heap/heap.h b/src/heap/heap.h
index 5e56d94..6c679e6 100644
--- a/src/heap/heap.h
+++ b/src/heap/heap.h
@@ -227,6 +227,8 @@
   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")                                   \
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc
index 2843195..b353672 100644
--- a/src/hydrogen-instructions.cc
+++ b/src/hydrogen-instructions.cc
@@ -1158,7 +1158,8 @@
   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)) {
@@ -1323,6 +1324,8 @@
     }
     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();
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index fa62703..7ff278c 100644
--- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc
@@ -1704,6 +1704,9 @@
       // 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.
diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc
index a317977..820d28ea 100644
--- a/src/ia32/full-codegen-ia32.cc
+++ b/src/ia32/full-codegen-ia32.cc
@@ -5169,6 +5169,10 @@
     __ 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);
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index c236f73..0086011 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -2164,6 +2164,12 @@
         __ 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;
@@ -5510,6 +5516,11 @@
               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);
   }
diff --git a/src/ic/handler-compiler.cc b/src/ic/handler-compiler.cc
index 26d1953..beeea32 100644
--- a/src/ic/handler-compiler.cc
+++ b/src/ic/handler-compiler.cc
@@ -107,6 +107,8 @@
     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 {
diff --git a/src/ic/ic-inl.h b/src/ic/ic-inl.h
index a697093..85c6edb 100644
--- a/src/ic/ic-inl.h
+++ b/src/ic/ic-inl.h
@@ -136,6 +136,8 @@
     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;
   }
diff --git a/src/macros.py b/src/macros.py
index 5e28c66..91b4132 100644
--- a/src/macros.py
+++ b/src/macros.py
@@ -90,6 +90,7 @@
 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');
@@ -103,6 +104,7 @@
 macro IS_WEAKMAP(arg)           = (%_ClassOf(arg) === 'WeakMap');
 macro IS_WEAKSET(arg)           = (%_ClassOf(arg) === 'WeakSet');
 macro IS_NUMBER_WRAPPER(arg)    = (%_ClassOf(arg) === 'Number');
+macro IS_FLOAT32X4_WRAPPER(arg) = (%_ClassOf(arg) === 'Float32x4');
 macro IS_STRING_WRAPPER(arg)    = (%_ClassOf(arg) === 'String');
 macro IS_SYMBOL_WRAPPER(arg)    = (%_ClassOf(arg) === 'Symbol');
 macro IS_BOOLEAN_WRAPPER(arg)   = (%_ClassOf(arg) === 'Boolean');
diff --git a/src/messages.h b/src/messages.h
index 98ec631..f83023b 100644
--- a/src/messages.h
+++ b/src/messages.h
@@ -243,6 +243,7 @@
     "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 "         \
diff --git a/src/messages.js b/src/messages.js
index d7ca7cd..6490ed3 100644
--- a/src/messages.js
+++ b/src/messages.js
@@ -86,6 +86,7 @@
     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");
diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc
index 41235c0..91e10f5 100644
--- a/src/mips/code-stubs-mips.cc
+++ b/src/mips/code-stubs-mips.cc
@@ -295,6 +295,8 @@
     __ 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.
@@ -309,6 +311,8 @@
     __ 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
diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc
index 71acc70..b9c801e 100644
--- a/src/mips/full-codegen-mips.cc
+++ b/src/mips/full-codegen-mips.cc
@@ -5257,6 +5257,10 @@
     __ 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));
diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc
index 0781e47..9d004ca 100644
--- a/src/mips/lithium-codegen-mips.cc
+++ b/src/mips/lithium-codegen-mips.cc
@@ -2181,6 +2181,14 @@
         __ 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();
@@ -5718,6 +5726,13 @@
     *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.
diff --git a/src/mips64/code-stubs-mips64.cc b/src/mips64/code-stubs-mips64.cc
index 2439e1b..b8204b3 100644
--- a/src/mips64/code-stubs-mips64.cc
+++ b/src/mips64/code-stubs-mips64.cc
@@ -291,6 +291,8 @@
     __ 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.
@@ -305,6 +307,8 @@
     __ 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
diff --git a/src/mips64/full-codegen-mips64.cc b/src/mips64/full-codegen-mips64.cc
index ebd9abe..d4606ed 100644
--- a/src/mips64/full-codegen-mips64.cc
+++ b/src/mips64/full-codegen-mips64.cc
@@ -5258,6 +5258,10 @@
     __ 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));
diff --git a/src/mips64/lithium-codegen-mips64.cc b/src/mips64/lithium-codegen-mips64.cc
index f4d4774..533abb0 100644
--- a/src/mips64/lithium-codegen-mips64.cc
+++ b/src/mips64/lithium-codegen-mips64.cc
@@ -2282,6 +2282,14 @@
         __ 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();
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 4f1ad41..c0ec455 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -2214,15 +2214,9 @@
 
 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
diff --git a/src/objects.cc b/src/objects.cc
index 4fdb63d..efe35ed 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -81,6 +81,8 @@
     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>();
   }
@@ -605,7 +607,7 @@
 
   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();
@@ -624,6 +626,9 @@
   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();
 }
 
@@ -639,7 +644,7 @@
 
 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);
@@ -662,6 +667,16 @@
     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();
@@ -688,6 +703,14 @@
   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;
 }
 
@@ -703,6 +726,14 @@
   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;
 }
 
@@ -1515,8 +1546,12 @@
 
 
 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));
 }
 
 
diff --git a/src/objects.h b/src/objects.h
index 106307b..2ad2015 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -377,6 +377,7 @@
   V(SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE) \
                                                                 \
   V(SYMBOL_TYPE)                                                \
+  V(FLOAT32X4_TYPE)                                             \
                                                                 \
   V(MAP_TYPE)                                                   \
   V(CODE_TYPE)                                                  \
@@ -386,7 +387,6 @@
                                                                 \
   V(HEAP_NUMBER_TYPE)                                           \
   V(MUTABLE_HEAP_NUMBER_TYPE)                                   \
-  V(FLOAT32X4_TYPE)                                             \
   V(FOREIGN_TYPE)                                               \
   V(BYTE_ARRAY_TYPE)                                            \
   V(FREE_SPACE_TYPE)                                            \
@@ -915,6 +915,7 @@
 #define HEAP_OBJECT_TYPE_LIST(V)   \
   V(HeapNumber)                    \
   V(MutableHeapNumber)             \
+  V(Float32x4)                     \
   V(Name)                          \
   V(UniqueName)                    \
   V(String)                        \
@@ -949,7 +950,6 @@
   V(FixedFloat32Array)             \
   V(FixedFloat64Array)             \
   V(FixedUint8ClampedArray)        \
-  V(Float32x4)                     \
   V(ByteArray)                     \
   V(FreeSpace)                     \
   V(JSReceiver)                    \
diff --git a/src/ppc/code-stubs-ppc.cc b/src/ppc/code-stubs-ppc.cc
index cd7d30b..e7c11e7 100644
--- a/src/ppc/code-stubs-ppc.cc
+++ b/src/ppc/code-stubs-ppc.cc
@@ -266,6 +266,9 @@
     // 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.
@@ -284,6 +287,9 @@
       // 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
diff --git a/src/ppc/full-codegen-ppc.cc b/src/ppc/full-codegen-ppc.cc
index 0f455a0..455cc1e 100644
--- a/src/ppc/full-codegen-ppc.cc
+++ b/src/ppc/full-codegen-ppc.cc
@@ -5274,6 +5274,10 @@
     __ 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);
diff --git a/src/ppc/lithium-codegen-ppc.cc b/src/ppc/lithium-codegen-ppc.cc
index de2e10e..87e1a8d 100644
--- a/src/ppc/lithium-codegen-ppc.cc
+++ b/src/ppc/lithium-codegen-ppc.cc
@@ -2305,6 +2305,12 @@
         __ 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;
@@ -5967,6 +5973,11 @@
     __ 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);
   }
diff --git a/src/runtime.js b/src/runtime.js
index e5ac221..dd776db 100644
--- a/src/runtime.js
+++ b/src/runtime.js
@@ -103,7 +103,7 @@
       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));
@@ -113,7 +113,7 @@
     } 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
@@ -127,19 +127,23 @@
       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);
     }
@@ -158,6 +162,9 @@
     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.
@@ -760,6 +767,7 @@
   // 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);
 }
@@ -785,6 +793,7 @@
   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));
 }
 
@@ -796,6 +805,7 @@
   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));
 }
 
@@ -831,6 +841,7 @@
   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);
   }
@@ -878,6 +889,9 @@
       return false;
     }
   }
+  if (IS_FLOAT32X4(x)) {
+    return %Float32x4SameValue(x, y);
+  }
   return x === y;
 }
 
@@ -888,9 +902,13 @@
   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) {
@@ -926,7 +944,7 @@
 
 // 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);
diff --git a/src/runtime/runtime-simd.cc b/src/runtime/runtime-simd.cc
new file mode 100644
index 0000000..5c60ad5
--- /dev/null
+++ b/src/runtime/runtime-simd.cc
@@ -0,0 +1,129 @@
+// 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
diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h
index 1d1028f..06182c6 100644
--- a/src/runtime/runtime.h
+++ b/src/runtime/runtime.h
@@ -557,6 +557,16 @@
   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)                        \
@@ -732,6 +742,7 @@
   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)                \
diff --git a/src/type-info.cc b/src/type-info.cc
index ba983d6..a813311 100644
--- a/src/type-info.cc
+++ b/src/type-info.cc
@@ -82,7 +82,8 @@
     obj = cell->value();
   }
 
-  if (obj->IsJSFunction() || obj->IsAllocationSite() || obj->IsSymbol()) {
+  if (obj->IsJSFunction() || obj->IsAllocationSite() || obj->IsSymbol() ||
+      obj->IsFloat32x4()) {
     return Handle<Object>(obj, isolate());
   }
 
diff --git a/src/types.cc b/src/types.cc
index 1c6b84e..6bbf655 100644
--- a/src/types.cc
+++ b/src/types.cc
@@ -228,6 +228,9 @@
     }
     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:
diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
index 80ce630..45f2ae3 100644
--- a/src/x64/code-stubs-x64.cc
+++ b/src/x64/code-stubs-x64.cc
@@ -1576,6 +1576,9 @@
       // 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.
diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc
index 8f2da73..51b1763 100644
--- a/src/x64/full-codegen-x64.cc
+++ b/src/x64/full-codegen-x64.cc
@@ -5184,6 +5184,10 @@
     __ 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);
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index c65b1dd..b45917e 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -2208,6 +2208,12 @@
         __ 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;
@@ -5711,6 +5717,11 @@
              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);
   }
diff --git a/src/x87/code-stubs-x87.cc b/src/x87/code-stubs-x87.cc
index 6aae562..959160a 100644
--- a/src/x87/code-stubs-x87.cc
+++ b/src/x87/code-stubs-x87.cc
@@ -1379,6 +1379,9 @@
       // 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.
diff --git a/src/x87/full-codegen-x87.cc b/src/x87/full-codegen-x87.cc
index 584c2b9..f113bb0 100644
--- a/src/x87/full-codegen-x87.cc
+++ b/src/x87/full-codegen-x87.cc
@@ -5169,6 +5169,10 @@
     __ 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);
diff --git a/src/x87/lithium-codegen-x87.cc b/src/x87/lithium-codegen-x87.cc
index 9c6798b..a77771d 100644
--- a/src/x87/lithium-codegen-x87.cc
+++ b/src/x87/lithium-codegen-x87.cc
@@ -2434,6 +2434,12 @@
         __ 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;
@@ -6121,6 +6127,11 @@
               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);
   }
diff --git a/test/cctest/cctest.gyp b/test/cctest/cctest.gyp
index bcbbe7b..23bf36c 100644
--- a/test/cctest/cctest.gyp
+++ b/test/cctest/cctest.gyp
@@ -145,6 +145,7 @@
         'test-representation.cc',
         'test-sampler-api.cc',
         'test-serialize.cc',
+        'test-simd.cc',
         'test-spaces.cc',
         'test-strings.cc',
         'test-symbols.cc',
diff --git a/test/cctest/test-heap-profiler.cc b/test/cctest/test-heap-profiler.cc
index 6fa8ede..5d3310e 100644
--- a/test/cctest/test-heap-profiler.cc
+++ b/test/cctest/test-heap-profiler.cc
@@ -482,6 +482,23 @@
 }
 
 
+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());
diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc
index 98accbc..eba2659 100644
--- a/test/cctest/test-heap.cc
+++ b/test/cctest/test-heap.cc
@@ -239,32 +239,43 @@
 
   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.
+  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);
 
-  Float32x4* float32x4 = *Handle<Float32x4>::cast(value);
-  CheckSimdLanes<Float32x4, float, 4>(float32x4);
+  CheckSimdLanes<Float32x4, float, 4>(*value);
 
-  // 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 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());
+  }
 }
 
 
diff --git a/test/cctest/test-simd.cc b/test/cctest/test-simd.cc
new file mode 100644
index 0000000..e87032d
--- /dev/null
+++ b/test/cctest/test-simd.cc
@@ -0,0 +1,45 @@
+// 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);
+  }
+}
diff --git a/test/mjsunit/harmony/simd.js b/test/mjsunit/harmony/simd.js
new file mode 100644
index 0000000..51a04c7
--- /dev/null
+++ b/test/mjsunit/harmony/simd.js
@@ -0,0 +1,408 @@
+// 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();
diff --git a/test/mjsunit/messages.js b/test/mjsunit/messages.js
index c30e59f..9b3ca18 100644
--- a/test/mjsunit/messages.js
+++ b/test/mjsunit/messages.js
@@ -3,7 +3,7 @@
 // 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 {
@@ -323,6 +323,11 @@
   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);
diff --git a/test/mjsunit/samevalue.js b/test/mjsunit/samevalue.js
index 229db0d..174afd2 100644
--- a/test/mjsunit/samevalue.js
+++ b/test/mjsunit/samevalue.js
@@ -27,78 +27,94 @@
 
 
 // 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));
+assertTrue(sameValueBoth());
+assertTrue(sameValueBoth(undefined, undefined));
 
-assertFalse(sameValue(0,1));
-assertFalse(sameValue("foo", "bar"));
-assertFalse(sameValue(obj1, obj2));
-assertFalse(sameValue(true, false));
+assertFalse(sameValueBoth(0,1));
+assertFalse(sameValueBoth("foo", "bar"));
+assertFalse(sameValueBoth(obj1, obj2));
+assertFalse(sameValueBoth(true, false));
 
-assertFalse(sameValue(obj1, true));
-assertFalse(sameValue(obj1, "foo"));
-assertFalse(sameValue(obj1, 1));
-assertFalse(sameValue(obj1, undefined));
-assertFalse(sameValue(obj1, NaN));
+assertFalse(sameValueBoth(obj1, true));
+assertFalse(sameValueBoth(obj1, "foo"));
+assertFalse(sameValueBoth(obj1, 1));
+assertFalse(sameValueBoth(obj1, undefined));
+assertFalse(sameValueBoth(obj1, NaN));
 
-assertFalse(sameValue(undefined, true));
-assertFalse(sameValue(undefined, "foo"));
-assertFalse(sameValue(undefined, 1));
-assertFalse(sameValue(undefined, obj1));
-assertFalse(sameValue(undefined, NaN));
+assertFalse(sameValueBoth(undefined, true));
+assertFalse(sameValueBoth(undefined, "foo"));
+assertFalse(sameValueBoth(undefined, 1));
+assertFalse(sameValueBoth(undefined, obj1));
+assertFalse(sameValueBoth(undefined, NaN));
 
-assertFalse(sameValue(NaN, true));
-assertFalse(sameValue(NaN, "foo"));
-assertFalse(sameValue(NaN, 1));
-assertFalse(sameValue(NaN, obj1));
-assertFalse(sameValue(NaN, undefined));
+assertFalse(sameValueBoth(NaN, true));
+assertFalse(sameValueBoth(NaN, "foo"));
+assertFalse(sameValueBoth(NaN, 1));
+assertFalse(sameValueBoth(NaN, obj1));
+assertFalse(sameValueBoth(NaN, undefined));
 
-assertFalse(sameValue("foo", true));
-assertFalse(sameValue("foo", 1));
-assertFalse(sameValue("foo", obj1));
-assertFalse(sameValue("foo", undefined));
-assertFalse(sameValue("foo", NaN));
+assertFalse(sameValueBoth("foo", true));
+assertFalse(sameValueBoth("foo", 1));
+assertFalse(sameValueBoth("foo", obj1));
+assertFalse(sameValueBoth("foo", undefined));
+assertFalse(sameValueBoth("foo", NaN));
 
-assertFalse(sameValue(true, 1));
-assertFalse(sameValue(true, obj1));
-assertFalse(sameValue(true, undefined));
-assertFalse(sameValue(true, NaN));
-assertFalse(sameValue(true, "foo"));
+assertFalse(sameValueBoth(true, 1));
+assertFalse(sameValueBoth(true, obj1));
+assertFalse(sameValueBoth(true, undefined));
+assertFalse(sameValueBoth(true, NaN));
+assertFalse(sameValueBoth(true, "foo"));
 
-assertFalse(sameValue(1, true));
-assertFalse(sameValue(1, obj1));
-assertFalse(sameValue(1, undefined));
-assertFalse(sameValue(1, NaN));
-assertFalse(sameValue(1, "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));
+assertFalse(sameValueBoth("1", 1));
+assertFalse(sameValueBoth("true", true));
+assertFalse(sameValueBoth("false", false));
+assertFalse(sameValueBoth("undefined", undefined));
+assertFalse(sameValueBoth("NaN", NaN));
 
-// -0 and +0 are should be different
-assertFalse(sameValue(+0, -0));
-assertFalse(sameValue(-0, +0));
+// 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));
diff --git a/test/simdjs/harness-adapt.js b/test/simdjs/harness-adapt.js
index a2ca237..21f5600 100644
--- a/test/simdjs/harness-adapt.js
+++ b/test/simdjs/harness-adapt.js
@@ -27,3 +27,8 @@
 load('base.js');
 
 })();
+
+// ecmascript_simd_tests logs errors to the console.
+var console = {
+  log: function(x) { print(x); },
+};
diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp
index e52cfcc..04855e5 100644
--- a/tools/gyp/v8.gyp
+++ b/tools/gyp/v8.gyp
@@ -881,6 +881,7 @@
         '../../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',
@@ -1798,6 +1799,7 @@
           '../../src/harmony-spread.js',
           '../../src/harmony-object.js',
           '../../src/harmony-sharedarraybuffer.js',
+          '../../src/harmony-simd.js',
         ],
         'code_stub_library_files': [
           '../../src/macros.py',