2010-04-26: Version 2.2.5

Various performance improvements (especially for ARM and x64)

Fixed bug in CPU profiling (http://crbug.com/42137)

Fixed a bug with the natives cache.
        
Fixed two bugs in the ARM code generator that can cause wrong calculations.

Fixed a bug that may cause a wrong result for shift operations.


git-svn-id: http://v8.googlecode.com/svn/trunk@4498 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/arm/assembler-arm.cc b/src/arm/assembler-arm.cc
index 23d5e00..a6d81bf 100644
--- a/src/arm/assembler-arm.cc
+++ b/src/arm/assembler-arm.cc
@@ -306,6 +306,7 @@
   reloc_info_writer.Reposition(buffer_ + buffer_size, pc_);
   num_prinfo_ = 0;
   next_buffer_check_ = 0;
+  const_pool_blocked_nesting_ = 0;
   no_const_pool_before_ = 0;
   last_const_pool_end_ = 0;
   last_bound_pos_ = 0;
@@ -317,6 +318,7 @@
 
 
 Assembler::~Assembler() {
+  ASSERT(const_pool_blocked_nesting_ == 0);
   if (own_buffer_) {
     if (spare_buffer_ == NULL && buffer_size_ == kMinimalBufferSize) {
       spare_buffer_ = buffer_;
@@ -348,6 +350,51 @@
 }
 
 
+bool Assembler::IsNop(Instr instr, int type) {
+  // Check for mov rx, rx.
+  ASSERT(0 <= type && type <= 14);  // mov pc, pc is not a nop.
+  return instr == (al | 13*B21 | type*B12 | type);
+}
+
+
+bool Assembler::IsBranch(Instr instr) {
+  return (instr & (B27 | B25)) == (B27 | B25);
+}
+
+
+int Assembler::GetBranchOffset(Instr instr) {
+  ASSERT(IsBranch(instr));
+  // Take the jump offset in the lower 24 bits, sign extend it and multiply it
+  // with 4 to get the offset in bytes.
+  return ((instr & Imm24Mask) << 8) >> 6;
+}
+
+
+bool Assembler::IsLdrRegisterImmediate(Instr instr) {
+  return (instr & (B27 | B26 | B25 | B22 | B20)) == (B26 | B20);
+}
+
+
+int Assembler::GetLdrRegisterImmediateOffset(Instr instr) {
+  ASSERT(IsLdrRegisterImmediate(instr));
+  bool positive = (instr & B23) == B23;
+  int offset = instr & Off12Mask;  // Zero extended offset.
+  return positive ? offset : -offset;
+}
+
+
+Instr Assembler::SetLdrRegisterImmediateOffset(Instr instr, int offset) {
+  ASSERT(IsLdrRegisterImmediate(instr));
+  bool positive = offset >= 0;
+  if (!positive) offset = -offset;
+  ASSERT(is_uint12(offset));
+  // Set bit indicating whether the offset should be added.
+  instr = (instr & ~B23) | (positive ? B23 : 0);
+  // Set the actual offset.
+  return (instr & ~Off12Mask) | offset;
+}
+
+
 // Labels refer to positions in the (to be) generated code.
 // There are bound, linked, and unused labels.
 //
@@ -371,10 +418,10 @@
   }
   ASSERT((instr & 7*B25) == 5*B25);  // b, bl, or blx imm24
   int imm26 = ((instr & Imm24Mask) << 8) >> 6;
-  if ((instr & CondMask) == nv && (instr & B24) != 0)
+  if ((instr & CondMask) == nv && (instr & B24) != 0) {
     // blx uses bit 24 to encode bit 2 of imm26
     imm26 += 2;
-
+  }
   return pos + kPcLoadDelta + imm26;
 }
 
@@ -902,6 +949,10 @@
   if (dst.is(pc)) {
     WriteRecordedPositions();
   }
+  // Don't allow nop instructions in the form mov rn, rn to be generated using
+  // the mov instruction. They must be generated using nop(int)
+  // pseudo instructions.
+  ASSERT(!(src.is_reg() && src.rm().is(dst) && s == LeaveCC && cond == al));
   addrmod1(cond | 13*B21 | s, r0, dst, src);
 }
 
@@ -1691,6 +1742,13 @@
 
 
 // Pseudo instructions.
+void Assembler::nop(int type) {
+  // This is mov rx, rx.
+  ASSERT(0 <= type && type <= 14);  // mov pc, pc is not a nop.
+  emit(al | 13*B21 | type*B12 | type);
+}
+
+
 void Assembler::lea(Register dst,
                     const MemOperand& x,
                     SBit s,
@@ -1726,11 +1784,6 @@
 }
 
 
-void Assembler::BlockConstPoolFor(int instructions) {
-  BlockConstPoolBefore(pc_offset() + instructions * kInstrSize);
-}
-
-
 // Debugging.
 void Assembler::RecordJSReturn() {
   WriteRecordedPositions();
@@ -1894,12 +1947,17 @@
 
   // However, some small sequences of instructions must not be broken up by the
   // insertion of a constant pool; such sequences are protected by setting
-  // no_const_pool_before_, which is checked here. Also, recursive calls to
-  // CheckConstPool are blocked by no_const_pool_before_.
-  if (pc_offset() < no_const_pool_before_) {
+  // either const_pool_blocked_nesting_ or no_const_pool_before_, which are
+  // both checked here. Also, recursive calls to CheckConstPool are blocked by
+  // no_const_pool_before_.
+  if (const_pool_blocked_nesting_ > 0 || pc_offset() < no_const_pool_before_) {
     // Emission is currently blocked; make sure we try again as soon as
     // possible.
-    next_buffer_check_ = no_const_pool_before_;
+    if (const_pool_blocked_nesting_ > 0) {
+      next_buffer_check_ = pc_offset() + kInstrSize;
+    } else {
+      next_buffer_check_ = no_const_pool_before_;
+    }
 
     // Something is wrong if emission is forced and blocked at the same time.
     ASSERT(!force_emit);
diff --git a/src/arm/assembler-arm.h b/src/arm/assembler-arm.h
index 98be7b5..e6284d3 100644
--- a/src/arm/assembler-arm.h
+++ b/src/arm/assembler-arm.h
@@ -896,7 +896,7 @@
             const Condition cond = al);
 
   // Pseudo instructions
-  void nop()  { mov(r0, Operand(r0)); }
+  void nop(int type = 0);
 
   void push(Register src, Condition cond = al) {
     str(src, MemOperand(sp, 4, NegPreIndex), cond);
@@ -925,9 +925,21 @@
   // Check whether an immediate fits an addressing mode 1 instruction.
   bool ImmediateFitsAddrMode1Instruction(int32_t imm32);
 
-  // Postpone the generation of the constant pool for the specified number of
-  // instructions.
-  void BlockConstPoolFor(int instructions);
+  // Class for scoping postponing the constant pool generation.
+  class BlockConstPoolScope {
+   public:
+    explicit BlockConstPoolScope(Assembler* assem) : assem_(assem) {
+      assem_->StartBlockConstPool();
+    }
+    ~BlockConstPoolScope() {
+      assem_->EndBlockConstPool();
+    }
+
+   private:
+    Assembler* assem_;
+
+    DISALLOW_IMPLICIT_CONSTRUCTORS(BlockConstPoolScope);
+  };
 
   // Debugging
 
@@ -946,14 +958,30 @@
   int current_position() const { return current_position_; }
   int current_statement_position() const { return current_position_; }
 
+  void StartBlockConstPool() {
+    const_pool_blocked_nesting_++;
+  }
+  void EndBlockConstPool() {
+    const_pool_blocked_nesting_--;
+  }
+
+  // Read/patch instructions
+  static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); }
+  static void instr_at_put(byte* pc, Instr instr) {
+    *reinterpret_cast<Instr*>(pc) = instr;
+  }
+  static bool IsNop(Instr instr, int type = 0);
+  static bool IsBranch(Instr instr);
+  static int GetBranchOffset(Instr instr);
+  static bool IsLdrRegisterImmediate(Instr instr);
+  static int GetLdrRegisterImmediateOffset(Instr instr);
+  static Instr SetLdrRegisterImmediateOffset(Instr instr, int offset);
+
+
  protected:
   int buffer_space() const { return reloc_info_writer.pos() - pc_; }
 
   // Read/patch instructions
-  static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); }
-  void instr_at_put(byte* pc, Instr instr) {
-    *reinterpret_cast<Instr*>(pc) = instr;
-  }
   Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); }
   void instr_at_put(int pos, Instr instr) {
     *reinterpret_cast<Instr*>(buffer_ + pos) = instr;
@@ -1022,8 +1050,9 @@
   // distance between pools.
   static const int kMaxDistBetweenPools = 4*KB - 2*kBufferCheckInterval;
 
-  // Emission of the constant pool may be blocked in some code sequences
-  int no_const_pool_before_;  // block emission before this pc offset
+  // Emission of the constant pool may be blocked in some code sequences.
+  int const_pool_blocked_nesting_;  // Block emission if this is not zero.
+  int no_const_pool_before_;  // Block emission before this pc offset.
 
   // Keep track of the last emitted pool to guarantee a maximal distance
   int last_const_pool_end_;  // pc offset following the last constant pool
@@ -1075,6 +1104,7 @@
   friend class RegExpMacroAssemblerARM;
   friend class RelocInfo;
   friend class CodePatcher;
+  friend class BlockConstPoolScope;
 };
 
 } }  // namespace v8::internal
diff --git a/src/arm/builtins-arm.cc b/src/arm/builtins-arm.cc
index 91e896d..7bb8c46 100644
--- a/src/arm/builtins-arm.cc
+++ b/src/arm/builtins-arm.cc
@@ -593,7 +593,7 @@
       __ bind(&loop);
       __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
       __ bind(&entry);
-      __ cmp(r5, Operand(r6));
+      __ cmp(r5, r6);
       __ b(lt, &loop);
     }
 
@@ -666,7 +666,7 @@
       __ bind(&loop);
       __ str(r7, MemOperand(r2, kPointerSize, PostIndex));
       __ bind(&entry);
-      __ cmp(r2, Operand(r6));
+      __ cmp(r2, r6);
       __ b(lt, &loop);
     }
 
@@ -863,7 +863,7 @@
   __ ldr(r0, MemOperand(r0));  // dereference handle
   __ push(r0);  // push parameter
   __ bind(&entry);
-  __ cmp(r4, Operand(r2));
+  __ cmp(r4, r2);
   __ b(ne, &loop);
 
   // Initialize all JavaScript callee-saved registers, since they will be seen
@@ -1213,7 +1213,7 @@
   Label invoke, dont_adapt_arguments;
 
   Label enough, too_few;
-  __ cmp(r0, Operand(r2));
+  __ cmp(r0, r2);
   __ b(lt, &too_few);
   __ cmp(r2, Operand(SharedFunctionInfo::kDontAdaptArgumentsSentinel));
   __ b(eq, &dont_adapt_arguments);
diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc
index b2fe05f..3594aab 100644
--- a/src/arm/codegen-arm.cc
+++ b/src/arm/codegen-arm.cc
@@ -206,7 +206,7 @@
 
 #ifdef DEBUG
         JumpTarget verified_true;
-        __ cmp(r0, Operand(cp));
+        __ cmp(r0, cp);
         verified_true.Branch(eq);
         __ stop("NewContext: r0 is expected to be the same as cp");
         verified_true.Bind();
@@ -247,29 +247,10 @@
       }
 
       // Store the arguments object.  This must happen after context
-      // initialization because the arguments object may be stored in the
-      // context.
-      if (scope()->arguments() != NULL) {
-        Comment cmnt(masm_, "[ allocate arguments object");
-        ASSERT(scope()->arguments_shadow() != NULL);
-        Variable* arguments = scope()->arguments()->var();
-        Variable* shadow = scope()->arguments_shadow()->var();
-        ASSERT(arguments != NULL && arguments->slot() != NULL);
-        ASSERT(shadow != NULL && shadow->slot() != NULL);
-        ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
-        __ ldr(r2, frame_->Function());
-        // The receiver is below the arguments, the return address, and the
-        // frame pointer on the stack.
-        const int kReceiverDisplacement = 2 + scope()->num_parameters();
-        __ add(r1, fp, Operand(kReceiverDisplacement * kPointerSize));
-        __ mov(r0, Operand(Smi::FromInt(scope()->num_parameters())));
-        frame_->Adjust(3);
-        __ stm(db_w, sp, r0.bit() | r1.bit() | r2.bit());
-        frame_->CallStub(&stub, 3);
-        frame_->EmitPush(r0);
-        StoreToSlot(arguments->slot(), NOT_CONST_INIT);
-        StoreToSlot(shadow->slot(), NOT_CONST_INIT);
-        frame_->Drop();  // Value is no longer needed.
+      // initialization because the arguments object may be stored in
+      // the context.
+      if (ArgumentsMode() != NO_ARGUMENTS_ALLOCATION) {
+        StoreArgumentsObject(true);
       }
 
       // Initialize ThisFunction reference if present.
@@ -353,37 +334,34 @@
       frame_->CallRuntime(Runtime::kTraceExit, 1);
     }
 
+#ifdef DEBUG
     // Add a label for checking the size of the code used for returning.
     Label check_exit_codesize;
     masm_->bind(&check_exit_codesize);
+#endif
+    // Make sure that the constant pool is not emitted inside of the return
+    // sequence.
+    { Assembler::BlockConstPoolScope block_const_pool(masm_);
+      // Tear down the frame which will restore the caller's frame pointer and
+      // the link register.
+      frame_->Exit();
 
-    // Calculate the exact length of the return sequence and make sure that
-    // the constant pool is not emitted inside of the return sequence.
-    int32_t sp_delta = (scope()->num_parameters() + 1) * kPointerSize;
-    int return_sequence_length = Assembler::kJSReturnSequenceLength;
-    if (!masm_->ImmediateFitsAddrMode1Instruction(sp_delta)) {
-      // Additional mov instruction generated.
-      return_sequence_length++;
+      // Here we use masm_-> instead of the __ macro to avoid the code coverage
+      // tool from instrumenting as we rely on the code size here.
+      int32_t sp_delta = (scope()->num_parameters() + 1) * kPointerSize;
+      masm_->add(sp, sp, Operand(sp_delta));
+      masm_->Jump(lr);
     }
-    masm_->BlockConstPoolFor(return_sequence_length);
 
-    // Tear down the frame which will restore the caller's frame pointer and
-    // the link register.
-    frame_->Exit();
-
-    // Here we use masm_-> instead of the __ macro to avoid the code coverage
-    // tool from instrumenting as we rely on the code size here.
-    masm_->add(sp, sp, Operand(sp_delta));
-    masm_->Jump(lr);
-
+#ifdef DEBUG
     // Check that the size of the code used for returning matches what is
-    // expected by the debugger. The add instruction above is an addressing
-    // mode 1 instruction where there are restrictions on which immediate values
-    // can be encoded in the instruction and which immediate values requires
-    // use of an additional instruction for moving the immediate to a temporary
-    // register.
-    ASSERT_EQ(return_sequence_length,
-              masm_->InstructionsGeneratedSince(&check_exit_codesize));
+    // expected by the debugger. If the sp_delts above cannot be encoded in the
+    // add instruction the add will generate two instructions.
+    int return_sequence_length =
+        masm_->InstructionsGeneratedSince(&check_exit_codesize);
+    CHECK(return_sequence_length == Assembler::kJSReturnSequenceLength ||
+          return_sequence_length == Assembler::kJSReturnSequenceLength + 1);
+#endif
   }
 
   // Adjust for function-level loop nesting.
@@ -393,6 +371,7 @@
   // Code generation state must be reset.
   ASSERT(!has_cc());
   ASSERT(state_ == NULL);
+  ASSERT(loop_nesting() == 0);
   ASSERT(!function_return_is_shadowed_);
   function_return_.Unuse();
   DeleteFrame();
@@ -606,6 +585,66 @@
 }
 
 
+ArgumentsAllocationMode CodeGenerator::ArgumentsMode() {
+  if (scope()->arguments() == NULL) return NO_ARGUMENTS_ALLOCATION;
+  ASSERT(scope()->arguments_shadow() != NULL);
+  // We don't want to do lazy arguments allocation for functions that
+  // have heap-allocated contexts, because it interfers with the
+  // uninitialized const tracking in the context objects.
+  return (scope()->num_heap_slots() > 0)
+      ? EAGER_ARGUMENTS_ALLOCATION
+      : LAZY_ARGUMENTS_ALLOCATION;
+}
+
+
+void CodeGenerator::StoreArgumentsObject(bool initial) {
+  VirtualFrame::SpilledScope spilled_scope(frame_);
+
+  ArgumentsAllocationMode mode = ArgumentsMode();
+  ASSERT(mode != NO_ARGUMENTS_ALLOCATION);
+
+  Comment cmnt(masm_, "[ store arguments object");
+  if (mode == LAZY_ARGUMENTS_ALLOCATION && initial) {
+    // When using lazy arguments allocation, we store the hole value
+    // as a sentinel indicating that the arguments object hasn't been
+    // allocated yet.
+    __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
+    frame_->EmitPush(ip);
+  } else {
+    ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
+    __ ldr(r2, frame_->Function());
+    // The receiver is below the arguments, the return address, and the
+    // frame pointer on the stack.
+    const int kReceiverDisplacement = 2 + scope()->num_parameters();
+    __ add(r1, fp, Operand(kReceiverDisplacement * kPointerSize));
+    __ mov(r0, Operand(Smi::FromInt(scope()->num_parameters())));
+    frame_->Adjust(3);
+    __ stm(db_w, sp, r0.bit() | r1.bit() | r2.bit());
+    frame_->CallStub(&stub, 3);
+    frame_->EmitPush(r0);
+  }
+
+  Variable* arguments = scope()->arguments()->var();
+  Variable* shadow = scope()->arguments_shadow()->var();
+  ASSERT(arguments != NULL && arguments->slot() != NULL);
+  ASSERT(shadow != NULL && shadow->slot() != NULL);
+  JumpTarget done;
+  if (mode == LAZY_ARGUMENTS_ALLOCATION && !initial) {
+    // We have to skip storing into the arguments slot if it has
+    // already been written to. This can happen if the a function
+    // has a local variable named 'arguments'.
+    LoadFromSlot(scope()->arguments()->var()->slot(), NOT_INSIDE_TYPEOF);
+    frame_->EmitPop(r0);
+    __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
+    __ cmp(r0, ip);
+    done.Branch(ne);
+  }
+  StoreToSlot(arguments->slot(), NOT_CONST_INIT);
+  if (mode == LAZY_ARGUMENTS_ALLOCATION) done.Bind();
+  StoreToSlot(shadow->slot(), NOT_CONST_INIT);
+}
+
+
 void CodeGenerator::LoadTypeofExpression(Expression* expr) {
   // Special handling of identifiers as subexpressions of typeof.
   VirtualFrame::SpilledScope spilled_scope(frame_);
@@ -622,7 +661,7 @@
   } else if (variable != NULL && variable->slot() != NULL) {
     // For a variable that rewrites to a slot, we signal it is the immediate
     // subexpression of a typeof.
-    LoadFromSlot(variable->slot(), INSIDE_TYPEOF);
+    LoadFromSlotCheckForArguments(variable->slot(), INSIDE_TYPEOF);
     frame_->SpillAll();
   } else {
     // Anything else can be handled normally.
@@ -1466,6 +1505,188 @@
 }
 
 
+void CodeGenerator::CallApplyLazy(Expression* applicand,
+                                  Expression* receiver,
+                                  VariableProxy* arguments,
+                                  int position) {
+  // An optimized implementation of expressions of the form
+  // x.apply(y, arguments).
+  // If the arguments object of the scope has not been allocated,
+  // and x.apply is Function.prototype.apply, this optimization
+  // just copies y and the arguments of the current function on the
+  // stack, as receiver and arguments, and calls x.
+  // In the implementation comments, we call x the applicand
+  // and y the receiver.
+  VirtualFrame::SpilledScope spilled_scope(frame_);
+
+  ASSERT(ArgumentsMode() == LAZY_ARGUMENTS_ALLOCATION);
+  ASSERT(arguments->IsArguments());
+
+  // Load applicand.apply onto the stack. This will usually
+  // give us a megamorphic load site. Not super, but it works.
+  LoadAndSpill(applicand);
+  Handle<String> name = Factory::LookupAsciiSymbol("apply");
+  __ mov(r2, Operand(name));
+  frame_->CallLoadIC(RelocInfo::CODE_TARGET);
+  frame_->EmitPush(r0);
+
+  // Load the receiver and the existing arguments object onto the
+  // expression stack. Avoid allocating the arguments object here.
+  LoadAndSpill(receiver);
+  LoadFromSlot(scope()->arguments()->var()->slot(), NOT_INSIDE_TYPEOF);
+
+  // Emit the source position information after having loaded the
+  // receiver and the arguments.
+  CodeForSourcePosition(position);
+  // Contents of the stack at this point:
+  //   sp[0]: arguments object of the current function or the hole.
+  //   sp[1]: receiver
+  //   sp[2]: applicand.apply
+  //   sp[3]: applicand.
+
+  // Check if the arguments object has been lazily allocated
+  // already. If so, just use that instead of copying the arguments
+  // from the stack. This also deals with cases where a local variable
+  // named 'arguments' has been introduced.
+  __ ldr(r0, MemOperand(sp, 0));
+
+  Label slow, done;
+  __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
+  __ cmp(ip, r0);
+  __ b(ne, &slow);
+
+  Label build_args;
+  // Get rid of the arguments object probe.
+  frame_->Drop();
+  // Stack now has 3 elements on it.
+  // Contents of stack at this point:
+  //   sp[0]: receiver
+  //   sp[1]: applicand.apply
+  //   sp[2]: applicand.
+
+  // Check that the receiver really is a JavaScript object.
+  __ ldr(r0, MemOperand(sp, 0));
+  __ BranchOnSmi(r0, &build_args);
+  // We allow all JSObjects including JSFunctions.  As long as
+  // JS_FUNCTION_TYPE is the last instance type and it is right
+  // after LAST_JS_OBJECT_TYPE, we do not have to check the upper
+  // bound.
+  ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
+  ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1);
+  __ CompareObjectType(r0, r1, r2, FIRST_JS_OBJECT_TYPE);
+  __ b(lt, &build_args);
+
+  // Check that applicand.apply is Function.prototype.apply.
+  __ ldr(r0, MemOperand(sp, kPointerSize));
+  __ BranchOnSmi(r0, &build_args);
+  __ CompareObjectType(r0, r1, r2, JS_FUNCTION_TYPE);
+  __ b(ne, &build_args);
+  __ ldr(r0, FieldMemOperand(r0, JSFunction::kSharedFunctionInfoOffset));
+  Handle<Code> apply_code(Builtins::builtin(Builtins::FunctionApply));
+  __ ldr(r1, FieldMemOperand(r0, SharedFunctionInfo::kCodeOffset));
+  __ cmp(r1, Operand(apply_code));
+  __ b(ne, &build_args);
+
+  // Check that applicand is a function.
+  __ ldr(r1, MemOperand(sp, 2 * kPointerSize));
+  __ BranchOnSmi(r1, &build_args);
+  __ CompareObjectType(r1, r2, r3, JS_FUNCTION_TYPE);
+  __ b(ne, &build_args);
+
+  // Copy the arguments to this function possibly from the
+  // adaptor frame below it.
+  Label invoke, adapted;
+  __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
+  __ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset));
+  __ cmp(r3, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
+  __ b(eq, &adapted);
+
+  // No arguments adaptor frame. Copy fixed number of arguments.
+  __ mov(r0, Operand(scope()->num_parameters()));
+  for (int i = 0; i < scope()->num_parameters(); i++) {
+    __ ldr(r2, frame_->ParameterAt(i));
+    __ push(r2);
+  }
+  __ jmp(&invoke);
+
+  // Arguments adaptor frame present. Copy arguments from there, but
+  // avoid copying too many arguments to avoid stack overflows.
+  __ bind(&adapted);
+  static const uint32_t kArgumentsLimit = 1 * KB;
+  __ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset));
+  __ mov(r0, Operand(r0, LSR, kSmiTagSize));
+  __ mov(r3, r0);
+  __ cmp(r0, Operand(kArgumentsLimit));
+  __ b(gt, &build_args);
+
+  // Loop through the arguments pushing them onto the execution
+  // stack. We don't inform the virtual frame of the push, so we don't
+  // have to worry about getting rid of the elements from the virtual
+  // frame.
+  Label loop;
+  // r3 is a small non-negative integer, due to the test above.
+  __ cmp(r3, Operand(0));
+  __ b(eq, &invoke);
+  // Compute the address of the first argument.
+  __ add(r2, r2, Operand(r3, LSL, kPointerSizeLog2));
+  __ add(r2, r2, Operand(kPointerSize));
+  __ bind(&loop);
+  // Post-decrement argument address by kPointerSize on each iteration.
+  __ ldr(r4, MemOperand(r2, kPointerSize, NegPostIndex));
+  __ push(r4);
+  __ sub(r3, r3, Operand(1), SetCC);
+  __ b(gt, &loop);
+
+  // Invoke the function.
+  __ bind(&invoke);
+  ParameterCount actual(r0);
+  __ InvokeFunction(r1, actual, CALL_FUNCTION);
+  // Drop applicand.apply and applicand from the stack, and push
+  // the result of the function call, but leave the spilled frame
+  // unchanged, with 3 elements, so it is correct when we compile the
+  // slow-case code.
+  __ add(sp, sp, Operand(2 * kPointerSize));
+  __ push(r0);
+  // Stack now has 1 element:
+  //   sp[0]: result
+  __ jmp(&done);
+
+  // Slow-case: Allocate the arguments object since we know it isn't
+  // there, and fall-through to the slow-case where we call
+  // applicand.apply.
+  __ bind(&build_args);
+  // Stack now has 3 elements, because we have jumped from where:
+  //   sp[0]: receiver
+  //   sp[1]: applicand.apply
+  //   sp[2]: applicand.
+  StoreArgumentsObject(false);
+
+  // Stack and frame now have 4 elements.
+  __ bind(&slow);
+
+  // Generic computation of x.apply(y, args) with no special optimization.
+  // Flip applicand.apply and applicand on the stack, so
+  // applicand looks like the receiver of the applicand.apply call.
+  // Then process it as a normal function call.
+  __ ldr(r0, MemOperand(sp, 3 * kPointerSize));
+  __ ldr(r1, MemOperand(sp, 2 * kPointerSize));
+  __ str(r0, MemOperand(sp, 2 * kPointerSize));
+  __ str(r1, MemOperand(sp, 3 * kPointerSize));
+
+  CallFunctionStub call_function(2, NOT_IN_LOOP, NO_CALL_FUNCTION_FLAGS);
+  frame_->CallStub(&call_function, 3);
+  // The function and its two arguments have been dropped.
+  frame_->Drop();  // Drop the receiver as well.
+  frame_->EmitPush(r0);
+  // Stack now has 1 element:
+  //   sp[0]: result
+  __ bind(&done);
+
+  // Restore the context register after a call.
+  __ ldr(cp, frame_->Context());
+}
+
+
 void CodeGenerator::Branch(bool if_true, JumpTarget* target) {
   VirtualFrame::SpilledScope spilled_scope(frame_);
   ASSERT(has_cc());
@@ -1771,7 +1992,7 @@
   }
 #ifdef DEBUG
   JumpTarget verified_true;
-  __ cmp(r0, Operand(cp));
+  __ cmp(r0, cp);
   verified_true.Branch(eq);
   __ stop("PushContext: r0 is expected to be the same as cp");
   verified_true.Bind();
@@ -2248,7 +2469,7 @@
 
   __ ldr(r0, frame_->ElementAt(0));  // load the current count
   __ ldr(r1, frame_->ElementAt(1));  // load the length
-  __ cmp(r0, Operand(r1));  // compare to the array length
+  __ cmp(r0, r1);  // compare to the array length
   node->break_target()->Branch(hs);
 
   __ ldr(r0, frame_->ElementAt(0));
@@ -2802,6 +3023,34 @@
 }
 
 
+void CodeGenerator::LoadFromSlotCheckForArguments(Slot* slot,
+                                                  TypeofState state) {
+  LoadFromSlot(slot, state);
+
+  // Bail out quickly if we're not using lazy arguments allocation.
+  if (ArgumentsMode() != LAZY_ARGUMENTS_ALLOCATION) return;
+
+  // ... or if the slot isn't a non-parameter arguments slot.
+  if (slot->type() == Slot::PARAMETER || !slot->is_arguments()) return;
+
+  VirtualFrame::SpilledScope spilled_scope(frame_);
+
+  // Load the loaded value from the stack into r0 but leave it on the
+  // stack.
+  __ ldr(r0, MemOperand(sp, 0));
+
+  // If the loaded value is the sentinel that indicates that we
+  // haven't loaded the arguments object yet, we need to do it now.
+  JumpTarget exit;
+  __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
+  __ cmp(r0, ip);
+  exit.Branch(ne);
+  frame_->Drop();
+  StoreArgumentsObject(false);
+  exit.Bind();
+}
+
+
 void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) {
   ASSERT(slot != NULL);
   if (slot->type() == Slot::LOOKUP) {
@@ -2940,20 +3189,13 @@
     __ bind(&fast);
   }
 
-  // All extension objects were empty and it is safe to use a global
-  // load IC call.
-  Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
   // Load the global object.
   LoadGlobal();
-  // Setup the name register.
+  // Setup the name register and call load IC.
   __ mov(r2, Operand(slot->var()->name()));
-  // Call IC stub.
-  if (typeof_state == INSIDE_TYPEOF) {
-    frame_->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0);
-  } else {
-    frame_->CallCodeObject(ic, RelocInfo::CODE_TARGET_CONTEXT, 0);
-  }
-
+  frame_->CallLoadIC(typeof_state == INSIDE_TYPEOF
+                     ? RelocInfo::CODE_TARGET
+                     : RelocInfo::CODE_TARGET_CONTEXT);
   // Drop the global object. The result is in r0.
   frame_->Drop();
 }
@@ -2964,7 +3206,7 @@
   int original_height = frame_->height();
 #endif
   Comment cmnt(masm_, "[ Slot");
-  LoadFromSlot(node, NOT_INSIDE_TYPEOF);
+  LoadFromSlotCheckForArguments(node, NOT_INSIDE_TYPEOF);
   ASSERT(frame_->height() == original_height + 1);
 }
 
@@ -3422,21 +3664,37 @@
       // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)'
       // ------------------------------------------------------------------
 
-      LoadAndSpill(property->obj());  // Receiver.
-      // Load the arguments.
-      int arg_count = args->length();
-      for (int i = 0; i < arg_count; i++) {
-        LoadAndSpill(args->at(i));
-      }
+      Handle<String> name = Handle<String>::cast(literal->handle());
 
-      // Set the name register and call the IC initialization code.
-      __ mov(r2, Operand(literal->handle()));
-      InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP;
-      Handle<Code> stub = ComputeCallInitialize(arg_count, in_loop);
-      CodeForSourcePosition(node->position());
-      frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1);
-      __ ldr(cp, frame_->Context());
-      frame_->EmitPush(r0);
+      if (ArgumentsMode() == LAZY_ARGUMENTS_ALLOCATION &&
+          name->IsEqualTo(CStrVector("apply")) &&
+          args->length() == 2 &&
+          args->at(1)->AsVariableProxy() != NULL &&
+          args->at(1)->AsVariableProxy()->IsArguments()) {
+        // Use the optimized Function.prototype.apply that avoids
+        // allocating lazily allocated arguments objects.
+        CallApplyLazy(property->obj(),
+                      args->at(0),
+                      args->at(1)->AsVariableProxy(),
+                      node->position());
+
+      } else {
+        LoadAndSpill(property->obj());  // Receiver.
+        // Load the arguments.
+        int arg_count = args->length();
+        for (int i = 0; i < arg_count; i++) {
+          LoadAndSpill(args->at(i));
+        }
+
+        // Set the name register and call the IC initialization code.
+        __ mov(r2, Operand(name));
+        InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP;
+        Handle<Code> stub = ComputeCallInitialize(arg_count, in_loop);
+        CodeForSourcePosition(node->position());
+        frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1);
+        __ ldr(cp, frame_->Context());
+        frame_->EmitPush(r0);
+      }
 
     } else {
       // -------------------------------------------
@@ -3974,19 +4232,49 @@
   Label slow_allocate_heapnumber;
   Label heapnumber_allocated;
 
-  __ AllocateHeapNumber(r0, r1, r2, &slow_allocate_heapnumber);
+  __ AllocateHeapNumber(r4, r1, r2, &slow_allocate_heapnumber);
   __ jmp(&heapnumber_allocated);
 
   __ bind(&slow_allocate_heapnumber);
+  // To allocate a heap number, and ensure that it is not a smi, we
+  // call the runtime function FUnaryMinus on 0, returning the double
+  // -0.0. A new, distinct heap number is returned each time.
   __ mov(r0, Operand(Smi::FromInt(0)));
   __ push(r0);
   __ CallRuntime(Runtime::kNumberUnaryMinus, 1);
+  __ mov(r4, Operand(r0));
 
   __ bind(&heapnumber_allocated);
-  __ PrepareCallCFunction(1, r1);
-  __ CallCFunction(
-      ExternalReference::fill_heap_number_with_random_function(), 1);
-  frame_->EmitPush(r0);
+
+  // Convert 32 random bits in r0 to 0.(32 random bits) in a double
+  // by computing:
+  // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
+  if (CpuFeatures::IsSupported(VFP3)) {
+    __ PrepareCallCFunction(0, r1);
+    __ CallCFunction(ExternalReference::random_uint32_function(), 0);
+
+    CpuFeatures::Scope scope(VFP3);
+    // 0x41300000 is the top half of 1.0 x 2^20 as a double.
+    // Create this constant using mov/orr to avoid PC relative load.
+    __ mov(r1, Operand(0x41000000));
+    __ orr(r1, r1, Operand(0x300000));
+    // Move 0x41300000xxxxxxxx (x = random bits) to VFP.
+    __ vmov(d7, r0, r1);
+    // Move 0x4130000000000000 to VFP.
+    __ mov(r0, Operand(0));
+    __ vmov(d8, r0, r1);
+    // Subtract and store the result in the heap number.
+    __ vsub(d7, d7, d8);
+    __ sub(r0, r4, Operand(kHeapObjectTag));
+    __ vstr(d7, r0, HeapNumber::kValueOffset);
+    frame_->EmitPush(r4);
+  } else {
+    __ mov(r0, Operand(r4));
+    __ PrepareCallCFunction(1, r1);
+    __ CallCFunction(
+        ExternalReference::fill_heap_number_with_random_function(), 1);
+    frame_->EmitPush(r0);
+  }
 }
 
 
@@ -4172,18 +4460,20 @@
     frame_->EmitPush(r0);
     return;
   }
-  Handle<FixedArray> cache_obj(
-      FixedArray::cast(jsfunction_result_caches->get(cache_id)));
 
   Load(args->at(1));
   frame_->EmitPop(r2);
 
+  __ ldr(r1, ContextOperand(cp, Context::GLOBAL_INDEX));
+  __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalContextOffset));
+  __ ldr(r1, ContextOperand(r1, Context::JSFUNCTION_RESULT_CACHES_INDEX));
+  __ ldr(r1, FieldMemOperand(r1, FixedArray::OffsetOfElementAt(cache_id)));
+
   DeferredSearchCache* deferred = new DeferredSearchCache(r0, r1, r2);
 
   const int kFingerOffset =
       FixedArray::OffsetOfElementAt(JSFunctionResultCache::kFingerIndex);
   ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
-  __ mov(r1, Operand(cache_obj));
   __ ldr(r0, FieldMemOperand(r1, kFingerOffset));
   // r0 now holds finger offset as a smi.
   __ add(r3, r1, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
@@ -4255,7 +4545,7 @@
   LoadAndSpill(args->at(1));
   frame_->EmitPop(r0);
   frame_->EmitPop(r1);
-  __ cmp(r0, Operand(r1));
+  __ cmp(r0, r1);
   cc_reg_ = eq;
 }
 
@@ -4935,6 +5225,97 @@
 }
 
 
+class DeferredReferenceGetNamedValue: public DeferredCode {
+ public:
+  explicit DeferredReferenceGetNamedValue(Handle<String> name) : name_(name) {
+    set_comment("[ DeferredReferenceGetNamedValue");
+  }
+
+  virtual void BeforeGenerate();
+  virtual void Generate();
+  virtual void AfterGenerate();
+
+ private:
+  Handle<String> name_;
+};
+
+
+void DeferredReferenceGetNamedValue::BeforeGenerate() {
+  __ StartBlockConstPool();
+}
+
+
+void DeferredReferenceGetNamedValue::Generate() {
+  __ IncrementCounter(&Counters::named_load_inline_miss, 1, r1, r2);
+  // Setup the name register and call load IC.
+  __ mov(r2, Operand(name_));
+  Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+  __ Call(ic, RelocInfo::CODE_TARGET);
+  // The call must be followed by a nop(1) instruction to indicate that the
+  // inobject has been inlined.
+  __ nop(NAMED_PROPERTY_LOAD_INLINED);
+}
+
+
+void DeferredReferenceGetNamedValue::AfterGenerate() {
+  __ EndBlockConstPool();
+}
+
+
+void CodeGenerator::EmitNamedLoad(Handle<String> name, bool is_contextual) {
+  if (is_contextual || scope()->is_global_scope() || loop_nesting() == 0) {
+    Comment cmnt(masm(), "[ Load from named Property");
+    // Setup the name register and call load IC.
+    __ mov(r2, Operand(name));
+    frame_->CallLoadIC(is_contextual
+                       ? RelocInfo::CODE_TARGET_CONTEXT
+                       : RelocInfo::CODE_TARGET);
+  } else {
+    // Inline the inobject property case.
+    Comment cmnt(masm(), "[ Inlined named property load");
+
+    DeferredReferenceGetNamedValue* deferred =
+        new DeferredReferenceGetNamedValue(name);
+
+    // The following instructions are the inlined load of an in-object property.
+    // Parts of this code is patched, so the exact instructions generated needs
+    // to be fixed. Therefore the instruction pool is blocked when generating
+    // this code
+#ifdef DEBUG
+    int kInlinedNamedLoadInstructions = 8;
+    Label check_inlined_codesize;
+    masm_->bind(&check_inlined_codesize);
+#endif
+    { Assembler::BlockConstPoolScope block_const_pool(masm_);
+      // Load the receiver from the stack.
+      __ ldr(r1, MemOperand(sp, 0));
+
+      // Check that the receiver is a heap object.
+      __ tst(r1, Operand(kSmiTagMask));
+      deferred->Branch(eq);
+
+      // Check the map. The null map used below is patched by the inline cache
+      // code.
+      __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
+      __ mov(r3, Operand(Factory::null_value()));
+      __ cmp(r2, r3);
+      deferred->Branch(ne);
+
+      // Use initially use an invalid index. The index will be patched by the
+      // inline cache code.
+      __ ldr(r0, MemOperand(r1, 0));
+    }
+
+    // Make sure that the expected number of instructions are generated.
+    ASSERT_EQ(kInlinedNamedLoadInstructions,
+              masm_->InstructionsGeneratedSince(&check_inlined_codesize));
+
+    __ IncrementCounter(&Counters::named_load_inline, 1, r1, r2);
+    deferred->BindExit();
+  }
+}
+
+
 void CodeGenerator::EmitKeyedLoad(bool is_global) {
   Comment cmnt(masm_, "[ Load from keyed Property");
   Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
@@ -4986,24 +5367,16 @@
       Comment cmnt(masm, "[ Load from Slot");
       Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot();
       ASSERT(slot != NULL);
-      cgen_->LoadFromSlot(slot, NOT_INSIDE_TYPEOF);
+      cgen_->LoadFromSlotCheckForArguments(slot, NOT_INSIDE_TYPEOF);
       break;
     }
 
     case NAMED: {
-      VirtualFrame* frame = cgen_->frame();
-      Comment cmnt(masm, "[ Load from named Property");
-      Handle<String> name(GetName());
       Variable* var = expression_->AsVariableProxy()->AsVariable();
-      Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
-      // Setup the name register.
-      __ mov(r2, Operand(name));
-      ASSERT(var == NULL || var->is_global());
-      RelocInfo::Mode rmode = (var == NULL)
-                            ? RelocInfo::CODE_TARGET
-                            : RelocInfo::CODE_TARGET_CONTEXT;
-      frame->CallCodeObject(ic, rmode, 0);
-      frame->EmitPush(r0);
+      bool is_global = var != NULL;
+      ASSERT(!is_global || var->is_global());
+      cgen_->EmitNamedLoad(GetName(), is_global);
+      cgen_->frame()->EmitPush(r0);
       break;
     }
 
@@ -5400,7 +5773,7 @@
   Label not_identical;
   Label heap_number, return_equal;
   Register exp_mask_reg = r5;
-  __ cmp(r0, Operand(r1));
+  __ cmp(r0, r1);
   __ b(ne, &not_identical);
 
   // The two objects are identical.  If we know that one of them isn't NaN then
@@ -5429,7 +5802,7 @@
           __ cmp(r4, Operand(ODDBALL_TYPE));
           __ b(ne, &return_equal);
           __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
-          __ cmp(r0, Operand(r2));
+          __ cmp(r0, r2);
           __ b(ne, &return_equal);
           if (cc == le) {
             // undefined <= undefined should fail.
@@ -5992,8 +6365,7 @@
     Register lhs,
     Register rhs,
     const Builtins::JavaScript& builtin) {
-  Label slow, slow_pop_2_first, do_the_call;
-  Label r0_is_smi, r1_is_smi, finished_loading_r0, finished_loading_r1;
+  Label slow, slow_reverse, do_the_call;
   bool use_fp_registers = CpuFeatures::IsSupported(VFP3) && Token::MOD != op_;
 
   ASSERT((lhs.is(r0) && rhs.is(r1)) || (lhs.is(r1) && rhs.is(r0)));
@@ -6002,7 +6374,7 @@
     // Smi-smi case (overflow).
     // Since both are Smis there is no heap number to overwrite, so allocate.
     // The new heap number is in r5.  r6 and r7 are scratch.
-    __ AllocateHeapNumber(r5, r6, r7, &slow);
+    __ AllocateHeapNumber(r5, r6, r7, lhs.is(r0) ? &slow_reverse : &slow);
 
     // If we have floating point hardware, inline ADD, SUB, MUL, and DIV,
     // using registers d7 and d6 for the double values.
@@ -6032,11 +6404,15 @@
   // We branch here if at least one of r0 and r1 is not a Smi.
   __ bind(not_smi);
 
+  // After this point we have the left hand side in r1 and the right hand side
+  // in r0.
   if (lhs.is(r0)) {
     __ Swap(r0, r1, ip);
   }
 
   if (ShouldGenerateFPCode()) {
+    Label r0_is_smi, r1_is_smi, finished_loading_r0, finished_loading_r1;
+
     if (runtime_operands_type_ == BinaryOpIC::DEFAULT) {
       switch (op_) {
         case Token::ADD:
@@ -6054,7 +6430,7 @@
     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, r6, r7, &slow);
+      __ AllocateHeapNumber(r5, r6, r7, &slow);
     }
 
     // Move r0 to a double in r2-r3.
@@ -6097,11 +6473,22 @@
       __ 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);
+      __ 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);
     __ CompareObjectType(r1, r4, r4, HEAP_NUMBER_TYPE);
     __ b(ne, &slow);
     if (mode_ == OVERWRITE_LEFT) {
@@ -6194,6 +6581,14 @@
       __ pop(pc);
     }
   }
+
+
+  if (lhs.is(r0)) {
+    __ b(&slow);
+    __ bind(&slow_reverse);
+    __ Swap(r0, r1, ip);
+  }
+
   // We jump to here if something goes wrong (one param is not a number of any
   // sort or new-space allocation fails).
   __ bind(&slow);
@@ -7743,7 +8138,8 @@
   __ ldr(last_match_info_elements,
          FieldMemOperand(r0, JSArray::kElementsOffset));
   __ ldr(r0, FieldMemOperand(last_match_info_elements, HeapObject::kMapOffset));
-  __ cmp(r0, Operand(Factory::fixed_array_map()));
+  __ LoadRoot(ip, kFixedArrayMapRootIndex);
+  __ cmp(r0, ip);
   __ b(ne, &runtime);
   // Check that the last match info has space for the capture registers and the
   // additional information.
diff --git a/src/arm/codegen-arm.h b/src/arm/codegen-arm.h
index 5abd814..525b22b 100644
--- a/src/arm/codegen-arm.h
+++ b/src/arm/codegen-arm.h
@@ -144,6 +144,24 @@
 
 
 // -------------------------------------------------------------------------
+// Arguments allocation mode
+
+enum ArgumentsAllocationMode {
+  NO_ARGUMENTS_ALLOCATION,
+  EAGER_ARGUMENTS_ALLOCATION,
+  LAZY_ARGUMENTS_ALLOCATION
+};
+
+
+// Different nop operations are used by the code generator to detect certain
+// states of the generated code.
+enum NopMarkerTypes {
+  NON_MARKING_NOP = 0,
+  NAMED_PROPERTY_LOAD_INLINED
+};
+
+
+// -------------------------------------------------------------------------
 // CodeGenerator
 
 class CodeGenerator: public AstVisitor {
@@ -241,6 +259,12 @@
   // Main code generation function
   void Generate(CompilationInfo* info);
 
+  // Returns the arguments allocation mode.
+  ArgumentsAllocationMode ArgumentsMode();
+
+  // Store the arguments object and allocate it if necessary.
+  void StoreArgumentsObject(bool initial);
+
   // The following are used by class Reference.
   void LoadReference(Reference* ref);
   void UnloadReference(Reference* ref);
@@ -284,9 +308,14 @@
 
   // Read a value from a slot and leave it on top of the expression stack.
   void LoadFromSlot(Slot* slot, TypeofState typeof_state);
+  void LoadFromSlotCheckForArguments(Slot* slot, TypeofState state);
   // Store the value on top of the stack to a slot.
   void StoreToSlot(Slot* slot, InitState init_state);
 
+  // Load a named property, leaving it in r0. The receiver is passed on the
+  // stack, and remains there.
+  void EmitNamedLoad(Handle<String> name, bool is_contextual);
+
   // Load a keyed property, leaving it in r0.  The receiver and key are
   // passed on the stack, and remain there.
   void EmitKeyedLoad(bool is_global);
@@ -335,6 +364,14 @@
                          CallFunctionFlags flags,
                          int position);
 
+  // An optimized implementation of expressions of the form
+  // x.apply(y, arguments).  We call x the applicand and y the receiver.
+  // The optimization avoids allocating an arguments object if possible.
+  void CallApplyLazy(Expression* applicand,
+                     Expression* receiver,
+                     VariableProxy* arguments,
+                     int position);
+
   // Control flow
   void Branch(bool if_true, JumpTarget* target);
   void CheckStack();
diff --git a/src/arm/cpu-arm.cc b/src/arm/cpu-arm.cc
index 55f31d4..d50c203 100644
--- a/src/arm/cpu-arm.cc
+++ b/src/arm/cpu-arm.cc
@@ -26,7 +26,7 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 // CPU specific code for arm independent of OS goes here.
-#if defined(__arm__)
+#ifdef __arm__
 #include <sys/syscall.h>  // for cache flushing.
 #endif
 
@@ -35,6 +35,10 @@
 #include "cpu.h"
 #include "macro-assembler.h"
 
+#ifndef __arm__
+#include "simulator-arm.h"  // for cache flushing.
+#endif
+
 namespace v8 {
 namespace internal {
 
@@ -46,9 +50,11 @@
 void CPU::FlushICache(void* start, size_t size) {
 #if !defined (__arm__)
   // Not generating ARM instructions for C-code. This means that we are
-  // building an ARM emulator based target. No I$ flushes are necessary.
+  // building an ARM emulator based target.  We should notify the simulator
+  // that the Icache was flushed.
   // None of this code ends up in the snapshot so there are no issues
   // around whether or not to generate the code when building snapshots.
+  assembler::arm::Simulator::FlushICache(start, size);
 #else
   // Ideally, we would call
   //   syscall(__ARM_NR_cacheflush, start,
diff --git a/src/arm/disasm-arm.cc b/src/arm/disasm-arm.cc
index a89c6b8..4ba3094 100644
--- a/src/arm/disasm-arm.cc
+++ b/src/arm/disasm-arm.cc
@@ -34,10 +34,9 @@
 //   NameConverter converter;
 //   Disassembler d(converter);
 //   for (byte* pc = begin; pc < end;) {
-//     char buffer[128];
-//     buffer[0] = '\0';
+//     v8::internal::EmbeddedVector<char, 256> buffer;
 //     byte* prev_pc = pc;
-//     pc += d.InstructionDecode(buffer, sizeof buffer, pc);
+//     pc += d.InstructionDecode(buffer, pc);
 //     printf("%p    %08x      %s\n",
 //            prev_pc, *reinterpret_cast<int32_t*>(prev_pc), buffer);
 //   }
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc
index 62365ff..10ccf9c 100644
--- a/src/arm/full-codegen-arm.cc
+++ b/src/arm/full-codegen-arm.cc
@@ -194,36 +194,34 @@
       __ CallRuntime(Runtime::kTraceExit, 1);
     }
 
+#ifdef DEBUG
     // Add a label for checking the size of the code used for returning.
     Label check_exit_codesize;
     masm_->bind(&check_exit_codesize);
-
-    // Calculate the exact length of the return sequence and make sure that
-    // the constant pool is not emitted inside of the return sequence.
-    int num_parameters = scope()->num_parameters();
-    int32_t sp_delta = (num_parameters + 1) * kPointerSize;
-    int return_sequence_length = Assembler::kJSReturnSequenceLength;
-    if (!masm_->ImmediateFitsAddrMode1Instruction(sp_delta)) {
-      // Additional mov instruction generated.
-      return_sequence_length++;
+#endif
+    // Make sure that the constant pool is not emitted inside of the return
+    // sequence.
+    { Assembler::BlockConstPoolScope block_const_pool(masm_);
+      // Here we use masm_-> instead of the __ macro to avoid the code coverage
+      // tool from instrumenting as we rely on the code size here.
+      int32_t sp_delta = (scope()->num_parameters() + 1) * kPointerSize;
+      CodeGenerator::RecordPositions(masm_, position);
+      __ RecordJSReturn();
+      masm_->mov(sp, fp);
+      masm_->ldm(ia_w, sp, fp.bit() | lr.bit());
+      masm_->add(sp, sp, Operand(sp_delta));
+      masm_->Jump(lr);
     }
-    masm_->BlockConstPoolFor(return_sequence_length);
 
-    CodeGenerator::RecordPositions(masm_, position);
-    __ RecordJSReturn();
-    __ mov(sp, fp);
-    __ ldm(ia_w, sp, fp.bit() | lr.bit());
-    __ add(sp, sp, Operand(sp_delta));
-    __ Jump(lr);
-
+#ifdef DEBUG
     // Check that the size of the code used for returning matches what is
-    // expected by the debugger. The add instruction above is an addressing
-    // mode 1 instruction where there are restrictions on which immediate values
-    // can be encoded in the instruction and which immediate values requires
-    // use of an additional instruction for moving the immediate to a temporary
-    // register.
-    ASSERT_EQ(return_sequence_length,
-              masm_->InstructionsGeneratedSince(&check_exit_codesize));
+    // expected by the debugger. If the sp_delts above cannot be encoded in the
+    // add instruction the add will generate two instructions.
+    int return_sequence_length =
+        masm_->InstructionsGeneratedSince(&check_exit_codesize);
+    CHECK(return_sequence_length == Assembler::kJSReturnSequenceLength ||
+          return_sequence_length == Assembler::kJSReturnSequenceLength + 1);
+#endif
   }
 }
 
@@ -1594,10 +1592,9 @@
 
   // Inline smi case if we are in a loop.
   Label stub_call, done;
+  int count_value = expr->op() == Token::INC ? 1 : -1;
   if (loop_depth() > 0) {
-    __ add(r0, r0, Operand(expr->op() == Token::INC
-                           ? Smi::FromInt(1)
-                           : Smi::FromInt(-1)));
+    __ add(r0, r0, Operand(Smi::FromInt(count_value)), SetCC);
     __ b(vs, &stub_call);
     // We could eliminate this smi check if we split the code at
     // the first smi check before calling ToNumber.
@@ -1605,11 +1602,9 @@
     __ b(eq, &done);
     __ bind(&stub_call);
     // Call stub. Undo operation first.
-    __ sub(r0, r0, Operand(r1));
+    __ sub(r0, r0, Operand(Smi::FromInt(count_value)));
   }
-  __ mov(r1, Operand(expr->op() == Token::INC
-                     ? Smi::FromInt(1)
-                     : Smi::FromInt(-1)));
+  __ mov(r1, Operand(Smi::FromInt(count_value)));
   GenericBinaryOpStub stub(Token::ADD, NO_OVERWRITE, r1, r0);
   __ CallStub(&stub);
   __ bind(&done);
diff --git a/src/arm/ic-arm.cc b/src/arm/ic-arm.cc
index 0ac4217..2b7dac6 100644
--- a/src/arm/ic-arm.cc
+++ b/src/arm/ic-arm.cc
@@ -27,7 +27,9 @@
 
 #include "v8.h"
 
+#include "assembler-arm.h"
 #include "codegen-inl.h"
+#include "disasm.h"
 #include "ic-inl.h"
 #include "runtime.h"
 #include "stub-cache.h"
@@ -561,21 +563,72 @@
 }
 
 
-// TODO(181): Implement map patching once loop nesting is tracked on the
-// ARM platform so we can generate inlined fast-case code loads in
-// loops.
-void LoadIC::ClearInlinedVersion(Address address) {}
-bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) {
-  return false;
+void LoadIC::ClearInlinedVersion(Address address) {
+  // Reset the map check of the inlined inobject property load (if present) to
+  // guarantee failure by holding an invalid map (the null value). The offset
+  // can be patched to anything.
+  PatchInlinedLoad(address, Heap::null_value(), 0);
 }
 
+
+bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) {
+  // If the instruction after the call site is not the pseudo instruction nop1
+  // then this is not related to an inlined in-object property load. The nop1
+  // instruction is located just after the call to the IC in the deferred code
+  // handling the miss in the inlined code. After the nop1 instruction there is
+  // a branch instruction for jumping back from the deferred code.
+  Address address_after_call = address + Assembler::kCallTargetAddressOffset;
+  Instr instr_after_call = Assembler::instr_at(address_after_call);
+  if (!Assembler::IsNop(instr_after_call, NAMED_PROPERTY_LOAD_INLINED)) {
+    return false;
+  }
+  ASSERT_EQ(0, RegisterAllocator::kNumRegisters);
+  Address address_after_nop1 = address_after_call + Assembler::kInstrSize;
+  Instr instr_after_nop1 = Assembler::instr_at(address_after_nop1);
+  ASSERT(Assembler::IsBranch(instr_after_nop1));
+
+  // Find the end of the inlined code for handling the load.
+  int b_offset =
+      Assembler::GetBranchOffset(instr_after_nop1) + Assembler::kPcLoadDelta;
+  ASSERT(b_offset < 0);  // Jumping back from deferred code.
+  Address inline_end_address = address_after_nop1 + b_offset;
+
+  // Patch the offset of the property load instruction (ldr r0, [r1, #+XXX]).
+  // The immediate must be represenatble in 12 bits.
+  ASSERT((JSObject::kMaxInstanceSize - JSObject::kHeaderSize) < (1 << 12));
+  Address ldr_property_instr_address = inline_end_address - 4;
+  ASSERT(Assembler::IsLdrRegisterImmediate(
+      Assembler::instr_at(ldr_property_instr_address)));
+  Instr ldr_property_instr = Assembler::instr_at(ldr_property_instr_address);
+  ldr_property_instr = Assembler::SetLdrRegisterImmediateOffset(
+      ldr_property_instr, offset - kHeapObjectTag);
+  Assembler::instr_at_put(ldr_property_instr_address, ldr_property_instr);
+
+  // Indicate that code has changed.
+  CPU::FlushICache(ldr_property_instr_address, 1 * Assembler::kInstrSize);
+
+  // Patch the map check.
+  Address ldr_map_instr_address = inline_end_address - 16;
+  Assembler::set_target_address_at(ldr_map_instr_address,
+                                   reinterpret_cast<Address>(map));
+  return true;
+}
+
+
 void KeyedLoadIC::ClearInlinedVersion(Address address) {}
+
+
 bool KeyedLoadIC::PatchInlinedLoad(Address address, Object* map) {
   return false;
 }
 
+
 void KeyedStoreIC::ClearInlinedVersion(Address address) {}
+
+
 void KeyedStoreIC::RestoreInlinedVersion(Address address) {}
+
+
 bool KeyedStoreIC::PatchInlinedStore(Address address, Object* map) {
   return false;
 }
@@ -656,8 +709,8 @@
   __ b(ne, &check_pixel_array);
   // Check that the key (index) is within bounds.
   __ ldr(r3, FieldMemOperand(r1, Array::kLengthOffset));
-  __ cmp(r0, Operand(r3));
-  __ b(ge, &slow);
+  __ cmp(r0, r3);
+  __ b(hs, &slow);
   // Fast case: Do the load.
   __ add(r3, r1, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
   __ ldr(r0, MemOperand(r3, r0, LSL, kPointerSizeLog2));
diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc
index 376c4fb..17d6a10 100644
--- a/src/arm/macro-assembler-arm.cc
+++ b/src/arm/macro-assembler-arm.cc
@@ -117,18 +117,19 @@
   //  ldr ip, [pc, #...]
   //  blx ip
 
-  // The two instructions (ldr and blx) could be separated by a literal
+  // The two instructions (ldr and blx) could be separated by a constant
   // pool and the code would still work. The issue comes from the
   // patching code which expect the ldr to be just above the blx.
-  BlockConstPoolFor(2);
-  // Statement positions are expected to be recorded when the target
-  // address is loaded. The mov method will automatically record
-  // positions when pc is the target, since this is not the case here
-  // we have to do it explicitly.
-  WriteRecordedPositions();
+  { BlockConstPoolScope block_const_pool(this);
+    // Statement positions are expected to be recorded when the target
+    // address is loaded. The mov method will automatically record
+    // positions when pc is the target, since this is not the case here
+    // we have to do it explicitly.
+    WriteRecordedPositions();
 
-  mov(ip, Operand(target, rmode), LeaveCC, cond);
-  blx(ip, cond);
+    mov(ip, Operand(target, rmode), LeaveCC, cond);
+    blx(ip, cond);
+  }
 
   ASSERT(kCallTargetAddressOffset == 2 * kInstrSize);
 #else
diff --git a/src/arm/simulator-arm.cc b/src/arm/simulator-arm.cc
index 827a88f..b44a738 100644
--- a/src/arm/simulator-arm.cc
+++ b/src/arm/simulator-arm.cc
@@ -474,6 +474,96 @@
 }
 
 
+static bool ICacheMatch(void* one, void* two) {
+  ASSERT((reinterpret_cast<intptr_t>(one) & CachePage::kPageMask) == 0);
+  ASSERT((reinterpret_cast<intptr_t>(two) & CachePage::kPageMask) == 0);
+  return one == two;
+}
+
+
+static uint32_t ICacheHash(void* key) {
+  return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)) >> 2;
+}
+
+
+static bool AllOnOnePage(uintptr_t start, int size) {
+  intptr_t start_page = (start & ~CachePage::kPageMask);
+  intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
+  return start_page == end_page;
+}
+
+
+void Simulator::FlushICache(void* start_addr, size_t size) {
+  intptr_t start = reinterpret_cast<intptr_t>(start_addr);
+  int intra_line = (start & CachePage::kLineMask);
+  start -= intra_line;
+  size += intra_line;
+  size = ((size - 1) | CachePage::kLineMask) + 1;
+  int offset = (start & CachePage::kPageMask);
+  while (!AllOnOnePage(start, size - 1)) {
+    int bytes_to_flush = CachePage::kPageSize - offset;
+    FlushOnePage(start, bytes_to_flush);
+    start += bytes_to_flush;
+    size -= bytes_to_flush;
+    ASSERT_EQ(0, start & CachePage::kPageMask);
+    offset = 0;
+  }
+  if (size != 0) {
+    FlushOnePage(start, size);
+  }
+}
+
+
+CachePage* Simulator::GetCachePage(void* page) {
+  v8::internal::HashMap::Entry* entry = i_cache_->Lookup(page,
+                                                         ICacheHash(page),
+                                                         true);
+  if (entry->value == NULL) {
+    CachePage* new_page = new CachePage();
+    entry->value = new_page;
+  }
+  return reinterpret_cast<CachePage*>(entry->value);
+}
+
+
+// Flush from start up to and not including start + size.
+void Simulator::FlushOnePage(intptr_t start, int size) {
+  ASSERT(size <= CachePage::kPageSize);
+  ASSERT(AllOnOnePage(start, size - 1));
+  ASSERT((start & CachePage::kLineMask) == 0);
+  ASSERT((size & CachePage::kLineMask) == 0);
+  void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
+  int offset = (start & CachePage::kPageMask);
+  CachePage* cache_page = GetCachePage(page);
+  char* valid_bytemap = cache_page->ValidityByte(offset);
+  memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
+}
+
+
+void Simulator::CheckICache(Instr* instr) {
+#ifdef DEBUG
+  intptr_t address = reinterpret_cast<intptr_t>(instr);
+  void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
+  void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
+  int offset = (address & CachePage::kPageMask);
+  CachePage* cache_page = GetCachePage(page);
+  char* cache_valid_byte = cache_page->ValidityByte(offset);
+  bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
+  char* cached_line = cache_page->CachedData(offset & ~CachePage::kLineMask);
+  if (cache_hit) {
+    // Check that the data in memory matches the contents of the I-cache.
+    CHECK(memcmp(reinterpret_cast<void*>(instr),
+                 cache_page->CachedData(offset),
+                 Instr::kInstrSize) == 0);
+  } else {
+    // Cache miss.  Load memory into the cache.
+    memcpy(cached_line, line, CachePage::kLineLength);
+    *cache_valid_byte = CachePage::LINE_VALID;
+  }
+#endif
+}
+
+
 // Create one simulator per thread and keep it in thread local storage.
 static v8::internal::Thread::LocalStorageKey simulator_key;
 
@@ -489,7 +579,13 @@
 }
 
 
+v8::internal::HashMap* Simulator::i_cache_ = NULL;
+
+
 Simulator::Simulator() {
+  if (i_cache_ == NULL) {
+    i_cache_ = new v8::internal::HashMap(&ICacheMatch);
+  }
   Initialize();
   // Setup simulator support first. Some of this information is needed to
   // setup the architecture state.
@@ -554,6 +650,9 @@
         swi_instruction_((AL << 28) | (0xf << 24) | call_rt_redirected),
         fp_return_(fp_return),
         next_(list_) {
+    Simulator::current()->
+        FlushICache(reinterpret_cast<void*>(&swi_instruction_),
+                      Instr::kInstrSize);
     list_ = this;
   }
 
@@ -2342,6 +2441,7 @@
 
 // Executes the current instruction.
 void Simulator::InstructionDecode(Instr* instr) {
+  CheckICache(instr);
   pc_modified_ = false;
   if (::v8::internal::FLAG_trace_sim) {
     disasm::NameConverter converter;
@@ -2536,7 +2636,6 @@
   return address;
 }
 
-
 } }  // namespace assembler::arm
 
 #endif  // __arm__
diff --git a/src/arm/simulator-arm.h b/src/arm/simulator-arm.h
index 4ee9070..91614ea 100644
--- a/src/arm/simulator-arm.h
+++ b/src/arm/simulator-arm.h
@@ -89,11 +89,43 @@
 
 
 #include "constants-arm.h"
+#include "hashmap.h"
 
 
 namespace assembler {
 namespace arm {
 
+class CachePage {
+ public:
+  static const int LINE_VALID = 0;
+  static const int LINE_INVALID = 1;
+
+  static const int kPageShift = 12;
+  static const int kPageSize = 1 << kPageShift;
+  static const int kPageMask = kPageSize - 1;
+  static const int kLineShift = 2;  // The cache line is only 4 bytes right now.
+  static const int kLineLength = 1 << kLineShift;
+  static const int kLineMask = kLineLength - 1;
+
+  CachePage() {
+    memset(&validity_map_, LINE_INVALID, sizeof(validity_map_));
+  }
+
+  char* ValidityByte(int offset) {
+    return &validity_map_[offset >> kLineShift];
+  }
+
+  char* CachedData(int offset) {
+    return &data_[offset];
+  }
+
+ private:
+  char data_[kPageSize];   // The cached data.
+  static const int kValidityMapSize = kPageSize >> kLineShift;
+  char validity_map_[kValidityMapSize];  // One byte per line.
+};
+
+
 class Simulator {
  public:
   friend class Debugger;
@@ -162,6 +194,9 @@
   // Pop an address from the JS stack.
   uintptr_t PopAddress();
 
+  // ICache checking.
+  static void FlushICache(void* start, size_t size);
+
  private:
   enum special_values {
     // Known bad pc value to ensure that the simulator does not execute
@@ -239,6 +274,11 @@
   // Executes one instruction.
   void InstructionDecode(Instr* instr);
 
+  // ICache.
+  static void CheckICache(Instr* instr);
+  static void FlushOnePage(intptr_t start, int size);
+  static CachePage* GetCachePage(void* page);
+
   // Runtime call support.
   static void* RedirectExternalReference(void* external_function,
                                          bool fp_return);
@@ -276,6 +316,9 @@
   int icount_;
   static bool initialized_;
 
+  // Icache simulation
+  static v8::internal::HashMap* i_cache_;
+
   // Registered breakpoints.
   Instr* break_pc_;
   instr_t break_instr_;
diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc
index e0e166c..1cb88b4 100644
--- a/src/arm/stub-cache-arm.cc
+++ b/src/arm/stub-cache-arm.cc
@@ -53,7 +53,7 @@
   // Check that the key in the entry matches the name.
   __ mov(ip, Operand(key_offset));
   __ ldr(ip, MemOperand(ip, offset, LSL, 1));
-  __ cmp(name, Operand(ip));
+  __ cmp(name, ip);
   __ b(ne, &miss);
 
   // Get the code entry from the cache.
diff --git a/src/arm/virtual-frame-arm.cc b/src/arm/virtual-frame-arm.cc
index a4c5484..3183c09 100644
--- a/src/arm/virtual-frame-arm.cc
+++ b/src/arm/virtual-frame-arm.cc
@@ -299,6 +299,12 @@
 }
 
 
+void VirtualFrame::CallLoadIC(RelocInfo::Mode mode) {
+  Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+  CallCodeObject(ic, mode, 0);
+}
+
+
 void VirtualFrame::CallCodeObject(Handle<Code> code,
                                   RelocInfo::Mode rmode,
                                   int dropped_args) {
diff --git a/src/arm/virtual-frame-arm.h b/src/arm/virtual-frame-arm.h
index c5a7fbb..c378b58 100644
--- a/src/arm/virtual-frame-arm.h
+++ b/src/arm/virtual-frame-arm.h
@@ -308,6 +308,10 @@
                      InvokeJSFlags flag,
                      int arg_count);
 
+  // Call load IC. Receiver on stack and property name in r2. Result returned in
+  // r0.
+  void CallLoadIC(RelocInfo::Mode mode);
+
   // Call into an IC stub given the number of arguments it removes
   // from the stack.  Register arguments to the IC stub are implicit,
   // and depend on the type of IC stub.
diff --git a/src/builtins.cc b/src/builtins.cc
index 767820a..9850f55 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -348,15 +348,7 @@
   // Technically in new space this write might be omitted (except for
   // debug mode which iterates through the heap), but to play safer
   // we still do it.
-  if (to_trim == 1) {
-    former_start[0] = Heap::raw_unchecked_one_pointer_filler_map();
-  } else if (to_trim == 2) {
-    former_start[0] = Heap::raw_unchecked_two_pointer_filler_map();
-  } else {
-    former_start[0] = Heap::raw_unchecked_byte_array_map();
-    ByteArray* as_byte_array = reinterpret_cast<ByteArray*>(elms);
-    as_byte_array->set_length(ByteArray::LengthFor(to_trim * kPointerSize));
-  }
+  Heap::CreateFillerObjectAt(elms->address(), to_trim * kPointerSize);
 
   former_start[to_trim] = Heap::fixed_array_map();
   former_start[to_trim + 1] = reinterpret_cast<Object*>(len - to_trim);
diff --git a/src/codegen.cc b/src/codegen.cc
index 5bbf050..20ea41e 100644
--- a/src/codegen.cc
+++ b/src/codegen.cc
@@ -77,11 +77,13 @@
     }
     // Generate the code.
     Comment cmnt(masm_, code->comment());
+    code->BeforeGenerate();
     masm_->bind(code->entry_label());
     code->SaveRegisters();
     code->Generate();
     code->RestoreRegisters();
     masm_->jmp(code->exit_label());
+    code->AfterGenerate();
   }
 }
 
diff --git a/src/codegen.h b/src/codegen.h
index a42eb4a..6232dd4 100644
--- a/src/codegen.h
+++ b/src/codegen.h
@@ -212,6 +212,9 @@
   void SaveRegisters();
   void RestoreRegisters();
 
+  virtual void BeforeGenerate() { }
+  virtual void AfterGenerate() { }
+
  protected:
   MacroAssembler* masm_;
 
diff --git a/src/globals.h b/src/globals.h
index e3ef958..bef5e8e 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -50,15 +50,32 @@
 #define V8_HOST_ARCH_MIPS 1
 #define V8_HOST_ARCH_32_BIT 1
 #else
-#error Your host architecture was not detected as supported by v8
+#error Host architecture was not detected as supported by v8
 #endif
 
+// Check for supported combinations of host and target architectures.
+#if defined(V8_TARGET_ARCH_IA32) && !defined(V8_HOST_ARCH_IA32)
+#error Target architecture ia32 is only supported on ia32 host
+#endif
+#if defined(V8_TARGET_ARCH_X64) && !defined(V8_HOST_ARCH_X64)
+#error Target architecture x64 is only supported on x64 host
+#endif
+#if (defined(V8_TARGET_ARCH_ARM) && \
+    !(defined(V8_HOST_ARCH_IA32) || defined(V8_HOST_ARCH_ARM)))
+#error Target architecture arm is only supported on arm and ia32 host
+#endif
+#if (defined(V8_TARGET_ARCH_MIPS) && \
+    !(defined(V8_HOST_ARCH_IA32) || defined(V8_HOST_ARCH_MIPS)))
+#error Target architecture mips is only supported on mips and ia32 host
+#endif
+
+// Define unaligned read for the target architectures supporting it.
 #if defined(V8_TARGET_ARCH_X64) || defined(V8_TARGET_ARCH_IA32)
 #define V8_TARGET_CAN_READ_UNALIGNED 1
 #elif V8_TARGET_ARCH_ARM
 #elif V8_TARGET_ARCH_MIPS
 #else
-#error Your target architecture is not supported by v8
+#error Target architecture is not supported by v8
 #endif
 
 // Support for alternative bool type. This is only enabled if the code is
diff --git a/src/heap.cc b/src/heap.cc
index eb47884..0cd1791 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -2188,9 +2188,11 @@
   if (size == 0) return;
   HeapObject* filler = HeapObject::FromAddress(addr);
   if (size == kPointerSize) {
-    filler->set_map(Heap::one_pointer_filler_map());
+    filler->set_map(one_pointer_filler_map());
+  } else if (size == 2 * kPointerSize) {
+    filler->set_map(two_pointer_filler_map());
   } else {
-    filler->set_map(Heap::byte_array_map());
+    filler->set_map(byte_array_map());
     ByteArray::cast(filler)->set_length(ByteArray::LengthFor(size));
   }
 }
diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc
index 5ab7a53..e1f2d66 100644
--- a/src/ia32/codegen-ia32.cc
+++ b/src/ia32/codegen-ia32.cc
@@ -154,8 +154,7 @@
 #endif
 
   // New scope to get automatic timing calculation.
-  {  // NOLINT
-    HistogramTimerScope codegen_timer(&Counters::code_generation);
+  { HistogramTimerScope codegen_timer(&Counters::code_generation);
     CodeGenState state(this);
 
     // Entry:
@@ -1181,16 +1180,23 @@
     case Token::SAR:
       if (left.is_smi()) return TypeInfo::Smi();
       // Result is a smi if we shift by a constant >= 1, otherwise an integer32.
+      // Shift amount is masked with 0x1F (ECMA standard 11.7.2).
       return (right.is_constant() && right.handle()->IsSmi()
-                     && Smi::cast(*right.handle())->value() >= 1)
+              && (Smi::cast(*right.handle())->value() & 0x1F)  >= 1)
           ? TypeInfo::Smi()
           : TypeInfo::Integer32();
     case Token::SHR:
-      // Result is a smi if we shift by a constant >= 2, otherwise an integer32.
-      return (right.is_constant() && right.handle()->IsSmi()
-                     && Smi::cast(*right.handle())->value() >= 2)
-          ? TypeInfo::Smi()
-          : TypeInfo::Integer32();
+      // Result is a smi if we shift by a constant >= 2, an integer32 if
+      // we shift by 1, and an unsigned 32-bit integer if we shift by 0.
+      if (right.is_constant() && right.handle()->IsSmi()) {
+        int shift_amount = Smi::cast(*right.handle())->value() & 0x1F;
+        if (shift_amount > 1) {
+          return TypeInfo::Smi();
+        } else if (shift_amount > 0) {
+          return TypeInfo::Integer32();
+        }
+      }
+      return TypeInfo::Number();
     case Token::ADD:
       if (operands_type.IsSmi()) {
         // The Integer32 range is big enough to take the sum of any two Smis.
@@ -2773,11 +2779,7 @@
       // number comparison in the stub if it was inlined.
       CompareStub stub(cc, strict, nan_info, !inline_number_compare);
       Result answer = frame_->CallStub(&stub, &left_side, &right_side);
-      if (cc == equal) {
-        __ test(answer.reg(), Operand(answer.reg()));
-      } else {
-        __ cmp(answer.reg(), 0);
-      }
+      __ test(answer.reg(), Operand(answer.reg()));
       answer.Unuse();
       dest->Split(cc);
     } else {
@@ -6551,17 +6553,23 @@
     frame_->Push(Factory::undefined_value());
     return;
   }
-  Handle<FixedArray> cache_obj(
-      FixedArray::cast(jsfunction_result_caches->get(cache_id)));
 
   Load(args->at(1));
   Result key = frame_->Pop();
   key.ToRegister();
 
   Result cache = allocator()->Allocate();
-  __ mov(cache.reg(), cache_obj);
+  ASSERT(cache.is_valid());
+  __ mov(cache.reg(), ContextOperand(esi, Context::GLOBAL_INDEX));
+  __ mov(cache.reg(),
+         FieldOperand(cache.reg(), GlobalObject::kGlobalContextOffset));
+  __ mov(cache.reg(),
+         ContextOperand(cache.reg(), Context::JSFUNCTION_RESULT_CACHES_INDEX));
+  __ mov(cache.reg(),
+         FieldOperand(cache.reg(), FixedArray::OffsetOfElementAt(cache_id)));
 
   Result tmp = allocator()->Allocate();
+  ASSERT(tmp.is_valid());
 
   DeferredSearchCache* deferred = new DeferredSearchCache(tmp.reg(),
                                                           cache.reg(),
@@ -7045,6 +7053,12 @@
           (node->expression()->AsBinaryOperation() != NULL &&
            node->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
       switch (op) {
+        case Token::NOT:
+        case Token::DELETE:
+        case Token::TYPEOF:
+          UNREACHABLE();  // handled above
+          break;
+
         case Token::SUB: {
           GenericUnaryOpStub stub(Token::SUB, overwrite);
           Result operand = frame_->Pop();
@@ -7085,11 +7099,7 @@
             __ not_(answer.reg());
 
             continue_label.Bind(&answer);
-            if (operand_info.IsInteger32()) {
-              answer.set_type_info(TypeInfo::Integer32());
-            } else {
-              answer.set_type_info(TypeInfo::Number());
-            }
+            answer.set_type_info(TypeInfo::Integer32());
             frame_->Push(&answer);
           }
           break;
@@ -7119,8 +7129,6 @@
           break;
         }
         default:
-          // NOT, DELETE, TYPEOF, and VOID are handled outside the
-          // switch.
           UNREACHABLE();
       }
     }
@@ -9814,8 +9822,7 @@
   __ j(zero, &runtime_call_clear_stack);
 #ifdef DEBUG
   // Check that the layout of cache elements match expectations.
-  {  // NOLINT - doesn't like a single brace on a line.
-    TranscendentalCache::Element test_elem[2];
+  { TranscendentalCache::Element test_elem[2];
     char* elem_start = reinterpret_cast<char*>(&test_elem[0]);
     char* elem2_start = reinterpret_cast<char*>(&test_elem[1]);
     char* elem_in0  = reinterpret_cast<char*>(&(test_elem[0].in[0]));
diff --git a/src/liveedit-debugger.js b/src/liveedit-debugger.js
index d2aee87..8fbff41 100644
--- a/src/liveedit-debugger.js
+++ b/src/liveedit-debugger.js
@@ -28,26 +28,52 @@
 // LiveEdit feature implementation. The script should be executed after
 // debug-debugger.js.
 
-// A LiveEdit namespace is declared inside a single function constructor.
+// A LiveEdit namespace. It contains functions that modifies JavaScript code
+// according to changes of script source (if possible).
+//
+// When new script source is put in, the difference is calculated textually,
+// in form of list of delete/add/change chunks. The functions that include
+// change chunk(s) get recompiled, or their enclosing functions are
+// recompiled instead.
+// If the function may not be recompiled (e.g. it was completely erased in new
+// version of the script) it remains unchanged, but the code that could
+// create a new instance of this function goes away. An old version of script
+// is created to back up this obsolete function.
+// All unchanged functions have their positions updated accordingly.
+//
+// LiveEdit namespace is declared inside a single function constructor.
 Debug.LiveEdit = new function() {
 
-  // Changes script text and recompiles all relevant functions if possible.
+  // Applies the change to the script.
   // The change is always a substring (change_pos, change_pos + change_len)
   // being replaced with a completely different string new_str.
-  //
-  // Only one function will have its Code changed in result of this function.
-  // All nested functions (should they have any instances at the moment) are
-  // left unchanged and re-linked to a newly created script instance
-  // representing old version of the source. (Generally speaking,
-  // during the change all nested functions are erased and completely different
-  // set of nested functions are introduced.) All other functions just have
-  // their positions updated.
+  // This API is a legacy and is obsolete.
   //
   // @param {Script} script that is being changed
   // @param {Array} change_log a list that collects engineer-readable
   //     description of what happened.
   function ApplyPatch(script, change_pos, change_len, new_str,
       change_log) {
+    var old_source = script.source;
+  
+    // Prepare new source string.
+    var new_source = old_source.substring(0, change_pos) +
+        new_str + old_source.substring(change_pos + change_len);
+    
+    return ApplyPatchMultiChunk(script,
+        [ change_pos, change_pos + change_len, change_pos + new_str.length],
+        new_source, change_log);
+  }
+  // Function is public.
+  this.ApplyPatch = ApplyPatch;
+
+  // Forward declaration for minifier.
+  var FunctionStatus;
+  
+  // Applies the change to the script.
+  // The change is in form of list of chunks encoded in a single array as
+  // a series of triplets (pos1_start, pos1_end, pos2_end)
+  function ApplyPatchMultiChunk(script, diff_array, new_source, change_log) {
 
     // Fully compiles source string as a script. Returns Array of
     // FunctionCompileInfo -- a descriptions of all functions of the script.
@@ -117,27 +143,6 @@
       return compile_info;
     }
   
-    // Given a positions, finds a function that fully includes the entire
-    // change.
-    function FindChangedFunction(compile_info, offset, len) {
-      // First condition: function should start before the change region.
-      // Function #0 (whole-script function) always does, but we want
-      // one, that is later in this list.
-      var index = 0;
-      while (index + 1 < compile_info.length &&
-          compile_info[index + 1].start_position <= offset) {
-        index++;
-      }
-      // Now we are at the last function that begins before the change
-      // region. The function that covers entire change region is either
-      // this function or the enclosing one.
-      for (; compile_info[index].end_position < offset + len;
-          index = compile_info[index].outer_index) {
-        Assert(index != -1);
-      }
-      return index;
-    }
-  
     // Variable forward declarations. Preprocessor "Minifier" needs them.
     var old_compile_info;
     var shared_infos;
@@ -156,34 +161,27 @@
   
     // Replaces function's Code.
     function PatchCode(new_info, shared_info) {
-      %LiveEditReplaceFunctionCode(new_info.raw_array, shared_info.raw_array);
+      if (shared_info) {
+        %LiveEditReplaceFunctionCode(new_info.raw_array, shared_info.raw_array);
+        change_log.push( {function_patched: new_info.function_name} );
+      } else {
+        change_log.push( {function_patched: new_info.function_name,
+            function_info_not_found: true} );
+      }
   
-      change_log.push( {function_patched: new_info.function_name} );
     }
   
-    var change_len_old;
-    var change_len_new;
-    // Translate position in old version of script into position in new
-    // version of script.
-    function PosTranslator(old_pos) {
-      if (old_pos <= change_pos) {
-        return old_pos;
-      }
-      if (old_pos >= change_pos + change_len_old) {
-        return old_pos + change_len_new - change_len_old;
-      }
-      return -1;
-    }
-  
-    var position_change_array;
+    
     var position_patch_report;
-    function PatchPositions(new_info, shared_info) {
+    function PatchPositions(old_info, shared_info) {
       if (!shared_info) {
-        // TODO(LiveEdit): explain what is happening.
+        // TODO(LiveEdit): function is not compiled yet or is already collected.
+        position_patch_report.push( 
+            { name: old_info.function_name, info_not_found: true } );
         return;
       }
       var breakpoint_position_update = %LiveEditPatchFunctionPositions(
-          shared_info.raw_array, position_change_array);
+          shared_info.raw_array, diff_array);
       for (var i = 0; i < breakpoint_position_update.length; i += 2) {
         var new_pos = breakpoint_position_update[i];
         var break_point_object = breakpoint_position_update[i + 1];
@@ -191,7 +189,7 @@
             { from: break_point_object.source_position(), to: new_pos } } );
         break_point_object.updateSourcePosition(new_pos, script);
       }
-      position_patch_report.push( { name: new_info.function_name } );
+      position_patch_report.push( { name: old_info.function_name } );
     }
   
     var link_to_old_script_report;
@@ -199,22 +197,19 @@
     // Makes a function associated with another instance of a script (the
     // one representing its old version). This way the function still
     // may access its own text.
-    function LinkToOldScript(shared_info) {
-      %LiveEditRelinkFunctionToScript(shared_info.raw_array, old_script);
-  
-      link_to_old_script_report.push( { name: shared_info.function_name } );
+    function LinkToOldScript(shared_info, old_info_node) {
+      if (shared_info) {
+        %LiveEditRelinkFunctionToScript(shared_info.raw_array, old_script);
+        link_to_old_script_report.push( { name: shared_info.function_name } );
+      } else {
+        link_to_old_script_report.push(
+            { name: old_info_node.info.function_name, not_found: true } );
+      }
     }
-  
-  
+    
   
     var old_source = script.source;
-    var change_len_old = change_len;
-    var change_len_new = new_str.length;
-  
-    // Prepare new source string.
-    var new_source = old_source.substring(0, change_pos) +
-        new_str + old_source.substring(change_pos + change_len);
-  
+   
     // Find all SharedFunctionInfo's that are compiled from this script.
     var shared_raw_list = %LiveEditFindSharedFunctionInfosForScript(script);
   
@@ -234,94 +229,103 @@
     } catch (e) {
       throw new Failure("Failed to compile new version of script: " + e);
     }
-  
-    // An index of a single function, that is going to have its code replaced.
-    var function_being_patched =
-        FindChangedFunction(old_compile_info, change_pos, change_len_old);
-  
-    // In old and new script versions function with a change should have the
-    // same indexes.
-    var function_being_patched2 =
-        FindChangedFunction(new_compile_info, change_pos, change_len_new);
-    Assert(function_being_patched == function_being_patched2,
-           "inconsistent old/new compile info");
-  
-    // Check that function being patched has the same expectations in a new
-    // version. Otherwise we cannot safely patch its behavior and should
-    // choose the outer function instead.
-    while (!CompareFunctionExpectations(
-        old_compile_info[function_being_patched],
-        new_compile_info[function_being_patched])) {
-  
-      Assert(old_compile_info[function_being_patched].outer_index ==
-          new_compile_info[function_being_patched].outer_index);
-      function_being_patched =
-          old_compile_info[function_being_patched].outer_index;
-      Assert(function_being_patched != -1);
+    
+    var pos_translator = new PosTranslator(diff_array);
+
+    // Build tree structures for old and new versions of the script.
+    var root_old_node = BuildCodeInfoTree(old_compile_info);
+    var root_new_node = BuildCodeInfoTree(new_compile_info);
+
+    // Analyze changes.
+    MarkChangedFunctions(root_old_node, pos_translator.GetChunks());
+    FindCorrespondingFunctions(root_old_node, root_new_node);
+    
+    // Prepare to-do lists.
+    var replace_code_list = new Array();
+    var link_to_old_script_list = new Array();
+    var update_positions_list = new Array();
+
+    function HarvestTodo(old_node) {
+      function CollectDamaged(node) {
+        link_to_old_script_list.push(node);
+        for (var i = 0; i < node.children.length; i++) {
+          CollectDamaged(node.children[i]);
+        }
+      }
+      
+      if (old_node.status == FunctionStatus.DAMAGED) {
+        CollectDamaged(old_node);
+        return;
+      }
+      if (old_node.status == FunctionStatus.UNCHANGED) {
+        update_positions_list.push(old_node);
+      } else if (old_node.status == FunctionStatus.SOURCE_CHANGED) {
+        update_positions_list.push(old_node);
+      } else if (old_node.status == FunctionStatus.CHANGED) {
+        replace_code_list.push(old_node);
+      }
+      for (var i = 0; i < old_node.children.length; i++) {
+        HarvestTodo(old_node.children[i]);
+      }
     }
-  
+
+    HarvestTodo(root_old_node);
+    
+    // Collect shared infos for functions whose code need to be patched.
+    var replaced_function_infos = new Array();
+    for (var i = 0; i < replace_code_list.length; i++) {
+      var info = FindFunctionInfo(replace_code_list[i].array_index);
+      if (info) {
+        replaced_function_infos.push(info);
+      }
+    }
+
     // Check that function being patched is not currently on stack.
-    CheckStackActivations(
-        [ FindFunctionInfo(function_being_patched) ], change_log );
+    CheckStackActivations(replaced_function_infos, change_log);
   
   
+    // We haven't changed anything before this line yet.
     // Committing all changes.
-    var old_script_name = CreateNameForOldScript(script);
-  
-    // Update the script text and create a new script representing an old
-    // version of the script.
-    var old_script = %LiveEditReplaceScript(script, new_source,
-        old_script_name);
-  
-    PatchCode(new_compile_info[function_being_patched],
-        FindFunctionInfo(function_being_patched));
+
+    // Create old script if there are function linked to old version.
+    if (link_to_old_script_list.length > 0) {
+      var old_script_name = CreateNameForOldScript(script);
+      
+      // Update the script text and create a new script representing an old
+      // version of the script.
+      var old_script = %LiveEditReplaceScript(script, new_source,
+          old_script_name);
+      
+      var link_to_old_script_report = new Array();
+      change_log.push( { linked_to_old_script: link_to_old_script_report } );
+    
+      // We need to link to old script all former nested functions.
+      for (var i = 0; i < link_to_old_script_list.length; i++) {
+        LinkToOldScript(
+            FindFunctionInfo(link_to_old_script_list[i].array_index),
+            link_to_old_script_list[i]);
+      }
+    }
+    
+
+    for (var i = 0; i < replace_code_list.length; i++) {
+      PatchCode(replace_code_list[i].corresponding_node.info,
+          FindFunctionInfo(replace_code_list[i].array_index));
+    }
   
     var position_patch_report = new Array();
     change_log.push( {position_patched: position_patch_report} );
-  
-    var position_change_array = [ change_pos,
-                                  change_pos + change_len_old,
-                                  change_pos + change_len_new ];
-  
-    // Update positions of all outer functions (i.e. all functions, that
-    // are partially below the function being patched).
-    for (var i = new_compile_info[function_being_patched].outer_index;
-        i != -1;
-        i = new_compile_info[i].outer_index) {
-      PatchPositions(new_compile_info[i], FindFunctionInfo(i));
-    }
-  
-    // Update positions of all functions that are fully below the function
-    // being patched.
-    var old_next_sibling =
-        old_compile_info[function_being_patched].next_sibling_index;
-    var new_next_sibling =
-        new_compile_info[function_being_patched].next_sibling_index;
-  
-    // We simply go over the tail of both old and new lists. Their tails should
-    // have an identical structure.
-    if (old_next_sibling == -1) {
-      Assert(new_next_sibling == -1);
-    } else {
-      Assert(old_compile_info.length - old_next_sibling ==
-          new_compile_info.length - new_next_sibling);
-  
-      for (var i = old_next_sibling, j = new_next_sibling;
-          i < old_compile_info.length; i++, j++) {
-        PatchPositions(new_compile_info[j], FindFunctionInfo(i));
-      }
-    }
-  
-    var link_to_old_script_report = new Array();
-    change_log.push( { linked_to_old_script: link_to_old_script_report } );
-  
-    // We need to link to old script all former nested functions.
-    for (var i = function_being_patched + 1; i < old_next_sibling; i++) {
-      LinkToOldScript(FindFunctionInfo(i), old_script);
+    
+    for (var i = 0; i < update_positions_list.length; i++) {
+      // TODO(LiveEdit): take into account wether it's source_changed or
+      // unchanged and whether positions changed at all.
+      PatchPositions(update_positions_list[i].info,
+          FindFunctionInfo(update_positions_list[i].array_index));
     }
   }
   // Function is public.
-  this.ApplyPatch = ApplyPatch;
+  this.ApplyPatchMultiChunk = ApplyPatchMultiChunk;
+
   
   function Assert(condition, message) {
     if (!condition) {
@@ -332,6 +336,296 @@
       }
     }
   }
+
+  function DiffChunk(pos1, pos2, len1, len2) {
+    this.pos1 = pos1;
+    this.pos2 = pos2;
+    this.len1 = len1;
+    this.len2 = len2;
+  }
+  
+  function PosTranslator(diff_array) {
+    var chunks = new Array();
+    var pos1 = 0;
+    var pos2 = 0;
+    for (var i = 0; i < diff_array.length; i += 3) {
+      pos2 += diff_array[i] - pos1 + pos2;
+      pos1 = diff_array[i];
+      chunks.push(new DiffChunk(pos1, pos2, diff_array[i + 1] - pos1,
+          diff_array[i + 2] - pos2));
+      pos1 = diff_array[i + 1];
+      pos2 = diff_array[i + 2];
+    }
+    this.chunks = chunks;
+  }
+  PosTranslator.prototype.GetChunks = function() {
+    return this.chunks;
+  }
+  
+  PosTranslator.prototype.Translate = function(pos, inside_chunk_handler) {
+    var array = this.chunks; 
+    if (array.length == 0 || pos < array[0]) {
+      return pos;
+    }
+    var chunk_index1 = 0;
+    var chunk_index2 = array.length - 1;
+
+    while (chunk_index1 < chunk_index2) {
+      var middle_index = (chunk_index1 + chunk_index2) / 2;
+      if (pos < array[middle_index + 1].pos1) {
+        chunk_index2 = middle_index;
+      } else {
+        chunk_index1 = middle_index + 1;
+      }
+    }
+    var chunk = array[chunk_index1];
+    if (pos >= chunk.pos1 + chunk.len1) {
+      return pos += chunk.pos2 + chunk.len2 - chunk.pos1 - chunk.len1; 
+    }
+    
+    if (!inside_chunk_handler) {
+      inside_chunk_handler = PosTranslator.default_inside_chunk_handler;
+    }
+    inside_chunk_handler(pos, chunk);
+  }
+
+  PosTranslator.default_inside_chunk_handler = function() {
+    Assert(false, "Cannot translate position in chaged area");
+  }
+  
+  var FunctionStatus = {
+      // No change to function or its inner functions; however its positions
+      // in script may have been shifted. 
+      UNCHANGED: "unchanged",
+      // The code of a function remains unchanged, but something happened inside
+      // some inner functions.
+      SOURCE_CHANGED: "source changed",
+      // The code of a function is changed or some nested function cannot be
+      // properly patched so this function must be recompiled.
+      CHANGED: "changed",
+      // Function is changed but cannot be patched.
+      DAMAGED: "damaged"
+  }
+  
+  function CodeInfoTreeNode(code_info, children, array_index) {
+    this.info = code_info;
+    this.children = children;
+    // an index in array of compile_info
+    this.array_index = array_index; 
+    this.parent = void(0);
+    
+    this.status = FunctionStatus.UNCHANGED;
+    // Status explanation is used for debugging purposes and will be shown
+    // in user UI if some explanations are needed.
+    this.status_explanation = void(0);
+    this.new_start_pos = void(0);
+    this.new_end_pos = void(0);
+    this.corresponding_node = void(0);
+  }
+  
+  // From array of function infos that is implicitly a tree creates
+  // an actual tree of functions in script.
+  function BuildCodeInfoTree(code_info_array) {
+    // Throughtout all function we iterate over input array.
+    var index = 0;
+
+    // Recursive function that builds a branch of tree. 
+    function BuildNode() {
+      var my_index = index;
+      index++;
+      var child_array = new Array();
+      while (index < code_info_array.length &&
+          code_info_array[index].outer_index == my_index) {
+        child_array.push(BuildNode());
+      }
+      var node = new CodeInfoTreeNode(code_info_array[my_index], child_array,
+          my_index);
+      for (var i = 0; i < child_array.length; i++) {
+        child_array[i].parent = node;
+      }
+      return node;
+    }
+    
+    var root = BuildNode();
+    Assert(index == code_info_array.length);
+    return root;
+  }
+
+  // Applies a list of the textual diff chunks onto the tree of functions.
+  // Determines status of each function (from unchanged to damaged). However
+  // children of unchanged functions are ignored.
+  function MarkChangedFunctions(code_info_tree, chunks) {
+
+    // A convenient interator over diff chunks that also translates
+    // positions from old to new in a current non-changed part of script.
+    var chunk_it = new function() {
+      var chunk_index = 0;
+      var pos_diff = 0;
+      this.current = function() { return chunks[chunk_index]; }
+      this.next = function() {
+        var chunk = chunks[chunk_index];
+        pos_diff = chunk.pos2 + chunk.len2 - (chunk.pos1 + chunk.len1); 
+        chunk_index++;
+      }
+      this.done = function() { return chunk_index >= chunks.length; }
+      this.TranslatePos = function(pos) { return pos + pos_diff; }
+    };
+
+    // A recursive function that processes internals of a function and all its
+    // inner functions. Iterator chunk_it initially points to a chunk that is
+    // below function start.
+    function ProcessInternals(info_node) {
+      info_node.new_start_pos = chunk_it.TranslatePos(
+          info_node.info.start_position); 
+      var child_index = 0;
+      var code_changed = false;
+      var source_changed = false;
+      // Simultaneously iterates over child functions and over chunks.
+      while (!chunk_it.done() &&
+          chunk_it.current().pos1 < info_node.info.end_position) {
+        if (child_index < info_node.children.length) {
+          var child = info_node.children[child_index];
+          
+          if (child.info.end_position <= chunk_it.current().pos1) {
+            ProcessUnchangedChild(child);
+            child_index++;
+            continue;
+          } else if (child.info.start_position >=
+              chunk_it.current().pos1 + chunk_it.current().len1) {
+            code_changed = true;
+            chunk_it.next();
+            continue;
+          } else if (child.info.start_position <= chunk_it.current().pos1 &&
+              child.info.end_position >= chunk_it.current().pos1 +
+              chunk_it.current().len1) {
+            ProcessInternals(child);
+            source_changed = source_changed ||
+                ( child.status != FunctionStatus.UNCHANGED );
+            code_changed = code_changed ||
+                ( child.status == FunctionStatus.DAMAGED );
+            child_index++;
+            continue;
+          } else {
+            code_changed = true;
+            child.status = FunctionStatus.DAMAGED;
+            child.status_explanation =
+                "Text diff overlaps with function boundary";
+            child_index++;
+            continue;
+          }
+        } else {
+          if (chunk_it.current().pos1 + chunk_it.current().len1 <= 
+              info_node.info.end_position) {
+            info_node.status = FunctionStatus.CHANGED;
+            chunk_it.next();
+            continue;
+          } else {
+            info_node.status = FunctionStatus.DAMAGED;
+            info_node.status_explanation =
+                "Text diff overlaps with function boundary";
+            return;
+          }
+        }
+        Assert("Unreachable", false);
+      }
+      while (child_index < info_node.children.length) {
+        var child = info_node.children[child_index];
+        ProcessUnchangedChild(child);
+        child_index++;
+      }
+      if (code_changed) {
+        info_node.status = FunctionStatus.CHANGED;
+      } else if (source_changed) {
+        info_node.status = FunctionStatus.SOURCE_CHANGED;
+      }
+      info_node.new_end_pos =
+          chunk_it.TranslatePos(info_node.info.end_position); 
+    }
+    
+    function ProcessUnchangedChild(node) {
+      node.new_start_pos = chunk_it.TranslatePos(node.info.start_position);
+      node.new_end_pos = chunk_it.TranslatePos(node.info.end_position);
+    }
+    
+    ProcessInternals(code_info_tree);
+  }
+
+  // For ecah old function (if it is not damaged) tries to find a corresponding
+  // function in new script. Typically it should succeed (non-damaged functions
+  // by definition may only have changes inside their bodies). However there are
+  // reasons for corresponence not to be found; function with unmodified text
+  // in new script may become enclosed into other function; the innocent change
+  // inside function body may in fact be something like "} function B() {" that
+  // splits a function into 2 functions.
+  function FindCorrespondingFunctions(old_code_tree, new_code_tree) {
+
+    // A recursive function that tries to find a correspondence for all
+    // child functions and for their inner functions.
+    function ProcessChildren(old_node, new_node) {
+      var old_children = old_node.children;
+      var new_children = new_node.children;
+
+      var old_index = 0;
+      var new_index = 0;
+      while (old_index < old_children.length) {
+        if (old_children[old_index].status == FunctionStatus.DAMAGED) {
+          old_index++;
+        } else if (new_index < new_children.length) {
+          if (new_children[new_index].info.start_position <
+              old_children[old_index].new_start_pos) {
+            new_index++;
+          } else if (new_children[new_index].info.start_position ==
+              old_children[old_index].new_start_pos) {
+            if (new_children[new_index].info.end_position ==
+                old_children[old_index].new_end_pos) {
+              old_children[old_index].corresponding_node =
+                  new_children[new_index];
+              if (old_children[old_index].status != FunctionStatus.UNCHANGED) {
+                ProcessChildren(old_children[old_index],
+                    new_children[new_index]);
+                if (old_children[old_index].status == FunctionStatus.DAMAGED) {
+                  old_node.status = FunctionStatus.CHANGED;
+                }
+              }
+            } else {
+              old_children[old_index].status = FunctionStatus.DAMAGED;
+              old_children[old_index].status_explanation =
+                  "No corresponding function in new script found";
+              old_node.status = FunctionStatus.CHANGED;
+            }
+            new_index++;
+            old_index++;
+          } else {
+            old_children[old_index].status = FunctionStatus.DAMAGED;
+            old_children[old_index].status_explanation =
+                "No corresponding function in new script found";
+            old_node.status = FunctionStatus.CHANGED;
+            old_index++;
+          }
+        } else {
+          old_children[old_index].status = FunctionStatus.DAMAGED;
+          old_children[old_index].status_explanation =
+              "No corresponding function in new script found";
+          old_node.status = FunctionStatus.CHANGED;
+          old_index++;
+        }
+      }
+      
+      if (old_node.status == FunctionStatus.CHANGED) {
+        if (!CompareFunctionExpectations(old_node.info, new_node.info)) {
+          old_node.status = FunctionStatus.DAMAGED;
+          old_node.status_explanation = "Changed code expectations";
+        }
+      }
+    }
+
+    ProcessChildren(old_code_tree, new_code_tree);
+    
+    old_code_tree.corresponding_node = new_code_tree;
+    Assert(old_code_tree.status != FunctionStatus.DAMAGED,
+        "Script became damaged");
+  }
+
   
   // An object describing function compilation details. Its index fields
   // apply to indexes inside array that stores these objects.
@@ -469,13 +763,12 @@
   // LiveEdit main entry point: changes a script text to a new string.
   function SetScriptSource(script, new_source, change_log) {
     var old_source = script.source;
-    var diff = FindSimpleDiff(old_source, new_source);
-    if (!diff) {
+    var diff = CompareStringsLinewise(old_source, new_source);
+    if (diff.length == 0) {
+      change_log.push( { empty_diff: true } );
       return;
     }
-    ApplyPatch(script, diff.change_pos, diff.old_len,
-        new_source.substring(diff.change_pos, diff.change_pos + diff.new_len),
-        change_log);
+    ApplyPatchMultiChunk(script, diff, new_source, change_log);
   }
   // Function is public.
   this.SetScriptSource = SetScriptSource;
diff --git a/src/liveedit.cc b/src/liveedit.cc
index 4b30b2a..f016fc8 100644
--- a/src/liveedit.cc
+++ b/src/liveedit.cc
@@ -346,7 +346,7 @@
 
 
 // Stores compare result in JSArray. Each chunk is stored as 3 array elements:
-// (pos1, len1, len2).
+// (pos1_begin, pos1_end, pos2_end).
 class LineArrayCompareOutput : public Compare::Output {
  public:
   LineArrayCompareOutput(LineEndsWrapper line_ends1, LineEndsWrapper line_ends2)
@@ -362,9 +362,9 @@
 
     SetElement(array_, current_size_, Handle<Object>(Smi::FromInt(char_pos1)));
     SetElement(array_, current_size_ + 1,
-               Handle<Object>(Smi::FromInt(char_len1)));
+               Handle<Object>(Smi::FromInt(char_pos1 + char_len1)));
     SetElement(array_, current_size_ + 2,
-               Handle<Object>(Smi::FromInt(char_len2)));
+               Handle<Object>(Smi::FromInt(char_pos2 + char_len2)));
     current_size_ += 3;
   }
 
@@ -717,8 +717,8 @@
   }
 
   void VisitCodeTarget(RelocInfo* rinfo) {
-    ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
-    if (Code::GetCodeFromTargetAddress(rinfo->target_address()) == original_) {
+    if (RelocInfo::IsCodeTarget(rinfo->rmode()) &&
+        Code::GetCodeFromTargetAddress(rinfo->target_address()) == original_) {
       reloc_infos_.Add(*rinfo);
     }
   }
diff --git a/src/liveedit.h b/src/liveedit.h
index 5c73313..47e09d1 100644
--- a/src/liveedit.h
+++ b/src/liveedit.h
@@ -111,7 +111,7 @@
   };
 
   // Compares 2 strings line-by-line and returns diff in form of array of
-  // triplets (pos1, len1, len2) describing list of diff chunks.
+  // triplets (pos1, pos1_end, pos2_end) describing list of diff chunks.
   static Handle<JSArray> CompareStringsLinewise(Handle<String> s1,
                                                 Handle<String> s2);
 };
diff --git a/src/mark-compact.cc b/src/mark-compact.cc
index 80ad389..8421125 100644
--- a/src/mark-compact.cc
+++ b/src/mark-compact.cc
@@ -1055,6 +1055,7 @@
   PageIterator it(space, PageIterator::PAGES_IN_USE);
   while (it.has_next()) {
     Page* p = it.next();
+
     // The offset of each live object in the page from the first live object
     // in the page.
     int offset = 0;
@@ -1277,6 +1278,29 @@
 
 static void SweepSpace(PagedSpace* space, DeallocateFunction dealloc) {
   PageIterator it(space, PageIterator::PAGES_IN_USE);
+
+  // During sweeping of paged space we are trying to find longest sequences
+  // of pages without live objects and free them (instead of putting them on
+  // the free list).
+
+  // Page preceding current.
+  Page* prev = Page::FromAddress(NULL);
+
+  // First empty page in a sequence.
+  Page* first_empty_page = Page::FromAddress(NULL);
+
+  // Page preceding first empty page.
+  Page* prec_first_empty_page = Page::FromAddress(NULL);
+
+  // If last used page of space ends with a sequence of dead objects
+  // we can adjust allocation top instead of puting this free area into
+  // the free list. Thus during sweeping we keep track of such areas
+  // and defer their deallocation until the sweeping of the next page
+  // is done: if one of the next pages contains live objects we have
+  // to put such area into the free list.
+  Address last_free_start = NULL;
+  int last_free_size = 0;
+
   while (it.has_next()) {
     Page* p = it.next();
 
@@ -1291,8 +1315,9 @@
       if (object->IsMarked()) {
         object->ClearMark();
         MarkCompactCollector::tracer()->decrement_marked_count();
+
         if (!is_previous_alive) {  // Transition from free to live.
-          dealloc(free_start, static_cast<int>(current - free_start));
+          dealloc(free_start, static_cast<int>(current - free_start), true);
           is_previous_alive = true;
         }
       } else {
@@ -1306,39 +1331,113 @@
       // loop.
     }
 
-    // If the last region was not live we need to deallocate from
-    // free_start to the allocation top in the page.
-    if (!is_previous_alive) {
-      int free_size = static_cast<int>(p->AllocationTop() - free_start);
-      if (free_size > 0) {
-        dealloc(free_start, free_size);
+    bool page_is_empty = (p->ObjectAreaStart() == p->AllocationTop())
+        || (!is_previous_alive && free_start == p->ObjectAreaStart());
+
+    if (page_is_empty) {
+      // This page is empty. Check whether we are in the middle of
+      // sequence of empty pages and start one if not.
+      if (!first_empty_page->is_valid()) {
+        first_empty_page = p;
+        prec_first_empty_page = prev;
+      }
+
+      if (!is_previous_alive) {
+        // There are dead objects on this page. Update space accounting stats
+        // without putting anything into free list.
+        int size_in_bytes = static_cast<int>(p->AllocationTop() - free_start);
+        if (size_in_bytes > 0) {
+          dealloc(free_start, size_in_bytes, false);
+        }
+      }
+    } else {
+      // This page is not empty. Sequence of empty pages ended on the previous
+      // one.
+      if (first_empty_page->is_valid()) {
+        space->FreePages(prec_first_empty_page, prev);
+        prec_first_empty_page = first_empty_page = Page::FromAddress(NULL);
+      }
+
+      // If there is a free ending area on one of the previous pages we have
+      // deallocate that area and put it on the free list.
+      if (last_free_size > 0) {
+        dealloc(last_free_start, last_free_size, true);
+        last_free_start = NULL;
+        last_free_size  = 0;
+      }
+
+      // If the last region of this page was not live we remember it.
+      if (!is_previous_alive) {
+        ASSERT(last_free_size == 0);
+        last_free_size = static_cast<int>(p->AllocationTop() - free_start);
+        last_free_start = free_start;
       }
     }
+
+    prev = p;
+  }
+
+  // We reached end of space. See if we need to adjust allocation top.
+  Address new_allocation_top = NULL;
+
+  if (first_empty_page->is_valid()) {
+    // Last used pages in space are empty. We can move allocation top backwards
+    // to the beginning of first empty page.
+    ASSERT(prev == space->AllocationTopPage());
+
+    new_allocation_top = first_empty_page->ObjectAreaStart();
+  }
+
+  if (last_free_size > 0) {
+    // There was a free ending area on the previous page.
+    // Deallocate it without putting it into freelist and move allocation
+    // top to the beginning of this free area.
+    dealloc(last_free_start, last_free_size, false);
+    new_allocation_top = last_free_start;
+  }
+
+  if (new_allocation_top != NULL) {
+#ifdef DEBUG
+    Page* new_allocation_top_page = Page::FromAllocationTop(new_allocation_top);
+    if (!first_empty_page->is_valid()) {
+      ASSERT(new_allocation_top_page == space->AllocationTopPage());
+    } else if (last_free_size > 0) {
+      ASSERT(new_allocation_top_page == prec_first_empty_page);
+    } else {
+      ASSERT(new_allocation_top_page == first_empty_page);
+    }
+#endif
+
+    space->SetTop(new_allocation_top);
   }
 }
 
 
 void MarkCompactCollector::DeallocateOldPointerBlock(Address start,
-                                                     int size_in_bytes) {
+                                                     int size_in_bytes,
+                                                     bool add_to_freelist) {
   Heap::ClearRSetRange(start, size_in_bytes);
-  Heap::old_pointer_space()->Free(start, size_in_bytes);
+  Heap::old_pointer_space()->Free(start, size_in_bytes, add_to_freelist);
 }
 
 
 void MarkCompactCollector::DeallocateOldDataBlock(Address start,
-                                                  int size_in_bytes) {
-  Heap::old_data_space()->Free(start, size_in_bytes);
+                                                  int size_in_bytes,
+                                                  bool add_to_freelist) {
+  Heap::old_data_space()->Free(start, size_in_bytes, add_to_freelist);
 }
 
 
 void MarkCompactCollector::DeallocateCodeBlock(Address start,
-                                               int size_in_bytes) {
-  Heap::code_space()->Free(start, size_in_bytes);
+                                               int size_in_bytes,
+                                               bool add_to_freelist) {
+  Heap::code_space()->Free(start, size_in_bytes, add_to_freelist);
 }
 
 
 void MarkCompactCollector::DeallocateMapBlock(Address start,
-                                              int size_in_bytes) {
+                                              int size_in_bytes,
+                                              bool add_to_freelist) {
   // Objects in map space are assumed to have size Map::kSize and a
   // valid map in their first word.  Thus, we break the free block up into
   // chunks and free them separately.
@@ -1346,13 +1445,14 @@
   Heap::ClearRSetRange(start, size_in_bytes);
   Address end = start + size_in_bytes;
   for (Address a = start; a < end; a += Map::kSize) {
-    Heap::map_space()->Free(a);
+    Heap::map_space()->Free(a, add_to_freelist);
   }
 }
 
 
 void MarkCompactCollector::DeallocateCellBlock(Address start,
-                                               int size_in_bytes) {
+                                               int size_in_bytes,
+                                               bool add_to_freelist) {
   // Free-list elements in cell space are assumed to have a fixed size.
   // We break the free block into chunks and add them to the free list
   // individually.
@@ -1361,7 +1461,7 @@
   Heap::ClearRSetRange(start, size_in_bytes);
   Address end = start + size_in_bytes;
   for (Address a = start; a < end; a += size) {
-    Heap::cell_space()->Free(a);
+    Heap::cell_space()->Free(a, add_to_freelist);
   }
 }
 
diff --git a/src/mark-compact.h b/src/mark-compact.h
index 27335f2..3950e75 100644
--- a/src/mark-compact.h
+++ b/src/mark-compact.h
@@ -37,7 +37,11 @@
 typedef bool (*IsAliveFunction)(HeapObject* obj, int* size, int* offset);
 
 // Callback function for non-live blocks in the old generation.
-typedef void (*DeallocateFunction)(Address start, int size_in_bytes);
+// If add_to_freelist is false then just accounting stats are updated and
+// no attempt to add area to free list is made.
+typedef void (*DeallocateFunction)(Address start,
+                                   int size_in_bytes,
+                                   bool add_to_freelist);
 
 
 // Forward declarations.
@@ -313,11 +317,25 @@
 
   // Callback functions for deallocating non-live blocks in the old
   // generation.
-  static void DeallocateOldPointerBlock(Address start, int size_in_bytes);
-  static void DeallocateOldDataBlock(Address start, int size_in_bytes);
-  static void DeallocateCodeBlock(Address start, int size_in_bytes);
-  static void DeallocateMapBlock(Address start, int size_in_bytes);
-  static void DeallocateCellBlock(Address start, int size_in_bytes);
+  static void DeallocateOldPointerBlock(Address start,
+                                        int size_in_bytes,
+                                        bool add_to_freelist);
+
+  static void DeallocateOldDataBlock(Address start,
+                                     int size_in_bytes,
+                                     bool add_to_freelist);
+
+  static void DeallocateCodeBlock(Address start,
+                                  int size_in_bytes,
+                                  bool add_to_freelist);
+
+  static void DeallocateMapBlock(Address start,
+                                 int size_in_bytes,
+                                 bool add_to_freelist);
+
+  static void DeallocateCellBlock(Address start,
+                                  int size_in_bytes,
+                                  bool add_to_freelist);
 
   // If we are not compacting the heap, we simply sweep the spaces except
   // for the large object space, clearing mark bits and adding unmarked
diff --git a/src/regexp.js b/src/regexp.js
index 9929b11..24e3309 100644
--- a/src/regexp.js
+++ b/src/regexp.js
@@ -115,7 +115,9 @@
 
 
 function DoRegExpExec(regexp, string, index) {
-  return %_RegExpExec(regexp, string, index, lastMatchInfo);
+  var result = %_RegExpExec(regexp, string, index, lastMatchInfo);
+  if (result !== null) lastMatchInfoOverride = null;
+  return result;
 }
 
 
@@ -136,7 +138,7 @@
 
 
 function CloneRegExpResult(array) {
-  if (array == null) return null; 
+  if (array == null) return null;
   var length = array.length;
   var answer = %_RegExpConstructResult(length, array.index, array.input);
   for (var i = 0; i < length; i++) {
@@ -237,7 +239,7 @@
     cache.type = 'exec';
     return matchIndices;        // No match.
   }
-
+  lastMatchInfoOverride = null;
   var result = BuildResultFromMatchInfo(matchIndices, s);
 
   if (this.global) {
@@ -312,7 +314,7 @@
     cache.answer = false;
     return false;
   }
-
+  lastMatchInfoOverride = null;
   if (this.global) this.lastIndex = lastMatchInfo[CAPTURE1];
   cache.answer = true;
   return true;
@@ -340,7 +342,9 @@
 // on the captures array of the last successful match and the subject string
 // of the last successful match.
 function RegExpGetLastMatch() {
-  if (lastMatchInfoOverride) { return lastMatchInfoOverride[0]; }
+  if (lastMatchInfoOverride !== null) {
+    return lastMatchInfoOverride[0];
+  }
   var regExpSubject = LAST_SUBJECT(lastMatchInfo);
   return SubString(regExpSubject,
                    lastMatchInfo[CAPTURE0],
diff --git a/src/runtime.cc b/src/runtime.cc
index ab77018..dd0a3d2 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -9766,7 +9766,7 @@
 }
 
 // Compares 2 strings line-by-line and returns diff in form of JSArray of
-// triplets (pos1, len1, len2) describing list of diff chunks.
+// triplets (pos1, pos1_end, pos2_end) describing list of diff chunks.
 static Object* Runtime_LiveEditCompareStringsLinewise(Arguments args) {
   ASSERT(args.length() == 2);
   HandleScope scope;
diff --git a/src/serialize.cc b/src/serialize.cc
index 1c0b731..6841267 100644
--- a/src/serialize.cc
+++ b/src/serialize.cc
@@ -836,6 +836,9 @@
       case START_NEW_PAGE_SERIALIZATION: {
         int space = source_->Get();
         pages_[space].Add(last_object_address_);
+        if (space == CODE_SPACE) {
+          CPU::FlushICache(last_object_address_, Page::kPageSize);
+        }
         break;
       }
       case NATIVES_STRING_RESOURCE: {
diff --git a/src/spaces-inl.h b/src/spaces-inl.h
index 72f8305..66894c4 100644
--- a/src/spaces-inl.h
+++ b/src/spaces-inl.h
@@ -145,6 +145,40 @@
 }
 
 
+bool Page::GetPageFlag(PageFlag flag) {
+  return (flags & flag) != 0;
+}
+
+
+void Page::SetPageFlag(PageFlag flag, bool value) {
+  if (value) {
+    flags |= flag;
+  } else {
+    flags &= ~flag;
+  }
+}
+
+
+bool Page::WasInUseBeforeMC() {
+  return GetPageFlag(WAS_IN_USE_BEFORE_MC);
+}
+
+
+void Page::SetWasInUseBeforeMC(bool was_in_use) {
+  SetPageFlag(WAS_IN_USE_BEFORE_MC, was_in_use);
+}
+
+
+bool Page::IsLargeObjectPage() {
+  return !GetPageFlag(IS_NORMAL_PAGE);
+}
+
+
+void Page::SetIsLargeObjectPage(bool is_large_object_page) {
+  SetPageFlag(IS_NORMAL_PAGE, !is_large_object_page);
+}
+
+
 // -----------------------------------------------------------------------------
 // MemoryAllocator
 
diff --git a/src/spaces.cc b/src/spaces.cc
index 5f191ed..6b6d926 100644
--- a/src/spaces.cc
+++ b/src/spaces.cc
@@ -524,7 +524,7 @@
   for (int i = 0; i < pages_in_chunk; i++) {
     Page* p = Page::FromAddress(page_addr);
     p->opaque_header = OffsetFrom(page_addr + Page::kPageSize) | chunk_id;
-    p->is_normal_page = 1;
+    p->SetIsLargeObjectPage(false);
     page_addr += Page::kPageSize;
   }
 
@@ -568,6 +568,15 @@
 }
 
 
+void MemoryAllocator::FreeAllPages(PagedSpace* space) {
+  for (int i = 0, length = chunks_.length(); i < length; i++) {
+    if (chunks_[i].owner() == space) {
+      DeleteChunk(i);
+    }
+  }
+}
+
+
 void MemoryAllocator::DeleteChunk(int chunk_id) {
   ASSERT(IsValidChunk(chunk_id));
 
@@ -622,6 +631,74 @@
 #endif
 
 
+void MemoryAllocator::RelinkPageListInChunkOrder(PagedSpace* space,
+                                                 Page** first_page,
+                                                 Page** last_page,
+                                                 Page** last_page_in_use) {
+  Page* first = NULL;
+  Page* last = NULL;
+
+  for (int i = 0, length = chunks_.length(); i < length; i++) {
+    ChunkInfo& chunk = chunks_[i];
+
+    if (chunk.owner() == space) {
+      if (first == NULL) {
+        Address low = RoundUp(chunk.address(), Page::kPageSize);
+        first = Page::FromAddress(low);
+      }
+      last = RelinkPagesInChunk(i,
+                                chunk.address(),
+                                chunk.size(),
+                                last,
+                                last_page_in_use);
+    }
+  }
+
+  if (first_page != NULL) {
+    *first_page = first;
+  }
+
+  if (last_page != NULL) {
+    *last_page = last;
+  }
+}
+
+
+Page* MemoryAllocator::RelinkPagesInChunk(int chunk_id,
+                                          Address chunk_start,
+                                          size_t chunk_size,
+                                          Page* prev,
+                                          Page** last_page_in_use) {
+  Address page_addr = RoundUp(chunk_start, Page::kPageSize);
+  int pages_in_chunk = PagesInChunk(chunk_start, chunk_size);
+
+  if (prev->is_valid()) {
+    SetNextPage(prev, Page::FromAddress(page_addr));
+  }
+
+  for (int i = 0; i < pages_in_chunk; i++) {
+    Page* p = Page::FromAddress(page_addr);
+    p->opaque_header = OffsetFrom(page_addr + Page::kPageSize) | chunk_id;
+    page_addr += Page::kPageSize;
+
+    if (p->WasInUseBeforeMC()) {
+      *last_page_in_use = p;
+    }
+  }
+
+  // Set the next page of the last page to 0.
+  Page* last_page = Page::FromAddress(page_addr - Page::kPageSize);
+  last_page->opaque_header = OffsetFrom(0) | chunk_id;
+
+  if (last_page->WasInUseBeforeMC()) {
+    *last_page_in_use = last_page;
+  }
+
+  return last_page;
+}
+
+
+
 // -----------------------------------------------------------------------------
 // PagedSpace implementation
 
@@ -677,6 +754,8 @@
   // Use first_page_ for allocation.
   SetAllocationInfo(&allocation_info_, first_page_);
 
+  page_list_is_chunk_ordered_ = true;
+
   return true;
 }
 
@@ -687,9 +766,8 @@
 
 
 void PagedSpace::TearDown() {
-  first_page_ = MemoryAllocator::FreePages(first_page_);
-  ASSERT(!first_page_->is_valid());
-
+  MemoryAllocator::FreeAllPages(this);
+  first_page_ = NULL;
   accounting_stats_.Clear();
 }
 
@@ -874,6 +952,12 @@
 
 
 void PagedSpace::Shrink() {
+  if (!page_list_is_chunk_ordered_) {
+    // We can't shrink space if pages is not chunk-ordered
+    // (see comment for class MemoryAllocator for definition).
+    return;
+  }
+
   // Release half of free pages.
   Page* top_page = AllocationTopPage();
   ASSERT(top_page->is_valid());
@@ -955,7 +1039,7 @@
         // The next page will be above the allocation top.
         above_allocation_top = true;
       } else {
-        ASSERT(top == current_page->ObjectAreaEnd() - page_extra_);
+        ASSERT(top == PageAllocationLimit(current_page));
       }
 
       // It should be packed with objects from the bottom to the top.
@@ -1363,7 +1447,7 @@
 
 
 static void ReportCodeKindStatistics() {
-  const char* table[Code::NUMBER_OF_KINDS];
+  const char* table[Code::NUMBER_OF_KINDS] = { NULL };
 
 #define CASE(name)                            \
   case Code::name: table[Code::name] = #name; \
@@ -1782,6 +1866,9 @@
 // OldSpace implementation
 
 void OldSpace::PrepareForMarkCompact(bool will_compact) {
+  // Call prepare of the super class.
+  PagedSpace::PrepareForMarkCompact(will_compact);
+
   if (will_compact) {
     // Reset relocation info.  During a compacting collection, everything in
     // the space is considered 'available' and we will rediscover live data
@@ -1852,6 +1939,112 @@
 }
 
 
+void PagedSpace::FreePages(Page* prev, Page* last) {
+  if (last == AllocationTopPage()) {
+    // Pages are already at the end of used pages.
+    return;
+  }
+
+  Page* first = NULL;
+
+  // Remove pages from the list.
+  if (prev == NULL) {
+    first = first_page_;
+    first_page_ = last->next_page();
+  } else {
+    first = prev->next_page();
+    MemoryAllocator::SetNextPage(prev, last->next_page());
+  }
+
+  // Attach it after the last page.
+  MemoryAllocator::SetNextPage(last_page_, first);
+  last_page_ = last;
+  MemoryAllocator::SetNextPage(last, NULL);
+
+  // Clean them up.
+  do {
+    first->ClearRSet();
+    first = first->next_page();
+  } while (first != NULL);
+
+  // Order of pages in this space might no longer be consistent with
+  // order of pages in chunks.
+  page_list_is_chunk_ordered_ = false;
+}
+
+
+void PagedSpace::PrepareForMarkCompact(bool will_compact) {
+  if (will_compact) {
+    // MarkCompact collector relies on WAS_IN_USE_BEFORE_MC page flag
+    // to skip unused pages. Update flag value for all pages in space.
+    PageIterator all_pages_iterator(this, PageIterator::ALL_PAGES);
+    Page* last_in_use = AllocationTopPage();
+    bool in_use = true;
+
+    while (all_pages_iterator.has_next()) {
+      Page* p = all_pages_iterator.next();
+      p->SetWasInUseBeforeMC(in_use);
+      if (p == last_in_use) {
+        // We passed a page containing allocation top. All consequent
+        // pages are not used.
+        in_use = false;
+      }
+    }
+
+    if (!page_list_is_chunk_ordered_) {
+      Page* new_last_in_use = Page::FromAddress(NULL);
+      MemoryAllocator::RelinkPageListInChunkOrder(this,
+                                                  &first_page_,
+                                                  &last_page_,
+                                                  &new_last_in_use);
+      ASSERT(new_last_in_use->is_valid());
+
+      if (new_last_in_use != last_in_use) {
+        // Current allocation top points to a page which is now in the middle
+        // of page list. We should move allocation top forward to the new last
+        // used page so various object iterators will continue to work properly.
+
+        int size_in_bytes = static_cast<int>(PageAllocationLimit(last_in_use) -
+                                             last_in_use->AllocationTop());
+
+        if (size_in_bytes > 0) {
+          // There is still some space left on this page. Create a fake
+          // object which will occupy all free space on this page.
+          // Otherwise iterators would not be able to scan this page
+          // correctly.
+
+          Heap::CreateFillerObjectAt(last_in_use->AllocationTop(),
+                                     size_in_bytes);
+        }
+
+        // New last in use page was in the middle of the list before
+        // sorting so it full.
+        SetTop(new_last_in_use->AllocationTop());
+
+        ASSERT(AllocationTopPage() == new_last_in_use);
+        ASSERT(AllocationTopPage()->WasInUseBeforeMC());
+      }
+
+      PageIterator pages_in_use_iterator(this, PageIterator::PAGES_IN_USE);
+      while (pages_in_use_iterator.has_next()) {
+        Page* p = pages_in_use_iterator.next();
+        if (!p->WasInUseBeforeMC()) {
+          // Empty page is in the middle of a sequence of used pages.
+          // Create a fake object which will occupy all free space on this page.
+          // Otherwise iterators would not be able to scan this page correctly.
+          int size_in_bytes = static_cast<int>(PageAllocationLimit(p) -
+                                               p->ObjectAreaStart());
+
+          Heap::CreateFillerObjectAt(p->ObjectAreaStart(), size_in_bytes);
+        }
+      }
+
+      page_list_is_chunk_ordered_ = true;
+    }
+  }
+}
+
+
 bool PagedSpace::ReserveSpace(int bytes) {
   Address limit = allocation_info_.limit;
   Address top = allocation_info_.top;
@@ -2263,6 +2456,9 @@
 // FixedSpace implementation
 
 void FixedSpace::PrepareForMarkCompact(bool will_compact) {
+  // Call prepare of the super class.
+  PagedSpace::PrepareForMarkCompact(will_compact);
+
   if (will_compact) {
     // Reset relocation info.
     MCResetRelocationInfo();
@@ -2360,7 +2556,7 @@
 HeapObject* FixedSpace::AllocateInNextPage(Page* current_page,
                                            int size_in_bytes) {
   ASSERT(current_page->next_page()->is_valid());
-  ASSERT(current_page->ObjectAreaEnd() - allocation_info_.top == page_extra_);
+  ASSERT(allocation_info_.top == PageAllocationLimit(current_page));
   ASSERT_EQ(object_size_in_bytes_, size_in_bytes);
   accounting_stats_.WasteBytes(page_extra_);
   SetAllocationInfo(&allocation_info_, current_page->next_page());
@@ -2605,7 +2801,7 @@
   // large object page.  If the chunk_size happened to be written there, its
   // low order bit should already be clear.
   ASSERT((chunk_size & 0x1) == 0);
-  page->is_normal_page &= ~0x1;
+  page->SetIsLargeObjectPage(true);
   page->ClearRSet();
   int extra_bytes = requested_size - object_size;
   if (extra_bytes > 0) {
diff --git a/src/spaces.h b/src/spaces.h
index 1237bdf..df42d51 100644
--- a/src/spaces.h
+++ b/src/spaces.h
@@ -167,8 +167,17 @@
     return 0 == (OffsetFrom(a) & kPageAlignmentMask);
   }
 
+  // True if this page was in use before current compaction started.
+  // Result is valid only for pages owned by paged spaces and
+  // only after PagedSpace::PrepareForMarkCompact was called.
+  inline bool WasInUseBeforeMC();
+
+  inline void SetWasInUseBeforeMC(bool was_in_use);
+
   // True if this page is a large object page.
-  bool IsLargeObjectPage() { return (is_normal_page & 0x1) == 0; }
+  inline bool IsLargeObjectPage();
+
+  inline void SetIsLargeObjectPage(bool is_large_object_page);
 
   // Returns the offset of a given address to this page.
   INLINE(int Offset(Address a)) {
@@ -244,6 +253,14 @@
   // Maximum object size that fits in a page.
   static const int kMaxHeapObjectSize = kObjectAreaSize;
 
+  enum PageFlag {
+    IS_NORMAL_PAGE = 1 << 0,
+    WAS_IN_USE_BEFORE_MC = 1 << 1
+  };
+
+  inline bool GetPageFlag(PageFlag flag);
+  inline void SetPageFlag(PageFlag flag, bool value);
+
   //---------------------------------------------------------------------------
   // Page header description.
   //
@@ -262,7 +279,8 @@
   // second word *may* (if the page start and large object chunk start are
   // the same) contain the large object chunk size.  In either case, the
   // low-order bit for large object pages will be cleared.
-  int is_normal_page;
+  // For normal pages this word is used to store various page flags.
+  int flags;
 
   // The following fields may overlap with remembered set, they can only
   // be used in the mark-compact collector when remembered set is not
@@ -407,6 +425,13 @@
 //
 // The memory allocator also allocates chunks for the large object space, but
 // they are managed by the space itself.  The new space does not expand.
+//
+// The fact that pages for paged spaces are allocated and deallocated in chunks
+// induces a constraint on the order of pages in a linked lists. We say that
+// pages are linked in the chunk-order if and only if every two consecutive
+// pages from the same chunk are consecutive in the linked list.
+//
+
 
 class MemoryAllocator : public AllStatic {
  public:
@@ -466,13 +491,18 @@
   static Page* AllocatePages(int requested_pages, int* allocated_pages,
                              PagedSpace* owner);
 
-  // Frees pages from a given page and after. If 'p' is the first page
-  // of a chunk, pages from 'p' are freed and this function returns an
-  // invalid page pointer. Otherwise, the function searches a page
-  // after 'p' that is the first page of a chunk. Pages after the
-  // found page are freed and the function returns 'p'.
+  // Frees pages from a given page and after. Requires pages to be
+  // linked in chunk-order (see comment for class).
+  // If 'p' is the first page of a chunk, pages from 'p' are freed
+  // and this function returns an invalid page pointer.
+  // Otherwise, the function searches a page after 'p' that is
+  // the first page of a chunk. Pages after the found page
+  // are freed and the function returns 'p'.
   static Page* FreePages(Page* p);
 
+  // Frees all pages owned by given space.
+  static void FreeAllPages(PagedSpace* space);
+
   // Allocates and frees raw memory of certain size.
   // These are just thin wrappers around OS::Allocate and OS::Free,
   // but keep track of allocated bytes as part of heap.
@@ -511,6 +541,15 @@
   static Page* FindFirstPageInSameChunk(Page* p);
   static Page* FindLastPageInSameChunk(Page* p);
 
+  // Relinks list of pages owned by space to make it chunk-ordered.
+  // Returns new first and last pages of space.
+  // Also returns last page in relinked list which has WasInUsedBeforeMC
+  // flag set.
+  static void RelinkPageListInChunkOrder(PagedSpace* space,
+                                         Page** first_page,
+                                         Page** last_page,
+                                         Page** last_page_in_use);
+
 #ifdef ENABLE_HEAP_PROTECTION
   // Protect/unprotect a block of memory by marking it read-only/writable.
   static inline void Protect(Address start, size_t size);
@@ -599,6 +638,12 @@
   // used as a marking stack and its page headers are destroyed.
   static Page* InitializePagesInChunk(int chunk_id, int pages_in_chunk,
                                       PagedSpace* owner);
+
+  static Page* RelinkPagesInChunk(int chunk_id,
+                                  Address chunk_start,
+                                  size_t chunk_size,
+                                  Page* prev,
+                                  Page** last_page_in_use);
 };
 
 
@@ -880,9 +925,16 @@
   void ClearRSet();
 
   // Prepares for a mark-compact GC.
-  virtual void PrepareForMarkCompact(bool will_compact) = 0;
+  virtual void PrepareForMarkCompact(bool will_compact);
 
-  virtual Address PageAllocationTop(Page* page) = 0;
+  // The top of allocation in a page in this space. Undefined if page is unused.
+  Address PageAllocationTop(Page* page) {
+    return page == TopPageOf(allocation_info_) ? top()
+        : PageAllocationLimit(page);
+  }
+
+  // The limit of allocation for a page in this space.
+  virtual Address PageAllocationLimit(Page* page) = 0;
 
   // Current capacity without growing (Size() + Available() + Waste()).
   int Capacity() { return accounting_stats_.Capacity(); }
@@ -920,6 +972,16 @@
   // Used by ReserveSpace.
   virtual void PutRestOfCurrentPageOnFreeList(Page* current_page) = 0;
 
+  // Free all pages in range from prev (exclusive) to last (inclusive).
+  // Freed pages are moved to the end of page list.
+  void FreePages(Page* prev, Page* last);
+
+  // Set space allocation info.
+  void SetTop(Address top) {
+    allocation_info_.top = top;
+    allocation_info_.limit = PageAllocationLimit(Page::FromAllocationTop(top));
+  }
+
   // ---------------------------------------------------------------------------
   // Mark-compact collection support functions
 
@@ -968,6 +1030,9 @@
   static void ResetCodeStatistics();
 #endif
 
+  // Returns the page of the allocation pointer.
+  Page* AllocationTopPage() { return TopPageOf(allocation_info_); }
+
  protected:
   // Maximum capacity of this space.
   int max_capacity_;
@@ -982,6 +1047,10 @@
   // Expand and Shrink.
   Page* last_page_;
 
+  // True if pages owned by this space are linked in chunk-order.
+  // See comment for class MemoryAllocator for definition of chunk-order.
+  bool page_list_is_chunk_ordered_;
+
   // Normal allocation information.
   AllocationInfo allocation_info_;
 
@@ -1043,8 +1112,6 @@
   void DoPrintRSet(const char* space_name);
 #endif
  private:
-  // Returns the page of the allocation pointer.
-  Page* AllocationTopPage() { return TopPageOf(allocation_info_); }
 
   // Returns a pointer to the page of the relocation pointer.
   Page* MCRelocationTopPage() { return TopPageOf(mc_forwarding_info_); }
@@ -1664,17 +1731,22 @@
   // pointer).
   int AvailableFree() { return free_list_.available(); }
 
-  // The top of allocation in a page in this space. Undefined if page is unused.
-  virtual Address PageAllocationTop(Page* page) {
-    return page == TopPageOf(allocation_info_) ? top() : page->ObjectAreaEnd();
+  // The limit of allocation for a page in this space.
+  virtual Address PageAllocationLimit(Page* page) {
+    return page->ObjectAreaEnd();
   }
 
   // Give a block of memory to the space's free list.  It might be added to
   // the free list or accounted as waste.
-  void Free(Address start, int size_in_bytes) {
-    int wasted_bytes = free_list_.Free(start, size_in_bytes);
+  // If add_to_freelist is false then just accounting stats are updated and
+  // no attempt to add area to free list is made.
+  void Free(Address start, int size_in_bytes, bool add_to_freelist) {
     accounting_stats_.DeallocateBytes(size_in_bytes);
-    accounting_stats_.WasteBytes(wasted_bytes);
+
+    if (add_to_freelist) {
+      int wasted_bytes = free_list_.Free(start, size_in_bytes);
+      accounting_stats_.WasteBytes(wasted_bytes);
+    }
   }
 
   // Prepare for full garbage collection.  Resets the relocation pointer and
@@ -1727,17 +1799,20 @@
     page_extra_ = Page::kObjectAreaSize % object_size_in_bytes;
   }
 
-  // The top of allocation in a page in this space. Undefined if page is unused.
-  virtual Address PageAllocationTop(Page* page) {
-    return page == TopPageOf(allocation_info_) ? top()
-        : page->ObjectAreaEnd() - page_extra_;
+  // The limit of allocation for a page in this space.
+  virtual Address PageAllocationLimit(Page* page) {
+    return page->ObjectAreaEnd() - page_extra_;
   }
 
   int object_size_in_bytes() { return object_size_in_bytes_; }
 
   // Give a fixed sized block of memory to the space's free list.
-  void Free(Address start) {
-    free_list_.Free(start);
+  // If add_to_freelist is false then just accounting stats are updated and
+  // no attempt to add area to free list is made.
+  void Free(Address start, bool add_to_freelist) {
+    if (add_to_freelist) {
+      free_list_.Free(start);
+    }
     accounting_stats_.DeallocateBytes(object_size_in_bytes_);
   }
 
diff --git a/src/string.js b/src/string.js
index daa179b..9433249 100644
--- a/src/string.js
+++ b/src/string.js
@@ -175,9 +175,9 @@
 // ECMA-262 section 15.5.4.10
 function StringMatch(regexp) {
   var subject = TO_STRING_INLINE(this);
-  if (IS_REGEXP(regexp)) { 
-    if (!regexp.global) return regexp.exec(subject); 
-    
+  if (IS_REGEXP(regexp)) {
+    if (!regexp.global) return regexp.exec(subject);
+
     var cache = regExpCache;
     var saveAnswer = false;
 
@@ -435,63 +435,63 @@
       // array to use in the future, or until the original is written back.
       resultArray = $Array(16);
     }
-    try {
-      // Must handle exceptions thrown by the replace functions correctly,
-      // including unregistering global regexps.
-      var res = %RegExpExecMultiple(regexp,
-                                    subject,
-                                    lastMatchInfo,
-                                    resultArray);
-      regexp.lastIndex = 0;
-      if (IS_NULL(res)) {
-        // No matches at all.
-        return subject;
-      }
-      var len = res.length;
-      var i = 0;
-      if (NUMBER_OF_CAPTURES(lastMatchInfo) == 2) {
-        var match_start = 0;
-        while (i < len) {
-          var elem = res[i];
-          if (%_IsSmi(elem)) {
-            if (elem > 0) {
-              match_start = (elem >> 11) + (elem & 0x7ff);
-            } else {
-              match_start = res[++i] - elem;
-            }
-          } else {
-            var func_result = replace.call(null, elem, match_start, subject);
-            if (!IS_STRING(func_result)) {
-              func_result = NonStringToString(func_result);
-            }
-            res[i] = func_result;
-            match_start += elem.length;
-          }
-          i++;
-        }
-      } else {
-        while (i < len) {
-          var elem = res[i];
-          if (!%_IsSmi(elem)) {
-            // elem must be an Array.
-            // Use the apply argument as backing for global RegExp properties.
-            lastMatchInfoOverride = elem;
-            var func_result = replace.apply(null, elem);
-            if (!IS_STRING(func_result)) {
-              func_result = NonStringToString(func_result);
-            }
-            res[i] = func_result;
-          }
-          i++;
-        }
-      }
-      var result = new ReplaceResultBuilder(subject, res);
-      return result.generate();
-    } finally {
-      lastMatchInfoOverride = null;
-      resultArray.length = 0;
-      reusableReplaceArray = resultArray;
+
+    var res = %RegExpExecMultiple(regexp,
+                                  subject,
+                                  lastMatchInfo,
+                                  resultArray);
+    regexp.lastIndex = 0;
+    if (IS_NULL(res)) {
+      // No matches at all.
+      return subject;
     }
+    var len = res.length;
+    var i = 0;
+    if (NUMBER_OF_CAPTURES(lastMatchInfo) == 2) {
+      var match_start = 0;
+      var override = [null, 0, subject];
+      while (i < len) {
+        var elem = res[i];
+        if (%_IsSmi(elem)) {
+          if (elem > 0) {
+            match_start = (elem >> 11) + (elem & 0x7ff);
+          } else {
+            match_start = res[++i] - elem;
+          }
+        } else {
+          override[0] = elem;
+          override[1] = match_start;
+          lastMatchInfoOverride = override;
+          var func_result = replace.call(null, elem, match_start, subject);
+          if (!IS_STRING(func_result)) {
+            func_result = NonStringToString(func_result);
+          }
+          res[i] = func_result;
+          match_start += elem.length;
+        }
+        i++;
+      }
+    } else {
+      while (i < len) {
+        var elem = res[i];
+        if (!%_IsSmi(elem)) {
+          // elem must be an Array.
+          // Use the apply argument as backing for global RegExp properties.
+          lastMatchInfoOverride = elem;
+          var func_result = replace.apply(null, elem);
+          if (!IS_STRING(func_result)) {
+            func_result = NonStringToString(func_result);
+          }
+          res[i] = func_result;
+        }
+        i++;
+      }
+    }
+    var resultBuilder = new ReplaceResultBuilder(subject, res);
+    var result = resultBuilder.generate();
+    resultArray.length = 0;
+    reusableReplaceArray = resultArray;
+    return result;
   } else { // Not a global regexp, no need to loop.
     var matchInfo = DoRegExpExec(regexp, subject, 0);
     if (IS_NULL(matchInfo)) return subject;
@@ -542,7 +542,6 @@
   var s = TO_STRING_INLINE(this);
   var match = DoRegExpExec(regexp, s, 0);
   if (match) {
-    lastMatchInfo = match;
     return match[CAPTURE0];
   }
   return -1;
diff --git a/src/version.cc b/src/version.cc
index cca8ac9..bf1d92c 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,8 +34,8 @@
 // cannot be changed without changing the SCons build script.
 #define MAJOR_VERSION     2
 #define MINOR_VERSION     2
-#define BUILD_NUMBER      4
-#define PATCH_LEVEL       2
+#define BUILD_NUMBER      5
+#define PATCH_LEVEL       0
 #define CANDIDATE_VERSION false
 
 // Define SONAME to have the SCons build the put a specific SONAME into the
diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc
index a6aa36d..7a3278c 100644
--- a/src/x64/codegen-x64.cc
+++ b/src/x64/codegen-x64.cc
@@ -304,8 +304,7 @@
 #endif
 
   // New scope to get automatic timing calculation.
-  {  // NOLINT
-    HistogramTimerScope codegen_timer(&Counters::code_generation);
+  { HistogramTimerScope codegen_timer(&Counters::code_generation);
     CodeGenState state(this);
 
     // Entry:
@@ -3118,6 +3117,7 @@
         GenericUnaryOpStub stub(Token::SUB, overwrite);
         Result operand = frame_->Pop();
         Result answer = frame_->CallStub(&stub, &operand);
+        answer.set_type_info(TypeInfo::Number());
         frame_->Push(&answer);
         break;
       }
@@ -3141,6 +3141,7 @@
         frame_->Spill(answer.reg());
         __ SmiNot(answer.reg(), answer.reg());
         continue_label.Bind(&answer);
+        answer.set_type_info(TypeInfo::Smi());
         frame_->Push(&answer);
         break;
       }
@@ -3149,6 +3150,7 @@
         // Smi check.
         JumpTarget continue_label;
         Result operand = frame_->Pop();
+        TypeInfo operand_info = operand.type_info();
         operand.ToRegister();
         Condition is_smi = masm_->CheckSmi(operand.reg());
         continue_label.Branch(is_smi, &operand);
@@ -3157,10 +3159,16 @@
                                               CALL_FUNCTION, 1);
 
         continue_label.Bind(&answer);
+        if (operand_info.IsSmi()) {
+          answer.set_type_info(TypeInfo::Smi());
+        } else if (operand_info.IsInteger32()) {
+          answer.set_type_info(TypeInfo::Integer32());
+        } else {
+          answer.set_type_info(TypeInfo::Number());
+        }
         frame_->Push(&answer);
         break;
       }
-
       default:
         UNREACHABLE();
     }
@@ -4297,17 +4305,23 @@
     frame_->Push(Factory::undefined_value());
     return;
   }
-  Handle<FixedArray> cache_obj(
-      FixedArray::cast(jsfunction_result_caches->get(cache_id)));
 
   Load(args->at(1));
   Result key = frame_->Pop();
   key.ToRegister();
 
   Result cache = allocator()->Allocate();
-  __ movq(cache.reg(), cache_obj, RelocInfo::EMBEDDED_OBJECT);
+  ASSERT(cache.is_valid());
+  __ movq(cache.reg(), ContextOperand(rsi, Context::GLOBAL_INDEX));
+  __ movq(cache.reg(),
+          FieldOperand(cache.reg(), GlobalObject::kGlobalContextOffset));
+  __ movq(cache.reg(),
+          ContextOperand(cache.reg(), Context::JSFUNCTION_RESULT_CACHES_INDEX));
+  __ movq(cache.reg(),
+          FieldOperand(cache.reg(), FixedArray::OffsetOfElementAt(cache_id)));
 
   Result tmp = allocator()->Allocate();
+  ASSERT(tmp.is_valid());
 
   DeferredSearchCache* deferred = new DeferredSearchCache(tmp.reg(),
                                                           cache.reg(),
@@ -5297,6 +5311,15 @@
 }
 
 
+static bool CouldBeNaN(const Result& result) {
+  if (result.type_info().IsSmi()) return false;
+  if (result.type_info().IsInteger32()) return false;
+  if (!result.is_constant()) return true;
+  if (!result.handle()->IsHeapNumber()) return false;
+  return isnan(HeapNumber::cast(*result.handle())->value());
+}
+
+
 void CodeGenerator::Comparison(AstNode* node,
                                Condition cc,
                                bool strict,
@@ -5614,15 +5637,29 @@
       right_side.Unuse();
       dest->Split(cc);
     }
-  } else {  // Neither side is a constant Smi or null.
+  } else {
+    // Neither side is a constant Smi, constant 1-char string, or constant null.
     // If either side is a non-smi constant, skip the smi check.
     bool known_non_smi =
         (left_side.is_constant() && !left_side.handle()->IsSmi()) ||
         (right_side.is_constant() && !right_side.handle()->IsSmi());
+
+    NaNInformation nan_info =
+        (CouldBeNaN(left_side) && CouldBeNaN(right_side)) ?
+        kBothCouldBeNaN :
+        kCantBothBeNaN;
+
     left_side.ToRegister();
     right_side.ToRegister();
 
     if (known_non_smi) {
+      // If at least one of the objects is not NaN, then if the objects
+      // are identical, they are equal.
+      if (nan_info == kCantBothBeNaN && cc == equal) {
+        __ cmpq(left_side.reg(), right_side.reg());
+        dest->true_target()->Branch(equal);
+      }
+
       // When non-smi, call out to the compare stub.
       CompareStub stub(cc, strict);
       Result answer = frame_->CallStub(&stub, &left_side, &right_side);
@@ -5642,7 +5679,14 @@
 
       Condition both_smi = masm_->CheckBothSmi(left_reg, right_reg);
       is_smi.Branch(both_smi);
-      // When non-smi, call out to the compare stub.
+      // When non-smi, call out to the compare stub, after inlined checks.
+      // If at least one of the objects is not NaN, then if the objects
+      // are identical, they are equal.
+      if (nan_info == kCantBothBeNaN && cc == equal) {
+        __ cmpq(left_side.reg(), right_side.reg());
+        dest->true_target()->Branch(equal);
+      }
+
       CompareStub stub(cc, strict);
       Result answer = frame_->CallStub(&stub, &left_side, &right_side);
       __ SmiTest(answer.reg());  // Sets both zero and sign flags.
@@ -5691,6 +5735,57 @@
 }
 
 
+static TypeInfo CalculateTypeInfo(TypeInfo operands_type,
+                                  Token::Value op,
+                                  const Result& right,
+                                  const Result& left) {
+  // Set TypeInfo of result according to the operation performed.
+  // We rely on the fact that smis have a 32 bit payload on x64.
+  STATIC_ASSERT(kSmiValueSize == 32);
+  switch (op) {
+    case Token::COMMA:
+      return right.type_info();
+    case Token::OR:
+    case Token::AND:
+      // Result type can be either of the two input types.
+      return operands_type;
+    case Token::BIT_OR:
+    case Token::BIT_XOR:
+    case Token::BIT_AND:
+      // Result is always a smi.
+      return TypeInfo::Smi();
+    case Token::SAR:
+    case Token::SHL:
+      // Result is always a smi.
+      return TypeInfo::Smi();
+    case Token::SHR:
+      // Result of x >>> y is always a smi if masked y >= 1, otherwise a number.
+      return (right.is_constant() && right.handle()->IsSmi()
+                     && (Smi::cast(*right.handle())->value() & 0x1F) >= 1)
+          ? TypeInfo::Smi()
+          : TypeInfo::Number();
+    case Token::ADD:
+      if (operands_type.IsNumber()) {
+        return TypeInfo::Number();
+      } else if (left.type_info().IsString() || right.type_info().IsString()) {
+        return TypeInfo::String();
+      } else {
+        return TypeInfo::Unknown();
+      }
+    case Token::SUB:
+    case Token::MUL:
+    case Token::DIV:
+    case Token::MOD:
+      // Result is always a number.
+      return TypeInfo::Number();
+    default:
+      UNREACHABLE();
+  }
+  UNREACHABLE();
+  return TypeInfo::Unknown();
+}
+
+
 void CodeGenerator::GenericBinaryOperation(Token::Value op,
                                            StaticType* type,
                                            OverwriteMode overwrite_mode) {
@@ -5756,6 +5851,8 @@
   TypeInfo operands_type =
       TypeInfo::Combine(left.type_info(), right.type_info());
 
+  TypeInfo result_type = CalculateTypeInfo(operands_type, op, right, left);
+
   Result answer;
   if (left_is_non_smi_constant || right_is_non_smi_constant) {
     GenericBinaryOpStub stub(op,
@@ -5786,56 +5883,6 @@
     }
   }
 
-  // Set TypeInfo of result according to the operation performed.
-  // We rely on the fact that smis have a 32 bit payload on x64.
-  ASSERT(kSmiValueSize == 32);
-  TypeInfo result_type = TypeInfo::Unknown();
-  switch (op) {
-    case Token::COMMA:
-      result_type = right.type_info();
-      break;
-    case Token::OR:
-    case Token::AND:
-      // Result type can be either of the two input types.
-      result_type = operands_type;
-      break;
-    case Token::BIT_OR:
-    case Token::BIT_XOR:
-    case Token::BIT_AND:
-      // Result is always a smi.
-      result_type = TypeInfo::Smi();
-      break;
-    case Token::SAR:
-    case Token::SHL:
-      // Result is always a smi.
-      result_type = TypeInfo::Smi();
-      break;
-    case Token::SHR:
-      // Result of x >>> y is always a smi if y >= 1, otherwise a number.
-      result_type = (right.is_constant() && right.handle()->IsSmi()
-                     && Smi::cast(*right.handle())->value() >= 1)
-          ? TypeInfo::Smi()
-          : TypeInfo::Number();
-      break;
-    case Token::ADD:
-      if (operands_type.IsNumber()) {
-        result_type = TypeInfo::Number();
-      } else if (operands_type.IsString()) {
-        result_type = TypeInfo::String();
-      } else {
-        result_type = TypeInfo::Unknown();
-      }
-      break;
-    case Token::SUB:
-    case Token::MUL:
-    case Token::DIV:
-    case Token::MOD:
-      // Result is always a number.
-      result_type = TypeInfo::Number();
-      break;
-    default:
-      UNREACHABLE();
-  }
   answer.set_type_info(result_type);
   frame_->Push(&answer);
 }