Version 3.23.3

Fixed compilation with GCC 4.8. (issue 2767, 2149)

Added explicit Isolate parameter to External::New. (Chromium issue 266838)

Performance and stability improvements on all platforms.

git-svn-id: http://v8.googlecode.com/svn/trunk@17690 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/ChangeLog b/ChangeLog
index a2b4a20..60e5fdc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2013-11-13: Version 3.23.3
+
+        Fixed compilation with GCC 4.8.
+        (issue 2767, 2149)
+
+        Added explicit Isolate parameter to External::New.
+        (Chromium issue 266838)
+
+        Performance and stability improvements on all platforms.
+
+
 2013-11-12: Version 3.23.2
 
         Fixed --extra-code flag for snapshot creation.
diff --git a/include/v8.h b/include/v8.h
index 1f8cbfd..f8ef7c1 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -114,6 +114,7 @@
 class StringObject;
 class Symbol;
 class SymbolObject;
+class Private;
 class Uint32;
 class Utils;
 class Value;
@@ -328,6 +329,8 @@
   friend Handle<Boolean> False(Isolate* isolate);
   friend class Context;
   friend class HandleScope;
+  friend class Object;
+  friend class Private;
 
   V8_INLINE static Handle<T> New(Isolate* isolate, T* that);
 
@@ -1926,11 +1929,9 @@
   // Returns the print name string of the symbol, or undefined if none.
   Local<Value> Name() const;
 
-  // Create a symbol without a print name.
-  static Local<Symbol> New(Isolate* isolate);
-
-  // Create a symbol with a print name.
-  static Local<Symbol> New(Isolate *isolate, const char* data, int length = -1);
+  // Create a symbol. If data is not NULL, it will be used as a print name.
+  static Local<Symbol> New(
+      Isolate *isolate, const char* data = NULL, int length = -1);
 
   V8_INLINE static Symbol* Cast(v8::Value* obj);
  private:
@@ -1940,6 +1941,25 @@
 
 
 /**
+ * A private symbol
+ *
+ * This is an experimental feature. Use at your own risk.
+ */
+class V8_EXPORT Private : public Data {
+ public:
+  // Returns the print name string of the private symbol, or undefined if none.
+  Local<Value> Name() const;
+
+  // Create a private symbol. If data is not NULL, it will be the print name.
+  static Local<Private> New(
+      Isolate *isolate, const char* data = NULL, int length = -1);
+
+ private:
+  Private();
+};
+
+
+/**
  * A JavaScript number value (ECMA-262, 4.3.20)
  */
 class V8_EXPORT Number : public Primitive {
@@ -2109,6 +2129,17 @@
                            AccessControl settings = DEFAULT);
 
   /**
+   * Functionality for private properties.
+   * This is an experimental feature, use at your own risk.
+   * Note: Private properties are inherited. Do not rely on this, since it may
+   * change.
+   */
+  bool HasPrivate(Handle<Private> key);
+  bool SetPrivate(Handle<Private> key, Handle<Value> value);
+  bool DeletePrivate(Handle<Private> key);
+  Local<Value> GetPrivate(Handle<Private> key);
+
+  /**
    * Returns an array containing the names of the enumerable properties
    * of this object, including properties from prototype objects.  The
    * array returned by this method contains the same values as would
@@ -3042,6 +3073,8 @@
  */
 class V8_EXPORT External : public Value {
  public:
+  static Local<External> New(Isolate* isolate, void* value);
+  // Deprecated, do not use.
   static Local<External> New(void* value);
   V8_INLINE static External* Cast(Value* obj);
   void* Value() const;
@@ -5819,7 +5852,6 @@
 template<typename T>
 void ReturnValue<T>::Set(uint32_t i) {
   TYPE_CHECK(T, Integer);
-  typedef internal::Internals I;
   // Can't simply use INT32_MAX here for whatever reason.
   bool fits_into_int32_t = (i & (1U << 31)) == 0;
   if (V8_LIKELY(fits_into_int32_t)) {
diff --git a/include/v8config.h b/include/v8config.h
index 834f9c5..631ad0d 100644
--- a/include/v8config.h
+++ b/include/v8config.h
@@ -187,6 +187,7 @@
 //                                        supported
 //  V8_HAS_ATTRIBUTE_DEPRECATED         - __attribute__((deprecated)) supported
 //  V8_HAS_ATTRIBUTE_NOINLINE           - __attribute__((noinline)) supported
+//  V8_HAS_ATTRIBUTE_UNUSED             - __attribute__((unused)) supported
 //  V8_HAS_ATTRIBUTE_VISIBILITY         - __attribute__((visibility)) supported
 //  V8_HAS_ATTRIBUTE_WARN_UNUSED_RESULT - __attribute__((warn_unused_result))
 //                                        supported
@@ -216,6 +217,7 @@
 # define V8_HAS_ATTRIBUTE_ALWAYS_INLINE (__has_attribute(always_inline))
 # define V8_HAS_ATTRIBUTE_DEPRECATED (__has_attribute(deprecated))
 # define V8_HAS_ATTRIBUTE_NOINLINE (__has_attribute(noinline))
+# define V8_HAS_ATTRIBUTE_UNUSED (__has_attribute(unused))
 # define V8_HAS_ATTRIBUTE_VISIBILITY (__has_attribute(visibility))
 # define V8_HAS_ATTRIBUTE_WARN_UNUSED_RESULT \
     (__has_attribute(warn_unused_result))
@@ -247,6 +249,7 @@
 # define V8_HAS_ATTRIBUTE_DEPRECATED (V8_GNUC_PREREQ(3, 4, 0))
 # define V8_HAS_ATTRIBUTE_DEPRECATED_MESSAGE (V8_GNUC_PREREQ(4, 5, 0))
 # define V8_HAS_ATTRIBUTE_NOINLINE (V8_GNUC_PREREQ(3, 4, 0))
+# define V8_HAS_ATTRIBUTE_UNUSED (V8_GNUC_PREREQ(2, 95, 0))
 # define V8_HAS_ATTRIBUTE_VISIBILITY (V8_GNUC_PREREQ(4, 3, 0))
 # define V8_HAS_ATTRIBUTE_WARN_UNUSED_RESULT \
     (!V8_CC_INTEL && V8_GNUC_PREREQ(4, 1, 0))
@@ -334,6 +337,14 @@
 #endif
 
 
+// A macro to mark variables or types as unused, avoiding compiler warnings.
+#if V8_HAS_ATTRIBUTE_UNUSED
+# define V8_UNUSED __attribute__((unused))
+#else
+# define V8_UNUSED
+#endif
+
+
 // Annotate a function indicating the caller must examine the return value.
 // Use like:
 //   int foo() V8_WARN_UNUSED_RESULT;
diff --git a/samples/process.cc b/samples/process.cc
index e6f2ee3..d1d36ca 100644
--- a/samples/process.cc
+++ b/samples/process.cc
@@ -324,7 +324,7 @@
 
   // Wrap the raw C++ pointer in an External so it can be referenced
   // from within JavaScript.
-  Handle<External> map_ptr = External::New(obj);
+  Handle<External> map_ptr = External::New(GetIsolate(), obj);
 
   // Store the map pointer in the JavaScript wrapper.
   result->SetInternalField(0, map_ptr);
@@ -432,7 +432,7 @@
 
   // Wrap the raw C++ pointer in an External so it can be referenced
   // from within JavaScript.
-  Handle<External> request_ptr = External::New(request);
+  Handle<External> request_ptr = External::New(GetIsolate(), request);
 
   // Store the request pointer in the JavaScript wrapper.
   result->SetInternalField(0, request_ptr);
diff --git a/src/api.cc b/src/api.cc
index 401007b..65e7345 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -3191,6 +3191,12 @@
 }
 
 
+bool v8::Object::SetPrivate(v8::Handle<Private> key, v8::Handle<Value> value) {
+  return Set(v8::Handle<Value>(reinterpret_cast<Value*>(*key)),
+             value, DontEnum);
+}
+
+
 bool v8::Object::ForceDelete(v8::Handle<Value> key) {
   i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
   ON_BAILOUT(isolate, "v8::Object::ForceDelete()", return false);
@@ -3242,6 +3248,11 @@
 }
 
 
+Local<Value> v8::Object::GetPrivate(v8::Handle<Private> key) {
+  return Get(v8::Handle<Value>(reinterpret_cast<Value*>(*key)));
+}
+
+
 PropertyAttribute v8::Object::GetPropertyAttributes(v8::Handle<Value> key) {
   i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
   ON_BAILOUT(isolate, "v8::Object::GetPropertyAttribute()",
@@ -3441,6 +3452,11 @@
 }
 
 
+bool v8::Object::DeletePrivate(v8::Handle<Private> key) {
+  return Delete(v8::Handle<Value>(reinterpret_cast<Value*>(*key)));
+}
+
+
 bool v8::Object::Has(v8::Handle<Value> key) {
   i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
   ON_BAILOUT(isolate, "v8::Object::Has()", return false);
@@ -3455,6 +3471,11 @@
 }
 
 
+bool v8::Object::HasPrivate(v8::Handle<Private> key) {
+  return Has(v8::Handle<Value>(reinterpret_cast<Value*>(*key)));
+}
+
+
 bool v8::Object::Delete(uint32_t index) {
   i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
   ON_BAILOUT(isolate, "v8::Object::DeleteProperty()",
@@ -4876,6 +4897,11 @@
 }
 
 
+Local<Value> Private::Name() const {
+  return reinterpret_cast<const Symbol*>(this)->Name();
+}
+
+
 double Number::Value() const {
   i::Handle<i::Object> obj = Utils::OpenHandle(this);
   return obj->Number();
@@ -5369,17 +5395,22 @@
 }
 
 
-Local<External> v8::External::New(void* value) {
+Local<External> v8::External::New(Isolate* isolate, void* value) {
   STATIC_ASSERT(sizeof(value) == sizeof(i::Address));
-  i::Isolate* isolate = i::Isolate::Current();
-  EnsureInitializedForIsolate(isolate, "v8::External::New()");
-  LOG_API(isolate, "External::New");
-  ENTER_V8(isolate);
-  i::Handle<i::JSObject> external = isolate->factory()->NewExternal(value);
+  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
+  EnsureInitializedForIsolate(i_isolate, "v8::External::New()");
+  LOG_API(i_isolate, "External::New");
+  ENTER_V8(i_isolate);
+  i::Handle<i::JSObject> external = i_isolate->factory()->NewExternal(value);
   return Utils::ExternalToLocal(external);
 }
 
 
+Local<External> v8::External::New(void* value) {
+  return v8::External::New(Isolate::GetCurrent(), value);
+}
+
+
 void* External::Value() const {
   return ExternalValue(*Utils::OpenHandle(this));
 }
@@ -6133,27 +6164,37 @@
 }
 
 
-Local<Symbol> v8::Symbol::New(Isolate* isolate) {
+Local<Symbol> v8::Symbol::New(Isolate* isolate, const char* data, int length) {
   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
   EnsureInitializedForIsolate(i_isolate, "v8::Symbol::New()");
   LOG_API(i_isolate, "Symbol::New()");
   ENTER_V8(i_isolate);
   i::Handle<i::Symbol> result = i_isolate->factory()->NewSymbol();
+  if (data != NULL) {
+    if (length == -1) length = i::StrLength(data);
+    i::Handle<i::String> name = i_isolate->factory()->NewStringFromUtf8(
+        i::Vector<const char>(data, length));
+    result->set_name(*name);
+  }
   return Utils::ToLocal(result);
 }
 
 
-Local<Symbol> v8::Symbol::New(Isolate* isolate, const char* data, int length) {
+Local<Private> v8::Private::New(
+    Isolate* isolate, const char* data, int length) {
   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
-  EnsureInitializedForIsolate(i_isolate, "v8::Symbol::New()");
-  LOG_API(i_isolate, "Symbol::New(char)");
+  EnsureInitializedForIsolate(i_isolate, "v8::Private::New()");
+  LOG_API(i_isolate, "Private::New()");
   ENTER_V8(i_isolate);
-  if (length == -1) length = i::StrLength(data);
-  i::Handle<i::String> name = i_isolate->factory()->NewStringFromUtf8(
-      i::Vector<const char>(data, length));
-  i::Handle<i::Symbol> result = i_isolate->factory()->NewSymbol();
-  result->set_name(*name);
-  return Utils::ToLocal(result);
+  i::Handle<i::Symbol> symbol = i_isolate->factory()->NewPrivateSymbol();
+  if (data != NULL) {
+    if (length == -1) length = i::StrLength(data);
+    i::Handle<i::String> name = i_isolate->factory()->NewStringFromUtf8(
+        i::Vector<const char>(data, length));
+    symbol->set_name(*name);
+  }
+  Local<Symbol> result = Utils::ToLocal(symbol);
+  return v8::Handle<Private>(reinterpret_cast<Private*>(*result));
 }
 
 
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
index 95a04f7..94e114f 100644
--- a/src/arm/code-stubs-arm.cc
+++ b/src/arm/code-stubs-arm.cc
@@ -189,14 +189,21 @@
   // r0 -- number of arguments
   // r1 -- function
   // r2 -- type info cell with elements kind
-  static Register registers[] = { r1, r2 };
-  descriptor->register_param_count_ = 2;
-  if (constant_stack_parameter_count != 0) {
+  static Register registers_variable_args[] = { r1, r2, r0 };
+  static Register registers_no_args[] = { r1, r2 };
+
+  if (constant_stack_parameter_count == 0) {
+    descriptor->register_param_count_ = 2;
+    descriptor->register_params_ = registers_no_args;
+  } else {
     // stack param count needs (constructor pointer, and single argument)
+    descriptor->handler_arguments_mode_ = PASS_ARGUMENTS;
     descriptor->stack_parameter_count_ = r0;
+    descriptor->register_param_count_ = 3;
+    descriptor->register_params_ = registers_variable_args;
   }
+
   descriptor->hint_stack_parameter_count_ = constant_stack_parameter_count;
-  descriptor->register_params_ = registers;
   descriptor->function_mode_ = JS_FUNCTION_STUB_MODE;
   descriptor->deoptimization_handler_ =
       Runtime::FunctionForId(Runtime::kArrayConstructor)->entry;
@@ -210,15 +217,21 @@
   // register state
   // r0 -- number of arguments
   // r1 -- constructor function
-  static Register registers[] = { r1 };
-  descriptor->register_param_count_ = 1;
+  static Register registers_variable_args[] = { r1, r0 };
+  static Register registers_no_args[] = { r1 };
 
-  if (constant_stack_parameter_count != 0) {
+  if (constant_stack_parameter_count == 0) {
+    descriptor->register_param_count_ = 1;
+    descriptor->register_params_ = registers_no_args;
+  } else {
     // stack param count needs (constructor pointer, and single argument)
+    descriptor->handler_arguments_mode_ = PASS_ARGUMENTS;
     descriptor->stack_parameter_count_ = r0;
+    descriptor->register_param_count_ = 2;
+    descriptor->register_params_ = registers_variable_args;
   }
+
   descriptor->hint_stack_parameter_count_ = constant_stack_parameter_count;
-  descriptor->register_params_ = registers;
   descriptor->function_mode_ = JS_FUNCTION_STUB_MODE;
   descriptor->deoptimization_handler_ =
       Runtime::FunctionForId(Runtime::kInternalArrayConstructor)->entry;
@@ -302,6 +315,17 @@
 }
 
 
+void NewStringAddStub::InitializeInterfaceDescriptor(
+    Isolate* isolate,
+    CodeStubInterfaceDescriptor* descriptor) {
+  static Register registers[] = { r1, r0 };
+  descriptor->register_param_count_ = 2;
+  descriptor->register_params_ = registers;
+  descriptor->deoptimization_handler_ =
+      Runtime::FunctionForId(Runtime::kStringAdd)->entry;
+}
+
+
 #define __ ACCESS_MASM(masm)
 
 
diff --git a/src/arm/deoptimizer-arm.cc b/src/arm/deoptimizer-arm.cc
index 9339c5f..c846f98 100644
--- a/src/arm/deoptimizer-arm.cc
+++ b/src/arm/deoptimizer-arm.cc
@@ -107,7 +107,7 @@
   ApiFunction function(descriptor->deoptimization_handler_);
   ExternalReference xref(&function, ExternalReference::BUILTIN_CALL, isolate_);
   intptr_t handler = reinterpret_cast<intptr_t>(xref.address());
-  int params = descriptor->environment_length();
+  int params = descriptor->GetHandlerParameterCount();
   output_frame->SetRegister(r0.code(), params);
   output_frame->SetRegister(r1.code(), handler);
 }
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc
index 8fb1e15..0cb8e46 100644
--- a/src/arm/full-codegen-arm.cc
+++ b/src/arm/full-codegen-arm.cc
@@ -3104,6 +3104,32 @@
 }
 
 
+void FullCodeGenerator::EmitIsMinusZero(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  ASSERT(args->length() == 1);
+
+  VisitForAccumulatorValue(args->at(0));
+
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false,
+                         &if_true, &if_false, &fall_through);
+
+  __ CheckMap(r0, r1, Heap::kHeapNumberMapRootIndex, if_false, DO_SMI_CHECK);
+  __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
+  __ ldr(r1, FieldMemOperand(r0, HeapNumber::kMantissaOffset));
+  __ cmp(r2, Operand(0x80000000));
+  __ cmp(r1, Operand(0x00000000), eq);
+
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  Split(eq, if_true, if_false, fall_through);
+
+  context()->Plug(if_true, if_false);
+}
+
+
 void FullCodeGenerator::EmitIsArray(CallRuntime* expr) {
   ZoneList<Expression*>* args = expr->arguments();
   ASSERT(args->length() == 1);
@@ -3705,11 +3731,21 @@
 void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) {
   ZoneList<Expression*>* args = expr->arguments();
   ASSERT_EQ(2, args->length());
-  VisitForStackValue(args->at(0));
-  VisitForStackValue(args->at(1));
 
-  StringAddStub stub(STRING_ADD_CHECK_BOTH);
-  __ CallStub(&stub);
+  if (FLAG_new_string_add) {
+    VisitForStackValue(args->at(0));
+    VisitForAccumulatorValue(args->at(1));
+
+    __ pop(r1);
+    NewStringAddStub stub(STRING_ADD_CHECK_BOTH, NOT_TENURED);
+    __ CallStub(&stub);
+  } else {
+    VisitForStackValue(args->at(0));
+    VisitForStackValue(args->at(1));
+
+    StringAddStub stub(STRING_ADD_CHECK_BOTH);
+    __ CallStub(&stub);
+  }
   context()->Plug(r0);
 }
 
@@ -3726,42 +3762,6 @@
 }
 
 
-void FullCodeGenerator::EmitMathSin(CallRuntime* expr) {
-  // Load the argument on the stack and call the stub.
-  TranscendentalCacheStub stub(TranscendentalCache::SIN,
-                               TranscendentalCacheStub::TAGGED);
-  ZoneList<Expression*>* args = expr->arguments();
-  ASSERT(args->length() == 1);
-  VisitForStackValue(args->at(0));
-  __ CallStub(&stub);
-  context()->Plug(r0);
-}
-
-
-void FullCodeGenerator::EmitMathCos(CallRuntime* expr) {
-  // Load the argument on the stack and call the stub.
-  TranscendentalCacheStub stub(TranscendentalCache::COS,
-                               TranscendentalCacheStub::TAGGED);
-  ZoneList<Expression*>* args = expr->arguments();
-  ASSERT(args->length() == 1);
-  VisitForStackValue(args->at(0));
-  __ CallStub(&stub);
-  context()->Plug(r0);
-}
-
-
-void FullCodeGenerator::EmitMathTan(CallRuntime* expr) {
-  // Load the argument on the stack and call the stub.
-  TranscendentalCacheStub stub(TranscendentalCache::TAN,
-                               TranscendentalCacheStub::TAGGED);
-  ZoneList<Expression*>* args = expr->arguments();
-  ASSERT(args->length() == 1);
-  VisitForStackValue(args->at(0));
-  __ CallStub(&stub);
-  context()->Plug(r0);
-}
-
-
 void FullCodeGenerator::EmitMathLog(CallRuntime* expr) {
   // Load the argument on the stack and call the stub.
   TranscendentalCacheStub stub(TranscendentalCache::LOG,
diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc
index 5fb0e53..787fc81 100644
--- a/src/arm/lithium-arm.cc
+++ b/src/arm/lithium-arm.cc
@@ -1783,6 +1783,16 @@
 }
 
 
+LInstruction* LChunkBuilder::DoCompareMinusZeroAndBranch(
+    HCompareMinusZeroAndBranch* instr) {
+  LInstruction* goto_instr = CheckElideControlInstruction(instr);
+  if (goto_instr != NULL) return goto_instr;
+  LOperand* value = UseRegister(instr->value());
+  LOperand* scratch = TempRegister();
+  return new(zone()) LCompareMinusZeroAndBranch(value, scratch);
+}
+
+
 LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) {
   ASSERT(instr->value()->representation().IsTagged());
   LOperand* value = UseRegisterAtStart(instr->value());
@@ -2413,8 +2423,12 @@
 
 LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) {
   LOperand* context = UseFixed(instr->context(), cp);
-  LOperand* left = UseRegisterAtStart(instr->left());
-  LOperand* right = UseRegisterAtStart(instr->right());
+  LOperand* left = FLAG_new_string_add
+      ? UseFixed(instr->left(), r1)
+      : UseRegisterAtStart(instr->left());
+  LOperand* right = FLAG_new_string_add
+      ? UseFixed(instr->right(), r0)
+      : UseRegisterAtStart(instr->right());
   return MarkAsCall(
       DefineFixed(new(zone()) LStringAdd(context, left, right), r0),
       instr);
@@ -2485,7 +2499,7 @@
     CodeStubInterfaceDescriptor* descriptor =
         info()->code_stub()->GetInterfaceDescriptor(info()->isolate());
     int index = static_cast<int>(instr->index());
-    Register reg = DESCRIPTOR_GET_PARAMETER_REGISTER(descriptor, index);
+    Register reg = descriptor->GetParameterRegister(index);
     return DefineFixed(result, reg);
   }
 }
diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h
index 559f26e..f67747b 100644
--- a/src/arm/lithium-arm.h
+++ b/src/arm/lithium-arm.h
@@ -72,6 +72,7 @@
   V(ClampIToUint8)                              \
   V(ClampTToUint8)                              \
   V(ClassOfTestAndBranch)                       \
+  V(CompareMinusZeroAndBranch)                  \
   V(CompareNumericAndBranch)                    \
   V(CmpObjectEqAndBranch)                       \
   V(CmpHoleAndBranch)                           \
@@ -928,6 +929,22 @@
 };
 
 
+class LCompareMinusZeroAndBranch V8_FINAL : public LControlInstruction<1, 1> {
+ public:
+  LCompareMinusZeroAndBranch(LOperand* value, LOperand* temp) {
+    inputs_[0] = value;
+    temps_[0] = temp;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CompareMinusZeroAndBranch,
+                               "cmp-minus-zero-and-branch")
+  DECLARE_HYDROGEN_ACCESSOR(CompareMinusZeroAndBranch)
+};
+
+
 class LIsObjectAndBranch V8_FINAL : public LControlInstruction<1, 1> {
  public:
   LIsObjectAndBranch(LOperand* value, LOperand* temp) {
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index 8049b68..207dd8c 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -2472,6 +2472,33 @@
 }
 
 
+void LCodeGen::DoCompareMinusZeroAndBranch(LCompareMinusZeroAndBranch* instr) {
+  Representation rep = instr->hydrogen()->value()->representation();
+  ASSERT(!rep.IsInteger32());
+  Register scratch = ToRegister(instr->temp());
+
+  if (rep.IsDouble()) {
+    DwVfpRegister value = ToDoubleRegister(instr->value());
+    __ VFPCompareAndSetFlags(value, 0.0);
+    EmitFalseBranch(instr, ne);
+    __ VmovHigh(scratch, value);
+    __ cmp(scratch, Operand(0x80000000));
+  } else {
+    Register value = ToRegister(instr->value());
+    __ CheckMap(value,
+                scratch,
+                Heap::kHeapNumberMapRootIndex,
+                instr->FalseLabel(chunk()),
+                DO_SMI_CHECK);
+    __ ldr(scratch, FieldMemOperand(value, HeapNumber::kExponentOffset));
+    __ ldr(ip, FieldMemOperand(value, HeapNumber::kMantissaOffset));
+    __ cmp(scratch, Operand(0x80000000));
+    __ cmp(ip, Operand(0x00000000), eq);
+  }
+  EmitBranch(instr, eq);
+}
+
+
 Condition LCodeGen::EmitIsObject(Register input,
                                  Register temp1,
                                  Label* is_not_object,
@@ -4562,10 +4589,18 @@
 
 void LCodeGen::DoStringAdd(LStringAdd* instr) {
   ASSERT(ToRegister(instr->context()).is(cp));
-  __ push(ToRegister(instr->left()));
-  __ push(ToRegister(instr->right()));
-  StringAddStub stub(instr->hydrogen()->flags());
-  CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
+  if (FLAG_new_string_add) {
+    ASSERT(ToRegister(instr->left()).is(r1));
+    ASSERT(ToRegister(instr->right()).is(r0));
+    NewStringAddStub stub(instr->hydrogen()->flags(),
+                          isolate()->heap()->GetPretenureMode());
+    CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
+  } else {
+    __ push(ToRegister(instr->left()));
+    __ push(ToRegister(instr->right()));
+    StringAddStub stub(instr->hydrogen()->flags());
+    CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
+  }
 }
 
 
diff --git a/src/arm/lithium-codegen-arm.h b/src/arm/lithium-codegen-arm.h
index cbd6b9c..7390a48 100644
--- a/src/arm/lithium-codegen-arm.h
+++ b/src/arm/lithium-codegen-arm.h
@@ -297,6 +297,8 @@
 
   static Condition TokenToCondition(Token::Value op, bool is_unsigned);
   void EmitGoto(int block);
+
+  // EmitBranch expects to be the last instruction of a block.
   template<class InstrType>
   void EmitBranch(InstrType instr, Condition condition);
   template<class InstrType>
diff --git a/src/array-iterator.js b/src/array-iterator.js
index e734986..a8c5e00 100644
--- a/src/array-iterator.js
+++ b/src/array-iterator.js
@@ -36,9 +36,9 @@
 var ARRAY_ITERATOR_KIND_ENTRIES = 3;
 // The spec draft also has "sparse" but it is never used.
 
-var iteratorObjectSymbol = %CreateSymbol(UNDEFINED);
-var arrayIteratorNextIndexSymbol = %CreateSymbol(UNDEFINED);
-var arrayIterationKindSymbol = %CreateSymbol(UNDEFINED);
+var iteratorObjectSymbol = NEW_PRIVATE("iterator_object");
+var arrayIteratorNextIndexSymbol = NEW_PRIVATE("iterator_next");
+var arrayIterationKindSymbol = NEW_PRIVATE("iterator_kind");
 
 function ArrayIterator() {}
 
@@ -46,9 +46,9 @@
 function CreateArrayIterator(array, kind) {
   var object = ToObject(array);
   var iterator = new ArrayIterator;
-  iterator[iteratorObjectSymbol] = object;
-  iterator[arrayIteratorNextIndexSymbol] = 0;
-  iterator[arrayIterationKindSymbol] = kind;
+  SET_PRIVATE(iterator, iteratorObjectSymbol, object);
+  SET_PRIVATE(iterator, arrayIteratorNextIndexSymbol, 0);
+  SET_PRIVATE(iterator, arrayIterationKindSymbol, kind);
   return iterator;
 }
 
@@ -60,24 +60,24 @@
 // 15.4.5.2.2 ArrayIterator.prototype.next( )
 function ArrayIteratorNext() {
   var iterator = ToObject(this);
-  var array = iterator[iteratorObjectSymbol];
+  var array = GET_PRIVATE(iterator, iteratorObjectSymbol);
   if (!array) {
     throw MakeTypeError('incompatible_method_receiver',
                         ['Array Iterator.prototype.next']);
   }
 
-  var index = iterator[arrayIteratorNextIndexSymbol];
-  var itemKind = iterator[arrayIterationKindSymbol];
+  var index = GET_PRIVATE(iterator, arrayIteratorNextIndexSymbol);
+  var itemKind = GET_PRIVATE(iterator, arrayIterationKindSymbol);
   var length = TO_UINT32(array.length);
 
   // "sparse" is never used.
 
   if (index >= length) {
-    iterator[arrayIteratorNextIndexSymbol] = 1 / 0; // Infinity
+    SET_PRIVATE(iterator, arrayIteratorNextIndexSymbol, INFINITY);
     return CreateIteratorResultObject(UNDEFINED, true);
   }
 
-  iterator[arrayIteratorNextIndexSymbol] = index + 1;
+  SET_PRIVATE(iterator, arrayIteratorNextIndexSymbol, index + 1);
 
   if (itemKind == ARRAY_ITERATOR_KIND_VALUES)
     return CreateIteratorResultObject(array[index], false);
diff --git a/src/checks.h b/src/checks.h
index 9d2db28..f7b145f 100644
--- a/src/checks.h
+++ b/src/checks.h
@@ -268,7 +268,7 @@
 #define STATIC_CHECK(test)                                                    \
   typedef                                                                     \
     StaticAssertionHelper<sizeof(StaticAssertion<static_cast<bool>((test))>)> \
-    SEMI_STATIC_JOIN(__StaticAssertTypedef__, __LINE__)
+    SEMI_STATIC_JOIN(__StaticAssertTypedef__, __LINE__) V8_UNUSED
 #endif
 
 
diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc
index 19b6088..a790179 100644
--- a/src/code-stubs-hydrogen.cc
+++ b/src/code-stubs-hydrogen.cc
@@ -150,26 +150,24 @@
   next_block->SetJoinId(BailoutId::StubEntry());
   set_current_block(next_block);
 
+  bool runtime_stack_params = descriptor_->stack_parameter_count_.is_valid();
+  HInstruction* stack_parameter_count = NULL;
   for (int i = 0; i < param_count; ++i) {
-    HParameter* param =
-        Add<HParameter>(i, HParameter::REGISTER_PARAMETER);
+    Representation r = descriptor_->IsParameterCountRegister(i)
+        ? Representation::Integer32()
+        : Representation::Tagged();
+    HParameter* param = Add<HParameter>(i, HParameter::REGISTER_PARAMETER, r);
     start_environment->Bind(i, param);
     parameters_[i] = param;
+    if (descriptor_->IsParameterCountRegister(i)) {
+      param->set_type(HType::Smi());
+      stack_parameter_count = param;
+      arguments_length_ = stack_parameter_count;
+    }
   }
 
-  HInstruction* stack_parameter_count;
-  if (descriptor_->stack_parameter_count_.is_valid()) {
-    ASSERT(descriptor_->environment_length() == (param_count + 1));
-    stack_parameter_count = New<HParameter>(param_count,
-                                            HParameter::REGISTER_PARAMETER,
-                                            Representation::Integer32());
-    stack_parameter_count->set_type(HType::Smi());
-    // It's essential to bind this value to the environment in case of deopt.
-    AddInstruction(stack_parameter_count);
-    start_environment->Bind(param_count, stack_parameter_count);
-    arguments_length_ = stack_parameter_count;
-  } else {
-    ASSERT(descriptor_->environment_length() == param_count);
+  ASSERT(!runtime_stack_params || arguments_length_ != NULL);
+  if (!runtime_stack_params) {
     stack_parameter_count = graph()->GetConstantMinus1();
     arguments_length_ = graph()->GetConstant0();
   }
@@ -189,10 +187,11 @@
   if (descriptor_->function_mode_ == JS_FUNCTION_STUB_MODE) {
     if (!stack_parameter_count->IsConstant() &&
         descriptor_->hint_stack_parameter_count_ < 0) {
-      HInstruction* amount = graph()->GetConstant1();
-      stack_pop_count = Add<HAdd>(stack_parameter_count, amount);
-      stack_pop_count->ChangeRepresentation(Representation::Integer32());
+      HInstruction* constant_one = graph()->GetConstant1();
+      stack_pop_count = Add<HAdd>(stack_parameter_count, constant_one);
       stack_pop_count->ClearFlag(HValue::kCanOverflow);
+      // TODO(mvstanton): verify that stack_parameter_count+1 really fits in a
+      // smi.
     } else {
       int count = descriptor_->hint_stack_parameter_count_;
       stack_pop_count = Add<HConstant>(count);
@@ -972,6 +971,38 @@
 
 
 template <>
+HValue* CodeStubGraphBuilder<NewStringAddStub>::BuildCodeInitializedStub() {
+  NewStringAddStub* stub = casted_stub();
+  StringAddFlags flags = stub->flags();
+  PretenureFlag pretenure_flag = stub->pretenure_flag();
+
+  HValue* left = GetParameter(NewStringAddStub::kLeft);
+  HValue* right = GetParameter(NewStringAddStub::kRight);
+
+  // Make sure that both arguments are strings if not known in advance.
+  if ((flags & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT) {
+    IfBuilder if_leftnotstring(this);
+    if_leftnotstring.IfNot<HIsStringAndBranch>(left);
+    if_leftnotstring.Then();
+    if_leftnotstring.Deopt("Expected string for LHS of string addition");
+  }
+  if ((flags & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT) {
+    IfBuilder if_rightnotstring(this);
+    if_rightnotstring.IfNot<HIsStringAndBranch>(right);
+    if_rightnotstring.Then();
+    if_rightnotstring.Deopt("Expected string for RHS of string addition");
+  }
+
+  return BuildStringAdd(left, right, pretenure_flag);
+}
+
+
+Handle<Code> NewStringAddStub::GenerateCode(Isolate* isolate) {
+  return DoGenerateCode(isolate, this);
+}
+
+
+template <>
 HValue* CodeStubGraphBuilder<ToBooleanStub>::BuildCodeInitializedStub() {
   ToBooleanStub* stub = casted_stub();
 
diff --git a/src/code-stubs.cc b/src/code-stubs.cc
index afa3cd0..f6e880f 100644
--- a/src/code-stubs.cc
+++ b/src/code-stubs.cc
@@ -46,6 +46,7 @@
       function_mode_(NOT_JS_FUNCTION_STUB_MODE),
       register_params_(NULL),
       deoptimization_handler_(NULL),
+      handler_arguments_mode_(DONT_PASS_ARGUMENTS),
       miss_handler_(),
       has_miss_handler_(false) { }
 
@@ -682,6 +683,21 @@
 }
 
 
+void NewStringAddStub::PrintBaseName(StringStream* stream) {
+  stream->Add("NewStringAddStub");
+  if ((flags() & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_BOTH) {
+    stream->Add("_CheckBoth");
+  } else if ((flags() & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT) {
+    stream->Add("_CheckLeft");
+  } else if ((flags() & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT) {
+    stream->Add("_CheckRight");
+  }
+  if (pretenure_flag() == TENURED) {
+    stream->Add("_Tenured");
+  }
+}
+
+
 InlineCacheState ICCompareStub::GetICState() {
   CompareIC::State state = Max(left_, right_);
   switch (state) {
@@ -1134,6 +1150,13 @@
 }
 
 
+// static
+void NewStringAddStub::InstallDescriptors(Isolate* isolate) {
+  NewStringAddStub stub(STRING_ADD_CHECK_NONE, NOT_TENURED);
+  InstallDescriptor(isolate, &stub);
+}
+
+
 ArrayConstructorStub::ArrayConstructorStub(Isolate* isolate)
     : argument_count_(ANY) {
   ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
diff --git a/src/code-stubs.h b/src/code-stubs.h
index 3dc32e8..8f1b686 100644
--- a/src/code-stubs.h
+++ b/src/code-stubs.h
@@ -43,6 +43,7 @@
   V(CallConstruct)                       \
   V(BinaryOp)                            \
   V(StringAdd)                           \
+  V(NewStringAdd)                        \
   V(SubString)                           \
   V(StringCompare)                       \
   V(Compare)                             \
@@ -276,23 +277,23 @@
 
 
 enum StubFunctionMode { NOT_JS_FUNCTION_STUB_MODE, JS_FUNCTION_STUB_MODE };
-
+enum HandlerArgumentsMode { DONT_PASS_ARGUMENTS, PASS_ARGUMENTS };
 
 struct CodeStubInterfaceDescriptor {
   CodeStubInterfaceDescriptor();
   int register_param_count_;
+
   Register stack_parameter_count_;
   // if hint_stack_parameter_count_ > 0, the code stub can optimize the
   // return sequence. Default value is -1, which means it is ignored.
   int hint_stack_parameter_count_;
   StubFunctionMode function_mode_;
   Register* register_params_;
+
   Address deoptimization_handler_;
+  HandlerArgumentsMode handler_arguments_mode_;
 
   int environment_length() const {
-    if (stack_parameter_count_.is_valid()) {
-      return register_param_count_ + 1;
-    }
     return register_param_count_;
   }
 
@@ -301,6 +302,9 @@
   void SetMissHandler(ExternalReference handler) {
     miss_handler_ = handler;
     has_miss_handler_ = true;
+    // Our miss handler infrastructure doesn't currently support
+    // variable stack parameter counts.
+    ASSERT(!stack_parameter_count_.is_valid());
   }
 
   ExternalReference miss_handler() {
@@ -312,18 +316,27 @@
     return has_miss_handler_;
   }
 
+  Register GetParameterRegister(int index) {
+    return register_params_[index];
+  }
+
+  bool IsParameterCountRegister(int index) {
+    return GetParameterRegister(index).is(stack_parameter_count_);
+  }
+
+  int GetHandlerParameterCount() {
+    int params = environment_length();
+    if (handler_arguments_mode_ == PASS_ARGUMENTS) {
+      params += 1;
+    }
+    return params;
+  }
+
  private:
   ExternalReference miss_handler_;
   bool has_miss_handler_;
 };
 
-// A helper to make up for the fact that type Register is not fully
-// defined outside of the platform directories
-#define DESCRIPTOR_GET_PARAMETER_REGISTER(descriptor, index) \
-  ((index) == (descriptor)->register_param_count_)           \
-      ? (descriptor)->stack_parameter_count_                 \
-      : (descriptor)->register_params_[(index)]
-
 
 class HydrogenCodeStub : public CodeStub {
  public:
@@ -1179,6 +1192,47 @@
 };
 
 
+// TODO(bmeurer): Rename to StringAddStub once we dropped the old StringAddStub.
+class NewStringAddStub V8_FINAL : public HydrogenCodeStub {
+ public:
+  NewStringAddStub(StringAddFlags flags, PretenureFlag pretenure_flag)
+      : bit_field_(StringAddFlagsBits::encode(flags) |
+                   PretenureFlagBits::encode(pretenure_flag)) {}
+
+  StringAddFlags flags() const {
+    return StringAddFlagsBits::decode(bit_field_);
+  }
+
+  PretenureFlag pretenure_flag() const {
+    return PretenureFlagBits::decode(bit_field_);
+  }
+
+  virtual Handle<Code> GenerateCode(Isolate* isolate) V8_OVERRIDE;
+
+  virtual void InitializeInterfaceDescriptor(
+      Isolate* isolate,
+      CodeStubInterfaceDescriptor* descriptor) V8_OVERRIDE;
+
+  static void InstallDescriptors(Isolate* isolate);
+
+  // Parameters accessed via CodeStubGraphBuilder::GetParameter()
+  static const int kLeft = 0;
+  static const int kRight = 1;
+
+ private:
+  class StringAddFlagsBits: public BitField<StringAddFlags, 0, 2> {};
+  class PretenureFlagBits: public BitField<PretenureFlag, 2, 1> {};
+  uint32_t bit_field_;
+
+  virtual Major MajorKey() V8_OVERRIDE { return NewStringAdd; }
+  virtual int NotMissMinorKey() V8_OVERRIDE { return bit_field_; }
+
+  virtual void PrintBaseName(StringStream* stream) V8_OVERRIDE;
+
+  DISALLOW_COPY_AND_ASSIGN(NewStringAddStub);
+};
+
+
 class ICCompareStub: public PlatformCodeStub {
  public:
   ICCompareStub(Token::Value op,
diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc
index 4f2cd03..ef4e39e 100644
--- a/src/deoptimizer.cc
+++ b/src/deoptimizer.cc
@@ -1586,15 +1586,34 @@
   }
 
   // Copy the register parameters to the failure frame.
+  int arguments_length_offset = -1;
   for (int i = 0; i < descriptor->register_param_count_; ++i) {
     output_frame_offset -= kPointerSize;
     DoTranslateCommand(iterator, 0, output_frame_offset);
+
+    if (!arg_count_known && descriptor->IsParameterCountRegister(i)) {
+      arguments_length_offset = output_frame_offset;
+    }
   }
 
+  ASSERT(0 == output_frame_offset);
+
   if (!arg_count_known) {
-    DoTranslateCommand(iterator, 0, length_frame_offset,
-                       TRANSLATED_VALUE_IS_NATIVE);
-    caller_arg_count = output_frame->GetFrameSlot(length_frame_offset);
+    ASSERT(arguments_length_offset >= 0);
+    // We know it's a smi because 1) the code stub guarantees the stack
+    // parameter count is in smi range, and 2) the DoTranslateCommand in the
+    // parameter loop above translated that to a tagged value.
+    Smi* smi_caller_arg_count = reinterpret_cast<Smi*>(
+        output_frame->GetFrameSlot(arguments_length_offset));
+    caller_arg_count = smi_caller_arg_count->value();
+    output_frame->SetFrameSlot(length_frame_offset, caller_arg_count);
+    if (trace_scope_ != NULL) {
+      PrintF(trace_scope_->file(),
+             "    0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
+             V8PRIxPTR " ; args.length\n",
+             top_address + length_frame_offset, length_frame_offset,
+             caller_arg_count);
+    }
     value = frame_ptr + StandardFrameConstants::kCallerSPOffset +
         (caller_arg_count - 1) * kPointerSize;
     output_frame->SetFrameSlot(args_arguments_offset, value);
@@ -1602,12 +1621,11 @@
       PrintF(trace_scope_->file(),
              "    0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
              V8PRIxPTR " ; args.arguments\n",
-             top_address + args_arguments_offset, args_arguments_offset, value);
+             top_address + args_arguments_offset, args_arguments_offset,
+             value);
     }
   }
 
-  ASSERT(0 == output_frame_offset);
-
   // Copy the double registers from the input into the output frame.
   CopyDoubleRegisters(output_frame);
 
@@ -1874,10 +1892,8 @@
 #endif
 
 
-static const char* TraceValueType(bool is_smi, bool is_native = false) {
-  if (is_native) {
-    return "native";
-  } else if (is_smi) {
+static const char* TraceValueType(bool is_smi) {
+  if (is_smi) {
     return "smi";
   }
 
@@ -2146,13 +2162,11 @@
 
 
 void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
-    int frame_index,
-    unsigned output_offset,
-    DeoptimizerTranslatedValueType value_type) {
+                                     int frame_index,
+                                     unsigned output_offset) {
   disasm::NameConverter converter;
   // A GC-safe temporary placeholder that we can put in the output frame.
   const intptr_t kPlaceholder = reinterpret_cast<intptr_t>(Smi::FromInt(0));
-  bool is_native = value_type == TRANSLATED_VALUE_IS_NATIVE;
 
   Translation::Opcode opcode =
       static_cast<Translation::Opcode>(iterator->Next());
@@ -2190,8 +2204,7 @@
     case Translation::INT32_REGISTER: {
       int input_reg = iterator->Next();
       intptr_t value = input_->GetRegister(input_reg);
-      bool is_smi = (value_type == TRANSLATED_VALUE_IS_TAGGED) &&
-          Smi::IsValid(value);
+      bool is_smi = Smi::IsValid(value);
       if (trace_scope_ != NULL) {
         PrintF(
             trace_scope_->file(),
@@ -2200,18 +2213,15 @@
             output_offset,
             value,
             converter.NameOfCPURegister(input_reg),
-            TraceValueType(is_smi, is_native));
+            TraceValueType(is_smi));
       }
       if (is_smi) {
         intptr_t tagged_value =
             reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
         output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
-      } else if (value_type == TRANSLATED_VALUE_IS_NATIVE) {
-        output_[frame_index]->SetFrameSlot(output_offset, value);
       } else {
         // We save the untagged value on the side and store a GC-safe
         // temporary placeholder in the frame.
-        ASSERT(value_type == TRANSLATED_VALUE_IS_TAGGED);
         AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
                        static_cast<double>(static_cast<int32_t>(value)));
         output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
@@ -2222,8 +2232,7 @@
     case Translation::UINT32_REGISTER: {
       int input_reg = iterator->Next();
       uintptr_t value = static_cast<uintptr_t>(input_->GetRegister(input_reg));
-      bool is_smi = (value_type == TRANSLATED_VALUE_IS_TAGGED) &&
-          (value <= static_cast<uintptr_t>(Smi::kMaxValue));
+      bool is_smi = value <= static_cast<uintptr_t>(Smi::kMaxValue);
       if (trace_scope_ != NULL) {
         PrintF(
             trace_scope_->file(),
@@ -2233,18 +2242,15 @@
             output_offset,
             value,
             converter.NameOfCPURegister(input_reg),
-            TraceValueType(is_smi, is_native));
+            TraceValueType(is_smi));
       }
       if (is_smi) {
         intptr_t tagged_value =
             reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
         output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
-      } else if (value_type == TRANSLATED_VALUE_IS_NATIVE) {
-        output_[frame_index]->SetFrameSlot(output_offset, value);
       } else {
         // We save the untagged value on the side and store a GC-safe
         // temporary placeholder in the frame.
-        ASSERT(value_type == TRANSLATED_VALUE_IS_TAGGED);
         AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
                        static_cast<double>(static_cast<uint32_t>(value)));
         output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
@@ -2295,8 +2301,7 @@
       int input_slot_index = iterator->Next();
       unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
       intptr_t value = input_->GetFrameSlot(input_offset);
-      bool is_smi = (value_type == TRANSLATED_VALUE_IS_TAGGED) &&
-          Smi::IsValid(value);
+      bool is_smi = Smi::IsValid(value);
       if (trace_scope_ != NULL) {
         PrintF(trace_scope_->file(),
                "    0x%08" V8PRIxPTR ": ",
@@ -2306,18 +2311,15 @@
                output_offset,
                value,
                input_offset,
-               TraceValueType(is_smi, is_native));
+               TraceValueType(is_smi));
       }
       if (is_smi) {
         intptr_t tagged_value =
             reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
         output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
-      } else if (value_type == TRANSLATED_VALUE_IS_NATIVE) {
-        output_[frame_index]->SetFrameSlot(output_offset, value);
       } else {
         // We save the untagged value on the side and store a GC-safe
         // temporary placeholder in the frame.
-        ASSERT(value_type == TRANSLATED_VALUE_IS_TAGGED);
         AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
                        static_cast<double>(static_cast<int32_t>(value)));
         output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
@@ -2330,8 +2332,7 @@
       unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
       uintptr_t value =
           static_cast<uintptr_t>(input_->GetFrameSlot(input_offset));
-      bool is_smi = (value_type == TRANSLATED_VALUE_IS_TAGGED) &&
-          (value <= static_cast<uintptr_t>(Smi::kMaxValue));
+      bool is_smi = value <= static_cast<uintptr_t>(Smi::kMaxValue);
       if (trace_scope_ != NULL) {
         PrintF(trace_scope_->file(),
                "    0x%08" V8PRIxPTR ": ",
@@ -2341,18 +2342,15 @@
                output_offset,
                value,
                input_offset,
-               TraceValueType(is_smi, is_native));
+               TraceValueType(is_smi));
       }
       if (is_smi) {
         intptr_t tagged_value =
             reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
         output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
-      } else if (value_type == TRANSLATED_VALUE_IS_NATIVE) {
-        output_[frame_index]->SetFrameSlot(output_offset, value);
       } else {
         // We save the untagged value on the side and store a GC-safe
         // temporary placeholder in the frame.
-        ASSERT(value_type == TRANSLATED_VALUE_IS_TAGGED);
         AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
                        static_cast<double>(static_cast<uint32_t>(value)));
         output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
diff --git a/src/deoptimizer.h b/src/deoptimizer.h
index f5530a8..52e4e24 100644
--- a/src/deoptimizer.h
+++ b/src/deoptimizer.h
@@ -333,15 +333,9 @@
                          int object_index,
                          int field_index);
 
-  enum DeoptimizerTranslatedValueType {
-    TRANSLATED_VALUE_IS_NATIVE,
-    TRANSLATED_VALUE_IS_TAGGED
-  };
-
   void DoTranslateCommand(TranslationIterator* iterator,
-      int frame_index,
-      unsigned output_offset,
-      DeoptimizerTranslatedValueType value_type = TRANSLATED_VALUE_IS_TAGGED);
+                          int frame_index,
+                          unsigned output_offset);
 
   unsigned ComputeInputFrameSize() const;
   unsigned ComputeFixedSize(JSFunction* function) const;
diff --git a/src/factory.cc b/src/factory.cc
index da85b12..6da9a2e 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -365,6 +365,14 @@
 }
 
 
+Handle<Symbol> Factory::NewPrivateSymbol() {
+  CALL_HEAP_FUNCTION(
+      isolate(),
+      isolate()->heap()->AllocatePrivateSymbol(),
+      Symbol);
+}
+
+
 Handle<Context> Factory::NewNativeContext() {
   CALL_HEAP_FUNCTION(
       isolate(),
diff --git a/src/factory.h b/src/factory.h
index 2b4ae7b..663f56f 100644
--- a/src/factory.h
+++ b/src/factory.h
@@ -186,6 +186,7 @@
 
   // Create a symbol.
   Handle<Symbol> NewSymbol();
+  Handle<Symbol> NewPrivateSymbol();
 
   // Create a global (but otherwise uninitialized) context.
   Handle<Context> NewNativeContext();
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index f0444d1..1781f7f 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -338,6 +338,8 @@
             "do not emit check maps for constant values that have a leaf map, "
             "deoptimize the optimized code if the layout of the maps changes.")
 
+DEFINE_bool(new_string_add, false, "enable new string addition")
+
 // Experimental profiler changes.
 DEFINE_bool(experimental_profiler, true, "enable all profiler experiments")
 DEFINE_bool(watch_ic_patching, false, "profiler considers IC stability")
diff --git a/src/heap.cc b/src/heap.cc
index 2ba3919..b5d03bc 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -3311,11 +3311,13 @@
   { MaybeObject* maybe_obj = AllocateSymbol();
     if (!maybe_obj->ToObject(&obj)) return false;
   }
+  Symbol::cast(obj)->set_is_private(true);
   set_frozen_symbol(Symbol::cast(obj));
 
   { MaybeObject* maybe_obj = AllocateSymbol();
     if (!maybe_obj->ToObject(&obj)) return false;
   }
+  Symbol::cast(obj)->set_is_private(true);
   set_elements_transition_symbol(Symbol::cast(obj));
 
   { MaybeObject* maybe_obj = SeededNumberDictionary::Allocate(this, 0, TENURED);
@@ -3327,6 +3329,7 @@
   { MaybeObject* maybe_obj = AllocateSymbol();
     if (!maybe_obj->ToObject(&obj)) return false;
   }
+  Symbol::cast(obj)->set_is_private(true);
   set_observed_symbol(Symbol::cast(obj));
 
   // Handling of script id generation is in Factory::NewScript.
@@ -5516,12 +5519,22 @@
   Symbol::cast(result)->set_hash_field(
       Name::kIsNotArrayIndexMask | (hash << Name::kHashShift));
   Symbol::cast(result)->set_name(undefined_value());
+  Symbol::cast(result)->set_flags(Smi::FromInt(0));
 
-  ASSERT(result->IsSymbol());
+  ASSERT(!Symbol::cast(result)->is_private());
   return result;
 }
 
 
+MaybeObject* Heap::AllocatePrivateSymbol() {
+  MaybeObject* maybe = AllocateSymbol();
+  Symbol* symbol;
+  if (!maybe->To(&symbol)) return maybe;
+  symbol->set_is_private(true);
+  return symbol;
+}
+
+
 MaybeObject* Heap::AllocateNativeContext() {
   Object* result;
   { MaybeObject* maybe_result =
diff --git a/src/heap.h b/src/heap.h
index eea94f8..a0c85e5 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -881,6 +881,7 @@
   // failed.
   // Please note this does not perform a garbage collection.
   MUST_USE_RESULT MaybeObject* AllocateSymbol();
+  MUST_USE_RESULT MaybeObject* AllocatePrivateSymbol();
 
   // Allocate a tenured AllocationSite. It's payload is null
   MUST_USE_RESULT MaybeObject* AllocateAllocationSite();
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc
index 79962db..39d5958 100644
--- a/src/hydrogen-instructions.cc
+++ b/src/hydrogen-instructions.cc
@@ -2944,6 +2944,24 @@
 }
 
 
+bool HCompareMinusZeroAndBranch::KnownSuccessorBlock(HBasicBlock** block) {
+  if (value()->representation().IsSmiOrInteger32()) {
+    // A Smi or Integer32 cannot contain minus zero.
+    *block = SecondSuccessor();
+    return true;
+  }
+  *block = NULL;
+  return false;
+}
+
+
+void HCompareMinusZeroAndBranch::InferRepresentation(
+    HInferRepresentationPhase* h_infer) {
+  ChangeRepresentation(value()->representation());
+}
+
+
+
 void HGoto::PrintDataTo(StringStream* stream) {
   stream->Add("B%d", SuccessorAt(0)->block_id());
 }
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index b9c0ca9..dd7781b 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -100,6 +100,7 @@
   V(CompareNumericAndBranch)                   \
   V(CompareHoleAndBranch)                      \
   V(CompareGeneric)                            \
+  V(CompareMinusZeroAndBranch)                 \
   V(CompareObjectEqAndBranch)                  \
   V(CompareMap)                                \
   V(Constant)                                  \
@@ -4165,6 +4166,28 @@
 };
 
 
+class HCompareMinusZeroAndBranch V8_FINAL : public HUnaryControlInstruction {
+ public:
+  DECLARE_INSTRUCTION_FACTORY_P1(HCompareMinusZeroAndBranch, HValue*);
+
+  virtual void InferRepresentation(
+      HInferRepresentationPhase* h_infer) V8_OVERRIDE;
+
+  virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
+    return representation();
+  }
+
+  virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE;
+
+  DECLARE_CONCRETE_INSTRUCTION(CompareMinusZeroAndBranch)
+
+ private:
+  explicit HCompareMinusZeroAndBranch(HValue* value)
+      : HUnaryControlInstruction(value, NULL, NULL) {
+  }
+};
+
+
 class HCompareObjectEqAndBranch : public HTemplateControlInstruction<2, 2> {
  public:
   HCompareObjectEqAndBranch(HValue* left,
@@ -5808,6 +5831,12 @@
         FLAG_track_fields ? Representation::Smi() : Representation::Tagged());
   }
 
+  static HObjectAccess ForStringHashField() {
+    return HObjectAccess(kInobject,
+                         String::kHashFieldOffset,
+                         Representation::Integer32());
+  }
+
   static HObjectAccess ForStringLength() {
     STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
     return HObjectAccess(
@@ -5816,6 +5845,14 @@
         FLAG_track_fields ? Representation::Smi() : Representation::Tagged());
   }
 
+  static HObjectAccess ForConsStringFirst() {
+    return HObjectAccess(kInobject, ConsString::kFirstOffset);
+  }
+
+  static HObjectAccess ForConsStringSecond() {
+    return HObjectAccess(kInobject, ConsString::kSecondOffset);
+  }
+
   static HObjectAccess ForPropertiesPointer() {
     return HObjectAccess(kInobject, JSObject::kPropertiesOffset);
   }
@@ -5863,6 +5900,12 @@
                          Representation::UInteger8());
   }
 
+  static HObjectAccess ForMapInstanceType() {
+    return HObjectAccess(kInobject,
+                         Map::kInstanceTypeOffset,
+                         Representation::UInteger8());
+  }
+
   static HObjectAccess ForPropertyCellValue() {
     return HObjectAccess(kInobject, PropertyCell::kValueOffset);
   }
diff --git a/src/hydrogen-minus-zero.cc b/src/hydrogen-minus-zero.cc
index 28ae6eb..316e0f5 100644
--- a/src/hydrogen-minus-zero.cc
+++ b/src/hydrogen-minus-zero.cc
@@ -49,6 +49,14 @@
           PropagateMinusZeroChecks(change->value());
           visited_.Clear();
         }
+      } else if (current->IsCompareMinusZeroAndBranch()) {
+        HCompareMinusZeroAndBranch* check =
+            HCompareMinusZeroAndBranch::cast(current);
+        if (check->value()->representation().IsSmiOrInteger32()) {
+          ASSERT(visited_.IsEmpty());
+          PropagateMinusZeroChecks(check->value());
+          visited_.Clear();
+        }
       }
     }
   }
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index 147563e..7c42a3b 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -1469,6 +1469,342 @@
 }
 
 
+HValue* HGraphBuilder::BuildSeqStringSizeFor(HValue* length,
+                                             String::Encoding encoding) {
+  STATIC_ASSERT((SeqString::kHeaderSize & kObjectAlignmentMask) == 0);
+  HValue* size = length;
+  if (encoding == String::TWO_BYTE_ENCODING) {
+    size = Add<HShl>(length, graph()->GetConstant1());
+    size->ClearFlag(HValue::kCanOverflow);
+    size->SetFlag(HValue::kUint32);
+  }
+  size = Add<HAdd>(size, Add<HConstant>(static_cast<int32_t>(
+              SeqString::kHeaderSize + kObjectAlignmentMask)));
+  size->ClearFlag(HValue::kCanOverflow);
+  size = Add<HBitwise>(
+      Token::BIT_AND, size, Add<HConstant>(static_cast<int32_t>(
+              ~kObjectAlignmentMask)));
+  return size;
+}
+
+
+void HGraphBuilder::BuildCopySeqStringChars(HValue* src,
+                                            HValue* src_offset,
+                                            String::Encoding src_encoding,
+                                            HValue* dst,
+                                            HValue* dst_offset,
+                                            String::Encoding dst_encoding,
+                                            HValue* length) {
+  ASSERT(dst_encoding != String::ONE_BYTE_ENCODING ||
+         src_encoding == String::ONE_BYTE_ENCODING);
+  LoopBuilder loop(this, context(), LoopBuilder::kPostIncrement);
+  HValue* index = loop.BeginBody(graph()->GetConstant0(), length, Token::LT);
+  {
+    HValue* src_index = Add<HAdd>(src_offset, index);
+    HValue* value = Add<HSeqStringGetChar>(src_encoding, src, src_index);
+    HValue* dst_index = Add<HAdd>(dst_offset, index);
+    Add<HSeqStringSetChar>(dst_encoding, dst, dst_index, value);
+  }
+  loop.EndBody();
+}
+
+
+HValue* HGraphBuilder::BuildUncheckedStringAdd(HValue* left,
+                                               HValue* right,
+                                               PretenureFlag pretenure_flag) {
+  // Determine the string lengths.
+  HValue* left_length = Add<HLoadNamedField>(
+      left, HObjectAccess::ForStringLength());
+  HValue* right_length = Add<HLoadNamedField>(
+      right, HObjectAccess::ForStringLength());
+
+  // Check if we concatenated the strings here, or if we have to resort to the
+  // runtime function.
+  HIfContinuation handled(graph()->CreateBasicBlock(),
+                          graph()->CreateBasicBlock());
+
+  // Check if both parameters do not exceed half the max string length, because
+  // exceptionally long strings should be handled in the runtime. Unfortunately
+  // we cannot actually check whether the combined length of both strings
+  // exceeds String::kMaxLength (because of unclear results from the
+  // representation inference phase), so we use a pessimistic approach here
+  // instead, checking that the length of either substring does not exceed half
+  // of String::kMaxLength.
+  HConstant* max_length = Add<HConstant>(String::kMaxLength / 2);
+  IfBuilder if_nooverflow(this);
+  if_nooverflow.If<HCompareNumericAndBranch>(
+      left_length, max_length, Token::LTE);
+  if_nooverflow.AndIf<HCompareNumericAndBranch>(
+      right_length, max_length, Token::LTE);
+  if_nooverflow.Then();
+  {
+    // Determine the string instance types.
+    HLoadNamedField* left_instance_type = Add<HLoadNamedField>(
+        Add<HLoadNamedField>(left, HObjectAccess::ForMap()),
+        HObjectAccess::ForMapInstanceType());
+    HLoadNamedField* right_instance_type = Add<HLoadNamedField>(
+        Add<HLoadNamedField>(right, HObjectAccess::ForMap()),
+        HObjectAccess::ForMapInstanceType());
+
+    // Compute difference of instance types.
+    HValue* xored_instance_types = Add<HBitwise>(
+        Token::BIT_XOR, left_instance_type, right_instance_type);
+
+    // Compute the length of the resulting string.
+    HValue* length = Add<HAdd>(left_length, right_length);
+
+    // Check if we should create a cons string.
+    IfBuilder if_createcons(this);
+    if_createcons.If<HCompareNumericAndBranch>(
+        length, Add<HConstant>(ConsString::kMinLength), Token::GTE);
+    if_createcons.Then();
+    {
+      // Allocate the cons string object. HAllocate does not care whether we
+      // pass CONS_STRING_TYPE or CONS_ASCII_STRING_TYPE here, so we just use
+      // CONS_STRING_TYPE here. Below we decide whether the cons string is
+      // one-byte or two-byte and set the appropriate map.
+      HAllocate* string = Add<HAllocate>(Add<HConstant>(ConsString::kSize),
+                                         HType::String(), pretenure_flag,
+                                         CONS_STRING_TYPE);
+
+      // Compute the intersection of instance types.
+      HValue* anded_instance_types = Add<HBitwise>(
+          Token::BIT_AND, left_instance_type, right_instance_type);
+
+      // We create a one-byte cons string if
+      // 1. both strings are one-byte, or
+      // 2. at least one of the strings is two-byte, but happens to contain only
+      //    one-byte characters.
+      // To do this, we check
+      // 1. if both strings are one-byte, or if the one-byte data hint is set in
+      //    both strings, or
+      // 2. if one of the strings has the one-byte data hint set and the other
+      //    string is one-byte.
+      IfBuilder if_onebyte(this);
+      STATIC_ASSERT(kOneByteStringTag != 0);
+      STATIC_ASSERT(kOneByteDataHintMask != 0);
+      if_onebyte.If<HCompareNumericAndBranch>(
+          Add<HBitwise>(
+              Token::BIT_AND, anded_instance_types,
+              Add<HConstant>(static_cast<int32_t>(
+                      kStringEncodingMask | kOneByteDataHintMask))),
+          graph()->GetConstant0(), Token::NE);
+      if_onebyte.Or();
+      STATIC_ASSERT(kOneByteStringTag != 0 &&
+                    kOneByteDataHintTag != 0 &&
+                    kOneByteDataHintTag != kOneByteStringTag);
+      if_onebyte.If<HCompareNumericAndBranch>(
+          Add<HBitwise>(
+              Token::BIT_AND, xored_instance_types,
+              Add<HConstant>(static_cast<int32_t>(
+                      kOneByteStringTag | kOneByteDataHintTag))),
+          Add<HConstant>(static_cast<int32_t>(
+                  kOneByteStringTag | kOneByteDataHintTag)), Token::EQ);
+      if_onebyte.Then();
+      {
+        // We can safely skip the write barrier for storing the map here.
+        Handle<Map> map = isolate()->factory()->cons_ascii_string_map();
+        AddStoreMapConstantNoWriteBarrier(string, map);
+      }
+      if_onebyte.Else();
+      {
+        // We can safely skip the write barrier for storing the map here.
+        Handle<Map> map = isolate()->factory()->cons_string_map();
+        AddStoreMapConstantNoWriteBarrier(string, map);
+      }
+      if_onebyte.End();
+
+      // Initialize the cons string fields.
+      Add<HStoreNamedField>(string, HObjectAccess::ForStringHashField(),
+                            Add<HConstant>(String::kEmptyHashField));
+      Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(), length);
+      Add<HStoreNamedField>(string, HObjectAccess::ForConsStringFirst(), left);
+      Add<HStoreNamedField>(string, HObjectAccess::ForConsStringSecond(),
+                            right);
+
+      // Cons string is result.
+      Push(string);
+    }
+    if_createcons.Else();
+    {
+      // Compute union of instance types.
+      HValue* ored_instance_types = Add<HBitwise>(
+          Token::BIT_OR, left_instance_type, right_instance_type);
+
+      // Check if both strings have the same encoding and both are
+      // sequential.
+      IfBuilder if_sameencodingandsequential(this);
+      if_sameencodingandsequential.If<HCompareNumericAndBranch>(
+          Add<HBitwise>(
+              Token::BIT_AND, xored_instance_types,
+              Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))),
+          graph()->GetConstant0(), Token::EQ);
+      if_sameencodingandsequential.And();
+      STATIC_ASSERT(kSeqStringTag == 0);
+      if_sameencodingandsequential.If<HCompareNumericAndBranch>(
+          Add<HBitwise>(
+              Token::BIT_AND, ored_instance_types,
+              Add<HConstant>(static_cast<int32_t>(kStringRepresentationMask))),
+          graph()->GetConstant0(), Token::EQ);
+      if_sameencodingandsequential.Then();
+      {
+        // Check if the result is a one-byte string.
+        IfBuilder if_onebyte(this);
+        STATIC_ASSERT(kOneByteStringTag != 0);
+        if_onebyte.If<HCompareNumericAndBranch>(
+            Add<HBitwise>(
+                Token::BIT_AND, ored_instance_types,
+                Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))),
+            graph()->GetConstant0(), Token::NE);
+        if_onebyte.Then();
+        {
+          // Calculate the number of bytes needed for the characters in the
+          // string while observing object alignment.
+          HValue* size = BuildSeqStringSizeFor(
+              length, String::ONE_BYTE_ENCODING);
+
+          // Allocate the ASCII string object.
+          Handle<Map> map = isolate()->factory()->ascii_string_map();
+          HAllocate* string = Add<HAllocate>(size, HType::String(),
+                                             pretenure_flag, ASCII_STRING_TYPE);
+          string->set_known_initial_map(map);
+
+          // We can safely skip the write barrier for storing map here.
+          AddStoreMapConstantNoWriteBarrier(string, map);
+
+          // Copy bytes from the left string.
+          BuildCopySeqStringChars(
+              left, graph()->GetConstant0(), String::ONE_BYTE_ENCODING,
+              string, graph()->GetConstant0(), String::ONE_BYTE_ENCODING,
+              left_length);
+
+          // Copy bytes from the right string.
+          BuildCopySeqStringChars(
+              right, graph()->GetConstant0(), String::ONE_BYTE_ENCODING,
+              string, left_length, String::ONE_BYTE_ENCODING,
+              right_length);
+
+          // Return the string.
+          Push(string);
+        }
+        if_onebyte.Else();
+        {
+          // Calculate the number of bytes needed for the characters in the
+          // string while observing object alignment.
+          HValue* size = BuildSeqStringSizeFor(
+              length, String::TWO_BYTE_ENCODING);
+
+          // Allocate the two-byte string object.
+          Handle<Map> map = isolate()->factory()->string_map();
+          HAllocate* string = Add<HAllocate>(size, HType::String(),
+                                             pretenure_flag, STRING_TYPE);
+          string->set_known_initial_map(map);
+
+          // We can safely skip the write barrier for storing map here.
+          AddStoreMapConstantNoWriteBarrier(string, map);
+
+          // Copy bytes from the left string.
+          BuildCopySeqStringChars(
+              left, graph()->GetConstant0(), String::TWO_BYTE_ENCODING,
+              string, graph()->GetConstant0(), String::TWO_BYTE_ENCODING,
+              left_length);
+
+          // Copy bytes from the right string.
+          BuildCopySeqStringChars(
+              right, graph()->GetConstant0(), String::TWO_BYTE_ENCODING,
+              string, left_length, String::TWO_BYTE_ENCODING,
+              right_length);
+
+          // Return the string.
+          Push(string);
+        }
+        if_onebyte.End();
+
+        // Initialize the (common) string fields.
+        HValue* string = Pop();
+        Add<HStoreNamedField>(string, HObjectAccess::ForStringHashField(),
+                              Add<HConstant>(String::kEmptyHashField));
+        Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(),
+                              length);
+        Push(string);
+      }
+      if_sameencodingandsequential.JoinContinuation(&handled);
+    }
+    if_createcons.JoinContinuation(&handled);
+  }
+  if_nooverflow.JoinContinuation(&handled);
+
+  // Check if the strings were concatenated successfully, otherwise fallback to
+  // add the strings in the runtime.
+  IfBuilder if_handled(this, &handled);
+  if_handled.Then();
+  {
+    // Count the native string addition.
+    AddIncrementCounter(isolate()->counters()->string_add_native());
+  }
+  if_handled.Else();
+  {
+    // Fallback to the runtime to add the two strings.
+    Add<HPushArgument>(left);
+    Add<HPushArgument>(right);
+    Push(Add<HCallRuntime>(isolate()->factory()->empty_string(),
+                           Runtime::FunctionForId(Runtime::kStringAdd),
+                           2));
+  }
+  if_handled.End();
+
+  return Pop();
+}
+
+
+HValue* HGraphBuilder::BuildStringAdd(HValue* left,
+                                      HValue* right,
+                                      PretenureFlag pretenure_flag) {
+  // Determine the string lengths.
+  HValue* left_length = Add<HLoadNamedField>(
+      left, HObjectAccess::ForStringLength());
+  HValue* right_length = Add<HLoadNamedField>(
+      right, HObjectAccess::ForStringLength());
+
+  // Check if left string is empty.
+  IfBuilder if_leftisempty(this);
+  if_leftisempty.If<HCompareNumericAndBranch>(
+      left_length, graph()->GetConstant0(), Token::EQ);
+  if_leftisempty.Then();
+  {
+    // Count the native string addition.
+    AddIncrementCounter(isolate()->counters()->string_add_native());
+
+    // Just return the right string.
+    Push(right);
+  }
+  if_leftisempty.Else();
+  {
+    // Check if right string is empty.
+    IfBuilder if_rightisempty(this);
+    if_rightisempty.If<HCompareNumericAndBranch>(
+        right_length, graph()->GetConstant0(), Token::EQ);
+    if_rightisempty.Then();
+    {
+      // Count the native string addition.
+      AddIncrementCounter(isolate()->counters()->string_add_native());
+
+      // Just return the left string.
+      Push(left);
+    }
+    if_rightisempty.Else();
+    {
+      // Concatenate the two non-empty strings.
+      Push(BuildUncheckedStringAdd(left, right, pretenure_flag));
+    }
+    if_rightisempty.End();
+  }
+  if_leftisempty.End();
+
+  return Pop();
+}
+
+
 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
     HValue* checked_object,
     HValue* key,
@@ -6369,6 +6705,11 @@
   Handle<JSFunction> caller = current_info()->closure();
   Handle<SharedFunctionInfo> target_shared(target->shared());
 
+  // Always inline builtins marked for inlining.
+  if (target->IsBuiltin()) {
+    return target_shared->inline_builtin() ? 0 : kNotInlinable;
+  }
+
   // Do a quick check on source code length to avoid parsing large
   // inlining candidates.
   if (target_shared->SourceSize() >
@@ -6378,7 +6719,7 @@
   }
 
   // Target must be inlineable.
-  if (!target->IsInlineable()) {
+  if (!target_shared->IsInlineable()) {
     TraceInline(target, caller, "target not inlineable");
     return kNotInlinable;
   }
@@ -6758,9 +7099,6 @@
     case kMathAbs:
     case kMathSqrt:
     case kMathLog:
-    case kMathSin:
-    case kMathCos:
-    case kMathTan:
       if (expr->arguments()->length() == 1) {
         HValue* argument = Pop();
         Drop(1);  // Receiver.
@@ -6839,9 +7177,6 @@
     case kMathAbs:
     case kMathSqrt:
     case kMathLog:
-    case kMathSin:
-    case kMathCos:
-    case kMathTan:
       if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) {
         AddCheckConstantFunction(expr->holder(), receiver, receiver_map);
         HValue* argument = Pop();
@@ -8778,6 +9113,15 @@
 }
 
 
+void HOptimizedGraphBuilder::GenerateIsMinusZero(CallRuntime* call) {
+  ASSERT(call->arguments()->length() == 1);
+  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
+  HValue* value = Pop();
+  HCompareMinusZeroAndBranch* result = New<HCompareMinusZeroAndBranch>(value);
+  return ast_context()->ReturnControl(result, call->id());
+}
+
+
 void HOptimizedGraphBuilder::GenerateHasCachedArrayIndex(CallRuntime* call) {
   ASSERT(call->arguments()->length() == 1);
   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
@@ -9161,36 +9505,6 @@
 }
 
 
-void HOptimizedGraphBuilder::GenerateMathSin(CallRuntime* call) {
-  ASSERT_EQ(1, call->arguments()->length());
-  CHECK_ALIVE(VisitArgumentList(call->arguments()));
-  HCallStub* result = New<HCallStub>(CodeStub::TranscendentalCache, 1);
-  result->set_transcendental_type(TranscendentalCache::SIN);
-  Drop(1);
-  return ast_context()->ReturnInstruction(result, call->id());
-}
-
-
-void HOptimizedGraphBuilder::GenerateMathCos(CallRuntime* call) {
-  ASSERT_EQ(1, call->arguments()->length());
-  CHECK_ALIVE(VisitArgumentList(call->arguments()));
-  HCallStub* result = New<HCallStub>(CodeStub::TranscendentalCache, 1);
-  result->set_transcendental_type(TranscendentalCache::COS);
-  Drop(1);
-  return ast_context()->ReturnInstruction(result, call->id());
-}
-
-
-void HOptimizedGraphBuilder::GenerateMathTan(CallRuntime* call) {
-  ASSERT_EQ(1, call->arguments()->length());
-  CHECK_ALIVE(VisitArgumentList(call->arguments()));
-  HCallStub* result = New<HCallStub>(CodeStub::TranscendentalCache, 1);
-  result->set_transcendental_type(TranscendentalCache::TAN);
-  Drop(1);
-  return ast_context()->ReturnInstruction(result, call->id());
-}
-
-
 void HOptimizedGraphBuilder::GenerateMathLog(CallRuntime* call) {
   ASSERT_EQ(1, call->arguments()->length());
   CHECK_ALIVE(VisitArgumentList(call->arguments()));
diff --git a/src/hydrogen.h b/src/hydrogen.h
index 8f4878d..b3cb8ff 100644
--- a/src/hydrogen.h
+++ b/src/hydrogen.h
@@ -1276,6 +1276,26 @@
 
   HValue* BuildNumberToString(HValue* object, Handle<Type> type);
 
+  // Computes the size for a sequential string of the given length and encoding.
+  HValue* BuildSeqStringSizeFor(HValue* length,
+                                String::Encoding encoding);
+  // Copies characters from one sequential string to another.
+  void BuildCopySeqStringChars(HValue* src,
+                               HValue* src_offset,
+                               String::Encoding src_encoding,
+                               HValue* dst,
+                               HValue* dst_offset,
+                               String::Encoding dst_encoding,
+                               HValue* length);
+  // Both operands are non-empty strings.
+  HValue* BuildUncheckedStringAdd(HValue* left,
+                                  HValue* right,
+                                  PretenureFlag pretenure_flag);
+  // Both operands are strings.
+  HValue* BuildStringAdd(HValue* left,
+                         HValue* right,
+                         PretenureFlag pretenure_flag);
+
   HInstruction* BuildUncheckedMonomorphicElementAccess(
       HValue* checked_object,
       HValue* key,
@@ -1298,7 +1318,13 @@
   HLoadNamedField* BuildLoadNamedField(HValue* object, HObjectAccess access);
   HInstruction* AddLoadNamedField(HValue* object, HObjectAccess access);
   HInstruction* BuildLoadStringLength(HValue* object, HValue* checked_value);
-  HStoreNamedField* AddStoreMapConstant(HValue* object, Handle<Map>);
+  HStoreNamedField* AddStoreMapConstant(HValue* object, Handle<Map> map);
+  HStoreNamedField* AddStoreMapConstantNoWriteBarrier(HValue* object,
+                                                      Handle<Map> map) {
+    HStoreNamedField* store_map = AddStoreMapConstant(object, map);
+    store_map->SkipWriteBarrier();
+    return store_map;
+  }
   HLoadNamedField* AddLoadElements(HValue* object);
 
   bool MatchRotateRight(HValue* left,
diff --git a/src/i18n.js b/src/i18n.js
index a64c7e6..6b563a0 100644
--- a/src/i18n.js
+++ b/src/i18n.js
@@ -1302,10 +1302,7 @@
  */
 function formatNumber(formatter, value) {
   // Spec treats -0 and +0 as 0.
-  var number = $Number(value);
-  if (number === -0) {
-    number = 0;
-  }
+  var number = $Number(value) + 0;
 
   return %InternalNumberFormat(formatter.formatter, number);
 }
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index 941bb32..adc2d50 100644
--- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc
@@ -168,15 +168,21 @@
   // eax -- number of arguments
   // edi -- function
   // ebx -- type info cell with elements kind
-  static Register registers[] = { edi, ebx };
-  descriptor->register_param_count_ = 2;
+  static Register registers_variable_args[] = { edi, ebx, eax };
+  static Register registers_no_args[] = { edi, ebx };
 
-  if (constant_stack_parameter_count != 0) {
+  if (constant_stack_parameter_count == 0) {
+    descriptor->register_param_count_ = 2;
+    descriptor->register_params_ = registers_no_args;
+  } else {
     // stack param count needs (constructor pointer, and single argument)
+    descriptor->handler_arguments_mode_ = PASS_ARGUMENTS;
     descriptor->stack_parameter_count_ = eax;
+    descriptor->register_param_count_ = 3;
+    descriptor->register_params_ = registers_variable_args;
   }
+
   descriptor->hint_stack_parameter_count_ = constant_stack_parameter_count;
-  descriptor->register_params_ = registers;
   descriptor->function_mode_ = JS_FUNCTION_STUB_MODE;
   descriptor->deoptimization_handler_ =
       Runtime::FunctionForId(Runtime::kArrayConstructor)->entry;
@@ -190,15 +196,21 @@
   // register state
   // eax -- number of arguments
   // edi -- constructor function
-  static Register registers[] = { edi };
-  descriptor->register_param_count_ = 1;
+  static Register registers_variable_args[] = { edi, eax };
+  static Register registers_no_args[] = { edi };
 
-  if (constant_stack_parameter_count != 0) {
+  if (constant_stack_parameter_count == 0) {
+    descriptor->register_param_count_ = 1;
+    descriptor->register_params_ = registers_no_args;
+  } else {
     // stack param count needs (constructor pointer, and single argument)
+    descriptor->handler_arguments_mode_ = PASS_ARGUMENTS;
     descriptor->stack_parameter_count_ = eax;
+    descriptor->register_param_count_ = 2;
+    descriptor->register_params_ = registers_variable_args;
   }
+
   descriptor->hint_stack_parameter_count_ = constant_stack_parameter_count;
-  descriptor->register_params_ = registers;
   descriptor->function_mode_ = JS_FUNCTION_STUB_MODE;
   descriptor->deoptimization_handler_ =
       Runtime::FunctionForId(Runtime::kInternalArrayConstructor)->entry;
@@ -306,6 +318,17 @@
 }
 
 
+void NewStringAddStub::InitializeInterfaceDescriptor(
+    Isolate* isolate,
+    CodeStubInterfaceDescriptor* descriptor) {
+  static Register registers[] = { edx, eax };
+  descriptor->register_param_count_ = 2;
+  descriptor->register_params_ = registers;
+  descriptor->deoptimization_handler_ =
+      Runtime::FunctionForId(Runtime::kStringAdd)->entry;
+}
+
+
 #define __ ACCESS_MASM(masm)
 
 
diff --git a/src/ia32/deoptimizer-ia32.cc b/src/ia32/deoptimizer-ia32.cc
index e339b3a..e043aa4 100644
--- a/src/ia32/deoptimizer-ia32.cc
+++ b/src/ia32/deoptimizer-ia32.cc
@@ -202,7 +202,7 @@
     FrameDescription* output_frame, CodeStubInterfaceDescriptor* descriptor) {
   intptr_t handler =
       reinterpret_cast<intptr_t>(descriptor->deoptimization_handler_);
-  int params = descriptor->environment_length();
+  int params = descriptor->GetHandlerParameterCount();
   output_frame->SetRegister(eax.code(), params);
   output_frame->SetRegister(ebx.code(), handler);
 }
diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc
index b7ddeac..8a51fbc 100644
--- a/src/ia32/full-codegen-ia32.cc
+++ b/src/ia32/full-codegen-ia32.cc
@@ -3052,6 +3052,32 @@
 }
 
 
+void FullCodeGenerator::EmitIsMinusZero(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  ASSERT(args->length() == 1);
+
+  VisitForAccumulatorValue(args->at(0));
+
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false,
+                         &if_true, &if_false, &fall_through);
+
+  Handle<Map> map = masm()->isolate()->factory()->heap_number_map();
+  __ CheckMap(eax, map, if_false, DO_SMI_CHECK);
+  __ cmp(FieldOperand(eax, HeapNumber::kExponentOffset), Immediate(0x80000000));
+  __ j(not_equal, if_false);
+  __ cmp(FieldOperand(eax, HeapNumber::kMantissaOffset), Immediate(0x00000000));
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  Split(equal, if_true, if_false, fall_through);
+
+  context()->Plug(if_true, if_false);
+}
+
+
+
 void FullCodeGenerator::EmitIsArray(CallRuntime* expr) {
   ZoneList<Expression*>* args = expr->arguments();
   ASSERT(args->length() == 1);
@@ -3671,11 +3697,20 @@
   ZoneList<Expression*>* args = expr->arguments();
   ASSERT_EQ(2, args->length());
 
-  VisitForStackValue(args->at(0));
-  VisitForStackValue(args->at(1));
+  if (FLAG_new_string_add) {
+    VisitForStackValue(args->at(0));
+    VisitForAccumulatorValue(args->at(1));
 
-  StringAddStub stub(STRING_ADD_CHECK_BOTH);
-  __ CallStub(&stub);
+    __ pop(edx);
+    NewStringAddStub stub(STRING_ADD_CHECK_BOTH, NOT_TENURED);
+    __ CallStub(&stub);
+  } else {
+    VisitForStackValue(args->at(0));
+    VisitForStackValue(args->at(1));
+
+    StringAddStub stub(STRING_ADD_CHECK_BOTH);
+    __ CallStub(&stub);
+  }
   context()->Plug(eax);
 }
 
@@ -3693,42 +3728,6 @@
 }
 
 
-void FullCodeGenerator::EmitMathSin(CallRuntime* expr) {
-  // Load the argument on the stack and call the stub.
-  TranscendentalCacheStub stub(TranscendentalCache::SIN,
-                               TranscendentalCacheStub::TAGGED);
-  ZoneList<Expression*>* args = expr->arguments();
-  ASSERT(args->length() == 1);
-  VisitForStackValue(args->at(0));
-  __ CallStub(&stub);
-  context()->Plug(eax);
-}
-
-
-void FullCodeGenerator::EmitMathCos(CallRuntime* expr) {
-  // Load the argument on the stack and call the stub.
-  TranscendentalCacheStub stub(TranscendentalCache::COS,
-                               TranscendentalCacheStub::TAGGED);
-  ZoneList<Expression*>* args = expr->arguments();
-  ASSERT(args->length() == 1);
-  VisitForStackValue(args->at(0));
-  __ CallStub(&stub);
-  context()->Plug(eax);
-}
-
-
-void FullCodeGenerator::EmitMathTan(CallRuntime* expr) {
-  // Load the argument on the stack and call the stub.
-  TranscendentalCacheStub stub(TranscendentalCache::TAN,
-                               TranscendentalCacheStub::TAGGED);
-  ZoneList<Expression*>* args = expr->arguments();
-  ASSERT(args->length() == 1);
-  VisitForStackValue(args->at(0));
-  __ CallStub(&stub);
-  context()->Plug(eax);
-}
-
-
 void FullCodeGenerator::EmitMathLog(CallRuntime* expr) {
   // Load the argument on the stack and call the stub.
   TranscendentalCacheStub stub(TranscendentalCache::LOG,
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index 89df802..de52fad 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -2670,6 +2670,35 @@
 }
 
 
+void LCodeGen::DoCompareMinusZeroAndBranch(LCompareMinusZeroAndBranch* instr) {
+  Representation rep = instr->hydrogen()->value()->representation();
+  ASSERT(!rep.IsInteger32());
+  Register scratch = ToRegister(instr->temp());
+
+  if (rep.IsDouble()) {
+    CpuFeatureScope use_sse2(masm(), SSE2);
+    XMMRegister value = ToDoubleRegister(instr->value());
+    XMMRegister xmm_scratch = double_scratch0();
+    __ xorps(xmm_scratch, xmm_scratch);
+    __ ucomisd(xmm_scratch, value);
+    EmitFalseBranch(instr, not_equal);
+    __ movmskpd(scratch, value);
+    __ test(scratch, Immediate(1));
+    EmitBranch(instr, not_zero);
+  } else {
+    Register value = ToRegister(instr->value());
+    Handle<Map> map = masm()->isolate()->factory()->heap_number_map();
+    __ CheckMap(value, map, instr->FalseLabel(chunk()), DO_SMI_CHECK);
+    __ cmp(FieldOperand(value, HeapNumber::kExponentOffset),
+           Immediate(0x80000000));
+    EmitFalseBranch(instr, not_equal);
+    __ cmp(FieldOperand(value, HeapNumber::kMantissaOffset),
+           Immediate(0x00000000));
+    EmitBranch(instr, equal);
+  }
+}
+
+
 Condition LCodeGen::EmitIsObject(Register input,
                                  Register temp1,
                                  Label* is_not_object,
@@ -4551,6 +4580,10 @@
     if (operand_value->IsRegister()) {
       Register value = ToRegister(operand_value);
       __ Store(value, operand, representation);
+    } else if (representation.IsInteger32()) {
+      Immediate immediate = ToImmediate(operand_value, representation);
+      ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
+      __ mov(operand, immediate);
     } else {
       Handle<Object> handle_value = ToHandle(operand_value);
       ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
@@ -4997,10 +5030,18 @@
 
 void LCodeGen::DoStringAdd(LStringAdd* instr) {
   ASSERT(ToRegister(instr->context()).is(esi));
-  EmitPushTaggedOperand(instr->left());
-  EmitPushTaggedOperand(instr->right());
-  StringAddStub stub(instr->hydrogen()->flags());
-  CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
+  if (FLAG_new_string_add) {
+    ASSERT(ToRegister(instr->left()).is(edx));
+    ASSERT(ToRegister(instr->right()).is(eax));
+    NewStringAddStub stub(instr->hydrogen()->flags(),
+                          isolate()->heap()->GetPretenureMode());
+    CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
+  } else {
+    EmitPushTaggedOperand(instr->left());
+    EmitPushTaggedOperand(instr->right());
+    StringAddStub stub(instr->hydrogen()->flags());
+    CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
+  }
 }
 
 
diff --git a/src/ia32/lithium-codegen-ia32.h b/src/ia32/lithium-codegen-ia32.h
index 6c9cde3..514b42e 100644
--- a/src/ia32/lithium-codegen-ia32.h
+++ b/src/ia32/lithium-codegen-ia32.h
@@ -320,6 +320,8 @@
 
   static Condition TokenToCondition(Token::Value op, bool is_unsigned);
   void EmitGoto(int block);
+
+  // EmitBranch expects to be the last instruction of a block.
   template<class InstrType>
   void EmitBranch(InstrType instr, Condition cc);
   template<class InstrType>
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
index 632b065..29b42fe 100644
--- a/src/ia32/lithium-ia32.cc
+++ b/src/ia32/lithium-ia32.cc
@@ -1768,6 +1768,16 @@
 }
 
 
+LInstruction* LChunkBuilder::DoCompareMinusZeroAndBranch(
+    HCompareMinusZeroAndBranch* instr) {
+  LInstruction* goto_instr = CheckElideControlInstruction(instr);
+  if (goto_instr != NULL) return goto_instr;
+  LOperand* value = UseRegister(instr->value());
+  LOperand* scratch = TempRegister();
+  return new(zone()) LCompareMinusZeroAndBranch(value, scratch);
+}
+
+
 LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) {
   ASSERT(instr->value()->representation().IsSmiOrTagged());
   LOperand* temp = TempRegister();
@@ -2485,8 +2495,12 @@
 
 LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) {
   LOperand* context = UseFixed(instr->context(), esi);
-  LOperand* left = UseOrConstantAtStart(instr->left());
-  LOperand* right = UseOrConstantAtStart(instr->right());
+  LOperand* left = FLAG_new_string_add
+      ? UseFixed(instr->left(), edx)
+      : UseOrConstantAtStart(instr->left());
+  LOperand* right = FLAG_new_string_add
+      ? UseFixed(instr->right(), eax)
+      : UseOrConstantAtStart(instr->right());
   LStringAdd* string_add = new(zone()) LStringAdd(context, left, right);
   return MarkAsCall(DefineFixed(string_add, eax), instr);
 }
@@ -2555,7 +2569,7 @@
     CodeStubInterfaceDescriptor* descriptor =
         info()->code_stub()->GetInterfaceDescriptor(info()->isolate());
     int index = static_cast<int>(instr->index());
-    Register reg = DESCRIPTOR_GET_PARAMETER_REGISTER(descriptor, index);
+    Register reg = descriptor->GetParameterRegister(index);
     return DefineFixed(result, reg);
   }
 }
diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h
index 600c40f..b0d031a 100644
--- a/src/ia32/lithium-ia32.h
+++ b/src/ia32/lithium-ia32.h
@@ -74,6 +74,7 @@
   V(ClampTToUint8NoSSE2)                        \
   V(ClassOfTestAndBranch)                       \
   V(ClobberDoubles)                             \
+  V(CompareMinusZeroAndBranch)                  \
   V(CompareNumericAndBranch)                    \
   V(CmpObjectEqAndBranch)                       \
   V(CmpHoleAndBranch)                           \
@@ -900,6 +901,22 @@
 };
 
 
+class LCompareMinusZeroAndBranch V8_FINAL : public LControlInstruction<1, 1> {
+ public:
+  LCompareMinusZeroAndBranch(LOperand* value, LOperand* temp) {
+    inputs_[0] = value;
+    temps_[0] = temp;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CompareMinusZeroAndBranch,
+                               "cmp-minus-zero-and-branch")
+  DECLARE_HYDROGEN_ACCESSOR(CompareMinusZeroAndBranch)
+};
+
+
 class LIsObjectAndBranch V8_FINAL : public LControlInstruction<1, 1> {
  public:
   LIsObjectAndBranch(LOperand* value, LOperand* temp) {
diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc
index c673727..1bdd382 100644
--- a/src/ia32/macro-assembler-ia32.cc
+++ b/src/ia32/macro-assembler-ia32.cc
@@ -2010,30 +2010,48 @@
                                Register destination,
                                Register length,
                                Register scratch) {
-  Label loop, done, short_string, short_loop;
-  // Experimentation shows that the short string loop is faster if length < 10.
-  cmp(length, Immediate(10));
-  j(less_equal, &short_string);
-
+  Label short_loop, len4, len8, len12, done, short_string;
   ASSERT(source.is(esi));
   ASSERT(destination.is(edi));
   ASSERT(length.is(ecx));
+  cmp(length, Immediate(4));
+  j(below, &short_string, Label::kNear);
 
   // Because source is 4-byte aligned in our uses of this function,
   // we keep source aligned for the rep_movs call by copying the odd bytes
   // at the end of the ranges.
   mov(scratch, Operand(source, length, times_1, -4));
   mov(Operand(destination, length, times_1, -4), scratch);
+
+  cmp(length, Immediate(8));
+  j(below_equal, &len4, Label::kNear);
+  cmp(length, Immediate(12));
+  j(below_equal, &len8, Label::kNear);
+  cmp(length, Immediate(16));
+  j(below_equal, &len12, Label::kNear);
+
   mov(scratch, ecx);
   shr(ecx, 2);
   rep_movs();
   and_(scratch, Immediate(0x3));
   add(destination, scratch);
-  jmp(&done);
+  jmp(&done, Label::kNear);
+
+  bind(&len12);
+  mov(scratch, Operand(source, 8));
+  mov(Operand(destination, 8), scratch);
+  bind(&len8);
+  mov(scratch, Operand(source, 4));
+  mov(Operand(destination, 4), scratch);
+  bind(&len4);
+  mov(scratch, Operand(source, 0));
+  mov(Operand(destination, 0), scratch);
+  add(destination, length);
+  jmp(&done, Label::kNear);
 
   bind(&short_string);
   test(length, length);
-  j(zero, &done);
+  j(zero, &done, Label::kNear);
 
   bind(&short_loop);
   mov_b(scratch, Operand(source, 0));
diff --git a/src/isolate.cc b/src/isolate.cc
index 0e764bf..740cce0 100644
--- a/src/isolate.cc
+++ b/src/isolate.cc
@@ -2328,6 +2328,7 @@
     InternalArrayConstructorStubBase::InstallDescriptors(this);
     FastNewClosureStub::InstallDescriptors(this);
     NumberToStringStub::InstallDescriptors(this);
+    NewStringAddStub::InstallDescriptors(this);
   }
 
   if (FLAG_sweeper_threads > 0) {
diff --git a/src/macros.py b/src/macros.py
index 1785d44..7bad23b 100644
--- a/src/macros.py
+++ b/src/macros.py
@@ -157,6 +157,13 @@
 macro TO_OBJECT_INLINE(arg) = (IS_SPEC_OBJECT(%IS_VAR(arg)) ? arg : ToObject(arg));
 macro JSON_NUMBER_TO_STRING(arg) = ((%_IsSmi(%IS_VAR(arg)) || arg - arg == 0) ? %_NumberToString(arg) : "null");
 
+# Private names.
+macro NEW_PRIVATE(name) = (%CreatePrivateSymbol(name));
+macro HAS_PRIVATE(obj, sym) = (sym in obj);
+macro GET_PRIVATE(obj, sym) = (obj[sym]);
+macro SET_PRIVATE(obj, sym, val) = (obj[sym] = val);
+macro DELETE_PRIVATE(obj, sym) = (delete obj[sym]);
+
 # Constants.  The compiler constant folds them.
 const NAN = $NaN;
 const INFINITY = (1/0);
diff --git a/src/math.js b/src/math.js
index efab63a..385b3c2 100644
--- a/src/math.js
+++ b/src/math.js
@@ -79,7 +79,7 @@
 
 // ECMA 262 - 15.8.2.7
 function MathCos(x) {
-  return %_MathCos(TO_NUMBER_INLINE(x));
+  return MathCosImpl(x);
 }
 
 // ECMA 262 - 15.8.2.8
@@ -117,9 +117,8 @@
     if (arg2 > arg1) return arg2;
     if (arg1 > arg2) return arg1;
     if (arg1 == arg2) {
-      // Make sure -0 is considered less than +0.  -0 is never a Smi, +0 can be
-      // a Smi or a heap number.
-      return (arg1 == 0 && !%_IsSmi(arg1) && 1 / arg1 < 0) ? arg2 : arg1;
+      // Make sure -0 is considered less than +0.
+      return (arg1 === 0 && %_IsMinusZero(arg1)) ? arg2 : arg1;
     }
     // All comparisons failed, one of the arguments must be NaN.
     return NAN;
@@ -128,10 +127,8 @@
   for (var i = 0; i < length; i++) {
     var n = %_Arguments(i);
     if (!IS_NUMBER(n)) n = NonNumberToNumber(n);
-    // Make sure +0 is considered greater than -0.  -0 is never a Smi, +0 can be
-    // a Smi or heap number.
-    if (NUMBER_IS_NAN(n) || n > r ||
-        (r == 0 && n == 0 && !%_IsSmi(r) && 1 / r < 0)) {
+    // Make sure +0 is considered greater than -0.
+    if (NUMBER_IS_NAN(n) || n > r || (r === 0 && n === 0 && %_IsMinusZero(r))) {
       r = n;
     }
   }
@@ -147,9 +144,8 @@
     if (arg2 > arg1) return arg1;
     if (arg1 > arg2) return arg2;
     if (arg1 == arg2) {
-      // Make sure -0 is considered less than +0.  -0 is never a Smi, +0 can be
-      // a Smi or a heap number.
-      return (arg1 == 0 && !%_IsSmi(arg1) && 1 / arg1 < 0) ? arg1 : arg2;
+      // Make sure -0 is considered less than +0.
+      return (arg1 === 0 && %_IsMinusZero(arg1)) ? arg1 : arg2;
     }
     // All comparisons failed, one of the arguments must be NaN.
     return NAN;
@@ -158,10 +154,8 @@
   for (var i = 0; i < length; i++) {
     var n = %_Arguments(i);
     if (!IS_NUMBER(n)) n = NonNumberToNumber(n);
-    // Make sure -0 is considered less than +0.  -0 is never a Smi, +0 can be a
-    // Smi or a heap number.
-    if (NUMBER_IS_NAN(n) || n < r ||
-        (r == 0 && n == 0 && !%_IsSmi(n) && 1 / n < 0)) {
+    // Make sure -0 is considered less than +0.
+    if (NUMBER_IS_NAN(n) || n < r || (r === 0 && n === 0 && %_IsMinusZero(n))) {
       r = n;
     }
   }
@@ -185,7 +179,7 @@
 
 // ECMA 262 - 15.8.2.16
 function MathSin(x) {
-  return %_MathSin(TO_NUMBER_INLINE(x));
+  return MathSinImpl(x);
 }
 
 // ECMA 262 - 15.8.2.17
@@ -195,7 +189,7 @@
 
 // ECMA 262 - 15.8.2.18
 function MathTan(x) {
-  return %_MathTan(TO_NUMBER_INLINE(x));
+  return MathSinImpl(x) / MathCosImpl(x);
 }
 
 // Non-standard extension.
@@ -204,6 +198,92 @@
 }
 
 
+var MathSinImpl = function(x) {
+  InitTrigonometricFunctions();
+  return MathSinImpl(x);
+}
+
+
+var MathCosImpl = function(x) {
+  InitTrigonometricFunctions();
+  return MathCosImpl(x);
+}
+
+
+var InitTrigonometricFunctions;
+
+
+// Define constants and interpolation functions.
+// Also define the initialization function that populates the lookup table
+// and then wires up the function definitions.
+function SetupTrigonometricFunctions() {
+  var samples = 1800;  // Table size.
+  var pi = 3.1415926535897932;
+  var pi_half = pi / 2;
+  var inverse_pi_half = 1 / pi_half;
+  var two_pi = pi * 2;
+  var interval = pi_half / samples;
+  var inverse_interval = samples / pi_half;
+  var table_sin;
+  var table_cos_interval;
+
+  // This implements sine using the following algorithm.
+  // 1) Multiplication takes care of to-number conversion.
+  // 2) Reduce x to the first quadrant [0, pi/2].
+  //    Conveniently enough, in case of +/-Infinity, we get NaN.
+  // 3) Replace x by (pi/2-x) if x was in the 2nd or 4th quadrant.
+  // 4) Do a table lookup for the closest samples to the left and right of x.
+  // 5) Find the derivatives at those sampling points by table lookup:
+  //    dsin(x)/dx = cos(x) = sin(pi/2-x) for x in [0, pi/2].
+  // 6) Use cubic spline interpolation to approximate sin(x).
+  // 7) Negate the result if x was in the 3rd or 4th quadrant.
+  // 8) Get rid of -0 by adding 0.
+  var Interpolation = function(x) {
+    var double_index = x * inverse_interval;
+    var index = double_index | 0;
+    var t1 = double_index - index;
+    var t2 = 1 - t1;
+    var y1 = table_sin[index];
+    var y2 = table_sin[index + 1];
+    var dy = y2 - y1;
+    return (t2 * y1 + t1 * y2 +
+                t1 * t2 * ((table_cos_interval[index] - dy) * t2 +
+                           (dy - table_cos_interval[index + 1]) * t1));
+  }
+
+  var MathSinInterpolation = function(x) {
+    var multiple = MathFloor(x * inverse_pi_half);
+    if (%_IsMinusZero(multiple)) return multiple;
+    x = (multiple & 1) * pi_half +
+        (1 - ((multiple & 1) << 1)) * (x - multiple * pi_half);
+    return Interpolation(x) * (1 - (multiple & 2)) + 0;
+  }
+
+  // Cosine is sine with a phase offset of pi/2.
+  var MathCosInterpolation = function(x) {
+    var multiple = MathFloor(x * inverse_pi_half);
+    var phase = multiple + 1;
+    x = (phase & 1) * pi_half +
+        (1 - ((phase & 1) << 1)) * (x - multiple * pi_half);
+    return Interpolation(x) * (1 - (phase & 2)) + 0;
+  };
+
+  %SetInlineBuiltinFlag(Interpolation);
+  %SetInlineBuiltinFlag(MathSinInterpolation);
+  %SetInlineBuiltinFlag(MathCosInterpolation);
+
+  InitTrigonometricFunctions = function() {
+    table_sin = new global.Float64Array(samples + 2);
+    table_cos_interval = new global.Float64Array(samples + 2);
+    %PopulateTrigonometricTable(table_sin, table_cos_interval, samples);
+    MathSinImpl = MathSinInterpolation;
+    MathCosImpl = MathCosInterpolation;
+  }
+}
+
+SetupTrigonometricFunctions();
+
+
 // -------------------------------------------------------------------
 
 function SetUpMath() {
@@ -276,6 +356,10 @@
     "min", MathMin,
     "imul", MathImul
   ));
+
+  %SetInlineBuiltinFlag(MathSin);
+  %SetInlineBuiltinFlag(MathCos);
+  %SetInlineBuiltinFlag(MathTan);
 }
 
 SetUpMath();
diff --git a/src/messages.js b/src/messages.js
index bfd42de..926f294 100644
--- a/src/messages.js
+++ b/src/messages.js
@@ -783,64 +783,67 @@
 // ----------------------------------------------------------------------------
 // Error implementation
 
-var CallSiteReceiverKey = %CreateSymbol("receiver");
-var CallSiteFunctionKey = %CreateSymbol("function");
-var CallSitePositionKey = %CreateSymbol("position");
-var CallSiteStrictModeKey = %CreateSymbol("strict mode");
+//TODO(rossberg)
+var CallSiteReceiverKey = NEW_PRIVATE("receiver");
+var CallSiteFunctionKey = NEW_PRIVATE("function");
+var CallSitePositionKey = NEW_PRIVATE("position");
+var CallSiteStrictModeKey = NEW_PRIVATE("strict mode");
 
 function CallSite(receiver, fun, pos, strict_mode) {
-  this[CallSiteReceiverKey] = receiver;
-  this[CallSiteFunctionKey] = fun;
-  this[CallSitePositionKey] = pos;
-  this[CallSiteStrictModeKey] = strict_mode;
+  SET_PRIVATE(this, CallSiteReceiverKey, receiver);
+  SET_PRIVATE(this, CallSiteFunctionKey, fun);
+  SET_PRIVATE(this, CallSitePositionKey, pos);
+  SET_PRIVATE(this, CallSiteStrictModeKey, strict_mode);
 }
 
 function CallSiteGetThis() {
-  return this[CallSiteStrictModeKey] ? UNDEFINED : this[CallSiteReceiverKey];
+  return GET_PRIVATE(this, CallSiteStrictModeKey)
+      ? UNDEFINED : GET_PRIVATE(this, CallSiteReceiverKey);
 }
 
 function CallSiteGetTypeName() {
-  return GetTypeName(this[CallSiteReceiverKey], false);
+  return GetTypeName(GET_PRIVATE(this, CallSiteReceiverKey), false);
 }
 
 function CallSiteIsToplevel() {
-  if (this[CallSiteReceiverKey] == null) {
+  if (GET_PRIVATE(this, CallSiteReceiverKey) == null) {
     return true;
   }
-  return IS_GLOBAL(this[CallSiteReceiverKey]);
+  return IS_GLOBAL(GET_PRIVATE(this, CallSiteReceiverKey));
 }
 
 function CallSiteIsEval() {
-  var script = %FunctionGetScript(this[CallSiteFunctionKey]);
+  var script = %FunctionGetScript(GET_PRIVATE(this, CallSiteFunctionKey));
   return script && script.compilation_type == COMPILATION_TYPE_EVAL;
 }
 
 function CallSiteGetEvalOrigin() {
-  var script = %FunctionGetScript(this[CallSiteFunctionKey]);
+  var script = %FunctionGetScript(GET_PRIVATE(this, CallSiteFunctionKey));
   return FormatEvalOrigin(script);
 }
 
 function CallSiteGetScriptNameOrSourceURL() {
-  var script = %FunctionGetScript(this[CallSiteFunctionKey]);
+  var script = %FunctionGetScript(GET_PRIVATE(this, CallSiteFunctionKey));
   return script ? script.nameOrSourceURL() : null;
 }
 
 function CallSiteGetFunction() {
-  return this[CallSiteStrictModeKey] ? UNDEFINED : this[CallSiteFunctionKey];
+  return GET_PRIVATE(this, CallSiteStrictModeKey)
+      ? UNDEFINED : GET_PRIVATE(this, CallSiteFunctionKey);
 }
 
 function CallSiteGetFunctionName() {
   // See if the function knows its own name
-  var name = this[CallSiteFunctionKey].name;
+  var name = GET_PRIVATE(this, CallSiteFunctionKey).name;
   if (name) {
     return name;
   }
-  name = %FunctionGetInferredName(this[CallSiteFunctionKey]);
+  name = %FunctionGetInferredName(GET_PRIVATE(this, CallSiteFunctionKey));
   if (name) {
     return name;
   }
   // Maybe this is an evaluation?
-  var script = %FunctionGetScript(this[CallSiteFunctionKey]);
+  var script = %FunctionGetScript(GET_PRIVATE(this, CallSiteFunctionKey));
   if (script && script.compilation_type == COMPILATION_TYPE_EVAL) {
     return "eval";
   }
@@ -850,8 +853,8 @@
 function CallSiteGetMethodName() {
   // See if we can find a unique property on the receiver that holds
   // this function.
-  var receiver = this[CallSiteReceiverKey];
-  var fun = this[CallSiteFunctionKey];
+  var receiver = GET_PRIVATE(this, CallSiteReceiverKey);
+  var fun = GET_PRIVATE(this, CallSiteFunctionKey);
   var ownName = fun.name;
   if (ownName && receiver &&
       (%_CallFunction(receiver, ownName, ObjectLookupGetter) === fun ||
@@ -880,49 +883,51 @@
 }
 
 function CallSiteGetFileName() {
-  var script = %FunctionGetScript(this[CallSiteFunctionKey]);
+  var script = %FunctionGetScript(GET_PRIVATE(this, CallSiteFunctionKey));
   return script ? script.name : null;
 }
 
 function CallSiteGetLineNumber() {
-  if (this[CallSitePositionKey] == -1) {
+  if (GET_PRIVATE(this, CallSitePositionKey) == -1) {
     return null;
   }
-  var script = %FunctionGetScript(this[CallSiteFunctionKey]);
+  var script = %FunctionGetScript(GET_PRIVATE(this, CallSiteFunctionKey));
   var location = null;
   if (script) {
-    location = script.locationFromPosition(this[CallSitePositionKey], true);
+    location = script.locationFromPosition(
+        GET_PRIVATE(this, CallSitePositionKey), true);
   }
   return location ? location.line + 1 : null;
 }
 
 function CallSiteGetColumnNumber() {
-  if (this[CallSitePositionKey] == -1) {
+  if (GET_PRIVATE(this, CallSitePositionKey) == -1) {
     return null;
   }
-  var script = %FunctionGetScript(this[CallSiteFunctionKey]);
+  var script = %FunctionGetScript(GET_PRIVATE(this, CallSiteFunctionKey));
   var location = null;
   if (script) {
-    location = script.locationFromPosition(this[CallSitePositionKey], true);
+    location = script.locationFromPosition(
+      GET_PRIVATE(this, CallSitePositionKey), true);
   }
   return location ? location.column + 1: null;
 }
 
 function CallSiteIsNative() {
-  var script = %FunctionGetScript(this[CallSiteFunctionKey]);
+  var script = %FunctionGetScript(GET_PRIVATE(this, CallSiteFunctionKey));
   return script ? (script.type == TYPE_NATIVE) : false;
 }
 
 function CallSiteGetPosition() {
-  return this[CallSitePositionKey];
+  return GET_PRIVATE(this, CallSitePositionKey);
 }
 
 function CallSiteIsConstructor() {
-  var receiver = this[CallSiteReceiverKey];
+  var receiver = GET_PRIVATE(this, CallSiteReceiverKey);
   var constructor = (receiver != null && IS_OBJECT(receiver))
                         ? %GetDataProperty(receiver, "constructor") : null;
   if (!constructor) return false;
-  return this[CallSiteFunctionKey] === constructor;
+  return GET_PRIVATE(this, CallSiteFunctionKey) === constructor;
 }
 
 function CallSiteToString() {
@@ -965,7 +970,7 @@
   var isConstructor = this.isConstructor();
   var isMethodCall = !(this.isToplevel() || isConstructor);
   if (isMethodCall) {
-    var typeName = GetTypeName(this[CallSiteReceiverKey], true);
+    var typeName = GetTypeName(GET_PRIVATE(this, CallSiteReceiverKey), true);
     var methodName = this.getMethodName();
     if (functionName) {
       if (typeName &&
diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc
index a0e990c..f053c79 100644
--- a/src/mips/code-stubs-mips.cc
+++ b/src/mips/code-stubs-mips.cc
@@ -291,6 +291,17 @@
 }
 
 
+void NewStringAddStub::InitializeInterfaceDescriptor(
+    Isolate* isolate,
+    CodeStubInterfaceDescriptor* descriptor) {
+  static Register registers[] = { a1, a0 };
+  descriptor->register_param_count_ = 2;
+  descriptor->register_params_ = registers;
+  descriptor->deoptimization_handler_ =
+      Runtime::FunctionForId(Runtime::kStringAdd)->entry;
+}
+
+
 #define __ ACCESS_MASM(masm)
 
 
diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc
index caa7352..a9cf791 100644
--- a/src/mips/full-codegen-mips.cc
+++ b/src/mips/full-codegen-mips.cc
@@ -3133,6 +3133,36 @@
 }
 
 
+void FullCodeGenerator::EmitIsMinusZero(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  ASSERT(args->length() == 1);
+
+  VisitForAccumulatorValue(args->at(0));
+
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false,
+                         &if_true, &if_false, &fall_through);
+
+  __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, if_false, DO_SMI_CHECK);
+  __ lw(a2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
+  __ lw(a1, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
+  __ li(t0, 0x80000000);
+  Label not_nan;
+  __ Branch(&not_nan, ne, a2, Operand(t0));
+  __ mov(t0, zero_reg);
+  __ mov(a2, a1);
+  __ bind(&not_nan);
+
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  Split(eq, a2, Operand(t0), if_true, if_false, fall_through);
+
+  context()->Plug(if_true, if_false);
+}
+
+
 void FullCodeGenerator::EmitIsArray(CallRuntime* expr) {
   ZoneList<Expression*>* args = expr->arguments();
   ASSERT(args->length() == 1);
@@ -3740,11 +3770,20 @@
 void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) {
   ZoneList<Expression*>* args = expr->arguments();
   ASSERT_EQ(2, args->length());
-  VisitForStackValue(args->at(0));
-  VisitForStackValue(args->at(1));
+  if (FLAG_new_string_add) {
+    VisitForStackValue(args->at(0));
+    VisitForAccumulatorValue(args->at(1));
 
-  StringAddStub stub(STRING_ADD_CHECK_BOTH);
-  __ CallStub(&stub);
+    __ pop(a1);
+    NewStringAddStub stub(STRING_ADD_CHECK_BOTH, NOT_TENURED);
+    __ CallStub(&stub);
+  } else {
+    VisitForStackValue(args->at(0));
+    VisitForStackValue(args->at(1));
+
+    StringAddStub stub(STRING_ADD_CHECK_BOTH);
+    __ CallStub(&stub);
+  }
   context()->Plug(v0);
 }
 
@@ -3762,45 +3801,6 @@
 }
 
 
-void FullCodeGenerator::EmitMathSin(CallRuntime* expr) {
-  // Load the argument on the stack and call the stub.
-  TranscendentalCacheStub stub(TranscendentalCache::SIN,
-                               TranscendentalCacheStub::TAGGED);
-  ZoneList<Expression*>* args = expr->arguments();
-  ASSERT(args->length() == 1);
-  VisitForStackValue(args->at(0));
-  __ mov(a0, result_register());  // Stub requires parameter in a0 and on tos.
-  __ CallStub(&stub);
-  context()->Plug(v0);
-}
-
-
-void FullCodeGenerator::EmitMathCos(CallRuntime* expr) {
-  // Load the argument on the stack and call the stub.
-  TranscendentalCacheStub stub(TranscendentalCache::COS,
-                               TranscendentalCacheStub::TAGGED);
-  ZoneList<Expression*>* args = expr->arguments();
-  ASSERT(args->length() == 1);
-  VisitForStackValue(args->at(0));
-  __ mov(a0, result_register());  // Stub requires parameter in a0 and on tos.
-  __ CallStub(&stub);
-  context()->Plug(v0);
-}
-
-
-void FullCodeGenerator::EmitMathTan(CallRuntime* expr) {
-  // Load the argument on the stack and call the stub.
-  TranscendentalCacheStub stub(TranscendentalCache::TAN,
-                               TranscendentalCacheStub::TAGGED);
-  ZoneList<Expression*>* args = expr->arguments();
-  ASSERT(args->length() == 1);
-  VisitForStackValue(args->at(0));
-  __ mov(a0, result_register());  // Stub requires parameter in a0 and on tos.
-  __ CallStub(&stub);
-  context()->Plug(v0);
-}
-
-
 void FullCodeGenerator::EmitMathLog(CallRuntime* expr) {
   // Load the argument on the stack and call the stub.
   TranscendentalCacheStub stub(TranscendentalCache::LOG,
diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc
index 5c2d636..7f6e869 100644
--- a/src/mips/lithium-codegen-mips.cc
+++ b/src/mips/lithium-codegen-mips.cc
@@ -2039,6 +2039,16 @@
 
 
 template<class InstrType>
+void LCodeGen::EmitFalseBranch(InstrType instr,
+                               Condition condition,
+                               Register src1,
+                               const Operand& src2) {
+  int false_block = instr->FalseDestination(chunk_);
+  __ Branch(chunk_->GetAssemblyLabel(false_block), condition, src1, src2);
+}
+
+
+template<class InstrType>
 void LCodeGen::EmitFalseBranchF(InstrType instr,
                                 Condition condition,
                                 FPURegister src1,
@@ -2311,6 +2321,32 @@
 }
 
 
+void LCodeGen::DoCompareMinusZeroAndBranch(LCompareMinusZeroAndBranch* instr) {
+  Representation rep = instr->hydrogen()->value()->representation();
+  ASSERT(!rep.IsInteger32());
+  Register scratch = ToRegister(instr->temp());
+
+  if (rep.IsDouble()) {
+    DoubleRegister value = ToDoubleRegister(instr->value());
+    EmitFalseBranchF(instr, ne, value, kDoubleRegZero);
+    __ FmoveHigh(scratch, value);
+    __ li(at, 0x80000000);
+  } else {
+    Register value = ToRegister(instr->value());
+    __ CheckMap(value,
+                scratch,
+                Heap::kHeapNumberMapRootIndex,
+                instr->FalseLabel(chunk()),
+                DO_SMI_CHECK);
+    __ lw(scratch, FieldMemOperand(value, HeapNumber::kExponentOffset));
+    EmitFalseBranch(instr, ne, scratch, Operand(0x80000000));
+    __ lw(scratch, FieldMemOperand(value, HeapNumber::kMantissaOffset));
+    __ mov(at, zero_reg);
+  }
+  EmitBranch(instr, eq, scratch, Operand(at));
+}
+
+
 Condition LCodeGen::EmitIsObject(Register input,
                                  Register temp1,
                                  Register temp2,
@@ -4480,10 +4516,18 @@
 
 void LCodeGen::DoStringAdd(LStringAdd* instr) {
   ASSERT(ToRegister(instr->context()).is(cp));
-  __ push(ToRegister(instr->left()));
-  __ push(ToRegister(instr->right()));
-  StringAddStub stub(instr->hydrogen()->flags());
-  CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
+  if (FLAG_new_string_add) {
+    ASSERT(ToRegister(instr->left()).is(a1));
+    ASSERT(ToRegister(instr->right()).is(a0));
+    NewStringAddStub stub(instr->hydrogen()->flags(),
+                          isolate()->heap()->GetPretenureMode());
+    CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
+  } else {
+    __ push(ToRegister(instr->left()));
+    __ push(ToRegister(instr->right()));
+    StringAddStub stub(instr->hydrogen()->flags());
+    CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
+  }
 }
 
 
diff --git a/src/mips/lithium-codegen-mips.h b/src/mips/lithium-codegen-mips.h
index f41adbf..c15352f 100644
--- a/src/mips/lithium-codegen-mips.h
+++ b/src/mips/lithium-codegen-mips.h
@@ -301,6 +301,8 @@
 
   static Condition TokenToCondition(Token::Value op, bool is_unsigned);
   void EmitGoto(int block);
+
+  // EmitBranch expects to be the last instruction of a block.
   template<class InstrType>
   void EmitBranch(InstrType instr,
                   Condition condition,
@@ -312,6 +314,11 @@
                    FPURegister src1,
                    FPURegister src2);
   template<class InstrType>
+  void EmitFalseBranch(InstrType instr,
+                       Condition condition,
+                       Register src1,
+                       const Operand& src2);
+  template<class InstrType>
   void EmitFalseBranchF(InstrType instr,
                         Condition condition,
                         FPURegister src1,
diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc
index edb1206..70dd60d 100644
--- a/src/mips/lithium-mips.cc
+++ b/src/mips/lithium-mips.cc
@@ -1703,6 +1703,16 @@
 }
 
 
+LInstruction* LChunkBuilder::DoCompareMinusZeroAndBranch(
+    HCompareMinusZeroAndBranch* instr) {
+  LInstruction* goto_instr = CheckElideControlInstruction(instr);
+  if (goto_instr != NULL) return goto_instr;
+  LOperand* value = UseRegister(instr->value());
+  LOperand* scratch = TempRegister();
+  return new(zone()) LCompareMinusZeroAndBranch(value, scratch);
+}
+
+
 LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) {
   ASSERT(instr->value()->representation().IsTagged());
   LOperand* temp = TempRegister();
@@ -2335,8 +2345,12 @@
 
 LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) {
   LOperand* context = UseFixed(instr->context(), cp);
-  LOperand* left = UseRegisterAtStart(instr->left());
-  LOperand* right = UseRegisterAtStart(instr->right());
+  LOperand* left = FLAG_new_string_add
+      ? UseFixed(instr->left(), a1)
+      : UseRegisterAtStart(instr->left());
+  LOperand* right = FLAG_new_string_add
+      ? UseFixed(instr->right(), a0)
+      : UseRegisterAtStart(instr->right());
   return MarkAsCall(
       DefineFixed(new(zone()) LStringAdd(context, left, right), v0),
       instr);
diff --git a/src/mips/lithium-mips.h b/src/mips/lithium-mips.h
index 5678bb7..8c82a9d 100644
--- a/src/mips/lithium-mips.h
+++ b/src/mips/lithium-mips.h
@@ -72,6 +72,7 @@
   V(ClampIToUint8)                              \
   V(ClampTToUint8)                              \
   V(ClassOfTestAndBranch)                       \
+  V(CompareMinusZeroAndBranch)                  \
   V(CompareNumericAndBranch)                    \
   V(CmpObjectEqAndBranch)                       \
   V(CmpHoleAndBranch)                           \
@@ -923,6 +924,22 @@
 };
 
 
+class LCompareMinusZeroAndBranch V8_FINAL : public LControlInstruction<1, 1> {
+ public:
+  LCompareMinusZeroAndBranch(LOperand* value, LOperand* temp) {
+    inputs_[0] = value;
+    temps_[0] = temp;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CompareMinusZeroAndBranch,
+                               "cmp-minus-zero-and-branch")
+  DECLARE_HYDROGEN_ACCESSOR(CompareMinusZeroAndBranch)
+};
+
+
 class LIsObjectAndBranch V8_FINAL : public LControlInstruction<1, 1> {
  public:
   LIsObjectAndBranch(LOperand* value, LOperand* temp) {
diff --git a/src/objects-debug.cc b/src/objects-debug.cc
index 6ab2ddf..f59687a 100644
--- a/src/objects-debug.cc
+++ b/src/objects-debug.cc
@@ -243,6 +243,7 @@
   CHECK(HasHashCode());
   CHECK_GT(Hash(), 0);
   CHECK(name()->IsUndefined() || name()->IsString());
+  CHECK(flags()->IsSmi());
 }
 
 
diff --git a/src/objects-inl.h b/src/objects-inl.h
index bef807e..a89c049 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -2692,6 +2692,8 @@
 
 
 ACCESSORS(Symbol, name, Object, kNameOffset)
+ACCESSORS(Symbol, flags, Smi, kFlagsOffset)
+BOOL_ACCESSORS(Symbol, flags, is_private, kPrivateBit)
 
 
 bool String::Equals(String* other) {
@@ -4807,6 +4809,8 @@
 BOOL_GETTER(SharedFunctionInfo, compiler_hints, is_extended_mode,
             kExtendedModeFunction)
 BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, native, kNative)
+BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, inline_builtin,
+               kInlineBuiltin)
 BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints,
                name_should_print_as_anonymous,
                kNameShouldPrintAsAnonymous)
@@ -4867,6 +4871,7 @@
 
 
 void SharedFunctionInfo::set_code(Code* value, WriteBarrierMode mode) {
+  ASSERT(value->kind() != Code::OPTIMIZED_FUNCTION);
   WRITE_FIELD(this, kCodeOffset, value);
   CONDITIONAL_WRITE_BARRIER(value->GetHeap(), this, kCodeOffset, value, mode);
 }
diff --git a/src/objects-printer.cc b/src/objects-printer.cc
index 37ae9b6..6d2811b 100644
--- a/src/objects-printer.cc
+++ b/src/objects-printer.cc
@@ -523,6 +523,7 @@
   PrintF(out, " - hash: %d\n", Hash());
   PrintF(out, " - name: ");
   name()->ShortPrint();
+  PrintF(out, " - private: %d\n", is_private());
   PrintF(out, "\n");
 }
 
diff --git a/src/objects.cc b/src/objects.cc
index e5b4763..935e875 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -9742,20 +9742,6 @@
 }
 
 
-bool JSFunction::IsInlineable() {
-  if (IsBuiltin()) return false;
-  SharedFunctionInfo* shared_info = shared();
-  // Check that the function has a script associated with it.
-  if (!shared_info->script()->IsScript()) return false;
-  if (shared_info->optimization_disabled()) return false;
-  Code* code = shared_info->code();
-  if (code->kind() == Code::OPTIMIZED_FUNCTION) return true;
-  // If we never ran this (unlikely) then lets try to optimize it.
-  if (code->kind() != Code::FUNCTION) return true;
-  return code->optimizable();
-}
-
-
 void JSObject::OptimizeAsPrototype(Handle<JSObject> object) {
   if (object->IsGlobalObject()) return;
 
@@ -10024,6 +10010,16 @@
 }
 
 
+bool SharedFunctionInfo::IsInlineable() {
+  // Check that the function has a script associated with it.
+  if (!script()->IsScript()) return false;
+  if (optimization_disabled()) return false;
+  // If we never ran this (unlikely) then lets try to optimize it.
+  if (code()->kind() != Code::FUNCTION) return true;
+  return code()->optimizable();
+}
+
+
 int SharedFunctionInfo::SourceSize() {
   return end_position() - start_position();
 }
diff --git a/src/objects.h b/src/objects.h
index 0099cb2..2fc1d23 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -352,6 +352,7 @@
   V(SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE)                \
                                                                                \
   V(SYMBOL_TYPE)                                                               \
+                                                                               \
   V(MAP_TYPE)                                                                  \
   V(CODE_TYPE)                                                                 \
   V(ODDBALL_TYPE)                                                              \
@@ -684,7 +685,7 @@
       | kNotInternalizedTag,
 
   // Non-string names
-  SYMBOL_TYPE = kNotStringTag,  // LAST_NAME_TYPE, FIRST_NONSTRING_TYPE
+  SYMBOL_TYPE = kNotStringTag,  // FIRST_NONSTRING_TYPE, LAST_NAME_TYPE
 
   // Objects allocated in their own spaces (never in new space).
   MAP_TYPE,
@@ -6781,6 +6782,9 @@
   // global object.
   DECL_BOOLEAN_ACCESSORS(native)
 
+  // Indicate that this builtin needs to be inlined in crankshaft.
+  DECL_BOOLEAN_ACCESSORS(inline_builtin)
+
   // Indicates that the function was created by the Function function.
   // Though it's anonymous, toString should treat it as if it had the name
   // "anonymous".  We don't set the name itself so that the system does not
@@ -6870,6 +6874,9 @@
     set_dont_optimize(reason != kNoReason);
   }
 
+  // Check whether or not this function is inlineable.
+  bool IsInlineable();
+
   // Source size of this function.
   int SourceSize();
 
@@ -7020,6 +7027,7 @@
     kUsesArguments,
     kHasDuplicateParameters,
     kNative,
+    kInlineBuiltin,
     kBoundFunction,
     kIsAnonymous,
     kNameShouldPrintAsAnonymous,
@@ -7246,9 +7254,6 @@
   // Tells whether or not the function is on the concurrent recompilation queue.
   inline bool IsInRecompileQueue();
 
-  // Check whether or not this function is inlineable.
-  bool IsInlineable();
-
   // [literals_or_bindings]: Fixed array holding either
   // the materialized literals or the bindings of a bound function.
   //
@@ -8376,6 +8381,11 @@
   // [name]: the print name of a symbol, or undefined if none.
   DECL_ACCESSORS(name, Object)
 
+  DECL_ACCESSORS(flags, Smi)
+
+  // [is_private]: whether this is a private symbol.
+  DECL_BOOLEAN_ACCESSORS(is_private)
+
   // Casting.
   static inline Symbol* cast(Object* obj);
 
@@ -8385,12 +8395,14 @@
 
   // Layout description.
   static const int kNameOffset = Name::kSize;
-  static const int kSize = kNameOffset + kPointerSize;
+  static const int kFlagsOffset = kNameOffset + kPointerSize;
+  static const int kSize = kFlagsOffset + kPointerSize;
 
-  typedef FixedBodyDescriptor<kNameOffset, kNameOffset + kPointerSize, kSize>
-          BodyDescriptor;
+  typedef FixedBodyDescriptor<kNameOffset, kFlagsOffset, kSize> BodyDescriptor;
 
  private:
+  static const int kPrivateBit = 0;
+
   DISALLOW_IMPLICIT_CONSTRUCTORS(Symbol);
 };
 
diff --git a/src/parser.cc b/src/parser.cc
index 71c6f67..b168919 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -4114,8 +4114,7 @@
     while (!done) {
       bool is_strict_reserved = false;
       Handle<String> param_name =
-          ParseIdentifierOrStrictReservedWord(&is_strict_reserved,
-                                              CHECK_OK);
+          ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK);
 
       // Store locations for possible future error reports.
       if (!name_loc.IsValid() && IsEvalOrArguments(param_name)) {
diff --git a/src/runtime.cc b/src/runtime.cc
index bf4fa4e..9d317ca 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -588,6 +588,19 @@
 }
 
 
+RUNTIME_FUNCTION(MaybeObject*, Runtime_CreatePrivateSymbol) {
+  HandleScope scope(isolate);
+  ASSERT(args.length() == 1);
+  Handle<Object> name(args[0], isolate);
+  RUNTIME_ASSERT(name->IsString() || name->IsUndefined());
+  Symbol* symbol;
+  MaybeObject* maybe = isolate->heap()->AllocatePrivateSymbol();
+  if (!maybe->To(&symbol)) return maybe;
+  if (name->IsString()) symbol->set_name(*name);
+  return symbol;
+}
+
+
 RUNTIME_FUNCTION(MaybeObject*, Runtime_SymbolName) {
   SealHandleScope shs(isolate);
   ASSERT(args.length() == 1);
@@ -596,6 +609,14 @@
 }
 
 
+RUNTIME_FUNCTION(MaybeObject*, Runtime_SymbolIsPrivate) {
+  SealHandleScope shs(isolate);
+  ASSERT(args.length() == 1);
+  CONVERT_ARG_CHECKED(Symbol, symbol, 0);
+  return isolate->heap()->ToBoolean(symbol->is_private());
+}
+
+
 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
   SealHandleScope shs(isolate);
   ASSERT(args.length() == 2);
@@ -4790,6 +4811,19 @@
 }
 
 
+static Handle<Name> ToName(Isolate* isolate, Handle<Object> key) {
+  if (key->IsName()) {
+    return Handle<Name>::cast(key);
+  } else {
+    bool has_pending_exception = false;
+    Handle<Object> converted =
+        Execution::ToString(isolate, key, &has_pending_exception);
+    if (has_pending_exception) return Handle<Name>();
+    return Handle<Name>::cast(converted);
+  }
+}
+
+
 MaybeObject* Runtime::HasObjectProperty(Isolate* isolate,
                                         Handle<JSReceiver> object,
                                         Handle<Object> key) {
@@ -4802,16 +4836,8 @@
   }
 
   // Convert the key to a name - possibly by calling back into JavaScript.
-  Handle<Name> name;
-  if (key->IsName()) {
-    name = Handle<Name>::cast(key);
-  } else {
-    bool has_pending_exception = false;
-    Handle<Object> converted =
-        Execution::ToString(isolate, key, &has_pending_exception);
-    if (has_pending_exception) return Failure::Exception();
-    name = Handle<Name>::cast(converted);
-  }
+  Handle<Name> name = ToName(isolate, key);
+  RETURN_IF_EMPTY_HANDLE(isolate, name);
 
   return isolate->heap()->ToBoolean(JSReceiver::HasProperty(object, name));
 }
@@ -4844,16 +4870,8 @@
   }
 
   // Convert the key to a name - possibly by calling back into JavaScript.
-  Handle<Name> name;
-  if (key->IsName()) {
-    name = Handle<Name>::cast(key);
-  } else {
-    bool has_pending_exception = false;
-    Handle<Object> converted =
-        Execution::ToString(isolate, key, &has_pending_exception);
-    if (has_pending_exception) return Failure::Exception();
-    name = Handle<Name>::cast(converted);
-  }
+  Handle<Name> name = ToName(isolate, key);
+  RETURN_IF_EMPTY_HANDLE(isolate, name);
 
   // Check if the name is trivially convertible to an index and get
   // the element if so.
@@ -5379,6 +5397,20 @@
 }
 
 
+RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInlineBuiltinFlag) {
+  SealHandleScope shs(isolate);
+  RUNTIME_ASSERT(args.length() == 1);
+
+  Handle<Object> object = args.at<Object>(0);
+
+  if (object->IsJSFunction()) {
+    JSFunction* func = JSFunction::cast(*object);
+    func->shared()->set_inline_builtin(true);
+  }
+  return isolate->heap()->undefined_value();
+}
+
+
 RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
   HandleScope scope(isolate);
   RUNTIME_ASSERT(args.length() == 5);
@@ -7802,6 +7834,35 @@
 }
 
 
+RUNTIME_FUNCTION(MaybeObject*, Runtime_PopulateTrigonometricTable) {
+  HandleScope scope(isolate);
+  ASSERT(args.length() == 3);
+  CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sin_table, 0);
+  CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, cos_table, 1);
+  CONVERT_SMI_ARG_CHECKED(samples, 2);
+  RUNTIME_ASSERT(sin_table->type() == kExternalDoubleArray);
+  RUNTIME_ASSERT(cos_table->type() == kExternalDoubleArray);
+  double* sin_buffer = reinterpret_cast<double*>(
+      JSArrayBuffer::cast(sin_table->buffer())->backing_store());
+  double* cos_buffer = reinterpret_cast<double*>(
+      JSArrayBuffer::cast(cos_table->buffer())->backing_store());
+
+  static const double pi_half = 3.1415926535897932 / 2;
+  double interval = pi_half / samples;
+  for (int i = 0; i < samples + 1; i++) {
+    double sample = sin(i * interval);
+    sin_buffer[i] = sample;
+    cos_buffer[samples - i] = sample * interval;
+  }
+
+  // Fill this to catch out of bound accesses when calculating Math.sin(pi/2).
+  sin_buffer[samples + 1] = sin(pi_half + interval);
+  cos_buffer[samples + 1] = cos(pi_half + interval) * interval;
+
+  return isolate->heap()->undefined_value();
+}
+
+
 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
   SealHandleScope shs(isolate);
   ASSERT(args.length() == 2);
@@ -14691,18 +14752,25 @@
 RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConstructor) {
   HandleScope scope(isolate);
   // If we get 2 arguments then they are the stub parameters (constructor, type
-  // info).  If we get 3, then the first one is a pointer to the arguments
-  // passed by the caller.
+  // info).  If we get 4, then the first one is a pointer to the arguments
+  // passed by the caller, and the last one is the length of the arguments
+  // passed to the caller (redundant, but useful to check on the deoptimizer
+  // with an assert).
   Arguments empty_args(0, NULL);
   bool no_caller_args = args.length() == 2;
-  ASSERT(no_caller_args || args.length() == 3);
+  ASSERT(no_caller_args || args.length() == 4);
   int parameters_start = no_caller_args ? 0 : 1;
   Arguments* caller_args = no_caller_args
       ? &empty_args
       : reinterpret_cast<Arguments*>(args[0]);
   CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, parameters_start);
   CONVERT_ARG_HANDLE_CHECKED(Object, type_info, parameters_start + 1);
-
+#ifdef DEBUG
+  if (!no_caller_args) {
+    CONVERT_SMI_ARG_CHECKED(arg_count, parameters_start + 2);
+    ASSERT(arg_count == caller_args->length());
+  }
+#endif
   return ArrayConstructorCommon(isolate,
                                 constructor,
                                 type_info,
@@ -14714,13 +14782,18 @@
   HandleScope scope(isolate);
   Arguments empty_args(0, NULL);
   bool no_caller_args = args.length() == 1;
-  ASSERT(no_caller_args || args.length() == 2);
+  ASSERT(no_caller_args || args.length() == 3);
   int parameters_start = no_caller_args ? 0 : 1;
   Arguments* caller_args = no_caller_args
       ? &empty_args
       : reinterpret_cast<Arguments*>(args[0]);
   CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, parameters_start);
-
+#ifdef DEBUG
+  if (!no_caller_args) {
+    CONVERT_SMI_ARG_CHECKED(arg_count, parameters_start + 1);
+    ASSERT(arg_count == caller_args->length());
+  }
+#endif
   return ArrayConstructorCommon(isolate,
                                 constructor,
                                 Handle<Object>::null(),
diff --git a/src/runtime.h b/src/runtime.h
index c316d40..734875f 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -106,6 +106,7 @@
   F(AllocateInOldPointerSpace, 1, 1) \
   F(AllocateInOldDataSpace, 1, 1) \
   F(SetNativeFlag, 1, 1) \
+  F(SetInlineBuiltinFlag, 1, 1) \
   F(StoreArrayLiteralElement, 5, 1) \
   F(DebugCallbackSupportsStepping, 1, 1) \
   F(DebugPrepareStepInIfStepping, 1, 1) \
@@ -189,6 +190,7 @@
   F(Math_sin, 1, 1) \
   F(Math_sqrt, 1, 1) \
   F(Math_tan, 1, 1) \
+  F(PopulateTrigonometricTable, 3, 1) \
   \
   /* Regular expressions */ \
   F(RegExpCompile, 3, 1) \
@@ -315,7 +317,9 @@
   \
   /* Harmony symbols */ \
   F(CreateSymbol, 1, 1) \
+  F(CreatePrivateSymbol, 1, 1) \
   F(SymbolName, 1, 1) \
+  F(SymbolIsPrivate, 1, 1) \
   \
   /* Harmony proxies */ \
   F(CreateJSProxy, 2, 1) \
@@ -625,11 +629,9 @@
   F(IsSpecObject, 1, 1)                                                      \
   F(IsStringWrapperSafeForDefaultValueOf, 1, 1)                              \
   F(MathPow, 2, 1)                                                           \
-  F(MathSin, 1, 1)                                                           \
-  F(MathCos, 1, 1)                                                           \
-  F(MathTan, 1, 1)                                                           \
   F(MathSqrt, 1, 1)                                                          \
   F(MathLog, 1, 1)                                                           \
+  F(IsMinusZero, 1, 1)                                                       \
   F(IsRegExpEquivalent, 2, 1)                                                \
   F(HasCachedArrayIndex, 1, 1)                                               \
   F(GetCachedArrayIndex, 1, 1)                                               \
diff --git a/src/runtime.js b/src/runtime.js
index 875b6b0..19b858b 100644
--- a/src/runtime.js
+++ b/src/runtime.js
@@ -606,7 +606,9 @@
   if (IS_NUMBER(x)) {
     if (NUMBER_IS_NAN(x) && NUMBER_IS_NAN(y)) return true;
     // x is +0 and y is -0 or vice versa.
-    if (x === 0 && y === 0 && (1 / x) != (1 / y)) return false;
+    if (x === 0 && y === 0 && %_IsMinusZero(x) != %_IsMinusZero(y)) {
+      return false;
+    }
   }
   return x === y;
 }
diff --git a/src/spaces.cc b/src/spaces.cc
index f35db69..1e0d9bc 100644
--- a/src/spaces.cc
+++ b/src/spaces.cc
@@ -2504,29 +2504,6 @@
 // -----------------------------------------------------------------------------
 // OldSpace implementation
 
-bool NewSpace::ReserveSpace(int bytes) {
-  // We can't reliably unpack a partial snapshot that needs more new space
-  // space than the minimum NewSpace size.  The limit can be set lower than
-  // the end of new space either because there is more space on the next page
-  // or because we have lowered the limit in order to get periodic incremental
-  // marking.  The most reliable way to ensure that there is linear space is
-  // to do the allocation, then rewind the limit.
-  ASSERT(bytes <= InitialCapacity());
-  MaybeObject* maybe = AllocateRaw(bytes);
-  Object* object = NULL;
-  if (!maybe->ToObject(&object)) return false;
-  HeapObject* allocation = HeapObject::cast(object);
-  Address top = allocation_info_.top();
-  if ((top - bytes) == allocation->address()) {
-    allocation_info_.set_top(allocation->address());
-    return true;
-  }
-  // There may be a borderline case here where the allocation succeeded, but
-  // the limit and top have moved on to a new page.  In that case we try again.
-  return ReserveSpace(bytes);
-}
-
-
 void PagedSpace::PrepareForMarkCompact() {
   // We don't have a linear allocation area while sweeping.  It will be restored
   // on the first allocation after the sweep.
@@ -2561,28 +2538,6 @@
 }
 
 
-bool PagedSpace::ReserveSpace(int size_in_bytes) {
-  ASSERT(size_in_bytes <= AreaSize());
-  ASSERT(size_in_bytes == RoundSizeDownToObjectAlignment(size_in_bytes));
-  Address current_top = allocation_info_.top();
-  Address new_top = current_top + size_in_bytes;
-  if (new_top <= allocation_info_.limit()) return true;
-
-  HeapObject* new_area = free_list_.Allocate(size_in_bytes);
-  if (new_area == NULL) new_area = SlowAllocateRaw(size_in_bytes);
-  if (new_area == NULL) return false;
-
-  int old_linear_size = static_cast<int>(limit() - top());
-  // Mark the old linear allocation area with a free space so it can be
-  // skipped when scanning the heap.  This also puts it back in the free list
-  // if it is big enough.
-  Free(top(), old_linear_size);
-
-  SetTop(new_area->address(), new_area->address() + size_in_bytes);
-  return true;
-}
-
-
 intptr_t PagedSpace::SizeOfObjects() {
   ASSERT(!heap()->IsSweepingComplete() || (unswept_free_bytes_ == 0));
   return Size() - unswept_free_bytes_ - (limit() - top());
@@ -2598,15 +2553,6 @@
 }
 
 
-// You have to call this last, since the implementation from PagedSpace
-// doesn't know that memory was 'promised' to large object space.
-bool LargeObjectSpace::ReserveSpace(int bytes) {
-  return heap()->OldGenerationCapacityAvailable() >= bytes &&
-         (!heap()->incremental_marking()->IsStopped() ||
-           heap()->OldGenerationSpaceAvailable() >= bytes);
-}
-
-
 bool PagedSpace::AdvanceSweeper(intptr_t bytes_to_sweep) {
   if (IsLazySweepingComplete()) return true;
 
@@ -2861,23 +2807,6 @@
 }
 #endif
 
-// -----------------------------------------------------------------------------
-// FixedSpace implementation
-
-void FixedSpace::PrepareForMarkCompact() {
-  // Call prepare of the super class.
-  PagedSpace::PrepareForMarkCompact();
-
-  // During a non-compacting collection, everything below the linear
-  // allocation pointer except wasted top-of-page blocks is considered
-  // allocated and we will rediscover available bytes during the
-  // collection.
-  accounting_stats_.AllocateBytes(free_list_.available());
-
-  // Clear the free list before a full GC---it will be rebuilt afterward.
-  free_list_.Reset();
-}
-
 
 // -----------------------------------------------------------------------------
 // MapSpace implementation
diff --git a/src/spaces.h b/src/spaces.h
index 06f444d..83793e3 100644
--- a/src/spaces.h
+++ b/src/spaces.h
@@ -1683,10 +1683,10 @@
 
   // During boot the free_space_map is created, and afterwards we may need
   // to write it into the free list nodes that were already created.
-  virtual void RepairFreeListsAfterBoot();
+  void RepairFreeListsAfterBoot();
 
   // Prepares for a mark-compact GC.
-  virtual void PrepareForMarkCompact();
+  void PrepareForMarkCompact();
 
   // Current capacity without growing (Size() + Available()).
   intptr_t Capacity() { return accounting_stats_.Capacity(); }
@@ -1768,8 +1768,6 @@
   // failure object if not.
   MUST_USE_RESULT inline MaybeObject* AllocateRaw(int size_in_bytes);
 
-  virtual bool ReserveSpace(int bytes);
-
   // Give a block of memory to the space's free list.  It might be added to
   // the free list or accounted as waste.
   // If add_to_freelist is false then just accounting stats are updated and
@@ -1914,12 +1912,6 @@
   // Normal allocation information.
   AllocationInfo allocation_info_;
 
-  // Bytes of each page that cannot be allocated.  Possibly non-zero
-  // for pages in spaces with only fixed-size objects.  Always zero
-  // for pages in spaces with variable sized objects (those pages are
-  // padded with free-list nodes).
-  int page_extra_;
-
   bool was_swept_conservatively_;
 
   // The first page to be swept when the lazy sweeper advances. Is set
@@ -2167,11 +2159,6 @@
     return 0;
   }
 
-  virtual bool ReserveSpace(int bytes) {
-    UNREACHABLE();
-    return false;
-  }
-
   bool is_committed() { return committed_; }
   bool Commit();
   bool Uncommit();
@@ -2535,8 +2522,6 @@
   // if successful.
   bool AddFreshPage();
 
-  virtual bool ReserveSpace(int bytes);
-
 #ifdef VERIFY_HEAP
   // Verify the active semispace.
   virtual void Verify();
@@ -2632,12 +2617,6 @@
            AllocationSpace id,
            Executability executable)
       : PagedSpace(heap, max_capacity, id, executable) {
-    page_extra_ = 0;
-  }
-
-  // The limit of allocation for a page in this space.
-  virtual Address PageAllocationLimit(Page* page) {
-    return page->area_end();
   }
 
  public:
@@ -2654,43 +2633,13 @@
 
 
 // -----------------------------------------------------------------------------
-// Old space for objects of a fixed size
-
-class FixedSpace : public PagedSpace {
- public:
-  FixedSpace(Heap* heap,
-             intptr_t max_capacity,
-             AllocationSpace id,
-             int object_size_in_bytes)
-      : PagedSpace(heap, max_capacity, id, NOT_EXECUTABLE),
-        object_size_in_bytes_(object_size_in_bytes) {
-    page_extra_ = Page::kNonCodeObjectAreaSize % object_size_in_bytes;
-  }
-
-  // The limit of allocation for a page in this space.
-  virtual Address PageAllocationLimit(Page* page) {
-    return page->area_end() - page_extra_;
-  }
-
-  int object_size_in_bytes() { return object_size_in_bytes_; }
-
-  // Prepares for a mark-compact GC.
-  virtual void PrepareForMarkCompact();
-
- private:
-  // The size of objects in this space.
-  int object_size_in_bytes_;
-};
-
-
-// -----------------------------------------------------------------------------
 // Old space for all map objects
 
-class MapSpace : public FixedSpace {
+class MapSpace : public PagedSpace {
  public:
   // Creates a map space object with a maximum capacity.
   MapSpace(Heap* heap, intptr_t max_capacity, AllocationSpace id)
-      : FixedSpace(heap, max_capacity, id, Map::kSize),
+      : PagedSpace(heap, max_capacity, id, NOT_EXECUTABLE),
         max_map_space_pages_(kMaxMapPageIndex - 1) {
   }
 
@@ -2727,12 +2676,12 @@
 // -----------------------------------------------------------------------------
 // Old space for simple property cell objects
 
-class CellSpace : public FixedSpace {
+class CellSpace : public PagedSpace {
  public:
   // Creates a property cell space object with a maximum capacity.
   CellSpace(Heap* heap, intptr_t max_capacity, AllocationSpace id)
-      : FixedSpace(heap, max_capacity, id, Cell::kSize)
-  {}
+      : PagedSpace(heap, max_capacity, id, NOT_EXECUTABLE) {
+  }
 
   virtual int RoundSizeDownToObjectAlignment(int size) {
     if (IsPowerOf2(Cell::kSize)) {
@@ -2753,13 +2702,13 @@
 // -----------------------------------------------------------------------------
 // Old space for all global object property cell objects
 
-class PropertyCellSpace : public FixedSpace {
+class PropertyCellSpace : public PagedSpace {
  public:
   // Creates a property cell space object with a maximum capacity.
   PropertyCellSpace(Heap* heap, intptr_t max_capacity,
                     AllocationSpace id)
-      : FixedSpace(heap, max_capacity, id, PropertyCell::kSize)
-  {}
+      : PagedSpace(heap, max_capacity, id, NOT_EXECUTABLE) {
+  }
 
   virtual int RoundSizeDownToObjectAlignment(int size) {
     if (IsPowerOf2(PropertyCell::kSize)) {
@@ -2849,11 +2798,6 @@
   // Checks whether the space is empty.
   bool IsEmpty() { return first_page_ == NULL; }
 
-  // See the comments for ReserveSpace in the Space class.  This has to be
-  // called after ReserveSpace has been called on the paged spaces, since they
-  // may use some memory, leaving less for large objects.
-  virtual bool ReserveSpace(int bytes);
-
   LargePage* first_page() { return first_page_; }
 
 #ifdef VERIFY_HEAP
diff --git a/src/version.cc b/src/version.cc
index 164d08d..eef1029 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,7 +34,7 @@
 // system so their names cannot be changed without changing the scripts.
 #define MAJOR_VERSION     3
 #define MINOR_VERSION     23
-#define BUILD_NUMBER      2
+#define BUILD_NUMBER      3
 #define PATCH_LEVEL       0
 // Use 1 for candidates and 0 otherwise.
 // (Boolean macro values are not supported by all preprocessors.)
diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
index 7a7c0a7..9d95fc4 100644
--- a/src/x64/code-stubs-x64.cc
+++ b/src/x64/code-stubs-x64.cc
@@ -176,14 +176,21 @@
   // rax -- number of arguments
   // rdi -- function
   // rbx -- type info cell with elements kind
-  static Register registers[] = { rdi, rbx };
-  descriptor->register_param_count_ = 2;
-  if (constant_stack_parameter_count != 0) {
+  static Register registers_variable_args[] = { rdi, rbx, rax };
+  static Register registers_no_args[] = { rdi, rbx };
+
+  if (constant_stack_parameter_count == 0) {
+    descriptor->register_param_count_ = 2;
+    descriptor->register_params_ = registers_no_args;
+  } else {
     // stack param count needs (constructor pointer, and single argument)
+    descriptor->handler_arguments_mode_ = PASS_ARGUMENTS;
     descriptor->stack_parameter_count_ = rax;
+    descriptor->register_param_count_ = 3;
+    descriptor->register_params_ = registers_variable_args;
   }
+
   descriptor->hint_stack_parameter_count_ = constant_stack_parameter_count;
-  descriptor->register_params_ = registers;
   descriptor->function_mode_ = JS_FUNCTION_STUB_MODE;
   descriptor->deoptimization_handler_ =
       Runtime::FunctionForId(Runtime::kArrayConstructor)->entry;
@@ -197,15 +204,21 @@
   // register state
   // rax -- number of arguments
   // rdi -- constructor function
-  static Register registers[] = { rdi };
-  descriptor->register_param_count_ = 1;
+  static Register registers_variable_args[] = { rdi, rax };
+  static Register registers_no_args[] = { rdi };
 
-  if (constant_stack_parameter_count != 0) {
+  if (constant_stack_parameter_count == 0) {
+    descriptor->register_param_count_ = 1;
+    descriptor->register_params_ = registers_no_args;
+  } else {
     // stack param count needs (constructor pointer, and single argument)
+    descriptor->handler_arguments_mode_ = PASS_ARGUMENTS;
     descriptor->stack_parameter_count_ = rax;
+    descriptor->register_param_count_ = 2;
+    descriptor->register_params_ = registers_variable_args;
   }
+
   descriptor->hint_stack_parameter_count_ = constant_stack_parameter_count;
-  descriptor->register_params_ = registers;
   descriptor->function_mode_ = JS_FUNCTION_STUB_MODE;
   descriptor->deoptimization_handler_ =
       Runtime::FunctionForId(Runtime::kInternalArrayConstructor)->entry;
@@ -302,6 +315,17 @@
 }
 
 
+void NewStringAddStub::InitializeInterfaceDescriptor(
+    Isolate* isolate,
+    CodeStubInterfaceDescriptor* descriptor) {
+  static Register registers[] = { rdx, rax };
+  descriptor->register_param_count_ = 2;
+  descriptor->register_params_ = registers;
+  descriptor->deoptimization_handler_ =
+      Runtime::FunctionForId(Runtime::kStringAdd)->entry;
+}
+
+
 #define __ ACCESS_MASM(masm)
 
 
diff --git a/src/x64/deoptimizer-x64.cc b/src/x64/deoptimizer-x64.cc
index bf11e08..4528077 100644
--- a/src/x64/deoptimizer-x64.cc
+++ b/src/x64/deoptimizer-x64.cc
@@ -106,7 +106,7 @@
     FrameDescription* output_frame, CodeStubInterfaceDescriptor* descriptor) {
   intptr_t handler =
       reinterpret_cast<intptr_t>(descriptor->deoptimization_handler_);
-  int params = descriptor->environment_length();
+  int params = descriptor->GetHandlerParameterCount();
   output_frame->SetRegister(rax.code(), params);
   output_frame->SetRegister(rbx.code(), handler);
 }
diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc
index cc0d3d9..d5fa5e5 100644
--- a/src/x64/full-codegen-x64.cc
+++ b/src/x64/full-codegen-x64.cc
@@ -3026,6 +3026,33 @@
 }
 
 
+void FullCodeGenerator::EmitIsMinusZero(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  ASSERT(args->length() == 1);
+
+  VisitForAccumulatorValue(args->at(0));
+
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false,
+                         &if_true, &if_false, &fall_through);
+
+  Handle<Map> map = masm()->isolate()->factory()->heap_number_map();
+  __ CheckMap(rax, map, if_false, DO_SMI_CHECK);
+  __ cmpl(FieldOperand(rax, HeapNumber::kExponentOffset),
+          Immediate(0x80000000));
+  __ j(not_equal, if_false);
+  __ cmpl(FieldOperand(rax, HeapNumber::kMantissaOffset),
+          Immediate(0x00000000));
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  Split(equal, if_true, if_false, fall_through);
+
+  context()->Plug(if_true, if_false);
+}
+
+
 void FullCodeGenerator::EmitIsArray(CallRuntime* expr) {
   ZoneList<Expression*>* args = expr->arguments();
   ASSERT(args->length() == 1);
@@ -3628,11 +3655,20 @@
   ZoneList<Expression*>* args = expr->arguments();
   ASSERT_EQ(2, args->length());
 
-  VisitForStackValue(args->at(0));
-  VisitForStackValue(args->at(1));
+  if (FLAG_new_string_add) {
+    VisitForStackValue(args->at(0));
+    VisitForAccumulatorValue(args->at(1));
 
-  StringAddStub stub(STRING_ADD_CHECK_BOTH);
-  __ CallStub(&stub);
+    __ pop(rdx);
+    NewStringAddStub stub(STRING_ADD_CHECK_BOTH, NOT_TENURED);
+    __ CallStub(&stub);
+  } else {
+    VisitForStackValue(args->at(0));
+    VisitForStackValue(args->at(1));
+
+    StringAddStub stub(STRING_ADD_CHECK_BOTH);
+    __ CallStub(&stub);
+  }
   context()->Plug(rax);
 }
 
@@ -3650,42 +3686,6 @@
 }
 
 
-void FullCodeGenerator::EmitMathSin(CallRuntime* expr) {
-  // Load the argument on the stack and call the stub.
-  TranscendentalCacheStub stub(TranscendentalCache::SIN,
-                               TranscendentalCacheStub::TAGGED);
-  ZoneList<Expression*>* args = expr->arguments();
-  ASSERT(args->length() == 1);
-  VisitForStackValue(args->at(0));
-  __ CallStub(&stub);
-  context()->Plug(rax);
-}
-
-
-void FullCodeGenerator::EmitMathCos(CallRuntime* expr) {
-  // Load the argument on the stack and call the stub.
-  TranscendentalCacheStub stub(TranscendentalCache::COS,
-                               TranscendentalCacheStub::TAGGED);
-  ZoneList<Expression*>* args = expr->arguments();
-  ASSERT(args->length() == 1);
-  VisitForStackValue(args->at(0));
-  __ CallStub(&stub);
-  context()->Plug(rax);
-}
-
-
-void FullCodeGenerator::EmitMathTan(CallRuntime* expr) {
-  // Load the argument on the stack and call the stub.
-  TranscendentalCacheStub stub(TranscendentalCache::TAN,
-                               TranscendentalCacheStub::TAGGED);
-  ZoneList<Expression*>* args = expr->arguments();
-  ASSERT(args->length() == 1);
-  VisitForStackValue(args->at(0));
-  __ CallStub(&stub);
-  context()->Plug(rax);
-}
-
-
 void FullCodeGenerator::EmitMathLog(CallRuntime* expr) {
   // Load the argument on the stack and call the stub.
   TranscendentalCacheStub stub(TranscendentalCache::LOG,
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index 20b1897..dc6ddf9 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -2246,6 +2246,33 @@
 }
 
 
+void LCodeGen::DoCompareMinusZeroAndBranch(LCompareMinusZeroAndBranch* instr) {
+  Representation rep = instr->hydrogen()->value()->representation();
+  ASSERT(!rep.IsInteger32());
+
+  if (rep.IsDouble()) {
+    XMMRegister value = ToDoubleRegister(instr->value());
+    XMMRegister xmm_scratch = double_scratch0();
+    __ xorps(xmm_scratch, xmm_scratch);
+    __ ucomisd(xmm_scratch, value);
+    EmitFalseBranch(instr, not_equal);
+    __ movmskpd(kScratchRegister, value);
+    __ testl(kScratchRegister, Immediate(1));
+    EmitBranch(instr, not_zero);
+  } else {
+    Register value = ToRegister(instr->value());
+    Handle<Map> map = masm()->isolate()->factory()->heap_number_map();
+    __ CheckMap(value, map, instr->FalseLabel(chunk()), DO_SMI_CHECK);
+    __ cmpl(FieldOperand(value, HeapNumber::kExponentOffset),
+            Immediate(0x80000000));
+    EmitFalseBranch(instr, not_equal);
+    __ cmpl(FieldOperand(value, HeapNumber::kMantissaOffset),
+            Immediate(0x00000000));
+    EmitBranch(instr, equal);
+  }
+}
+
+
 Condition LCodeGen::EmitIsObject(Register input,
                                  Label* is_not_object,
                                  Label* is_object) {
@@ -4077,6 +4104,10 @@
     if (operand_value->IsRegister()) {
       Register value = ToRegister(operand_value);
       __ Store(FieldOperand(write_register, offset), value, representation);
+    } else if (representation.IsInteger32()) {
+      int32_t value = ToInteger32(operand_value);
+      ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
+      __ movl(FieldOperand(write_register, offset), Immediate(value));
     } else {
       Handle<Object> handle_value = ToHandle(operand_value);
       ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
@@ -4400,10 +4431,18 @@
 
 void LCodeGen::DoStringAdd(LStringAdd* instr) {
   ASSERT(ToRegister(instr->context()).is(rsi));
-  EmitPushTaggedOperand(instr->left());
-  EmitPushTaggedOperand(instr->right());
-  StringAddStub stub(instr->hydrogen()->flags());
-  CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
+  if (FLAG_new_string_add) {
+    ASSERT(ToRegister(instr->left()).is(rdx));
+    ASSERT(ToRegister(instr->right()).is(rax));
+    NewStringAddStub stub(instr->hydrogen()->flags(),
+                          isolate()->heap()->GetPretenureMode());
+    CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
+  } else {
+    EmitPushTaggedOperand(instr->left());
+    EmitPushTaggedOperand(instr->right());
+    StringAddStub stub(instr->hydrogen()->flags());
+    CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
+  }
 }
 
 
diff --git a/src/x64/lithium-codegen-x64.h b/src/x64/lithium-codegen-x64.h
index 060cbe8..ac238d0 100644
--- a/src/x64/lithium-codegen-x64.h
+++ b/src/x64/lithium-codegen-x64.h
@@ -270,6 +270,8 @@
 
   static Condition TokenToCondition(Token::Value op, bool is_unsigned);
   void EmitGoto(int block);
+
+  // EmitBranch expects to be the last instruction of a block.
   template<class InstrType>
   void EmitBranch(InstrType instr, Condition cc);
   template<class InstrType>
diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc
index 281589e..a121646 100644
--- a/src/x64/lithium-x64.cc
+++ b/src/x64/lithium-x64.cc
@@ -1672,6 +1672,15 @@
 }
 
 
+LInstruction* LChunkBuilder::DoCompareMinusZeroAndBranch(
+    HCompareMinusZeroAndBranch* instr) {
+  LInstruction* goto_instr = CheckElideControlInstruction(instr);
+  if (goto_instr != NULL) return goto_instr;
+  LOperand* value = UseRegister(instr->value());
+  return new(zone()) LCompareMinusZeroAndBranch(value);
+}
+
+
 LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) {
   ASSERT(instr->value()->representation().IsTagged());
   return new(zone()) LIsObjectAndBranch(UseRegisterAtStart(instr->value()));
@@ -2339,8 +2348,12 @@
 
 LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) {
   LOperand* context = UseFixed(instr->context(), rsi);
-  LOperand* left = UseOrConstantAtStart(instr->left());
-  LOperand* right = UseOrConstantAtStart(instr->right());
+  LOperand* left = FLAG_new_string_add
+      ? UseFixed(instr->left(), rdx)
+      : UseOrConstantAtStart(instr->left());
+  LOperand* right = FLAG_new_string_add
+      ? UseFixed(instr->right(), rax)
+      : UseOrConstantAtStart(instr->right());
   return MarkAsCall(
       DefineFixed(new(zone()) LStringAdd(context, left, right), rax), instr);
 }
@@ -2409,7 +2422,7 @@
     CodeStubInterfaceDescriptor* descriptor =
         info()->code_stub()->GetInterfaceDescriptor(info()->isolate());
     int index = static_cast<int>(instr->index());
-    Register reg = DESCRIPTOR_GET_PARAMETER_REGISTER(descriptor, index);
+    Register reg = descriptor->GetParameterRegister(index);
     return DefineFixed(result, reg);
   }
 }
diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h
index 17e74aa..6e236c7 100644
--- a/src/x64/lithium-x64.h
+++ b/src/x64/lithium-x64.h
@@ -72,6 +72,7 @@
   V(ClampIToUint8)                              \
   V(ClampTToUint8)                              \
   V(ClassOfTestAndBranch)                       \
+  V(CompareMinusZeroAndBranch)                  \
   V(CompareNumericAndBranch)                    \
   V(CmpObjectEqAndBranch)                       \
   V(CmpHoleAndBranch)                           \
@@ -874,6 +875,21 @@
 };
 
 
+class LCompareMinusZeroAndBranch V8_FINAL : public LControlInstruction<1, 0> {
+ public:
+  explicit LCompareMinusZeroAndBranch(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CompareMinusZeroAndBranch,
+                               "cmp-minus-zero-and-branch")
+  DECLARE_HYDROGEN_ACCESSOR(CompareMinusZeroAndBranch)
+};
+
+
+
 class LIsObjectAndBranch V8_FINAL : public LControlInstruction<1, 0> {
  public:
   explicit LIsObjectAndBranch(LOperand* value) {
diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc
index df984fc..2f7166e 100644
--- a/src/x64/macro-assembler-x64.cc
+++ b/src/x64/macro-assembler-x64.cc
@@ -4415,18 +4415,27 @@
     cmpl(length, Immediate(min_length));
     Assert(greater_equal, kInvalidMinLength);
   }
-  Label loop, done, short_string, short_loop;
+  Label short_loop, len8, len16, len24, done, short_string;
 
-  const int kLongStringLimit = 20;
+  const int kLongStringLimit = 4 * kPointerSize;
   if (min_length <= kLongStringLimit) {
-    cmpl(length, Immediate(kLongStringLimit));
-    j(less_equal, &short_string);
+    cmpl(length, Immediate(kPointerSize));
+    j(below, &short_string, Label::kNear);
   }
 
   ASSERT(source.is(rsi));
   ASSERT(destination.is(rdi));
   ASSERT(length.is(rcx));
 
+  if (min_length <= kLongStringLimit) {
+    cmpl(length, Immediate(2 * kPointerSize));
+    j(below_equal, &len8, Label::kNear);
+    cmpl(length, Immediate(3 * kPointerSize));
+    j(below_equal, &len16, Label::kNear);
+    cmpl(length, Immediate(4 * kPointerSize));
+    j(below_equal, &len24, Label::kNear);
+  }
+
   // Because source is 8-byte aligned in our uses of this function,
   // we keep source aligned for the rep movs operation by copying the odd bytes
   // at the end of the ranges.
@@ -4440,25 +4449,38 @@
   addq(destination, scratch);
 
   if (min_length <= kLongStringLimit) {
-    jmp(&done);
+    jmp(&done, Label::kNear);
+    bind(&len24);
+    movq(scratch, Operand(source, 2 * kPointerSize));
+    movq(Operand(destination, 2 * kPointerSize), scratch);
+    bind(&len16);
+    movq(scratch, Operand(source, kPointerSize));
+    movq(Operand(destination, kPointerSize), scratch);
+    bind(&len8);
+    movq(scratch, Operand(source, 0));
+    movq(Operand(destination, 0), scratch);
+    // Move remaining bytes of length.
+    movq(scratch, Operand(source, length, times_1, -kPointerSize));
+    movq(Operand(destination, length, times_1, -kPointerSize), scratch);
+    addq(destination, length);
+    jmp(&done, Label::kNear);
 
     bind(&short_string);
     if (min_length == 0) {
       testl(length, length);
-      j(zero, &done);
+      j(zero, &done, Label::kNear);
     }
-    lea(scratch, Operand(destination, length, times_1, 0));
 
     bind(&short_loop);
-    movb(length, Operand(source, 0));
-    movb(Operand(destination, 0), length);
+    movb(scratch, Operand(source, 0));
+    movb(Operand(destination, 0), scratch);
     incq(source);
     incq(destination);
-    cmpq(destination, scratch);
-    j(not_equal, &short_loop);
-
-    bind(&done);
+    decl(length);
+    j(not_zero, &short_loop);
   }
+
+  bind(&done);
 }
 
 
diff --git a/test/cctest/cctest.status b/test/cctest/cctest.status
index 59bf826..58550d8 100644
--- a/test/cctest/cctest.status
+++ b/test/cctest/cctest.status
@@ -63,6 +63,13 @@
 }],  # ALWAYS
 
 ##############################################################################
+['system == windows', {
+
+  # BUG(2999).
+  'test-cpu-profiler/CollectCpuProfile': [PASS, FAIL],
+}],  # 'system == windows'
+
+##############################################################################
 ['arch == arm', {
 
   # We cannot assume that we can throw OutOfMemory exceptions in all situations.
@@ -80,6 +87,7 @@
   'test-serialize/DeserializeAndRunScript2': [SKIP],
   'test-serialize/DeserializeFromSecondSerialization': [SKIP],
 }],  # 'arch == arm'
+
 ##############################################################################
 ['arch == mipsel', {
 
@@ -132,5 +140,8 @@
 
   # Fails since 16322 (new test).
   'test-code-stubs-arm/ConvertDToI': [SKIP],
+
+  # BUG(2998).
+  'test-macro-assembler-arm/LoadAndStoreWithRepresentation': [SKIP],
 }],  # 'arch == nacl_ia32 or arch == nacl_x64'
 ]
diff --git a/test/cctest/test-accessors.cc b/test/cctest/test-accessors.cc
index df4937e..4920ac2 100644
--- a/test/cctest/test-accessors.cc
+++ b/test/cctest/test-accessors.cc
@@ -122,18 +122,15 @@
   baz = 10;
   v8::HandleScope scope(CcTest::isolate());
   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
-  templ->InstanceTemplate()->SetAccessor(v8_str("foo"),
-                                         GetIntValue,
-                                         SetIntValue,
-                                         v8::External::New(&foo));
-  templ->InstanceTemplate()->SetAccessor(v8_str("bar"),
-                                         GetIntValue,
-                                         SetIntValue,
-                                         v8::External::New(&bar));
-  templ->InstanceTemplate()->SetAccessor(v8_str("baz"),
-                                         GetIntValue,
-                                         SetIntValue,
-                                         v8::External::New(&baz));
+  templ->InstanceTemplate()->SetAccessor(
+      v8_str("foo"), GetIntValue, SetIntValue,
+      v8::External::New(CcTest::isolate(), &foo));
+  templ->InstanceTemplate()->SetAccessor(
+      v8_str("bar"), GetIntValue, SetIntValue,
+      v8::External::New(CcTest::isolate(), &bar));
+  templ->InstanceTemplate()->SetAccessor(
+      v8_str("baz"), GetIntValue, SetIntValue,
+      v8::External::New(CcTest::isolate(), &baz));
   LocalContext env(0, templ->InstanceTemplate());
   v8_compile("foo = (++bar) + baz")->Run();
   CHECK_EQ(bar, -3);
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index f33d02b..15c7263 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -1306,7 +1306,8 @@
   LocalContext env;
   v8::HandleScope scope(env->GetIsolate());
 
-  v8::Handle<v8::Value> data = v8::External::New(expected_ptr);
+  v8::Handle<v8::Value> data =
+      v8::External::New(env->GetIsolate(), expected_ptr);
 
   v8::Handle<v8::Object> obj = v8::Object::New();
   obj->Set(v8_str("func"),
@@ -2743,6 +2744,70 @@
   CHECK(!obj->Has(sym2));
   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
+
+  // Symbol properties are inherited.
+  v8::Local<v8::Object> child = v8::Object::New();
+  child->SetPrototype(obj);
+  CHECK(child->Has(sym1));
+  CHECK_EQ(2002, child->Get(sym1)->Int32Value());
+  CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
+}
+
+
+THREADED_TEST(PrivateProperties) {
+  LocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+
+  v8::Local<v8::Object> obj = v8::Object::New();
+  v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
+  v8::Local<v8::Private> priv2 = v8::Private::New(isolate, "my-private");
+
+  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+
+  CHECK(priv2->Name()->Equals(v8::String::New("my-private")));
+
+  // Make sure delete of a non-existent private symbol property works.
+  CHECK(obj->DeletePrivate(priv1));
+  CHECK(!obj->HasPrivate(priv1));
+
+  CHECK(obj->SetPrivate(priv1, v8::Integer::New(1503)));
+  CHECK(obj->HasPrivate(priv1));
+  CHECK_EQ(1503, obj->GetPrivate(priv1)->Int32Value());
+  CHECK(obj->SetPrivate(priv1, v8::Integer::New(2002)));
+  CHECK(obj->HasPrivate(priv1));
+  CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
+
+  CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
+  int num_props = obj->GetPropertyNames()->Length();
+  CHECK(obj->Set(v8::String::New("bla"), v8::Integer::New(20)));
+  CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
+  CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
+
+  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+
+  // Add another property and delete it afterwards to force the object in
+  // slow case.
+  CHECK(obj->SetPrivate(priv2, v8::Integer::New(2008)));
+  CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
+  CHECK_EQ(2008, obj->GetPrivate(priv2)->Int32Value());
+  CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
+  CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
+
+  CHECK(obj->HasPrivate(priv1));
+  CHECK(obj->HasPrivate(priv2));
+  CHECK(obj->DeletePrivate(priv2));
+  CHECK(obj->HasPrivate(priv1));
+  CHECK(!obj->HasPrivate(priv2));
+  CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
+  CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
+
+  // Private properties are inherited (for the time being).
+  v8::Local<v8::Object> child = v8::Object::New();
+  child->SetPrototype(obj);
+  CHECK(child->HasPrivate(priv1));
+  CHECK_EQ(2002, child->GetPrivate(priv1)->Int32Value());
+  CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
 }
 
 
@@ -3119,7 +3184,7 @@
 THREADED_TEST(External) {
   v8::HandleScope scope(CcTest::isolate());
   int x = 3;
-  Local<v8::External> ext = v8::External::New(&x);
+  Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x);
   LocalContext env;
   env->Global()->Set(v8_str("ext"), ext);
   Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
@@ -3131,10 +3196,10 @@
 
   // Make sure unaligned pointers are wrapped properly.
   char* data = i::StrDup("0123456789");
-  Local<v8::Value> zero = v8::External::New(&data[0]);
-  Local<v8::Value> one = v8::External::New(&data[1]);
-  Local<v8::Value> two = v8::External::New(&data[2]);
-  Local<v8::Value> three = v8::External::New(&data[3]);
+  Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]);
+  Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]);
+  Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]);
+  Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]);
 
   char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
   CHECK_EQ('0', *char_ptr);
@@ -6874,7 +6939,7 @@
   Whammy* whammy = new Whammy(CcTest::isolate());
   templ->SetNamedPropertyHandler(WhammyPropertyGetter,
                                  0, 0, 0, 0,
-                                 v8::External::New(whammy));
+                                 v8::External::New(CcTest::isolate(), whammy));
   const char* extension_list[] = { "v8/gc" };
   v8::ExtensionConfiguration extensions(1, extension_list);
   v8::Handle<Context> context =
@@ -11569,9 +11634,9 @@
   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
   proto_templ->Set(v8_str("method"), method_templ);
   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
-  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
-                                 NULL, NULL, NULL, NULL,
-                                 v8::External::New(&interceptor_call_count));
+  templ->SetNamedPropertyHandler(
+      InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
+      v8::External::New(CcTest::isolate(), &interceptor_call_count));
   LocalContext context;
   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   GenerateSomeGarbage();
@@ -11598,9 +11663,9 @@
   proto_templ->Set(v8_str("method"), method_templ);
   fun_templ->SetHiddenPrototype(true);
   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
-  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
-                                 NULL, NULL, NULL, NULL,
-                                 v8::External::New(&interceptor_call_count));
+  templ->SetNamedPropertyHandler(
+      InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
+      v8::External::New(CcTest::isolate(), &interceptor_call_count));
   LocalContext context;
   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   GenerateSomeGarbage();
@@ -11630,9 +11695,9 @@
   proto_templ->Set(v8_str("method"), method_templ);
   fun_templ->SetHiddenPrototype(true);
   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
-  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
-                                 NULL, NULL, NULL, NULL,
-                                 v8::External::New(&interceptor_call_count));
+  templ->SetNamedPropertyHandler(
+      InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
+      v8::External::New(CcTest::isolate(), &interceptor_call_count));
   LocalContext context;
   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   GenerateSomeGarbage();
@@ -11668,9 +11733,9 @@
   proto_templ->Set(v8_str("method"), method_templ);
   fun_templ->SetHiddenPrototype(true);
   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
-  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
-                                 NULL, NULL, NULL, NULL,
-                                 v8::External::New(&interceptor_call_count));
+  templ->SetNamedPropertyHandler(
+      InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
+      v8::External::New(CcTest::isolate(), &interceptor_call_count));
   LocalContext context;
   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   GenerateSomeGarbage();
@@ -11706,9 +11771,9 @@
   proto_templ->Set(v8_str("method"), method_templ);
   fun_templ->SetHiddenPrototype(true);
   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
-  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
-                                 NULL, NULL, NULL, NULL,
-                                 v8::External::New(&interceptor_call_count));
+  templ->SetNamedPropertyHandler(
+      InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
+      v8::External::New(CcTest::isolate(), &interceptor_call_count));
   LocalContext context;
   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   GenerateSomeGarbage();
@@ -11747,9 +11812,9 @@
   proto_templ->Set(v8_str("method"), method_templ);
   fun_templ->SetHiddenPrototype(true);
   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
-  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
-                                 NULL, NULL, NULL, NULL,
-                                 v8::External::New(&interceptor_call_count));
+  templ->SetNamedPropertyHandler(
+      InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
+      v8::External::New(CcTest::isolate(), &interceptor_call_count));
   LocalContext context;
   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   GenerateSomeGarbage();
diff --git a/test/cctest/test-cpu-profiler.cc b/test/cctest/test-cpu-profiler.cc
index 9ef307c..33444ea 100644
--- a/test/cctest/test-cpu-profiler.cc
+++ b/test/cctest/test-cpu-profiler.cc
@@ -718,7 +718,8 @@
       func_template->InstanceTemplate();
 
   TestApiCallbacks accessors(100);
-  v8::Local<v8::External> data = v8::External::New(&accessors);
+  v8::Local<v8::External> data =
+      v8::External::New(env->GetIsolate(), &accessors);
   instance_template->SetAccessor(
       v8::String::New("foo"), &TestApiCallbacks::Getter,
       &TestApiCallbacks::Setter, data);
@@ -758,7 +759,8 @@
       func_template->InstanceTemplate();
 
   TestApiCallbacks accessors(1);
-  v8::Local<v8::External> data = v8::External::New(&accessors);
+  v8::Local<v8::External> data =
+      v8::External::New(env->GetIsolate(), &accessors);
   instance_template->SetAccessor(
       v8::String::New("foo"), &TestApiCallbacks::Getter,
       &TestApiCallbacks::Setter, data);
@@ -807,7 +809,8 @@
   v8::HandleScope scope(env->GetIsolate());
 
   TestApiCallbacks callbacks(100);
-  v8::Local<v8::External> data = v8::External::New(&callbacks);
+  v8::Local<v8::External> data =
+      v8::External::New(env->GetIsolate(), &callbacks);
 
   v8::Local<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
   func_template->SetClassName(v8::String::New("Test_InstanceCostructor"));
@@ -844,7 +847,8 @@
   v8::HandleScope scope(env->GetIsolate());
 
   TestApiCallbacks callbacks(1);
-  v8::Local<v8::External> data = v8::External::New(&callbacks);
+  v8::Local<v8::External> data =
+      v8::External::New(env->GetIsolate(), &callbacks);
 
   v8::Local<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
   func_template->SetClassName(v8::String::New("Test_InstanceCostructor"));
diff --git a/test/cctest/test-decls.cc b/test/cctest/test-decls.cc
index de27286..1d09f9c 100644
--- a/test/cctest/test-decls.cc
+++ b/test/cctest/test-decls.cc
@@ -119,7 +119,7 @@
   Isolate* isolate = CcTest::isolate();
   HandleScope scope(isolate);
   Local<FunctionTemplate> function = FunctionTemplate::New();
-  Local<Value> data = External::New(this);
+  Local<Value> data = External::New(CcTest::isolate(), this);
   GetHolder(function)->SetNamedPropertyHandler(&HandleGet,
                                                &HandleSet,
                                                &HandleQuery,
diff --git a/test/cctest/test-macro-assembler-x64.cc b/test/cctest/test-macro-assembler-x64.cc
index 3d28fc0..a85d8e0 100644
--- a/test/cctest/test-macro-assembler-x64.cc
+++ b/test/cctest/test-macro-assembler-x64.cc
@@ -2327,8 +2327,8 @@
 
 TEST(OperandOffset) {
   i::V8::Initialize(NULL);
-  int data[256];
-  for (int i = 0; i < 256; i++) { data[i] = i * 0x01010101; }
+  uint32_t data[256];
+  for (uint32_t i = 0; i < 256; i++) { data[i] = i * 0x01010101; }
 
   // Allocate an executable page of memory.
   size_t actual_size;
diff --git a/test/mjsunit/compiler/minus-zero.js b/test/mjsunit/compiler/minus-zero.js
index 6efceb5..c161257 100644
--- a/test/mjsunit/compiler/minus-zero.js
+++ b/test/mjsunit/compiler/minus-zero.js
@@ -25,7 +25,7 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// Flags: --allow-natives-syntax
+// Flags: --allow-natives-syntax --no-fold-constants
 
 function add(x, y) {
   return x + y;
@@ -35,3 +35,59 @@
 assertEquals(0, add(0, 0));
 %OptimizeFunctionOnNextCall(add);
 assertEquals(-0, add(-0, -0));
+
+
+function test(x, y) {
+  assertTrue(%_IsMinusZero(-0));
+  assertTrue(%_IsMinusZero(1/(-Infinity)));
+  assertTrue(%_IsMinusZero(x));
+
+  assertFalse(%_IsMinusZero(0));
+  assertFalse(%_IsMinusZero(1/Infinity));
+  assertFalse(%_IsMinusZero(0.1));
+  assertFalse(%_IsMinusZero(-0.2));
+  assertFalse(%_IsMinusZero({}));
+  assertFalse(%_IsMinusZero(""));
+  assertFalse(%_IsMinusZero("-0"));
+  assertFalse(%_IsMinusZero(function() {}));
+  assertFalse(%_IsMinusZero(y));
+}
+
+test(-0, 1.2);
+test(-0, 1.2);
+%OptimizeFunctionOnNextCall(test);
+test(-0, 1.2);
+assertOptimized(test);
+
+
+function testsin() {
+  assertTrue(%_IsMinusZero(Math.sin(-0)));
+}
+
+testsin();
+testsin();
+%OptimizeFunctionOnNextCall(testsin);
+testsin();
+
+
+function testfloor() {
+  assertTrue(%_IsMinusZero(Math.floor(-0)));
+  assertFalse(%_IsMinusZero(Math.floor(2)));
+}
+
+testfloor();
+testfloor();
+%OptimizeFunctionOnNextCall(testfloor);
+testfloor();
+
+
+var double_one = Math.cos(0);
+
+function add(a, b) {
+  return a + b;
+}
+
+assertEquals(1, 1/add(double_one, 0));
+assertEquals(1, 1/add(0, double_one));
+%OptimizeFunctionOnNextCall(add);
+assertEquals(1/(-0 + -0), 1/add(-0, -0));
diff --git a/test/mjsunit/constant-folding-2.js b/test/mjsunit/constant-folding-2.js
index 9e6b2c6..f429c6c 100644
--- a/test/mjsunit/constant-folding-2.js
+++ b/test/mjsunit/constant-folding-2.js
@@ -128,30 +128,6 @@
   assertEquals("Infinity", String(1 / Math.max(0.0, -0.0)));
 });
 
-test(function mathSin() {
-  assertEquals(0.0, Math.sin(0.0));
-  assertTrue(0.8 < Math.sin(1) && Math.sin(1) < 0.9);
-  assertEquals("NaN", String(Math.sin(Infinity)));
-  assertEquals("NaN", String(Math.sin(-Infinity)));
-  assertEquals("NaN", String(Math.sin(NaN)));
-});
-
-test(function mathCos() {
-  assertEquals(1.0, Math.cos(0.0));
-  assertTrue(0.5 < Math.cos(1) && Math.cos(1) < 0.6);
-  assertEquals("NaN", String(Math.cos(Infinity)));
-  assertEquals("NaN", String(Math.cos(-Infinity)));
-  assertEquals("NaN", String(Math.cos(NaN)));
-});
-
-test(function mathTan() {
-  assertEquals(0.0, Math.tan(0.0));
-  assertTrue(1.5 < Math.tan(1) && Math.tan(1) < 1.6);
-  assertEquals("NaN", String(Math.tan(Infinity)));
-  assertEquals("NaN", String(Math.tan(-Infinity)));
-  assertEquals("NaN", String(Math.tan(NaN)));
-});
-
 test(function mathExp() {
   assertEquals(1.0, Math.exp(0.0));
   assertTrue(2.7 < Math.exp(1) && Math.exp(1) < 2.8);
diff --git a/test/mjsunit/harmony/private.js b/test/mjsunit/harmony/private.js
new file mode 100644
index 0000000..884e31b
--- /dev/null
+++ b/test/mjsunit/harmony/private.js
@@ -0,0 +1,324 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --harmony-symbols --harmony-collections
+// Flags: --expose-gc --allow-natives-syntax
+
+var symbols = []
+
+// Test different forms of constructor calls, all equivalent.
+function TestNew() {
+  for (var i = 0; i < 2; ++i) {
+    for (var j = 0; j < 5; ++j) {
+      symbols.push(%CreatePrivateSymbol("66"))
+      symbols.push(Object(%CreatePrivateSymbol("66")).valueOf())
+    }
+    gc()  // Promote existing symbols and then allocate some more.
+  }
+}
+TestNew()
+
+
+function TestType() {
+  for (var i in symbols) {
+    assertEquals("symbol", typeof symbols[i])
+    assertTrue(typeof symbols[i] === "symbol")
+    assertTrue(%SymbolIsPrivate(symbols[i]))
+    assertEquals(null, %_ClassOf(symbols[i]))
+    assertEquals("Symbol", %_ClassOf(new Symbol(symbols[i])))
+    assertEquals("Symbol", %_ClassOf(Object(symbols[i])))
+  }
+}
+TestType()
+
+
+function TestPrototype() {
+  for (var i in symbols) {
+    assertSame(Symbol.prototype, symbols[i].__proto__)
+  }
+}
+TestPrototype()
+
+
+function TestConstructor() {
+  for (var i in symbols) {
+    assertSame(Symbol, symbols[i].__proto__.constructor)
+  }
+}
+TestConstructor()
+
+
+function TestName() {
+  for (var i in symbols) {
+    var name = symbols[i].name
+    assertTrue(name === "66")
+  }
+}
+TestName()
+
+
+function TestToString() {
+  for (var i in symbols) {
+    assertThrows(function() { String(symbols[i]) }, TypeError)
+    assertThrows(function() { symbols[i] + "" }, TypeError)
+    assertThrows(function() { symbols[i].toString() }, TypeError)
+    assertThrows(function() { (new Symbol(symbols[i])).toString() }, TypeError)
+    assertThrows(function() { Object(symbols[i]).toString() }, TypeError)
+    assertEquals("[object Symbol]", Object.prototype.toString.call(symbols[i]))
+  }
+}
+TestToString()
+
+
+function TestToBoolean() {
+  for (var i in symbols) {
+    assertTrue(Boolean(symbols[i]).valueOf())
+    assertFalse(!symbols[i])
+    assertTrue(!!symbols[i])
+    assertTrue(symbols[i] && true)
+    assertFalse(!symbols[i] && false)
+    assertTrue(!symbols[i] || true)
+    assertEquals(1, symbols[i] ? 1 : 2)
+    assertEquals(2, !symbols[i] ? 1 : 2)
+    if (!symbols[i]) assertUnreachable();
+    if (symbols[i]) {} else assertUnreachable();
+  }
+}
+TestToBoolean()
+
+
+function TestToNumber() {
+  for (var i in symbols) {
+    assertSame(NaN, Number(symbols[i]).valueOf())
+    assertSame(NaN, symbols[i] + 0)
+  }
+}
+TestToNumber()
+
+
+function TestEquality() {
+  // Every symbol should equal itself, and non-strictly equal its wrapper.
+  for (var i in symbols) {
+    assertSame(symbols[i], symbols[i])
+    assertEquals(symbols[i], symbols[i])
+    assertTrue(Object.is(symbols[i], symbols[i]))
+    assertTrue(symbols[i] === symbols[i])
+    assertTrue(symbols[i] == symbols[i])
+    assertFalse(symbols[i] === new Symbol(symbols[i]))
+    assertFalse(new Symbol(symbols[i]) === symbols[i])
+    assertTrue(symbols[i] == new Symbol(symbols[i]))
+    assertTrue(new Symbol(symbols[i]) == symbols[i])
+  }
+
+  // All symbols should be distinct.
+  for (var i = 0; i < symbols.length; ++i) {
+    for (var j = i + 1; j < symbols.length; ++j) {
+      assertFalse(Object.is(symbols[i], symbols[j]))
+      assertFalse(symbols[i] === symbols[j])
+      assertFalse(symbols[i] == symbols[j])
+    }
+  }
+
+  // Symbols should not be equal to any other value (and the test terminates).
+  var values = [347, 1.275, NaN, "string", null, undefined, {}, function() {}]
+  for (var i in symbols) {
+    for (var j in values) {
+      assertFalse(symbols[i] === values[j])
+      assertFalse(values[j] === symbols[i])
+      assertFalse(symbols[i] == values[j])
+      assertFalse(values[j] == symbols[i])
+    }
+  }
+}
+TestEquality()
+
+
+function TestGet() {
+  for (var i in symbols) {
+    assertThrows(function() { symbols[i].toString() }, TypeError)
+    assertEquals(symbols[i], symbols[i].valueOf())
+    assertEquals(undefined, symbols[i].a)
+    assertEquals(undefined, symbols[i]["a" + "b"])
+    assertEquals(undefined, symbols[i]["" + "1"])
+    assertEquals(undefined, symbols[i][62])
+  }
+}
+TestGet()
+
+
+function TestSet() {
+  for (var i in symbols) {
+    symbols[i].toString = 0
+    assertThrows(function() { symbols[i].toString() }, TypeError)
+    symbols[i].valueOf = 0
+    assertEquals(symbols[i], symbols[i].valueOf())
+    symbols[i].a = 0
+    assertEquals(undefined, symbols[i].a)
+    symbols[i]["a" + "b"] = 0
+    assertEquals(undefined, symbols[i]["a" + "b"])
+    symbols[i][62] = 0
+    assertEquals(undefined, symbols[i][62])
+  }
+}
+TestSet()
+
+
+function TestCollections() {
+  var set = new Set
+  var map = new Map
+  var weakmap = new WeakMap
+  for (var i in symbols) {
+    set.add(symbols[i])
+    map.set(symbols[i], i)
+    weakmap.set(symbols[i], i)
+  }
+  assertEquals(symbols.length, set.size)
+  assertEquals(symbols.length, map.size)
+  for (var i in symbols) {
+    assertTrue(set.has(symbols[i]))
+    assertTrue(map.has(symbols[i]))
+    assertTrue(weakmap.has(symbols[i]))
+    assertEquals(i, map.get(symbols[i]))
+    assertEquals(i, weakmap.get(symbols[i]))
+  }
+  for (var i in symbols) {
+    assertTrue(set.delete(symbols[i]))
+    assertTrue(map.delete(symbols[i]))
+    assertTrue(weakmap.delete(symbols[i]))
+  }
+  assertEquals(0, set.size)
+  assertEquals(0, map.size)
+}
+TestCollections()
+
+
+
+function TestKeySet(obj) {
+  assertTrue(%HasFastProperties(obj))
+  // Set the even symbols via assignment.
+  for (var i = 0; i < symbols.length; i += 2) {
+    obj[symbols[i]] = i
+    // Object should remain in fast mode until too many properties were added.
+    assertTrue(%HasFastProperties(obj) || i >= 30)
+  }
+}
+
+
+function TestKeyDefine(obj) {
+  // Set the odd symbols via defineProperty (as non-enumerable).
+  for (var i = 1; i < symbols.length; i += 2) {
+    Object.defineProperty(obj, symbols[i], {value: i, configurable: true})
+  }
+}
+
+
+function TestKeyGet(obj) {
+  var obj2 = Object.create(obj)
+  for (var i in symbols) {
+    assertEquals(i|0, obj[symbols[i]])
+    assertEquals(i|0, obj2[symbols[i]])
+  }
+}
+
+
+function TestKeyHas() {
+  for (var i in symbols) {
+    assertTrue(symbols[i] in obj)
+    assertTrue(Object.hasOwnProperty.call(obj, symbols[i]))
+  }
+}
+
+
+function TestKeyEnum(obj) {
+  for (var name in obj) {
+    assertEquals("string", typeof name)
+  }
+}
+
+
+function TestKeyNames(obj) {
+  assertEquals(0, Object.keys(obj).length)
+
+  var names = Object.getOwnPropertyNames(obj)
+  for (var i in names) {
+    assertEquals("string", typeof names[i])
+  }
+}
+
+
+function TestKeyDescriptor(obj) {
+  for (var i in symbols) {
+    var desc = Object.getOwnPropertyDescriptor(obj, symbols[i]);
+    assertEquals(i|0, desc.value)
+    assertTrue(desc.configurable)
+    assertEquals(i % 2 == 0, desc.writable)
+    assertEquals(i % 2 == 0, desc.enumerable)
+    assertEquals(i % 2 == 0,
+        Object.prototype.propertyIsEnumerable.call(obj, symbols[i]))
+  }
+}
+
+
+function TestKeyDelete(obj) {
+  for (var i in symbols) {
+    delete obj[symbols[i]]
+  }
+  for (var i in symbols) {
+    assertEquals(undefined, Object.getOwnPropertyDescriptor(obj, symbols[i]))
+  }
+}
+
+
+var objs = [{}, [], Object.create(null), Object(1), new Map, function(){}]
+
+for (var i in objs) {
+  var obj = objs[i]
+  TestKeySet(obj)
+  TestKeyDefine(obj)
+  TestKeyGet(obj)
+  TestKeyHas(obj)
+  TestKeyEnum(obj)
+  TestKeyNames(obj)
+  TestKeyDescriptor(obj)
+  TestKeyDelete(obj)
+}
+
+
+function TestCachedKeyAfterScavenge() {
+  gc();
+  // Keyed property lookup are cached.  Hereby we assume that the keys are
+  // tenured, so that we only have to clear the cache between mark compacts,
+  // but not between scavenges.  This must also apply for symbol keys.
+  var key = Symbol("key");
+  var a = {};
+  a[key] = "abc";
+
+  for (var i = 0; i < 1000000; i++) {
+    a[key] += "a";  // Allocations cause a scavenge.
+  }
+}
+TestCachedKeyAfterScavenge();
diff --git a/test/mjsunit/harmony/symbols.js b/test/mjsunit/harmony/symbols.js
index 5eaa1a3..1fc3945 100644
--- a/test/mjsunit/harmony/symbols.js
+++ b/test/mjsunit/harmony/symbols.js
@@ -59,6 +59,7 @@
   for (var i in symbols) {
     assertEquals("symbol", typeof symbols[i])
     assertTrue(typeof symbols[i] === "symbol")
+    assertFalse(%SymbolIsPrivate(symbols[i]))
     assertEquals(null, %_ClassOf(symbols[i]))
     assertEquals("Symbol", %_ClassOf(new Symbol(symbols[i])))
     assertEquals("Symbol", %_ClassOf(Object(symbols[i])))
diff --git a/test/mjsunit/new-string-add.js b/test/mjsunit/new-string-add.js
new file mode 100644
index 0000000..f5b7cbf
--- /dev/null
+++ b/test/mjsunit/new-string-add.js
@@ -0,0 +1,197 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --new-string-add
+
+assertEquals("ab", "a" + "b", "ll");
+
+assertEquals("12", "1" + "2", "dd");
+assertEquals("123", "1" + "2" + "3", "ddd");
+assertEquals("123", 1 + "2" + "3", "ndd");
+assertEquals("123", "1" + 2 + "3", "dnd");
+assertEquals("123", "1" + "2" + 3, "ddn");
+
+assertEquals("123", "1" + 2 + 3, "dnn");
+assertEquals("123", 1 + "2" + 3, "ndn");
+assertEquals("33", 1 + 2 + "3", "nnd");
+
+var x = "1";
+assertEquals("12", x + 2, "vn");
+assertEquals("12", x + "2", "vd");
+assertEquals("21", 2 + x, "nv");
+assertEquals("21", "2" + x, "dv");
+
+var y = "2";
+assertEquals("12", x + y, "vdvd");
+
+x = 1;
+assertEquals("12", x + y, "vnvd");
+
+y = 2;
+assertEquals(3, x + y, "vnvn");
+
+x = "1";
+assertEquals("12", x + y, "vdvn");
+
+y = "2";
+assertEquals("12", x + y, "vdvd2");
+
+(function(x, y) {
+  var z = "3";
+  var w = "4";
+
+  assertEquals("11", x + x, "xx");
+  assertEquals("12", x + y, "xy");
+  assertEquals("13", x + z, "xz");
+  assertEquals("14", x + w, "xw");
+
+  assertEquals("21", y + x, "yx");
+  assertEquals("22", y + y, "yy");
+  assertEquals("23", y + z, "yz");
+  assertEquals("24", y + w, "yw");
+
+  assertEquals("31", z + x, "zx");
+  assertEquals("32", z + y, "zy");
+  assertEquals("33", z + z, "zz");
+  assertEquals("34", z + w, "zw");
+
+  assertEquals("41", w + x, "wx");
+  assertEquals("42", w + y, "wy");
+  assertEquals("43", w + z, "wz");
+  assertEquals("44", w + w, "ww");
+
+  (function(){x = 1; z = 3;})();
+
+  assertEquals(2, x + x, "x'x");
+  assertEquals("12", x + y, "x'y");
+  assertEquals(4, x + z, "x'z'");
+  assertEquals("14", x + w, "x'w");
+
+  assertEquals("21", y + x, "yx'");
+  assertEquals("22", y + y, "yy");
+  assertEquals("23", y + z, "yz'");
+  assertEquals("24", y + w, "yw");
+
+  assertEquals(4, z + x, "z'x'");
+  assertEquals("32", z + y, "z'y");
+  assertEquals(6, z + z, "z'z'");
+  assertEquals("34", z + w, "z'w");
+
+  assertEquals("41", w + x, "wx'");
+  assertEquals("42", w + y, "wy");
+  assertEquals("43", w + z, "wz'");
+  assertEquals("44", w + w, "ww");
+})("1", "2");
+
+assertEquals("142", "1" + new Number(42), "sN");
+assertEquals("421", new Number(42) + "1", "Ns");
+assertEquals(84, new Number(42) + new Number(42), "NN");
+
+assertEquals("142", "1" + new String("42"), "sS");
+assertEquals("421", new String("42") + "1", "Ss");
+assertEquals("142", "1" + new String("42"), "sS");
+assertEquals("4242", new String("42") + new String("42"), "SS");
+
+assertEquals("1true", "1" + true, "sb");
+assertEquals("true1", true + "1", "bs");
+assertEquals(2, true + true, "bs");
+
+assertEquals("1true", "1" + new Boolean(true), "sB");
+assertEquals("true1", new Boolean(true) + "1", "Bs");
+assertEquals(2, new Boolean(true) + new Boolean(true), "Bs");
+
+assertEquals("1undefined", "1" + void 0, "sv");
+assertEquals("undefined1", (void 0)  + "1", "vs");
+assertTrue(isNaN(void 0 + void 0), "vv");
+
+assertEquals("1null", "1" + null, "su");
+assertEquals("null1", null + "1", "us");
+assertEquals(0, null + null, "uu");
+
+(function (i) {
+  // Check that incoming frames are merged correctly.
+  var x;
+  var y;
+  var z;
+  var w;
+  switch (i) {
+  case 1: x = 42; y = "stry"; z = "strz"; w = 42; break;
+  default: x = "strx", y = 42; z = "strz"; w = 42; break;
+  }
+  var resxx = x + x;
+  var resxy = x + y;
+  var resxz = x + z;
+  var resxw = x + w;
+  var resyx = y + x;
+  var resyy = y + y;
+  var resyz = y + z;
+  var resyw = y + w;
+  var reszx = z + x;
+  var reszy = z + y;
+  var reszz = z + z;
+  var reszw = z + w;
+  var reswx = w + x;
+  var reswy = w + y;
+  var reswz = w + z;
+  var resww = w + w;
+  assertEquals(84, resxx, "swxx");
+  assertEquals("42stry", resxy, "swxy");
+  assertEquals("42strz", resxz, "swxz");
+  assertEquals(84, resxw, "swxw");
+  assertEquals("stry42", resyx, "swyx");
+  assertEquals("strystry", resyy, "swyy");
+  assertEquals("strystrz", resyz, "swyz");
+  assertEquals("stry42", resyw, "swyw");
+  assertEquals("strz42", reszx, "swzx");
+  assertEquals("strzstry", reszy, "swzy");
+  assertEquals("strzstrz", reszz, "swzz");
+  assertEquals("strz42", reszw, "swzw");
+  assertEquals(84, reswx, "swwx");
+  assertEquals("42stry", reswy, "swwy");
+  assertEquals("42strz", reswz, "swwz");
+  assertEquals(84, resww, "swww");
+})(1);
+
+// Generate ascii and non ascii strings from length 0 to 20.
+var ascii = 'aaaaaaaaaaaaaaaaaaaa';
+var non_ascii = '\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234';
+assertEquals(20, ascii.length);
+assertEquals(20, non_ascii.length);
+var a = Array(21);
+var b = Array(21);
+for (var i = 0; i <= 20; i++) {
+  a[i] = ascii.substring(0, i);
+  b[i] = non_ascii.substring(0, i);
+}
+
+// Add ascii and non-ascii strings generating strings with length from 0 to 20.
+for (var i = 0; i <= 20; i++) {
+  for (var j = 0; j < i; j++) {
+    assertEquals(a[i], a[j] + a[i - j])
+    assertEquals(b[i], b[j] + b[i - j])
+  }
+}
diff --git a/test/mjsunit/sin-cos.js b/test/mjsunit/sin-cos.js
index e38dfdf..1176b6c 100644
--- a/test/mjsunit/sin-cos.js
+++ b/test/mjsunit/sin-cos.js
@@ -42,9 +42,102 @@
 
 // By accident, the slow case for sine and cosine were both sine at
 // some point.  This is a regression test for that issue.
-var x = Math.pow(2, 70);
+var x = Math.pow(2, 30);
 assertTrue(Math.sin(x) != Math.cos(x));
 
 // Ensure that sine and log are not the same.
 x = 0.5;
 assertTrue(Math.sin(x) != Math.log(x));
+
+// Test against approximation by series.
+var factorial = [1];
+var accuracy = 50;
+for (var i = 1; i < accuracy; i++) {
+  factorial[i] = factorial[i-1] * i;
+}
+
+// We sum up in the reverse order for higher precision, as we expect the terms
+// to grow smaller for x reasonably close to 0.
+function precision_sum(array) {
+  var result = 0;
+  while (array.length > 0) {
+    result += array.pop();
+  }
+  return result;
+}
+
+function sin(x) {
+  var sign = 1;
+  var x2 = x*x;
+  var terms = [];
+  for (var i = 1; i < accuracy; i += 2) {
+    terms.push(sign * x / factorial[i]);
+    x *= x2;
+    sign *= -1;
+  }
+  return precision_sum(terms);
+}
+
+function cos(x) {
+  var sign = -1;
+  var x2 = x*x;
+  x = x2;
+  var terms = [1];
+  for (var i = 2; i < accuracy; i += 2) {
+    terms.push(sign * x / factorial[i]);
+    x *= x2;
+    sign *= -1;
+  }
+  return precision_sum(terms);
+}
+
+function abs_error(fun, ref, x) {
+  return Math.abs(ref(x) - fun(x));
+}
+
+var test_inputs = [];
+for (var i = -10000; i < 10000; i += 177) test_inputs.push(i/1257);
+var epsilon = 0.000001;
+
+test_inputs.push(0);
+test_inputs.push(0 + epsilon);
+test_inputs.push(0 - epsilon);
+test_inputs.push(Math.PI/2);
+test_inputs.push(Math.PI/2 + epsilon);
+test_inputs.push(Math.PI/2 - epsilon);
+test_inputs.push(Math.PI);
+test_inputs.push(Math.PI + epsilon);
+test_inputs.push(Math.PI - epsilon);
+test_inputs.push(- 2*Math.PI);
+test_inputs.push(- 2*Math.PI + epsilon);
+test_inputs.push(- 2*Math.PI - epsilon);
+
+var squares = [];
+for (var i = 0; i < test_inputs.length; i++) {
+  var x = test_inputs[i];
+  var err_sin = abs_error(Math.sin, sin, x);
+  var err_cos = abs_error(Math.cos, cos, x)
+  assertTrue(err_sin < 1E-13);
+  assertTrue(err_cos < 1E-13);
+  squares.push(err_sin*err_sin + err_cos*err_cos);
+}
+
+// Sum squares up by adding them pairwise, to avoid losing precision.
+while (squares.length > 1) {
+  var reduced = [];
+  if (squares.length % 2 == 1) reduced.push(squares.pop());
+  // Remaining number of elements is even.
+  while(squares.length > 1) reduced.push(squares.pop() + squares.pop());
+  squares = reduced;
+}
+
+var err_rms = Math.sqrt(squares[0] / test_inputs.length / 2);
+assertTrue(err_rms < 1E-14);
+
+assertEquals(-1, Math.cos({ valueOf: function() { return Math.PI; } }));
+assertEquals(0, Math.sin("0x00000"));
+assertEquals(1, Math.cos("0x00000"));
+assertTrue(isNaN(Math.sin(Infinity)));
+assertTrue(isNaN(Math.cos("-Infinity")));
+assertEquals("Infinity", String(Math.tan(Math.PI/2)));
+assertEquals("-Infinity", String(Math.tan(-Math.PI/2)));
diff --git a/test/mozilla/mozilla.status b/test/mozilla/mozilla.status
index b27e991..9e23dce 100644
--- a/test/mozilla/mozilla.status
+++ b/test/mozilla/mozilla.status
@@ -600,6 +600,9 @@
   'ecma/TypeConversion/9.3.1-3': [FAIL_OK],
 
 
+  # Math.tan expectations are more strict than the spec.
+  'ecma/Math/15.8.2.18': [FAIL_OK],
+
   ##################### FAILING TESTS #####################
 
   # This section is for tests that fail in V8 and pass in JSC.
diff --git a/test/test262/test262.status b/test/test262/test262.status
index e546266..80a302b 100644
--- a/test/test262/test262.status
+++ b/test/test262/test262.status
@@ -73,6 +73,7 @@
   # trigonometric functions are platform/compiler dependent.  Furthermore, the
   # expectation values by far deviates from the actual result given by an
   # arbitrary-precision calculator, making those tests partly bogus.
+  'S15.8.2.7_A7': [PASS, FAIL_OK],  # Math.cos
   'S15.8.2.8_A6': [PASS, FAIL_OK],  # Math.exp (less precise with --fast-math)
   'S15.8.2.16_A7': [PASS, FAIL_OK],  # Math.sin
   'S15.8.2.18_A7': [PASS, FAIL_OK],  # Math.tan
diff --git a/test/webkit/webkit.status b/test/webkit/webkit.status
index bd22741..98935f7 100644
--- a/test/webkit/webkit.status
+++ b/test/webkit/webkit.status
@@ -30,8 +30,10 @@
   ##############################################################################
   # Flaky tests.
   # BUG(v8:2989).
+  'dfg-inline-arguments-become-double': [PASS, FLAKY],
   'dfg-inline-arguments-become-int32': [PASS, FLAKY],
   'dfg-inline-arguments-reset': [PASS, FLAKY],
+  'dfg-inline-arguments-reset-changetype': [PASS, FLAKY],
 }],  # ALWAYS
 ['mode == debug', {
   # Too slow in debug mode.
diff --git a/tools/push-to-trunk/common_includes.py b/tools/push-to-trunk/common_includes.py
index 3b2eab0..eb2bfb0 100644
--- a/tools/push-to-trunk/common_includes.py
+++ b/tools/push-to-trunk/common_includes.py
@@ -67,6 +67,14 @@
   return re.sub(rexp, replacement, text, flags=re.MULTILINE)
 
 
+def GetLastChangeLogEntries(change_log_file):
+  result = []
+  for line in LinesInFile(change_log_file):
+    if re.search(r"^\d{4}-\d{2}-\d{2}:", line) and result: break
+    result.append(line)
+  return "".join(result)
+
+
 # Some commands don't like the pipe, e.g. calling vi from within the script or
 # from subscripts like git cl upload.
 def Command(cmd, args="", prefix="", pipe=True):
diff --git a/tools/push-to-trunk/push_to_trunk.py b/tools/push-to-trunk/push_to_trunk.py
index 6ec03cb..9f72cd2 100755
--- a/tools/push-to-trunk/push_to_trunk.py
+++ b/tools/push-to-trunk/push_to_trunk.py
@@ -221,18 +221,10 @@
     self.WaitForLGTM()
     # Re-read the ChangeLog entry (to pick up possible changes).
     # FIXME(machenbach): This was hanging once with a broken pipe.
-    TextToFile(Command("cat %s | awk --posix '{\
-        if ($0 ~ /^[0-9]{4}-[0-9]{2}-[0-9]{2}:/) {\
-          if (in_firstblock == 1) {\
-            exit 0;\
-          } else {\
-            in_firstblock = 1;\
-          }\
-        };\
-        print $0;\
-      }'" % self.Config(CHANGELOG_FILE)), self.Config(CHANGELOG_ENTRY_FILE))
+    TextToFile(GetLastChangeLogEntries(self.Config(CHANGELOG_FILE)),
+               self.Config(CHANGELOG_ENTRY_FILE))
 
-    if self.Git("cl dcommit", "PRESUBMIT_TREE_CHECK=\"skip\"") is None:
+    if self.Git("cl dcommit -v", "PRESUBMIT_TREE_CHECK=\"skip\"") is None:
       self.Die("'git cl dcommit' failed, please try again.")
 
 
diff --git a/tools/push-to-trunk/test_scripts.py b/tools/push-to-trunk/test_scripts.py
index 9865ada..0975b0d 100644
--- a/tools/push-to-trunk/test_scripts.py
+++ b/tools/push-to-trunk/test_scripts.py
@@ -287,6 +287,22 @@
     self.assertEquals("6", self.MakeStep().Restore("new_build"))
     self.assertEquals("0", self.MakeStep().Restore("new_patch"))
 
+  def testLastChangeLogEntries(self):
+    TEST_CONFIG[CHANGELOG_FILE] = self.MakeEmptyTempFile()
+    l = """
+        Fixed something.
+        (issue 1234)\n"""
+    for _ in xrange(10): l = l + l
+
+    cl_chunk = """2013-11-12: Version 3.23.2\n%s
+        Performance and stability improvements on all platforms.\n\n\n""" % l
+
+    cl_chunk_full = cl_chunk + cl_chunk + cl_chunk
+    TextToFile(cl_chunk_full, TEST_CONFIG[CHANGELOG_FILE])
+
+    cl = GetLastChangeLogEntries(TEST_CONFIG[CHANGELOG_FILE])
+    self.assertEquals(cl_chunk, cl)
+
   def testSquashCommits(self):
     TEST_CONFIG[CHANGELOG_ENTRY_FILE] = self.MakeEmptyTempFile()
     with open(TEST_CONFIG[CHANGELOG_ENTRY_FILE], "w") as f:
@@ -368,7 +384,7 @@
        " 2 files changed\n",
         CheckPreparePush],
       ["cl upload -r \"reviewer@chromium.org\" --send-mail", "done\n"],
-      ["cl dcommit", "Closing issue\n"],
+      ["cl dcommit -v", "Closing issue\n"],
       ["svn fetch", "fetch result\n"],
       ["checkout svn/bleeding_edge", ""],
       [("log -1 --format=%H --grep=\"Prepare push to trunk.  "