Version 2.2.23

API change: Convert Unicode code points outside the basic multilingual
plane to the replacement character.  Previous behavior was to silently
truncate the value to 16 bits.

Fixed crash: handle all flat string types in regexp replace.

Prevent invalid pre-parsing data passed in through the API from
crashing V8.

Performance improvements on all platforms.
Review URL: http://codereview.chromium.org/2814050

git-svn-id: http://v8.googlecode.com/svn/trunk@5033 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc
index 4d18727..fa6efcd 100644
--- a/src/arm/codegen-arm.cc
+++ b/src/arm/codegen-arm.cc
@@ -5423,9 +5423,13 @@
     frame_->EmitPush(r0);  // r0 has result
 
   } else {
-    bool overwrite =
+    bool can_overwrite =
         (node->expression()->AsBinaryOperation() != NULL &&
          node->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
+    UnaryOverwriteMode overwrite =
+        can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
+
+    bool no_negative_zero = node->expression()->no_negative_zero();
     Load(node->expression());
     switch (op) {
       case Token::NOT:
@@ -5436,7 +5440,10 @@
 
       case Token::SUB: {
         frame_->PopToR0();
-        GenericUnaryOpStub stub(Token::SUB, overwrite);
+        GenericUnaryOpStub stub(
+            Token::SUB,
+            overwrite,
+            no_negative_zero ? kIgnoreNegativeZero : kStrictNegativeZero);
         frame_->CallStub(&stub, 0);
         frame_->EmitPush(r0);  // r0 has result
         break;
@@ -7641,187 +7648,195 @@
     __ Swap(r0, r1, ip);
   }
 
-  if (ShouldGenerateFPCode()) {
-    Label r0_is_smi, r1_is_smi, finished_loading_r0, finished_loading_r1;
+  // The type transition also calculates the answer.
+  bool generate_code_to_calculate_answer = true;
 
+  if (ShouldGenerateFPCode()) {
     if (runtime_operands_type_ == BinaryOpIC::DEFAULT) {
       switch (op_) {
         case Token::ADD:
         case Token::SUB:
         case Token::MUL:
         case Token::DIV:
-          GenerateTypeTransition(masm);
+          GenerateTypeTransition(masm);  // Tail call.
+          generate_code_to_calculate_answer = false;
           break;
 
         default:
           break;
       }
-      // Restore heap number map register.
-      __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
     }
 
-    if (mode_ == NO_OVERWRITE) {
-      // In the case where there is no chance of an overwritable float we may as
-      // well do the allocation immediately while r0 and r1 are untouched.
-      __ AllocateHeapNumber(r5, r3, r7, heap_number_map, &slow);
-    }
-
-    // Move r0 to a double in r2-r3.
-    __ tst(r0, Operand(kSmiTagMask));
-    __ b(eq, &r0_is_smi);  // It's a Smi so don't check it's a heap number.
-    __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset));
-    __ AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
-    __ cmp(r4, heap_number_map);
-    __ b(ne, &slow);
-    if (mode_ == OVERWRITE_RIGHT) {
-      __ mov(r5, Operand(r0));  // Overwrite this heap number.
-    }
-    if (use_fp_registers) {
-      CpuFeatures::Scope scope(VFP3);
-      // Load the double from tagged HeapNumber r0 to d7.
-      __ sub(r7, r0, Operand(kHeapObjectTag));
-      __ vldr(d7, r7, HeapNumber::kValueOffset);
-    } else {
-      // Calling convention says that second double is in r2 and r3.
-      __ Ldrd(r2, r3, FieldMemOperand(r0, HeapNumber::kValueOffset));
-    }
-    __ jmp(&finished_loading_r0);
-    __ bind(&r0_is_smi);
-    if (mode_ == OVERWRITE_RIGHT) {
-      // We can't overwrite a Smi so get address of new heap number into r5.
-    __ AllocateHeapNumber(r5, r4, r7, heap_number_map, &slow);
-    }
-
-    if (CpuFeatures::IsSupported(VFP3)) {
-      CpuFeatures::Scope scope(VFP3);
-      // Convert smi in r0 to double in d7.
-      __ mov(r7, Operand(r0, ASR, kSmiTagSize));
-      __ vmov(s15, r7);
-      __ vcvt_f64_s32(d7, s15);
-      if (!use_fp_registers) {
-        __ vmov(r2, r3, d7);
+    if (generate_code_to_calculate_answer) {
+      Label r0_is_smi, r1_is_smi, finished_loading_r0, finished_loading_r1;
+      if (mode_ == NO_OVERWRITE) {
+        // In the case where there is no chance of an overwritable float we may
+        // as well do the allocation immediately while r0 and r1 are untouched.
+        __ AllocateHeapNumber(r5, r3, r7, heap_number_map, &slow);
       }
-    } else {
-      // Write Smi from r0 to r3 and r2 in double format.
-      __ mov(r7, Operand(r0));
-      ConvertToDoubleStub stub3(r3, r2, r7, r4);
-      __ push(lr);
-      __ Call(stub3.GetCode(), RelocInfo::CODE_TARGET);
-      __ pop(lr);
-    }
 
-    // HEAP_NUMBERS stub is slower than GENERIC on a pair of smis.
-    // r0 is known to be a smi. If r1 is also a smi then switch to GENERIC.
-    Label r1_is_not_smi;
-    if (runtime_operands_type_ == BinaryOpIC::HEAP_NUMBERS) {
-      __ tst(r1, Operand(kSmiTagMask));
-      __ b(ne, &r1_is_not_smi);
-      GenerateTypeTransition(masm);
-      // Restore heap number map register.
-      __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
-      __ jmp(&r1_is_smi);
-    }
-
-    __ bind(&finished_loading_r0);
-
-    // Move r1 to a double in r0-r1.
-    __ tst(r1, Operand(kSmiTagMask));
-    __ b(eq, &r1_is_smi);  // It's a Smi so don't check it's a heap number.
-    __ bind(&r1_is_not_smi);
-    __ ldr(r4, FieldMemOperand(r1, HeapNumber::kMapOffset));
-    __ AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
-    __ cmp(r4, heap_number_map);
-    __ b(ne, &slow);
-    if (mode_ == OVERWRITE_LEFT) {
-      __ mov(r5, Operand(r1));  // Overwrite this heap number.
-    }
-    if (use_fp_registers) {
-      CpuFeatures::Scope scope(VFP3);
-      // Load the double from tagged HeapNumber r1 to d6.
-      __ sub(r7, r1, Operand(kHeapObjectTag));
-      __ vldr(d6, r7, HeapNumber::kValueOffset);
-    } else {
-      // Calling convention says that first double is in r0 and r1.
-      __ Ldrd(r0, r1, FieldMemOperand(r1, HeapNumber::kValueOffset));
-    }
-    __ jmp(&finished_loading_r1);
-    __ bind(&r1_is_smi);
-    if (mode_ == OVERWRITE_LEFT) {
-      // We can't overwrite a Smi so get address of new heap number into r5.
-    __ AllocateHeapNumber(r5, r4, r7, heap_number_map, &slow);
-    }
-
-    if (CpuFeatures::IsSupported(VFP3)) {
-      CpuFeatures::Scope scope(VFP3);
-      // Convert smi in r1 to double in d6.
-      __ mov(r7, Operand(r1, ASR, kSmiTagSize));
-      __ vmov(s13, r7);
-      __ vcvt_f64_s32(d6, s13);
-      if (!use_fp_registers) {
-        __ vmov(r0, r1, d6);
+      // Move r0 to a double in r2-r3.
+      __ tst(r0, Operand(kSmiTagMask));
+      __ b(eq, &r0_is_smi);  // It's a Smi so don't check it's a heap number.
+      __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset));
+      __ AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
+      __ cmp(r4, heap_number_map);
+      __ b(ne, &slow);
+      if (mode_ == OVERWRITE_RIGHT) {
+        __ mov(r5, Operand(r0));  // Overwrite this heap number.
       }
-    } else {
-      // Write Smi from r1 to r1 and r0 in double format.
-      __ mov(r7, Operand(r1));
-      ConvertToDoubleStub stub4(r1, r0, r7, r9);
-      __ push(lr);
-      __ Call(stub4.GetCode(), RelocInfo::CODE_TARGET);
-      __ pop(lr);
-    }
-
-    __ bind(&finished_loading_r1);
-
-    __ bind(&do_the_call);
-    // If we are inlining the operation using VFP3 instructions for
-    // add, subtract, multiply, or divide, the arguments are in d6 and d7.
-    if (use_fp_registers) {
-      CpuFeatures::Scope scope(VFP3);
-      // ARMv7 VFP3 instructions to implement
-      // double precision, add, subtract, multiply, divide.
-
-      if (Token::MUL == op_) {
-        __ vmul(d5, d6, d7);
-      } else if (Token::DIV == op_) {
-        __ vdiv(d5, d6, d7);
-      } else if (Token::ADD == op_) {
-        __ vadd(d5, d6, d7);
-      } else if (Token::SUB == op_) {
-        __ vsub(d5, d6, d7);
+      if (use_fp_registers) {
+        CpuFeatures::Scope scope(VFP3);
+        // Load the double from tagged HeapNumber r0 to d7.
+        __ sub(r7, r0, Operand(kHeapObjectTag));
+        __ vldr(d7, r7, HeapNumber::kValueOffset);
       } else {
-        UNREACHABLE();
+        // Calling convention says that second double is in r2 and r3.
+        __ Ldrd(r2, r3, FieldMemOperand(r0, HeapNumber::kValueOffset));
       }
-      __ sub(r0, r5, Operand(kHeapObjectTag));
-      __ vstr(d5, r0, HeapNumber::kValueOffset);
-      __ add(r0, r0, Operand(kHeapObjectTag));
-      __ mov(pc, lr);
-    } else {
-      // If we did not inline the operation, then the arguments are in:
-      // r0: Left value (least significant part of mantissa).
-      // r1: Left value (sign, exponent, top of mantissa).
-      // r2: Right value (least significant part of mantissa).
-      // r3: Right value (sign, exponent, top of mantissa).
-      // r5: Address of heap number for result.
+      __ jmp(&finished_loading_r0);
+      __ bind(&r0_is_smi);
+      if (mode_ == OVERWRITE_RIGHT) {
+        // We can't overwrite a Smi so get address of new heap number into r5.
+      __ AllocateHeapNumber(r5, r4, r7, heap_number_map, &slow);
+      }
 
-      __ push(lr);   // For later.
-      __ PrepareCallCFunction(4, r4);  // Two doubles count as 4 arguments.
-      // Call C routine that may not cause GC or other trouble. r5 is callee
-      // save.
-      __ CallCFunction(ExternalReference::double_fp_operation(op_), 4);
-      // Store answer in the overwritable heap number.
-  #if !defined(USE_ARM_EABI)
-      // Double returned in fp coprocessor register 0 and 1, encoded as register
-      // cr8.  Offsets must be divisible by 4 for coprocessor so we need to
-      // substract the tag from r5.
-      __ sub(r4, r5, Operand(kHeapObjectTag));
-      __ stc(p1, cr8, MemOperand(r4, HeapNumber::kValueOffset));
-  #else
-      // Double returned in registers 0 and 1.
-      __ Strd(r0, r1, FieldMemOperand(r5, HeapNumber::kValueOffset));
-  #endif
-      __ mov(r0, Operand(r5));
-      // And we are done.
-      __ pop(pc);
+      if (CpuFeatures::IsSupported(VFP3)) {
+        CpuFeatures::Scope scope(VFP3);
+        // Convert smi in r0 to double in d7.
+        __ mov(r7, Operand(r0, ASR, kSmiTagSize));
+        __ vmov(s15, r7);
+        __ vcvt_f64_s32(d7, s15);
+        if (!use_fp_registers) {
+          __ vmov(r2, r3, d7);
+        }
+      } else {
+        // Write Smi from r0 to r3 and r2 in double format.
+        __ mov(r7, Operand(r0));
+        ConvertToDoubleStub stub3(r3, r2, r7, r4);
+        __ push(lr);
+        __ Call(stub3.GetCode(), RelocInfo::CODE_TARGET);
+        __ pop(lr);
+      }
+
+      // HEAP_NUMBERS stub is slower than GENERIC on a pair of smis.
+      // r0 is known to be a smi. If r1 is also a smi then switch to GENERIC.
+      Label r1_is_not_smi;
+      if (runtime_operands_type_ == BinaryOpIC::HEAP_NUMBERS) {
+        __ tst(r1, Operand(kSmiTagMask));
+        __ b(ne, &r1_is_not_smi);
+        GenerateTypeTransition(masm);  // Tail call.
+      }
+
+      __ bind(&finished_loading_r0);
+
+      // Move r1 to a double in r0-r1.
+      __ tst(r1, Operand(kSmiTagMask));
+      __ b(eq, &r1_is_smi);  // It's a Smi so don't check it's a heap number.
+      __ bind(&r1_is_not_smi);
+      __ ldr(r4, FieldMemOperand(r1, HeapNumber::kMapOffset));
+      __ AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
+      __ cmp(r4, heap_number_map);
+      __ b(ne, &slow);
+      if (mode_ == OVERWRITE_LEFT) {
+        __ mov(r5, Operand(r1));  // Overwrite this heap number.
+      }
+      if (use_fp_registers) {
+        CpuFeatures::Scope scope(VFP3);
+        // Load the double from tagged HeapNumber r1 to d6.
+        __ sub(r7, r1, Operand(kHeapObjectTag));
+        __ vldr(d6, r7, HeapNumber::kValueOffset);
+      } else {
+        // Calling convention says that first double is in r0 and r1.
+        __ Ldrd(r0, r1, FieldMemOperand(r1, HeapNumber::kValueOffset));
+      }
+      __ jmp(&finished_loading_r1);
+      __ bind(&r1_is_smi);
+      if (mode_ == OVERWRITE_LEFT) {
+        // We can't overwrite a Smi so get address of new heap number into r5.
+      __ AllocateHeapNumber(r5, r4, r7, heap_number_map, &slow);
+      }
+
+      if (CpuFeatures::IsSupported(VFP3)) {
+        CpuFeatures::Scope scope(VFP3);
+        // Convert smi in r1 to double in d6.
+        __ mov(r7, Operand(r1, ASR, kSmiTagSize));
+        __ vmov(s13, r7);
+        __ vcvt_f64_s32(d6, s13);
+        if (!use_fp_registers) {
+          __ vmov(r0, r1, d6);
+        }
+      } else {
+        // Write Smi from r1 to r1 and r0 in double format.
+        __ mov(r7, Operand(r1));
+        ConvertToDoubleStub stub4(r1, r0, r7, r9);
+        __ push(lr);
+        __ Call(stub4.GetCode(), RelocInfo::CODE_TARGET);
+        __ pop(lr);
+      }
+
+      __ bind(&finished_loading_r1);
     }
+
+    if (generate_code_to_calculate_answer || do_the_call.is_linked()) {
+      __ bind(&do_the_call);
+      // If we are inlining the operation using VFP3 instructions for
+      // add, subtract, multiply, or divide, the arguments are in d6 and d7.
+      if (use_fp_registers) {
+        CpuFeatures::Scope scope(VFP3);
+        // ARMv7 VFP3 instructions to implement
+        // double precision, add, subtract, multiply, divide.
+
+        if (Token::MUL == op_) {
+          __ vmul(d5, d6, d7);
+        } else if (Token::DIV == op_) {
+          __ vdiv(d5, d6, d7);
+        } else if (Token::ADD == op_) {
+          __ vadd(d5, d6, d7);
+        } else if (Token::SUB == op_) {
+          __ vsub(d5, d6, d7);
+        } else {
+          UNREACHABLE();
+        }
+        __ sub(r0, r5, Operand(kHeapObjectTag));
+        __ vstr(d5, r0, HeapNumber::kValueOffset);
+        __ add(r0, r0, Operand(kHeapObjectTag));
+        __ mov(pc, lr);
+      } else {
+        // If we did not inline the operation, then the arguments are in:
+        // r0: Left value (least significant part of mantissa).
+        // r1: Left value (sign, exponent, top of mantissa).
+        // r2: Right value (least significant part of mantissa).
+        // r3: Right value (sign, exponent, top of mantissa).
+        // r5: Address of heap number for result.
+
+        __ push(lr);   // For later.
+        __ PrepareCallCFunction(4, r4);  // Two doubles count as 4 arguments.
+        // Call C routine that may not cause GC or other trouble. r5 is callee
+        // save.
+        __ CallCFunction(ExternalReference::double_fp_operation(op_), 4);
+        // Store answer in the overwritable heap number.
+    #if !defined(USE_ARM_EABI)
+        // Double returned in fp coprocessor register 0 and 1, encoded as
+        // register cr8.  Offsets must be divisible by 4 for coprocessor so we
+        // need to substract the tag from r5.
+        __ sub(r4, r5, Operand(kHeapObjectTag));
+        __ stc(p1, cr8, MemOperand(r4, HeapNumber::kValueOffset));
+    #else
+        // Double returned in registers 0 and 1.
+        __ Strd(r0, r1, FieldMemOperand(r5, HeapNumber::kValueOffset));
+    #endif
+        __ mov(r0, Operand(r5));
+        // And we are done.
+        __ pop(pc);
+      }
+    }
+  }
+
+  if (!generate_code_to_calculate_answer &&
+      !slow_reverse.is_linked() &&
+      !slow.is_linked()) {
+    return;
   }
 
   if (lhs.is(r0)) {
@@ -8745,29 +8760,15 @@
 
   __ Push(r1, r0);
 
-  // Internal frame is necessary to handle exceptions properly.
-  __ EnterInternalFrame();
-  // Call the stub proper to get the result in r0.
-  __ Call(&get_result);
-  __ LeaveInternalFrame();
-
-  __ push(r0);
-
-  __ mov(r0, Operand(Smi::FromInt(MinorKey())));
-  __ push(r0);
-  __ mov(r0, Operand(Smi::FromInt(op_)));
-  __ push(r0);
+  __ mov(r2, Operand(Smi::FromInt(MinorKey())));
+  __ mov(r1, Operand(Smi::FromInt(op_)));
   __ mov(r0, Operand(Smi::FromInt(runtime_operands_type_)));
-  __ push(r0);
+  __ Push(r2, r1, r0);
 
   __ TailCallExternalReference(
       ExternalReference(IC_Utility(IC::kBinaryOp_Patch)),
-      6,
+      5,
       1);
-
-  // The entry point for the result calculation is assumed to be immediately
-  // after this sequence.
-  __ bind(&get_result);
 }
 
 
@@ -8899,16 +8900,23 @@
 
     // Go slow case if the value of the expression is zero
     // to make sure that we switch between 0 and -0.
-    __ cmp(r0, Operand(0));
-    __ b(eq, &slow);
-
-    // The value of the expression is a smi that is not zero.  Try
-    // optimistic subtraction '0 - value'.
-    __ rsb(r1, r0, Operand(0), SetCC);
-    __ b(vs, &slow);
-
-    __ mov(r0, Operand(r1));  // Set r0 to result.
-    __ b(&done);
+    if (negative_zero_ == kStrictNegativeZero) {
+      // If we have to check for zero, then we can check for the max negative
+      // smi while we are at it.
+      __ bic(ip, r0, Operand(0x80000000), SetCC);
+      __ b(eq, &slow);
+      __ rsb(r0, r0, Operand(0));
+      __ StubReturn(1);
+    } else {
+      // The value of the expression is a smi and 0 is OK for -0.  Try
+      // optimistic subtraction '0 - value'.
+      __ rsb(r0, r0, Operand(0), SetCC);
+      __ StubReturn(1, vc);
+      // We don't have to reverse the optimistic neg since the only case
+      // where we fall through is the minimum negative Smi, which is the case
+      // where the neg leaves the register unchanged.
+      __ jmp(&slow);  // Go slow on max negative Smi.
+    }
 
     __ bind(&try_float);
     __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
@@ -8916,7 +8924,7 @@
     __ cmp(r1, heap_number_map);
     __ b(ne, &slow);
     // r0 is a heap number.  Get a new heap number in r1.
-    if (overwrite_) {
+    if (overwrite_ == UNARY_OVERWRITE) {
       __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
       __ eor(r2, r2, Operand(HeapNumber::kSignMask));  // Flip sign.
       __ str(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
@@ -8949,7 +8957,7 @@
     __ b(&done);
 
     __ bind(&try_float);
-    if (!overwrite_) {
+    if (!overwrite_ == UNARY_OVERWRITE) {
       // Allocate a fresh heap number, but don't overwrite r0 until
       // we're sure we can do it without going through the slow case
       // that needs the value in r0.
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc
index 6732873..080cb83 100644
--- a/src/arm/full-codegen-arm.cc
+++ b/src/arm/full-codegen-arm.cc
@@ -2736,9 +2736,11 @@
 
     case Token::SUB: {
       Comment cmt(masm_, "[ UnaryOperation (SUB)");
-      bool overwrite =
+      bool can_overwrite =
           (expr->expression()->AsBinaryOperation() != NULL &&
            expr->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
+      UnaryOverwriteMode overwrite =
+          can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
       GenericUnaryOpStub stub(Token::SUB, overwrite);
       // GenericUnaryOpStub expects the argument to be in the
       // accumulator register r0.
@@ -2750,9 +2752,11 @@
 
     case Token::BIT_NOT: {
       Comment cmt(masm_, "[ UnaryOperation (BIT_NOT)");
-      bool overwrite =
+      bool can_overwrite =
           (expr->expression()->AsBinaryOperation() != NULL &&
            expr->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
+      UnaryOverwriteMode overwrite =
+          can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
       GenericUnaryOpStub stub(Token::BIT_NOT, overwrite);
       // GenericUnaryOpStub expects the argument to be in the
       // accumulator register r0.
diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc
index 81fc11e..2896cc9 100644
--- a/src/arm/macro-assembler-arm.cc
+++ b/src/arm/macro-assembler-arm.cc
@@ -1372,12 +1372,12 @@
 }
 
 
-void MacroAssembler::StubReturn(int argc) {
+void MacroAssembler::StubReturn(int argc, Condition cond) {
   ASSERT(argc >= 1 && generating_stub());
   if (argc > 1) {
-    add(sp, sp, Operand((argc - 1) * kPointerSize));
+    add(sp, sp, Operand((argc - 1) * kPointerSize), LeaveCC, cond);
   }
-  Ret();
+  Ret(cond);
 }
 
 
diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h
index d57c565..f1f7de7 100644
--- a/src/arm/macro-assembler-arm.h
+++ b/src/arm/macro-assembler-arm.h
@@ -537,7 +537,7 @@
   void TailCallStub(CodeStub* stub, Condition cond = al);
 
   // Return from a code stub after popping its arguments.
-  void StubReturn(int argc);
+  void StubReturn(int argc, Condition cond = al);
 
   // Call a runtime routine.
   void CallRuntime(Runtime::Function* f, int num_arguments);
diff --git a/src/codegen.cc b/src/codegen.cc
index 686e173..8864c95 100644
--- a/src/codegen.cc
+++ b/src/codegen.cc
@@ -460,11 +460,17 @@
 const char* GenericUnaryOpStub::GetName() {
   switch (op_) {
     case Token::SUB:
-      return overwrite_
-          ? "GenericUnaryOpStub_SUB_Overwrite"
-          : "GenericUnaryOpStub_SUB_Alloc";
+      if (negative_zero_ == kStrictNegativeZero) {
+        return overwrite_ == UNARY_OVERWRITE
+            ? "GenericUnaryOpStub_SUB_Overwrite_Strict0"
+            : "GenericUnaryOpStub_SUB_Alloc_Strict0";
+      } else {
+        return overwrite_ == UNARY_OVERWRITE
+            ? "GenericUnaryOpStub_SUB_Overwrite_Ignore0"
+            : "GenericUnaryOpStub_SUB_Alloc_Ignore0";
+      }
     case Token::BIT_NOT:
-      return overwrite_
+      return overwrite_ == UNARY_OVERWRITE
           ? "GenericUnaryOpStub_BIT_NOT_Overwrite"
           : "GenericUnaryOpStub_BIT_NOT_Alloc";
     default:
diff --git a/src/codegen.h b/src/codegen.h
index 0576fbb..783bef0 100644
--- a/src/codegen.h
+++ b/src/codegen.h
@@ -75,6 +75,7 @@
 
 // Mode to overwrite BinaryExpression values.
 enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
+enum UnaryOverwriteMode { UNARY_OVERWRITE, UNARY_NO_OVERWRITE };
 
 // Types of uncatchable exceptions.
 enum UncatchableExceptionType { OUT_OF_MEMORY, TERMINATION };
@@ -414,21 +415,33 @@
 };
 
 
+enum NegativeZeroHandling {
+  kStrictNegativeZero,
+  kIgnoreNegativeZero
+};
+
+
 class GenericUnaryOpStub : public CodeStub {
  public:
-  GenericUnaryOpStub(Token::Value op, bool overwrite)
-      : op_(op), overwrite_(overwrite) { }
+  GenericUnaryOpStub(Token::Value op,
+                     UnaryOverwriteMode overwrite,
+                     NegativeZeroHandling negative_zero = kStrictNegativeZero)
+      : op_(op), overwrite_(overwrite), negative_zero_(negative_zero) { }
 
  private:
   Token::Value op_;
-  bool overwrite_;
+  UnaryOverwriteMode overwrite_;
+  NegativeZeroHandling negative_zero_;
 
-  class OverwriteField: public BitField<int, 0, 1> {};
-  class OpField: public BitField<Token::Value, 1, kMinorBits - 1> {};
+  class OverwriteField: public BitField<UnaryOverwriteMode, 0, 1> {};
+  class NegativeZeroField: public BitField<NegativeZeroHandling, 1, 1> {};
+  class OpField: public BitField<Token::Value, 2, kMinorBits - 2> {};
 
   Major MajorKey() { return GenericUnaryOp; }
   int MinorKey() {
-    return OpField::encode(op_) | OverwriteField::encode(overwrite_);
+    return OpField::encode(op_) |
+           OverwriteField::encode(overwrite_) |
+           NegativeZeroField::encode(negative_zero_);
   }
 
   void Generate(MacroAssembler* masm);
diff --git a/src/date.js b/src/date.js
index 83fca27..9c42a04 100644
--- a/src/date.js
+++ b/src/date.js
@@ -453,111 +453,6 @@
 });
 
 
-// Helper functions.
-function GetTimeFrom(aDate) {
-  return DATE_VALUE(aDate);
-}
-
-function GetMillisecondsFrom(aDate) {
-  var t = DATE_VALUE(aDate);
-  if (NUMBER_IS_NAN(t)) return t;
-  return MS_FROM_TIME(LocalTimeNoCheck(t));
-}
-
-
-function GetUTCMillisecondsFrom(aDate) {
-  var t = DATE_VALUE(aDate);
-  if (NUMBER_IS_NAN(t)) return t;
-  return MS_FROM_TIME(t);
-}
-
-
-function GetSecondsFrom(aDate) {
-  var t = DATE_VALUE(aDate);
-  if (NUMBER_IS_NAN(t)) return t;
-  return SEC_FROM_TIME(LocalTimeNoCheck(t));
-}
-
-
-function GetUTCSecondsFrom(aDate) {
-  var t = DATE_VALUE(aDate);
-  if (NUMBER_IS_NAN(t)) return t;
-  return SEC_FROM_TIME(t);
-}
-
-
-function GetMinutesFrom(aDate) {
-  var t = DATE_VALUE(aDate);
-  if (NUMBER_IS_NAN(t)) return t;
-  return MIN_FROM_TIME(LocalTimeNoCheck(t));
-}
-
-
-function GetUTCMinutesFrom(aDate) {
-  var t = DATE_VALUE(aDate);
-  if (NUMBER_IS_NAN(t)) return t;
-  return MIN_FROM_TIME(t);
-}
-
-
-function GetHoursFrom(aDate) {
-  var t = DATE_VALUE(aDate);
-  if (NUMBER_IS_NAN(t)) return t;
-  return HOUR_FROM_TIME(LocalTimeNoCheck(t));
-}
-
-
-function GetUTCHoursFrom(aDate) {
-  var t = DATE_VALUE(aDate);
-  if (NUMBER_IS_NAN(t)) return t;
-  return HOUR_FROM_TIME(t);
-}
-
-
-function GetFullYearFrom(aDate) {
-  var t = DATE_VALUE(aDate);
-  if (NUMBER_IS_NAN(t)) return t;
-  var cache = Date_cache;
-  if (cache.time === t) return cache.year;
-  return YEAR_FROM_TIME(LocalTimeNoCheck(t));
-}
-
-
-function GetUTCFullYearFrom(aDate) {
-  var t = DATE_VALUE(aDate);
-  if (NUMBER_IS_NAN(t)) return t;
-  return YEAR_FROM_TIME(t);
-}
-
-
-function GetMonthFrom(aDate) {
-  var t = DATE_VALUE(aDate);
-  if (NUMBER_IS_NAN(t)) return t;
-  return MONTH_FROM_TIME(LocalTimeNoCheck(t));
-}
-
-
-function GetUTCMonthFrom(aDate) {
-  var t = DATE_VALUE(aDate);
-  if (NUMBER_IS_NAN(t)) return t;
-  return MONTH_FROM_TIME(t);
-}
-
-
-function GetDateFrom(aDate) {
-  var t = DATE_VALUE(aDate);
-  if (NUMBER_IS_NAN(t)) return t;
-  return DATE_FROM_TIME(LocalTimeNoCheck(t));
-}
-
-
-function GetUTCDateFrom(aDate) {
-  var t = DATE_VALUE(aDate);
-  if (NUMBER_IS_NAN(t)) return t;
-  return DATE_FROM_TIME(t);
-}
-
-
 %FunctionSetPrototype($Date, new $Date($NaN));
 
 
@@ -737,37 +632,50 @@
 
 // ECMA 262 - 15.9.5.10
 function DateGetFullYear() {
-  return GetFullYearFrom(this)
+  var t = DATE_VALUE(this);
+  if (NUMBER_IS_NAN(t)) return t;
+  var cache = Date_cache;
+  if (cache.time === t) return cache.year;
+  return YEAR_FROM_TIME(LocalTimeNoCheck(t));
 }
 
 
 // ECMA 262 - 15.9.5.11
 function DateGetUTCFullYear() {
-  return GetUTCFullYearFrom(this)
+  var t = DATE_VALUE(this);
+  if (NUMBER_IS_NAN(t)) return t;
+  return YEAR_FROM_TIME(t);
 }
 
 
 // ECMA 262 - 15.9.5.12
 function DateGetMonth() {
-  return GetMonthFrom(this);
+  var t = DATE_VALUE(this);
+  if (NUMBER_IS_NAN(t)) return t;
+  return MONTH_FROM_TIME(LocalTimeNoCheck(t));
 }
 
 
 // ECMA 262 - 15.9.5.13
 function DateGetUTCMonth() {
-  return GetUTCMonthFrom(this);
+  var t = DATE_VALUE(this);
+  if (NUMBER_IS_NAN(t)) return t;
+  return MONTH_FROM_TIME(t);
 }
 
 
 // ECMA 262 - 15.9.5.14
 function DateGetDate() {
-  return GetDateFrom(this);
+  var t = DATE_VALUE(this);
+  if (NUMBER_IS_NAN(t)) return t;
+  return DATE_FROM_TIME(LocalTimeNoCheck(t));
 }
 
 
 // ECMA 262 - 15.9.5.15
 function DateGetUTCDate() {
-  return GetUTCDateFrom(this);
+  var t = DATE_VALUE(this);
+  return NAN_OR_DATE_FROM_TIME(t);
 }
 
 
@@ -789,49 +697,62 @@
 
 // ECMA 262 - 15.9.5.18
 function DateGetHours() {
-  return GetHoursFrom(this);
+  var t = DATE_VALUE(this);
+  if (NUMBER_IS_NAN(t)) return t;
+  return HOUR_FROM_TIME(LocalTimeNoCheck(t));
 }
 
 
 // ECMA 262 - 15.9.5.19
 function DateGetUTCHours() {
-  return GetUTCHoursFrom(this);
+  var t = DATE_VALUE(this);
+  if (NUMBER_IS_NAN(t)) return t;
+  return HOUR_FROM_TIME(t);
 }
 
 
 // ECMA 262 - 15.9.5.20
 function DateGetMinutes() {
-  return GetMinutesFrom(this);
+  var t = DATE_VALUE(this);
+  if (NUMBER_IS_NAN(t)) return t;
+  return MIN_FROM_TIME(LocalTimeNoCheck(t));
 }
 
 
 // ECMA 262 - 15.9.5.21
 function DateGetUTCMinutes() {
-  return GetUTCMinutesFrom(this);
+  var t = DATE_VALUE(this);
+  return NAN_OR_MIN_FROM_TIME(t);
 }
 
 
 // ECMA 262 - 15.9.5.22
 function DateGetSeconds() {
-  return GetSecondsFrom(this);
+  var t = DATE_VALUE(this);
+  if (NUMBER_IS_NAN(t)) return t;
+  return SEC_FROM_TIME(LocalTimeNoCheck(t));
 }
 
 
 // ECMA 262 - 15.9.5.23
 function DateGetUTCSeconds() {
-  return GetUTCSecondsFrom(this);
+  var t = DATE_VALUE(this);
+  return NAN_OR_SEC_FROM_TIME(t);
 }
 
 
 // ECMA 262 - 15.9.5.24
 function DateGetMilliseconds() {
-  return GetMillisecondsFrom(this);
+  var t = DATE_VALUE(this);
+  if (NUMBER_IS_NAN(t)) return t;
+  return MS_FROM_TIME(LocalTimeNoCheck(t));
 }
 
 
 // ECMA 262 - 15.9.5.25
 function DateGetUTCMilliseconds() {
-  return GetUTCMillisecondsFrom(this);
+  var t = DATE_VALUE(this);
+  return NAN_OR_MS_FROM_TIME(t);
 }
 
 
@@ -872,7 +793,7 @@
 function DateSetSeconds(sec, ms) {
   var t = LocalTime(DATE_VALUE(this));
   sec = ToNumber(sec);
-  ms = %_ArgumentsLength() < 2 ? GetMillisecondsFrom(this) : ToNumber(ms);
+  ms = %_ArgumentsLength() < 2 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
   var time = MakeTime(HOUR_FROM_TIME(t), MIN_FROM_TIME(t), sec, ms);
   return %_SetValueOf(this, TimeClip(UTC(MakeDate(DAY(t), time))));
 }
@@ -882,7 +803,7 @@
 function DateSetUTCSeconds(sec, ms) {
   var t = DATE_VALUE(this);
   sec = ToNumber(sec);
-  ms = %_ArgumentsLength() < 2 ? GetUTCMillisecondsFrom(this) : ToNumber(ms);
+  ms = %_ArgumentsLength() < 2 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
   var time = MakeTime(HOUR_FROM_TIME(t), MIN_FROM_TIME(t), sec, ms);
   return %_SetValueOf(this, TimeClip(MakeDate(DAY(t), time)));
 }
@@ -893,8 +814,8 @@
   var t = LocalTime(DATE_VALUE(this));
   min = ToNumber(min);
   var argc = %_ArgumentsLength();
-  sec = argc < 2 ? GetSecondsFrom(this) : ToNumber(sec);
-  ms = argc < 3 ? GetMillisecondsFrom(this) : ToNumber(ms);
+  sec = argc < 2 ? NAN_OR_SEC_FROM_TIME(t) : ToNumber(sec);
+  ms = argc < 3 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
   var time = MakeTime(HOUR_FROM_TIME(t), min, sec, ms);
   return %_SetValueOf(this, TimeClip(UTC(MakeDate(DAY(t), time))));
 }
@@ -905,8 +826,8 @@
   var t = DATE_VALUE(this);
   min = ToNumber(min);
   var argc = %_ArgumentsLength();
-  sec = argc < 2 ? GetUTCSecondsFrom(this) : ToNumber(sec);
-  ms = argc < 3 ? GetUTCMillisecondsFrom(this) : ToNumber(ms);
+  sec = argc < 2 ? NAN_OR_SEC_FROM_TIME(t) : ToNumber(sec);
+  ms = argc < 3 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
   var time = MakeTime(HOUR_FROM_TIME(t), min, sec, ms);
   return %_SetValueOf(this, TimeClip(MakeDate(DAY(t), time)));
 }
@@ -917,9 +838,9 @@
   var t = LocalTime(DATE_VALUE(this));
   hour = ToNumber(hour);
   var argc = %_ArgumentsLength();
-  min = argc < 2 ? GetMinutesFrom(this) : ToNumber(min);
-  sec = argc < 3 ? GetSecondsFrom(this) : ToNumber(sec);
-  ms = argc < 4 ? GetMillisecondsFrom(this) : ToNumber(ms);
+  min = argc < 2 ? NAN_OR_MIN_FROM_TIME(t) : ToNumber(min);
+  sec = argc < 3 ? NAN_OR_SEC_FROM_TIME(t) : ToNumber(sec);
+  ms = argc < 4 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
   var time = MakeTime(hour, min, sec, ms);
   return %_SetValueOf(this, TimeClip(UTC(MakeDate(DAY(t), time))));
 }
@@ -930,9 +851,9 @@
   var t = DATE_VALUE(this);
   hour = ToNumber(hour);
   var argc = %_ArgumentsLength();
-  min = argc < 2 ? GetUTCMinutesFrom(this) : ToNumber(min);
-  sec = argc < 3 ? GetUTCSecondsFrom(this) : ToNumber(sec);
-  ms = argc < 4 ? GetUTCMillisecondsFrom(this) : ToNumber(ms);
+  min = argc < 2 ? NAN_OR_MIN_FROM_TIME(t) : ToNumber(min);
+  sec = argc < 3 ? NAN_OR_SEC_FROM_TIME(t) : ToNumber(sec);
+  ms = argc < 4 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
   var time = MakeTime(hour, min, sec, ms);
   return %_SetValueOf(this, TimeClip(MakeDate(DAY(t), time)));
 }
@@ -960,7 +881,7 @@
 function DateSetMonth(month, date) {
   var t = LocalTime(DATE_VALUE(this));
   month = ToNumber(month);
-  date = %_ArgumentsLength() < 2 ? GetDateFrom(this) : ToNumber(date);
+  date = %_ArgumentsLength() < 2 ? NAN_OR_DATE_FROM_TIME(t) : ToNumber(date);
   var day = MakeDay(YEAR_FROM_TIME(t), month, date);
   return %_SetValueOf(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t)))));
 }
@@ -970,7 +891,7 @@
 function DateSetUTCMonth(month, date) {
   var t = DATE_VALUE(this);
   month = ToNumber(month);
-  date = %_ArgumentsLength() < 2 ? GetUTCDateFrom(this) : ToNumber(date);
+  date = %_ArgumentsLength() < 2 ? NAN_OR_DATE_FROM_TIME(t) : ToNumber(date);
   var day = MakeDay(YEAR_FROM_TIME(t), month, date);
   return %_SetValueOf(this, TimeClip(MakeDate(day, TimeWithinDay(t))));
 }
diff --git a/src/debug.cc b/src/debug.cc
index 1dc6275..b8e0252 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -472,8 +472,9 @@
 
   RelocInfo::Mode mode = rmode();
   if (RelocInfo::IsCodeTarget(mode)) {
+    AssertNoAllocation nogc;
     Address target = original_rinfo()->target_address();
-    Handle<Code> code(Code::GetCodeFromTargetAddress(target));
+    Code* code = Code::GetCodeFromTargetAddress(target);
 
     // Restore the inlined version of keyed stores to get back to the
     // fast case.  We need to patch back the keyed store because no
diff --git a/src/factory.cc b/src/factory.cc
index f6b93b0..39e881a 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -96,6 +96,12 @@
 }
 
 
+Handle<String> Factory::NewRawAsciiString(int length,
+                                          PretenureFlag pretenure) {
+  CALL_HEAP_FUNCTION(Heap::AllocateRawAsciiString(length, pretenure), String);
+}
+
+
 Handle<String> Factory::NewRawTwoByteString(int length,
                                             PretenureFlag pretenure) {
   CALL_HEAP_FUNCTION(Heap::AllocateRawTwoByteString(length, pretenure), String);
diff --git a/src/factory.h b/src/factory.h
index b0a0571..56deda5 100644
--- a/src/factory.h
+++ b/src/factory.h
@@ -95,12 +95,16 @@
       Vector<const char> str,
       PretenureFlag pretenure = NOT_TENURED);
 
-  static Handle<String> NewStringFromTwoByte(Vector<const uc16> str,
+  static Handle<String> NewStringFromTwoByte(
+      Vector<const uc16> str,
       PretenureFlag pretenure = NOT_TENURED);
 
-  // Allocates and partially initializes a TwoByte String. The characters of
-  // the string are uninitialized. Currently used in regexp code only, where
-  // they are pretenured.
+  // Allocates and partially initializes an ASCII or TwoByte String. The
+  // characters of the string are uninitialized. Currently used in regexp code
+  // only, where they are pretenured.
+  static Handle<String> NewRawAsciiString(
+      int length,
+      PretenureFlag pretenure = NOT_TENURED);
   static Handle<String> NewRawTwoByteString(
       int length,
       PretenureFlag pretenure = NOT_TENURED);
diff --git a/src/frames.cc b/src/frames.cc
index 9cf83c9..67a20d3 100644
--- a/src/frames.cc
+++ b/src/frames.cc
@@ -542,7 +542,7 @@
 
       Address pc = this->pc();
       if (code != NULL && code->kind() == Code::FUNCTION &&
-          pc >= code->instruction_start() && pc < code->relocation_start()) {
+          pc >= code->instruction_start() && pc < code->instruction_end()) {
         int source_pos = code->SourcePosition(pc);
         int line = GetScriptLineNumberSafe(script, source_pos) + 1;
         accumulator->Add(":%d", line);
diff --git a/src/heap.cc b/src/heap.cc
index 6ae46f2..1b62589 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -2351,8 +2351,13 @@
                          ZoneScopeInfo* sinfo,
                          Code::Flags flags,
                          Handle<Object> self_reference) {
+  // Allocate ByteArray before the Code object, so that we do not risk
+  // leaving uninitialized Code object (and breaking the heap).
+  Object* reloc_info = AllocateByteArray(desc.reloc_size, TENURED);
+  if (reloc_info->IsFailure()) return reloc_info;
+
   // Compute size
-  int body_size = RoundUp(desc.instr_size + desc.reloc_size, kObjectAlignment);
+  int body_size = RoundUp(desc.instr_size, kObjectAlignment);
   int sinfo_size = 0;
   if (sinfo != NULL) sinfo_size = sinfo->Serialize(NULL);
   int obj_size = Code::SizeFor(body_size, sinfo_size);
@@ -2371,7 +2376,7 @@
   Code* code = Code::cast(result);
   ASSERT(!CodeRange::exists() || CodeRange::contains(code->address()));
   code->set_instruction_size(desc.instr_size);
-  code->set_relocation_size(desc.reloc_size);
+  code->set_relocation_info(ByteArray::cast(reloc_info));
   code->set_sinfo_size(sinfo_size);
   code->set_flags(flags);
   // Allow self references to created code object by patching the handle to
@@ -2419,8 +2424,12 @@
 
 
 Object* Heap::CopyCode(Code* code, Vector<byte> reloc_info) {
-  int new_body_size = RoundUp(code->instruction_size() + reloc_info.length(),
-                              kObjectAlignment);
+  // Allocate ByteArray before the Code object, so that we do not risk
+  // leaving uninitialized Code object (and breaking the heap).
+  Object* reloc_info_array = AllocateByteArray(reloc_info.length(), TENURED);
+  if (reloc_info_array->IsFailure()) return reloc_info_array;
+
+  int new_body_size = RoundUp(code->instruction_size(), kObjectAlignment);
 
   int sinfo_size = code->sinfo_size();
 
@@ -2429,7 +2438,7 @@
   Address old_addr = code->address();
 
   size_t relocation_offset =
-      static_cast<size_t>(code->relocation_start() - old_addr);
+      static_cast<size_t>(code->instruction_end() - old_addr);
 
   Object* result;
   if (new_obj_size > MaxObjectSizeInPagedSpace()) {
@@ -2446,14 +2455,11 @@
   // Copy header and instructions.
   memcpy(new_addr, old_addr, relocation_offset);
 
-  // Copy patched rinfo.
-  memcpy(new_addr + relocation_offset,
-         reloc_info.start(),
-             reloc_info.length());
-
   Code* new_code = Code::cast(result);
-  new_code->set_relocation_size(reloc_info.length());
+  new_code->set_relocation_info(ByteArray::cast(reloc_info_array));
 
+  // Copy patched rinfo.
+  memcpy(new_code->relocation_start(), reloc_info.start(), reloc_info.length());
   // Copy sinfo.
   memcpy(new_code->sinfo_start(), code->sinfo_start(), code->sinfo_size());
 
@@ -2866,6 +2872,8 @@
 
 Object* Heap::AllocateStringFromUtf8(Vector<const char> string,
                                      PretenureFlag pretenure) {
+  // V8 only supports characters in the Basic Multilingual Plane.
+  const uc32 kMaxSupportedChar = 0xFFFF;
   // Count the number of characters in the UTF-8 string and check if
   // it is an ASCII string.
   Access<Scanner::Utf8Decoder> decoder(Scanner::utf8_decoder());
@@ -2890,6 +2898,7 @@
   decoder->Reset(string.start(), string.length());
   for (int i = 0; i < chars; i++) {
     uc32 r = decoder->GetNext();
+    if (r > kMaxSupportedChar) { r = unibrow::Utf8::kBadChar; }
     string_result->Set(i, r);
   }
   return result;
diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc
index fa09dd8..0f72074 100644
--- a/src/ia32/codegen-ia32.cc
+++ b/src/ia32/codegen-ia32.cc
@@ -7583,9 +7583,12 @@
       frame_->Push(&value);
     } else {
       Load(node->expression());
-      bool overwrite =
+      bool can_overwrite =
           (node->expression()->AsBinaryOperation() != NULL &&
            node->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
+      UnaryOverwriteMode overwrite =
+          can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
+      bool no_negative_zero = node->expression()->no_negative_zero();
       switch (op) {
         case Token::NOT:
         case Token::DELETE:
@@ -7594,7 +7597,10 @@
           break;
 
         case Token::SUB: {
-          GenericUnaryOpStub stub(Token::SUB, overwrite);
+          GenericUnaryOpStub stub(
+              Token::SUB,
+              overwrite,
+              no_negative_zero ? kIgnoreNegativeZero : kStrictNegativeZero);
           Result operand = frame_->Pop();
           Result answer = frame_->CallStub(&stub, &operand);
           answer.set_type_info(TypeInfo::Number());
@@ -9860,6 +9866,7 @@
           // the four basic operations. The stub stays in the DEFAULT state
           // forever for all other operations (also if smi code is skipped).
           GenerateTypeTransition(masm);
+          break;
         }
 
         Label not_floats;
@@ -10207,51 +10214,28 @@
 
 
 void GenericBinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
-  Label get_result;
-
-  // Keep a copy of operands on the stack and make sure they are also in
-  // edx, eax.
+  // Ensure the operands are on the stack.
   if (HasArgsInRegisters()) {
     GenerateRegisterArgsPush(masm);
-  } else {
-    GenerateLoadArguments(masm);
   }
 
-  // Internal frame is necessary to handle exceptions properly.
-  __ EnterInternalFrame();
+  __ pop(ecx);  // Save return address.
 
-  // Push arguments on stack if the stub expects them there.
-  if (!HasArgsInRegisters()) {
-    __ push(edx);
-    __ push(eax);
-  }
-  // Call the stub proper to get the result in eax.
-  __ call(&get_result);
-  __ LeaveInternalFrame();
-
-  __ pop(ecx);  // Return address.
   // Left and right arguments are now on top.
-  // Push the operation result. The tail call to BinaryOp_Patch will
-  // return it to the original caller.
-  __ push(eax);
   // Push this stub's key. Although the operation and the type info are
   // encoded into the key, the encoding is opaque, so push them too.
   __ push(Immediate(Smi::FromInt(MinorKey())));
   __ push(Immediate(Smi::FromInt(op_)));
   __ push(Immediate(Smi::FromInt(runtime_operands_type_)));
 
-  __ push(ecx);  // Return address.
+  __ push(ecx);  // Push return address.
 
-  // Patch the caller to an appropriate specialized stub
-  // and return the operation result.
+  // Patch the caller to an appropriate specialized stub and return the
+  // operation result to the caller of the stub.
   __ TailCallExternalReference(
       ExternalReference(IC_Utility(IC::kBinaryOp_Patch)),
-      6,
+      5,
       1);
-
-  // The entry point for the result calculation is assumed to be immediately
-  // after this sequence.
-  __ bind(&get_result);
 }
 
 
@@ -10934,10 +10918,12 @@
     __ test(eax, Immediate(kSmiTagMask));
     __ j(not_zero, &try_float, not_taken);
 
-    // Go slow case if the value of the expression is zero
-    // to make sure that we switch between 0 and -0.
-    __ test(eax, Operand(eax));
-    __ j(zero, &slow, not_taken);
+    if (negative_zero_ == kStrictNegativeZero) {
+      // Go slow case if the value of the expression is zero
+      // to make sure that we switch between 0 and -0.
+      __ test(eax, Operand(eax));
+      __ j(zero, &slow, not_taken);
+    }
 
     // The value of the expression is a smi that is not zero.  Try
     // optimistic subtraction '0 - value'.
@@ -10945,11 +10931,7 @@
     __ mov(edx, Operand(eax));
     __ Set(eax, Immediate(0));
     __ sub(eax, Operand(edx));
-    __ j(overflow, &undo, not_taken);
-
-    // If result is a smi we are done.
-    __ test(eax, Immediate(kSmiTagMask));
-    __ j(zero, &done, taken);
+    __ j(no_overflow, &done, taken);
 
     // Restore eax and go slow case.
     __ bind(&undo);
@@ -10961,7 +10943,7 @@
     __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
     __ cmp(edx, Factory::heap_number_map());
     __ j(not_equal, &slow);
-    if (overwrite_) {
+    if (overwrite_ == UNARY_OVERWRITE) {
       __ mov(edx, FieldOperand(eax, HeapNumber::kExponentOffset));
       __ xor_(edx, HeapNumber::kSignMask);  // Flip sign.
       __ mov(FieldOperand(eax, HeapNumber::kExponentOffset), edx);
@@ -11002,7 +10984,7 @@
 
     // Try to store the result in a heap number.
     __ bind(&try_float);
-    if (!overwrite_) {
+    if (overwrite_ == UNARY_NO_OVERWRITE) {
       // Allocate a fresh heap number, but don't overwrite eax until
       // we're sure we can do it without going through the slow case
       // that needs the value in eax.
diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc
index 13173e2..2ca1105 100644
--- a/src/ia32/full-codegen-ia32.cc
+++ b/src/ia32/full-codegen-ia32.cc
@@ -2813,9 +2813,11 @@
 
     case Token::SUB: {
       Comment cmt(masm_, "[ UnaryOperation (SUB)");
-      bool overwrite =
+      bool can_overwrite =
           (expr->expression()->AsBinaryOperation() != NULL &&
            expr->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
+      UnaryOverwriteMode overwrite =
+          can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
       GenericUnaryOpStub stub(Token::SUB, overwrite);
       // GenericUnaryOpStub expects the argument to be in the
       // accumulator register eax.
@@ -2827,9 +2829,11 @@
 
     case Token::BIT_NOT: {
       Comment cmt(masm_, "[ UnaryOperation (BIT_NOT)");
-      bool overwrite =
+      bool can_overwrite =
           (expr->expression()->AsBinaryOperation() != NULL &&
            expr->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
+      UnaryOverwriteMode overwrite =
+          can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
       GenericUnaryOpStub stub(Token::BIT_NOT, overwrite);
       // GenericUnaryOpStub expects the argument to be in the
       // accumulator register eax.
diff --git a/src/ic.cc b/src/ic.cc
index cdb06ac..12332f9 100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -1639,16 +1639,15 @@
 
 
 Object* BinaryOp_Patch(Arguments args) {
-  ASSERT(args.length() == 6);
+  ASSERT(args.length() == 5);
 
   Handle<Object> left = args.at<Object>(0);
   Handle<Object> right = args.at<Object>(1);
-  Handle<Object> result = args.at<Object>(2);
-  int key = Smi::cast(args[3])->value();
+  int key = Smi::cast(args[2])->value();
+  Token::Value op = static_cast<Token::Value>(Smi::cast(args[3])->value());
 #ifdef DEBUG
-  Token::Value op = static_cast<Token::Value>(Smi::cast(args[4])->value());
   BinaryOpIC::TypeInfo prev_type_info =
-      static_cast<BinaryOpIC::TypeInfo>(Smi::cast(args[5])->value());
+      static_cast<BinaryOpIC::TypeInfo>(Smi::cast(args[4])->value());
 #endif  // DEBUG
   { HandleScope scope;
     BinaryOpIC::TypeInfo type_info = BinaryOpIC::GetTypeInfo(*left, *right);
@@ -1667,6 +1666,61 @@
     }
   }
 
+  HandleScope scope;
+  Handle<JSBuiltinsObject> builtins = Top::builtins();
+
+  Object* builtin = NULL;  // Initialization calms down the compiler.
+
+  switch (op) {
+    case Token::ADD:
+      builtin = builtins->javascript_builtin(Builtins::ADD);
+      break;
+    case Token::SUB:
+      builtin = builtins->javascript_builtin(Builtins::SUB);
+      break;
+    case Token::MUL:
+      builtin = builtins->javascript_builtin(Builtins::MUL);
+      break;
+    case Token::DIV:
+      builtin = builtins->javascript_builtin(Builtins::DIV);
+      break;
+    case Token::MOD:
+      builtin = builtins->javascript_builtin(Builtins::MOD);
+      break;
+    case Token::BIT_AND:
+      builtin = builtins->javascript_builtin(Builtins::BIT_AND);
+      break;
+    case Token::BIT_OR:
+      builtin = builtins->javascript_builtin(Builtins::BIT_OR);
+      break;
+    case Token::BIT_XOR:
+      builtin = builtins->javascript_builtin(Builtins::BIT_XOR);
+      break;
+    case Token::SHR:
+      builtin = builtins->javascript_builtin(Builtins::SHR);
+      break;
+    case Token::SAR:
+      builtin = builtins->javascript_builtin(Builtins::SAR);
+      break;
+    case Token::SHL:
+      builtin = builtins->javascript_builtin(Builtins::SHL);
+      break;
+    default:
+      UNREACHABLE();
+  }
+
+  Handle<JSFunction> builtin_function(JSFunction::cast(builtin));
+
+  bool caught_exception;
+  Object** builtin_args[] = { right.location() };
+  Handle<Object> result = Execution::Call(builtin_function,
+                                          left,
+                                          ARRAY_SIZE(builtin_args),
+                                          builtin_args,
+                                          &caught_exception);
+  if (caught_exception) {
+    return Failure::Exception();
+  }
   return *result;
 }
 
diff --git a/src/macros.py b/src/macros.py
index 32c9651..b4be15b 100644
--- a/src/macros.py
+++ b/src/macros.py
@@ -146,11 +146,15 @@
 macro DAY(time) = ($floor(time / 86400000));
 macro MONTH_FROM_TIME(time) = (MonthFromTime(time));
 macro DATE_FROM_TIME(time) = (DateFromTime(time));
+macro NAN_OR_DATE_FROM_TIME(time) = (NUMBER_IS_NAN(time) ? time : DATE_FROM_TIME(time));
 macro YEAR_FROM_TIME(time) = (YearFromTime(time));
 macro HOUR_FROM_TIME(time) = (Modulo($floor(time / 3600000), 24));
 macro MIN_FROM_TIME(time) = (Modulo($floor(time / 60000), 60));
+macro NAN_OR_MIN_FROM_TIME(time) = (NUMBER_IS_NAN(time) ? time : MIN_FROM_TIME(time));
 macro SEC_FROM_TIME(time) = (Modulo($floor(time / 1000), 60));
+macro NAN_OR_SEC_FROM_TIME(time) = (NUMBER_IS_NAN(time) ? time : SEC_FROM_TIME(time));
 macro MS_FROM_TIME(time) = (Modulo(time, 1000));
+macro NAN_OR_MS_FROM_TIME(time) = (NUMBER_IS_NAN(time) ? time : MS_FROM_TIME(time));
 
 # Last input and last subject of regexp matches.
 macro LAST_SUBJECT(array) = ((array)[1]);
diff --git a/src/messages.js b/src/messages.js
index 7bac3b2..99ba454 100644
--- a/src/messages.js
+++ b/src/messages.js
@@ -197,7 +197,8 @@
       obj_ctor_property_non_object: "Object.%0 called on non-object",
       array_indexof_not_defined:    "Array.getIndexOf: Argument undefined",
       object_not_extensible:        "Can't add property %0, object is not extensible",
-      illegal_access:               "illegal access"
+      illegal_access:               "Illegal access",
+      invalid_preparser_data:       "Invalid preparser data for function %0"
     };
   }
   var format = kMessages[message.type];
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 79f2c97..0e45550 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -2807,7 +2807,7 @@
 
 
 INT_ACCESSORS(Code, instruction_size, kInstructionSizeOffset)
-INT_ACCESSORS(Code, relocation_size, kRelocationSizeOffset)
+ACCESSORS(Code, relocation_info, ByteArray, kRelocationInfoOffset)
 INT_ACCESSORS(Code, sinfo_size, kSInfoSizeOffset)
 
 
@@ -2816,13 +2816,28 @@
 }
 
 
+byte* Code::instruction_end()  {
+  return instruction_start() + instruction_size();
+}
+
+
 int Code::body_size() {
-  return RoundUp(instruction_size() + relocation_size(), kObjectAlignment);
+  return RoundUp(instruction_size(), kObjectAlignment);
+}
+
+
+ByteArray* Code::unchecked_relocation_info() {
+  return reinterpret_cast<ByteArray*>(READ_FIELD(this, kRelocationInfoOffset));
 }
 
 
 byte* Code::relocation_start() {
-  return FIELD_ADDR(this, kHeaderSize + instruction_size());
+  return unchecked_relocation_info()->GetDataStartAddress();
+}
+
+
+int Code::relocation_size() {
+  return unchecked_relocation_info()->length();
 }
 
 
diff --git a/src/objects.cc b/src/objects.cc
index 8288f63..e79a550 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -5314,7 +5314,15 @@
                   RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT) |
                   RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
 
-  for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
+  // Use the relocation info pointer before it is visited by
+  // the heap compaction in the next statement.
+  RelocIterator it(this, mode_mask);
+
+  IteratePointers(v,
+                  kRelocationInfoOffset,
+                  kRelocationInfoOffset + kPointerSize);
+
+  for (; !it.done(); it.next()) {
     it.rinfo()->Visit(v);
   }
 
@@ -5334,14 +5342,6 @@
   // copy code
   memmove(instruction_start(), desc.buffer, desc.instr_size);
 
-  // fill gap with zero bytes
-  { byte* p = instruction_start() + desc.instr_size;
-    byte* q = relocation_start();
-    while (p < q) {
-      *p++ = 0;
-    }
-  }
-
   // copy reloc info
   memmove(relocation_start(),
           desc.buffer + desc.buffer_size - desc.reloc_size,
diff --git a/src/objects.h b/src/objects.h
index 15cfd5c..4a7dee6 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -2736,9 +2736,13 @@
   inline int instruction_size();
   inline void set_instruction_size(int value);
 
-  // [relocation_size]: Size of relocation information.
+  // [relocation_info]: Code relocation information
+  DECL_ACCESSORS(relocation_info, ByteArray)
+
+  // Unchecked accessor to be used during GC.
+  inline ByteArray* unchecked_relocation_info();
+
   inline int relocation_size();
-  inline void set_relocation_size(int value);
 
   // [sinfo_size]: Size of scope information.
   inline int sinfo_size();
@@ -2797,6 +2801,9 @@
   // Returns the address of the first instruction.
   inline byte* instruction_start();
 
+  // Returns the address right after the last instruction.
+  inline byte* instruction_end();
+
   // Returns the size of the instructions, padding, and relocation information.
   inline int body_size();
 
@@ -2857,8 +2864,8 @@
 
   // Layout description.
   static const int kInstructionSizeOffset = HeapObject::kHeaderSize;
-  static const int kRelocationSizeOffset = kInstructionSizeOffset + kIntSize;
-  static const int kSInfoSizeOffset = kRelocationSizeOffset + kIntSize;
+  static const int kRelocationInfoOffset = kInstructionSizeOffset + kIntSize;
+  static const int kSInfoSizeOffset = kRelocationInfoOffset + kPointerSize;
   static const int kFlagsOffset = kSInfoSizeOffset + kIntSize;
   static const int kKindSpecificFlagsOffset  = kFlagsOffset + kIntSize;
   // Add padding to align the instruction start following right after
@@ -4406,6 +4413,8 @@
 // Each character in the AsciiString is an ascii character.
 class SeqAsciiString: public SeqString {
  public:
+  static const bool kHasAsciiEncoding = true;
+
   // Dispatched behavior.
   inline uint16_t SeqAsciiStringGet(int index);
   inline void SeqAsciiStringSet(int index, uint16_t value);
@@ -4455,6 +4464,8 @@
 // Each character in the TwoByteString is a two-byte uint16_t.
 class SeqTwoByteString: public SeqString {
  public:
+  static const bool kHasAsciiEncoding = false;
+
   // Dispatched behavior.
   inline uint16_t SeqTwoByteStringGet(int index);
   inline void SeqTwoByteStringSet(int index, uint16_t value);
@@ -4587,6 +4598,8 @@
 // ASCII string.
 class ExternalAsciiString: public ExternalString {
  public:
+  static const bool kHasAsciiEncoding = true;
+
   typedef v8::String::ExternalAsciiStringResource Resource;
 
   // The underlying resource.
@@ -4619,6 +4632,8 @@
 // encoded string.
 class ExternalTwoByteString: public ExternalString {
  public:
+  static const bool kHasAsciiEncoding = false;
+
   typedef v8::String::ExternalStringResource Resource;
 
   // The underlying string resource.
diff --git a/src/parser.cc b/src/parser.cc
index 31bac91..fb58cfa 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -134,6 +134,7 @@
 
   // Report syntax error
   void ReportUnexpectedToken(Token::Value token);
+  void ReportInvalidPreparseData(Handle<String> name, bool* ok);
 
   Handle<Script> script_;
   Scanner scanner_;
@@ -3263,6 +3264,15 @@
 }
 
 
+void Parser::ReportInvalidPreparseData(Handle<String> name, bool* ok) {
+  SmartPointer<char> name_string = name->ToCString(DISALLOW_NULLS);
+  const char* element[1] = { *name_string };
+  ReportMessage("invalid_preparser_data",
+                Vector<const char*>(element, 1));
+  *ok = false;
+}
+
+
 Expression* Parser::ParsePrimaryExpression(bool* ok) {
   // PrimaryExpression ::
   //   'this'
@@ -3810,7 +3820,14 @@
     Handle<FixedArray> this_property_assignments;
     if (is_lazily_compiled && pre_data() != NULL) {
       FunctionEntry entry = pre_data()->GetFunctionEnd(start_pos);
+      if (!entry.is_valid()) {
+        ReportInvalidPreparseData(name, CHECK_OK);
+      }
       int end_pos = entry.end_pos();
+      if (end_pos <= start_pos) {
+        // End position greater than end of stream is safe, and hard to check.
+        ReportInvalidPreparseData(name, CHECK_OK);
+      }
       Counters::total_preparse_skipped.Increment(end_pos - start_pos);
       scanner_.SeekForward(end_pos);
       materialized_literal_count = entry.literal_count();
diff --git a/src/runtime.cc b/src/runtime.cc
index a3eb09f..4a0fe7a 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -2285,6 +2285,134 @@
 }
 
 
+template <typename ResultSeqString>
+static Object* StringReplaceRegExpWithEmptyString(String* subject,
+                                                  JSRegExp* regexp,
+                                                  JSArray* last_match_info) {
+  ASSERT(subject->IsFlat());
+
+  HandleScope handles;
+
+  Handle<String> subject_handle(subject);
+  Handle<JSRegExp> regexp_handle(regexp);
+  Handle<JSArray> last_match_info_handle(last_match_info);
+  Handle<Object> match = RegExpImpl::Exec(regexp_handle,
+                                          subject_handle,
+                                          0,
+                                          last_match_info_handle);
+  if (match.is_null()) return Failure::Exception();
+  if (match->IsNull()) return *subject_handle;
+
+  ASSERT(last_match_info_handle->HasFastElements());
+
+  HandleScope loop_scope;
+  int start, end;
+  {
+    AssertNoAllocation match_info_array_is_not_in_a_handle;
+    FixedArray* match_info_array =
+        FixedArray::cast(last_match_info_handle->elements());
+
+    start = RegExpImpl::GetCapture(match_info_array, 0);
+    end = RegExpImpl::GetCapture(match_info_array, 1);
+  }
+
+  int length = subject->length();
+  int new_length = length - (end - start);
+  if (new_length == 0) {
+    return Heap::empty_string();
+  }
+  Handle<ResultSeqString> answer;
+  if (ResultSeqString::kHasAsciiEncoding) {
+    answer =
+        Handle<ResultSeqString>::cast(Factory::NewRawAsciiString(new_length));
+  } else {
+    answer =
+        Handle<ResultSeqString>::cast(Factory::NewRawTwoByteString(new_length));
+  }
+
+  // If the regexp isn't global, only match once.
+  if (!regexp_handle->GetFlags().is_global()) {
+    if (start > 0) {
+      String::WriteToFlat(*subject_handle,
+                          answer->GetChars(),
+                          0,
+                          start);
+    }
+    if (end < length) {
+      String::WriteToFlat(*subject_handle,
+                          answer->GetChars() + start,
+                          end,
+                          length);
+    }
+    return *answer;
+  }
+
+  int prev = 0;  // Index of end of last match.
+  int next = 0;  // Start of next search (prev unless last match was empty).
+  int position = 0;
+
+  do {
+    if (prev < start) {
+      // Add substring subject[prev;start] to answer string.
+      String::WriteToFlat(*subject_handle,
+                          answer->GetChars() + position,
+                          prev,
+                          start);
+      position += start - prev;
+    }
+    prev = end;
+    next = end;
+    // Continue from where the match ended, unless it was an empty match.
+    if (start == end) {
+      next++;
+      if (next > length) break;
+    }
+    match = RegExpImpl::Exec(regexp_handle,
+                             subject_handle,
+                             next,
+                             last_match_info_handle);
+    if (match.is_null()) return Failure::Exception();
+    if (match->IsNull()) break;
+
+    ASSERT(last_match_info_handle->HasFastElements());
+    HandleScope loop_scope;
+    {
+      AssertNoAllocation match_info_array_is_not_in_a_handle;
+      FixedArray* match_info_array =
+          FixedArray::cast(last_match_info_handle->elements());
+      start = RegExpImpl::GetCapture(match_info_array, 0);
+      end = RegExpImpl::GetCapture(match_info_array, 1);
+    }
+  } while (true);
+
+  if (prev < length) {
+    // Add substring subject[prev;length] to answer string.
+    String::WriteToFlat(*subject_handle,
+                        answer->GetChars() + position,
+                        prev,
+                        length);
+    position += length - prev;
+  }
+
+  if (position == 0) {
+    return Heap::empty_string();
+  }
+
+  // Shorten string and fill
+  int string_size = ResultSeqString::SizeFor(position);
+  int allocated_string_size = ResultSeqString::SizeFor(new_length);
+  int delta = allocated_string_size - string_size;
+
+  answer->set_length(position);
+  if (delta == 0) return *answer;
+
+  Address end_of_string = answer->address() + string_size;
+  Heap::CreateFillerObjectAt(end_of_string, delta);
+
+  return *answer;
+}
+
+
 static Object* Runtime_StringReplaceRegExpWithString(Arguments args) {
   ASSERT(args.length() == 4);
 
@@ -2311,6 +2439,16 @@
 
   ASSERT(last_match_info->HasFastElements());
 
+  if (replacement->length() == 0) {
+    if (subject->HasOnlyAsciiChars()) {
+      return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
+          subject, regexp, last_match_info);
+    } else {
+      return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
+          subject, regexp, last_match_info);
+    }
+  }
+
   return StringReplaceRegExpWithString(subject,
                                        regexp,
                                        replacement,
@@ -5437,7 +5575,7 @@
 
   CONVERT_DOUBLE_CHECKED(x, args[0]);
   CONVERT_DOUBLE_CHECKED(y, args[1]);
-  return Heap::AllocateHeapNumber(x + y);
+  return Heap::NumberFromDouble(x + y);
 }
 
 
@@ -5447,7 +5585,7 @@
 
   CONVERT_DOUBLE_CHECKED(x, args[0]);
   CONVERT_DOUBLE_CHECKED(y, args[1]);
-  return Heap::AllocateHeapNumber(x - y);
+  return Heap::NumberFromDouble(x - y);
 }
 
 
@@ -5457,7 +5595,7 @@
 
   CONVERT_DOUBLE_CHECKED(x, args[0]);
   CONVERT_DOUBLE_CHECKED(y, args[1]);
-  return Heap::AllocateHeapNumber(x * y);
+  return Heap::NumberFromDouble(x * y);
 }
 
 
@@ -5466,7 +5604,7 @@
   ASSERT(args.length() == 1);
 
   CONVERT_DOUBLE_CHECKED(x, args[0]);
-  return Heap::AllocateHeapNumber(-x);
+  return Heap::NumberFromDouble(-x);
 }
 
 
@@ -6068,7 +6206,7 @@
   // custom powi() function than the generic pow().
   if (args[1]->IsSmi()) {
     int y = Smi::cast(args[1])->value();
-    return Heap::AllocateHeapNumber(powi(x, y));
+    return Heap::NumberFromDouble(powi(x, y));
   }
 
   CONVERT_DOUBLE_CHECKED(y, args[1]);
diff --git a/src/spaces.cc b/src/spaces.cc
index 3c495ba..ca4b66a 100644
--- a/src/spaces.cc
+++ b/src/spaces.cc
@@ -2305,8 +2305,8 @@
       }
 
       ASSERT(code->instruction_start() <= prev_pc &&
-             prev_pc <= code->relocation_start());
-      delta += static_cast<int>(code->relocation_start() - prev_pc);
+             prev_pc <= code->instruction_end());
+      delta += static_cast<int>(code->instruction_end() - prev_pc);
       EnterComment("NoComment", delta);
     }
   }
diff --git a/src/version.cc b/src/version.cc
index db604e0..d930c8d 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,7 +34,7 @@
 // cannot be changed without changing the SCons build script.
 #define MAJOR_VERSION     2
 #define MINOR_VERSION     2
-#define BUILD_NUMBER      22
+#define BUILD_NUMBER      23
 #define PATCH_LEVEL       0
 #define CANDIDATE_VERSION false
 
diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc
index 3b1aeae..7e04c20 100644
--- a/src/x64/codegen-x64.cc
+++ b/src/x64/codegen-x64.cc
@@ -3373,9 +3373,12 @@
     }
 
   } else {
-    bool overwrite =
+    bool can_overwrite =
       (node->expression()->AsBinaryOperation() != NULL &&
        node->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
+    UnaryOverwriteMode overwrite =
+        can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
+    bool no_negative_zero = node->expression()->no_negative_zero();
     Load(node->expression());
     switch (op) {
       case Token::NOT:
@@ -3385,7 +3388,10 @@
         break;
 
       case Token::SUB: {
-        GenericUnaryOpStub stub(Token::SUB, overwrite);
+        GenericUnaryOpStub stub(
+            Token::SUB,
+            overwrite,
+            no_negative_zero ? kIgnoreNegativeZero : kStrictNegativeZero);
         Result operand = frame_->Pop();
         Result answer = frame_->CallStub(&stub, &operand);
         answer.set_type_info(TypeInfo::Number());
@@ -8506,6 +8512,11 @@
     Label try_float;
     __ JumpIfNotSmi(rax, &try_float);
 
+    if (negative_zero_ == kIgnoreNegativeZero) {
+      __ SmiCompare(rax, Smi::FromInt(0));
+      __ j(equal, &done);
+    }
+
     // Enter runtime system if the value of the smi is zero
     // to make sure that we switch between 0 and -0.
     // Also enter it if the value of the smi is Smi::kMinValue.
@@ -8513,10 +8524,14 @@
 
     // Either zero or Smi::kMinValue, neither of which become a smi when
     // negated.
-    __ SmiCompare(rax, Smi::FromInt(0));
-    __ j(not_equal, &slow);
-    __ Move(rax, Factory::minus_zero_value());
-    __ jmp(&done);
+    if (negative_zero_ == kStrictNegativeZero) {
+      __ SmiCompare(rax, Smi::FromInt(0));
+      __ j(not_equal, &slow);
+      __ Move(rax, Factory::minus_zero_value());
+      __ jmp(&done);
+    } else  {
+      __ jmp(&slow);
+    }
 
     // Try floating point case.
     __ bind(&try_float);
@@ -8529,7 +8544,7 @@
     __ shl(kScratchRegister, Immediate(63));
     __ xor_(rdx, kScratchRegister);  // Flip sign.
     // rdx is value to store.
-    if (overwrite_) {
+    if (overwrite_ == UNARY_OVERWRITE) {
       __ movq(FieldOperand(rax, HeapNumber::kValueOffset), rdx);
     } else {
       __ AllocateHeapNumber(rcx, rbx, &slow);
@@ -10596,6 +10611,7 @@
           // the four basic operations. The stub stays in the DEFAULT state
           // forever for all other operations (also if smi code is skipped).
           GenerateTypeTransition(masm);
+          break;
         }
 
         Label not_floats;
@@ -10913,31 +10929,13 @@
 void GenericBinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
   Label get_result;
 
-  // Keep a copy of operands on the stack and make sure they are also in
-  // rdx, rax.
+  // Ensure the operands are on the stack.
   if (HasArgsInRegisters()) {
     GenerateRegisterArgsPush(masm);
-  } else {
-    GenerateLoadArguments(masm);
   }
 
-  // Internal frame is necessary to handle exceptions properly.
-  __ EnterInternalFrame();
-
-  // Push arguments on stack if the stub expects them there.
-  if (!HasArgsInRegisters()) {
-    __ push(rdx);
-    __ push(rax);
-  }
-  // Call the stub proper to get the result in rax.
-  __ call(&get_result);
-  __ LeaveInternalFrame();
-
   // Left and right arguments are already on stack.
-  __ pop(rcx);
-  // Push the operation result. The tail call to BinaryOp_Patch will
-  // return it to the original caller..
-  __ push(rax);
+  __ pop(rcx);  // Save the return address.
 
   // Push this stub's key.
   __ Push(Smi::FromInt(MinorKey()));
@@ -10948,17 +10946,13 @@
 
   __ Push(Smi::FromInt(runtime_operands_type_));
 
-  __ push(rcx);
+  __ push(rcx);  // The return address.
 
   // Perform patching to an appropriate fast case and return the result.
   __ TailCallExternalReference(
       ExternalReference(IC_Utility(IC::kBinaryOp_Patch)),
-      6,
+      5,
       1);
-
-  // The entry point for the result calculation is assumed to be immediately
-  // after this sequence.
-  __ bind(&get_result);
 }
 
 
diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc
index e3f74f6..c6be503 100644
--- a/src/x64/full-codegen-x64.cc
+++ b/src/x64/full-codegen-x64.cc
@@ -2807,9 +2807,11 @@
 
     case Token::SUB: {
       Comment cmt(masm_, "[ UnaryOperation (SUB)");
-      bool overwrite =
+      bool can_overwrite =
           (expr->expression()->AsBinaryOperation() != NULL &&
            expr->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
+      UnaryOverwriteMode overwrite =
+          can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
       GenericUnaryOpStub stub(Token::SUB, overwrite);
       // GenericUnaryOpStub expects the argument to be in the
       // accumulator register rax.
@@ -2821,9 +2823,11 @@
 
     case Token::BIT_NOT: {
       Comment cmt(masm_, "[ UnaryOperation (BIT_NOT)");
-      bool overwrite =
+      bool can_overwrite =
           (expr->expression()->AsBinaryOperation() != NULL &&
            expr->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
+      UnaryOverwriteMode overwrite =
+          can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
       GenericUnaryOpStub stub(Token::BIT_NOT, overwrite);
       // GenericUnaryOpStub expects the argument to be in the
       // accumulator register rax.