Version 3.21.13

Added a ResourceConstraint for the embedder to specify that V8 is running on a memory constrained device. (Chromium issue 280984)

Removed HandleScope default ctor. (Chromium issue 236173)

Enabled escape analysis for Hydrogen.

Correctly stringified mixed encoding indirect strings. (Chromium issue 287476)

Performance and stability improvements on all platforms.

git-svn-id: http://v8.googlecode.com/svn/trunk@16634 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/ChangeLog b/ChangeLog
index 7a498ba..79be335 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2013-09-11: Version 3.21.13
+
+        Added a ResourceConstraint for the embedder to specify that V8 is
+        running on a memory constrained device.
+        (Chromium issue 280984)
+
+        Removed HandleScope default ctor.
+        (Chromium issue 236173)
+
+        Enabled escape analysis for Hydrogen.
+
+        Correctly stringified mixed encoding indirect strings.
+        (Chromium issue 287476)
+
+        Performance and stability improvements on all platforms.
+
+
 2013-09-09: Version 3.21.12
 
         Fixed bitwise negation on x64.
diff --git a/include/v8-debug.h b/include/v8-debug.h
index a7d2198..053b81d 100755
--- a/include/v8-debug.h
+++ b/include/v8-debug.h
@@ -106,6 +106,8 @@
      */
     virtual ClientData* GetClientData() const = 0;
 
+    virtual Isolate* GetIsolate() const = 0;
+
     virtual ~Message() {}
   };
 
diff --git a/include/v8-profiler.h b/include/v8-profiler.h
index d7350db..217a938 100644
--- a/include/v8-profiler.h
+++ b/include/v8-profiler.h
@@ -246,17 +246,19 @@
 class V8_EXPORT HeapGraphNode {
  public:
   enum Type {
-    kHidden = 0,      // Hidden node, may be filtered when shown to user.
-    kArray = 1,       // An array of elements.
-    kString = 2,      // A string.
-    kObject = 3,      // A JS object (except for arrays and strings).
-    kCode = 4,        // Compiled code.
-    kClosure = 5,     // Function closure.
-    kRegExp = 6,      // RegExp.
-    kHeapNumber = 7,  // Number stored in the heap.
-    kNative = 8,      // Native object (not from V8 heap).
-    kSynthetic = 9    // Synthetic object, usualy used for grouping
-                      // snapshot items together.
+    kHidden = 0,        // Hidden node, may be filtered when shown to user.
+    kArray = 1,         // An array of elements.
+    kString = 2,        // A string.
+    kObject = 3,        // A JS object (except for arrays and strings).
+    kCode = 4,          // Compiled code.
+    kClosure = 5,       // Function closure.
+    kRegExp = 6,        // RegExp.
+    kHeapNumber = 7,    // Number stored in the heap.
+    kNative = 8,        // Native object (not from V8 heap).
+    kSynthetic = 9,     // Synthetic object, usualy used for grouping
+                        // snapshot items together.
+    kConsString = 10,   // Concatenated string. A pair of pointers to strings.
+    kSlicedString = 11  // Sliced string. A fragment of another string.
   };
 
   /** Returns node type (see HeapGraphNode::Type). */
diff --git a/include/v8.h b/include/v8.h
index 55a8ea6..9e9ea8a 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -544,6 +544,14 @@
     Copy(that);
     return *this;
   }
+  /**
+   * The destructor will dispose the Persistent based on the
+   * kResetInDestructor flags in the traits class.  Since not calling dispose
+   * can result in a memory leak, it is recommended to always set this flag.
+   */
+  V8_INLINE(~Persistent()) {
+    if (M::kResetInDestructor) Reset();
+  }
 
   /**
    * If non-empty, destroy the underlying storage cell
@@ -748,9 +756,6 @@
  */
 class V8_EXPORT HandleScope {
  public:
-  // TODO(svenpanne) Deprecate me when Chrome is fixed!
-  HandleScope();
-
   HandleScope(Isolate* isolate);
 
   ~HandleScope();
@@ -812,6 +817,21 @@
 };
 
 
+/**
+ * A simple Maybe type, representing an object which may or may not have a
+ * value.
+ */
+template<class T>
+struct Maybe {
+  Maybe() : has_value(false) {}
+  explicit Maybe(T t) : has_value(true), value(t) {}
+  Maybe(bool has, T t) : has_value(has), value(t) {}
+
+  bool has_value;
+  T value;
+};
+
+
 // --- Special objects ---
 
 
@@ -3743,11 +3763,20 @@
   uint32_t* stack_limit() const { return stack_limit_; }
   // Sets an address beyond which the VM's stack may not grow.
   void set_stack_limit(uint32_t* value) { stack_limit_ = value; }
+  Maybe<bool> is_memory_constrained() const { return is_memory_constrained_; }
+  // If set to true, V8 will limit it's memory usage, at the potential cost of
+  // lower performance.  Note, this option is a tentative addition to the API
+  // and may be removed or modified without warning.
+  void set_memory_constrained(bool value) {
+    is_memory_constrained_ = Maybe<bool>(value);
+  }
+
  private:
   int max_young_space_size_;
   int max_old_space_size_;
   int max_executable_size_;
   uint32_t* stack_limit_;
+  Maybe<bool> is_memory_constrained_;
 };
 
 
diff --git a/src/accessors.cc b/src/accessors.cc
index 766d4da..f8cb0c8 100644
--- a/src/accessors.cc
+++ b/src/accessors.cc
@@ -400,7 +400,7 @@
       return *GetScriptWrapper(eval_from_script);
     }
   }
-  return HEAP->undefined_value();
+  return isolate->heap()->undefined_value();
 }
 
 
diff --git a/src/api.cc b/src/api.cc
index 1bc80d2..d1f6b78 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -62,6 +62,7 @@
 #include "scanner-character-streams.h"
 #include "snapshot.h"
 #include "unicode-inl.h"
+#include "utils/random-number-generator.h"
 #include "v8threads.h"
 #include "version.h"
 #include "vm-state-inl.h"
@@ -624,7 +625,8 @@
   : max_young_space_size_(0),
     max_old_space_size_(0),
     max_executable_size_(0),
-    stack_limit_(NULL) { }
+    stack_limit_(NULL),
+    is_memory_constrained_() { }
 
 
 bool SetResourceConstraints(ResourceConstraints* constraints) {
@@ -645,6 +647,10 @@
     uintptr_t limit = reinterpret_cast<uintptr_t>(constraints->stack_limit());
     isolate->stack_guard()->SetStackLimit(limit);
   }
+  if (constraints->is_memory_constrained().has_value) {
+    isolate->set_is_memory_constrained(
+        constraints->is_memory_constrained().value);
+  }
   return true;
 }
 
@@ -706,11 +712,6 @@
 // --- H a n d l e s ---
 
 
-HandleScope::HandleScope() {
-  Initialize(reinterpret_cast<Isolate*>(i::Isolate::Current()));
-}
-
-
 HandleScope::HandleScope(Isolate* isolate) {
   Initialize(isolate);
 }
@@ -5208,8 +5209,8 @@
 }
 
 
-void v8::V8::SetEntropySource(EntropySource source) {
-  i::V8::SetEntropySource(source);
+void v8::V8::SetEntropySource(EntropySource entropy_source) {
+  i::RandomNumberGenerator::SetEntropySource(entropy_source);
 }
 
 
diff --git a/src/arm/builtins-arm.cc b/src/arm/builtins-arm.cc
index 9ebee93..8862702 100644
--- a/src/arm/builtins-arm.cc
+++ b/src/arm/builtins-arm.cc
@@ -975,22 +975,30 @@
     __ CallRuntime(Runtime::kCompileForOnStackReplacement, 1);
   }
 
-  // If the result was -1 it means that we couldn't optimize the
-  // function. Just return and continue in the unoptimized version.
+  // If the code object is null, just return to the unoptimized code.
   Label skip;
-  __ cmp(r0, Operand(Smi::FromInt(-1)));
+  __ cmp(r0, Operand(Smi::FromInt(0)));
   __ b(ne, &skip);
   __ Ret();
 
   __ bind(&skip);
-  // Untag the AST id and push it on the stack.
-  __ SmiUntag(r0);
-  __ push(r0);
 
-  // Generate the code for doing the frame-to-frame translation using
-  // the deoptimizer infrastructure.
-  Deoptimizer::EntryGenerator generator(masm, Deoptimizer::OSR);
-  generator.Generate();
+  // Load deoptimization data from the code object.
+  // <deopt_data> = <code>[#deoptimization_data_offset]
+  __ ldr(r1, MemOperand(r0, Code::kDeoptimizationDataOffset - kHeapObjectTag));
+
+  // Load the OSR entrypoint offset from the deoptimization data.
+  // <osr_offset> = <deopt_data>[#header_size + #osr_pc_offset]
+  __ ldr(r1, MemOperand(r1, FixedArray::OffsetOfElementAt(
+      DeoptimizationInputData::kOsrPcOffsetIndex) - kHeapObjectTag));
+
+  // Compute the target address = code_obj + header_size + osr_offset
+  // <entry_addr> = <code_obj> + #header_size + <osr_offset>
+  __ add(r0, r0, Operand::SmiUntag(r1));
+  __ add(lr, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
+
+  // And "return" to the OSR entry point of the function.
+  __ Ret();
 }
 
 
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
index 310cf3e..87a76f0 100644
--- a/src/arm/code-stubs-arm.cc
+++ b/src/arm/code-stubs-arm.cc
@@ -2695,7 +2695,7 @@
 
 
 bool CEntryStub::IsPregenerated() {
-  return (!save_doubles_ || ISOLATE->fp_stubs_generated()) &&
+  return (!save_doubles_ || Isolate::Current()->fp_stubs_generated()) &&
           result_size_ == 1;
 }
 
@@ -6143,6 +6143,11 @@
 
 
 void DirectCEntryStub::Generate(MacroAssembler* masm) {
+  // Place the return address on the stack, making the call
+  // GC safe. The RegExp backend also relies on this.
+  __ str(lr, MemOperand(sp, 0));
+  __ blx(ip);  // Call the C++ function.
+  __ VFPEnsureFPSCRState(r2);
   __ ldr(pc, MemOperand(sp, 0));
 }
 
@@ -6151,21 +6156,9 @@
                                     Register target) {
   intptr_t code =
       reinterpret_cast<intptr_t>(GetCode(masm->isolate()).location());
+  __ Move(ip, target);
   __ mov(lr, Operand(code, RelocInfo::CODE_TARGET));
-
-  // Prevent literal pool emission during calculation of return address.
-  Assembler::BlockConstPoolScope block_const_pool(masm);
-
-  // Push return address (accessible to GC through exit frame pc).
-  // Note that using pc with str is deprecated.
-  Label start;
-  __ bind(&start);
-  __ add(ip, pc, Operand(Assembler::kInstrSize));
-  __ str(ip, MemOperand(sp, 0));
-  __ Jump(target);  // Call the C++ function.
-  ASSERT_EQ(Assembler::kInstrSize + Assembler::kPcLoadDelta,
-            masm->SizeOfCodeGeneratedSince(&start));
-  __ VFPEnsureFPSCRState(r2);
+  __ blx(lr);  // Call the stub.
 }
 
 
@@ -6843,6 +6836,9 @@
 #else
   // Under the simulator we need to indirect the entry hook through a
   // trampoline function at a known address.
+  // It additionally takes an isolate as a third parameter
+  __ mov(r2, Operand(ExternalReference::isolate_address(masm->isolate())));
+
   ApiFunction dispatcher(FUNCTION_ADDR(EntryHookTrampoline));
   __ mov(ip, Operand(ExternalReference(&dispatcher,
                                        ExternalReference::BUILTIN_CALL,
diff --git a/src/arm/code-stubs-arm.h b/src/arm/code-stubs-arm.h
index bee3e1e..e7e7bfc 100644
--- a/src/arm/code-stubs-arm.h
+++ b/src/arm/code-stubs-arm.h
@@ -465,23 +465,6 @@
 };
 
 
-// Enter C code from generated RegExp code in a way that allows
-// the C code to fix the return address in case of a GC.
-// Currently only needed on ARM.
-class RegExpCEntryStub: public PlatformCodeStub {
- public:
-  RegExpCEntryStub() {}
-  virtual ~RegExpCEntryStub() {}
-  void Generate(MacroAssembler* masm);
-
- private:
-  Major MajorKey() { return RegExpCEntry; }
-  int MinorKey() { return 0; }
-
-  bool NeedsImmovableCode() { return true; }
-};
-
-
 // Trampoline stub to call into native code. To call safely into native code
 // in the presence of compacting GC (which can move code objects) we need to
 // keep the code which called into native pinned in the memory. Currently the
diff --git a/src/arm/deoptimizer-arm.cc b/src/arm/deoptimizer-arm.cc
index e49e5bc..3c57b64 100644
--- a/src/arm/deoptimizer-arm.cc
+++ b/src/arm/deoptimizer-arm.cc
@@ -175,169 +175,6 @@
 #endif  // DEBUG
 
 
-static int LookupBailoutId(DeoptimizationInputData* data, BailoutId ast_id) {
-  ByteArray* translations = data->TranslationByteArray();
-  int length = data->DeoptCount();
-  for (int i = 0; i < length; i++) {
-    if (data->AstId(i) == ast_id) {
-      TranslationIterator it(translations,  data->TranslationIndex(i)->value());
-      int value = it.Next();
-      ASSERT(Translation::BEGIN == static_cast<Translation::Opcode>(value));
-      // Read the number of frames.
-      value = it.Next();
-      if (value == 1) return i;
-    }
-  }
-  UNREACHABLE();
-  return -1;
-}
-
-
-void Deoptimizer::DoComputeOsrOutputFrame() {
-  DeoptimizationInputData* data = DeoptimizationInputData::cast(
-      compiled_code_->deoptimization_data());
-  unsigned ast_id = data->OsrAstId()->value();
-
-  int bailout_id = LookupBailoutId(data, BailoutId(ast_id));
-  unsigned translation_index = data->TranslationIndex(bailout_id)->value();
-  ByteArray* translations = data->TranslationByteArray();
-
-  TranslationIterator iterator(translations, translation_index);
-  Translation::Opcode opcode =
-      static_cast<Translation::Opcode>(iterator.Next());
-  ASSERT(Translation::BEGIN == opcode);
-  USE(opcode);
-  int count = iterator.Next();
-  iterator.Skip(1);  // Drop JS frame count.
-  ASSERT(count == 1);
-  USE(count);
-
-  opcode = static_cast<Translation::Opcode>(iterator.Next());
-  USE(opcode);
-  ASSERT(Translation::JS_FRAME == opcode);
-  unsigned node_id = iterator.Next();
-  USE(node_id);
-  ASSERT(node_id == ast_id);
-  int closure_id = iterator.Next();
-  USE(closure_id);
-  ASSERT_EQ(Translation::kSelfLiteralId, closure_id);
-  unsigned height = iterator.Next();
-  unsigned height_in_bytes = height * kPointerSize;
-  USE(height_in_bytes);
-
-  unsigned fixed_size = ComputeFixedSize(function_);
-  unsigned input_frame_size = input_->GetFrameSize();
-  ASSERT(fixed_size + height_in_bytes == input_frame_size);
-
-  unsigned stack_slot_size = compiled_code_->stack_slots() * kPointerSize;
-  unsigned outgoing_height = data->ArgumentsStackHeight(bailout_id)->value();
-  unsigned outgoing_size = outgoing_height * kPointerSize;
-  unsigned output_frame_size = fixed_size + stack_slot_size + outgoing_size;
-  ASSERT(outgoing_size == 0);  // OSR does not happen in the middle of a call.
-
-  if (FLAG_trace_osr) {
-    PrintF("[on-stack replacement: begin 0x%08" V8PRIxPTR " ",
-           reinterpret_cast<intptr_t>(function_));
-    PrintFunctionName();
-    PrintF(" => node=%u, frame=%d->%d]\n",
-           ast_id,
-           input_frame_size,
-           output_frame_size);
-  }
-
-  // There's only one output frame in the OSR case.
-  output_count_ = 1;
-  output_ = new FrameDescription*[1];
-  output_[0] = new(output_frame_size) FrameDescription(
-      output_frame_size, function_);
-  output_[0]->SetFrameType(StackFrame::JAVA_SCRIPT);
-
-  // Clear the incoming parameters in the optimized frame to avoid
-  // confusing the garbage collector.
-  unsigned output_offset = output_frame_size - kPointerSize;
-  int parameter_count = function_->shared()->formal_parameter_count() + 1;
-  for (int i = 0; i < parameter_count; ++i) {
-    output_[0]->SetFrameSlot(output_offset, 0);
-    output_offset -= kPointerSize;
-  }
-
-  // Translate the incoming parameters. This may overwrite some of the
-  // incoming argument slots we've just cleared.
-  int input_offset = input_frame_size - kPointerSize;
-  bool ok = true;
-  int limit = input_offset - (parameter_count * kPointerSize);
-  while (ok && input_offset > limit) {
-    ok = DoOsrTranslateCommand(&iterator, &input_offset);
-  }
-
-  // There are no translation commands for the caller's pc and fp, the
-  // context, and the function.  Set them up explicitly.
-  for (int i =  StandardFrameConstants::kCallerPCOffset;
-       ok && i >=  StandardFrameConstants::kMarkerOffset;
-       i -= kPointerSize) {
-    uint32_t input_value = input_->GetFrameSlot(input_offset);
-    if (FLAG_trace_osr) {
-      const char* name = "UNKNOWN";
-      switch (i) {
-        case StandardFrameConstants::kCallerPCOffset:
-          name = "caller's pc";
-          break;
-        case StandardFrameConstants::kCallerFPOffset:
-          name = "fp";
-          break;
-        case StandardFrameConstants::kContextOffset:
-          name = "context";
-          break;
-        case StandardFrameConstants::kMarkerOffset:
-          name = "function";
-          break;
-      }
-      PrintF("    [sp + %d] <- 0x%08x ; [sp + %d] (fixed part - %s)\n",
-             output_offset,
-             input_value,
-             input_offset,
-             name);
-    }
-
-    output_[0]->SetFrameSlot(output_offset, input_->GetFrameSlot(input_offset));
-    input_offset -= kPointerSize;
-    output_offset -= kPointerSize;
-  }
-
-  // Translate the rest of the frame.
-  while (ok && input_offset >= 0) {
-    ok = DoOsrTranslateCommand(&iterator, &input_offset);
-  }
-
-  // If translation of any command failed, continue using the input frame.
-  if (!ok) {
-    delete output_[0];
-    output_[0] = input_;
-    output_[0]->SetPc(reinterpret_cast<uint32_t>(from_));
-  } else {
-    // Set up the frame pointer and the context pointer.
-    output_[0]->SetRegister(fp.code(), input_->GetRegister(fp.code()));
-    output_[0]->SetRegister(cp.code(), input_->GetRegister(cp.code()));
-
-    unsigned pc_offset = data->OsrPcOffset()->value();
-    uint32_t pc = reinterpret_cast<uint32_t>(
-        compiled_code_->entry() + pc_offset);
-    output_[0]->SetPc(pc);
-  }
-  Code* continuation = isolate_->builtins()->builtin(Builtins::kNotifyOSR);
-  output_[0]->SetContinuation(
-      reinterpret_cast<uint32_t>(continuation->entry()));
-
-  if (FLAG_trace_osr) {
-    PrintF("[on-stack replacement translation %s: 0x%08" V8PRIxPTR " ",
-           ok ? "finished" : "aborted",
-           reinterpret_cast<intptr_t>(function_));
-    PrintFunctionName();
-    PrintF(" => pc=0x%0x]\n", output_[0]->GetPc());
-  }
-}
-
-
 void Deoptimizer::FillInputFrame(Address tos, JavaScriptFrame* frame) {
   // Set the register values. The values are not important as there are no
   // callee saved registers in JavaScript frames, so all registers are
@@ -550,11 +387,8 @@
   }
 
   // Push state, pc, and continuation from the last output frame.
-  if (type() != OSR) {
-    __ ldr(r6, MemOperand(r2, FrameDescription::state_offset()));
-    __ push(r6);
-  }
-
+  __ ldr(r6, MemOperand(r2, FrameDescription::state_offset()));
+  __ push(r6);
   __ ldr(r6, MemOperand(r2, FrameDescription::pc_offset()));
   __ push(r6);
   __ ldr(r6, MemOperand(r2, FrameDescription::continuation_offset()));
diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc
index 132e1a6..9695072 100644
--- a/src/arm/lithium-arm.cc
+++ b/src/arm/lithium-arm.cc
@@ -30,6 +30,7 @@
 #include "lithium-allocator-inl.h"
 #include "arm/lithium-arm.h"
 #include "arm/lithium-codegen-arm.h"
+#include "hydrogen-osr.h"
 
 namespace v8 {
 namespace internal {
@@ -433,6 +434,15 @@
   chunk_ = new(zone()) LPlatformChunk(info(), graph());
   LPhase phase("L_Building chunk", chunk_);
   status_ = BUILDING;
+
+  // If compiling for OSR, reserve space for the unoptimized frame,
+  // which will be subsumed into this frame.
+  if (graph()->has_osr()) {
+    for (int i = graph()->osr()->UnoptimizedFrameSlots(); i > 0; i--) {
+      chunk_->GetNextSpillIndex(false);
+    }
+  }
+
   const ZoneList<HBasicBlock*>* blocks = graph()->blocks();
   for (int i = 0; i < blocks->length(); i++) {
     HBasicBlock* next = NULL;
@@ -2439,10 +2449,18 @@
 
 
 LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
-  int spill_index = chunk()->GetNextSpillIndex(false);  // Not double-width.
-  if (spill_index > LUnallocated::kMaxFixedSlotIndex) {
-    Abort(kTooManySpillSlotsNeededForOSR);
-    spill_index = 0;
+  // Use an index that corresponds to the location in the unoptimized frame,
+  // which the optimized frame will subsume.
+  int env_index = instr->index();
+  int spill_index = 0;
+  if (instr->environment()->is_parameter_index(env_index)) {
+    spill_index = chunk()->GetParameterStackSlot(env_index);
+  } else {
+    spill_index = env_index - instr->environment()->first_local_index();
+    if (spill_index > LUnallocated::kMaxFixedSlotIndex) {
+      Abort(kTooManySpillSlotsNeededForOSR);
+      spill_index = 0;
+    }
   }
   return DefineAsSpilled(new(zone()) LUnknownOSRValue, spill_index);
 }
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index d880286..cf76a08 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -31,6 +31,7 @@
 #include "arm/lithium-gap-resolver-arm.h"
 #include "code-stubs.h"
 #include "stub-cache.h"
+#include "hydrogen-osr.h"
 
 namespace v8 {
 namespace internal {
@@ -253,6 +254,21 @@
 }
 
 
+void LCodeGen::GenerateOsrPrologue() {
+  // Generate the OSR entry prologue at the first unknown OSR value, or if there
+  // are none, at the OSR entrypoint instruction.
+  if (osr_pc_offset_ >= 0) return;
+
+  osr_pc_offset_ = masm()->pc_offset();
+
+  // Adjust the frame size, subsuming the unoptimized frame into the
+  // optimized frame.
+  int slots = GetStackSlotCount() - graph()->osr()->UnoptimizedFrameSlots();
+  ASSERT(slots >= 0);
+  __ sub(sp, sp, Operand(slots * kPointerSize));
+}
+
+
 bool LCodeGen::GenerateBody() {
   ASSERT(is_generating());
   bool emit_instructions = true;
@@ -1098,8 +1114,7 @@
 
 
 void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
-  // Record the address of the first unknown OSR value as the place to enter.
-  if (osr_pc_offset_ == -1) osr_pc_offset_ = masm()->pc_offset();
+  GenerateOsrPrologue();
 }
 
 
@@ -5684,9 +5699,7 @@
   ASSERT(!environment->HasBeenRegistered());
   RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
 
-  // Normally we record the first unknown OSR value as the entrypoint to the OSR
-  // code, but if there were none, record the entrypoint here.
-  if (osr_pc_offset_ == -1) osr_pc_offset_ = masm()->pc_offset();
+  GenerateOsrPrologue();
 }
 
 
diff --git a/src/arm/lithium-codegen-arm.h b/src/arm/lithium-codegen-arm.h
index 8a0d3be..5826849 100644
--- a/src/arm/lithium-codegen-arm.h
+++ b/src/arm/lithium-codegen-arm.h
@@ -227,6 +227,9 @@
   bool GenerateDeoptJumpTable();
   bool GenerateSafepointTable();
 
+  // Generates the custom OSR entrypoint and sets the osr_pc_offset.
+  void GenerateOsrPrologue();
+
   enum SafepointMode {
     RECORD_SIMPLE_SAFEPOINT,
     RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS
diff --git a/src/arm/regexp-macro-assembler-arm.cc b/src/arm/regexp-macro-assembler-arm.cc
index 189ea8d..2a81fac 100644
--- a/src/arm/regexp-macro-assembler-arm.cc
+++ b/src/arm/regexp-macro-assembler-arm.cc
@@ -1055,16 +1055,34 @@
 // Private methods:
 
 void RegExpMacroAssemblerARM::CallCheckStackGuardState(Register scratch) {
-  static const int num_arguments = 3;
-  __ PrepareCallCFunction(num_arguments, scratch);
+  __ PrepareCallCFunction(3, scratch);
+
   // RegExp code frame pointer.
   __ mov(r2, frame_pointer());
   // Code* of self.
   __ mov(r1, Operand(masm_->CodeObject()));
-  // r0 becomes return address pointer.
+
+  // We need to make room for the return address on the stack.
+  int stack_alignment = OS::ActivationFrameAlignment();
+  ASSERT(IsAligned(stack_alignment, kPointerSize));
+  __ sub(sp, sp, Operand(stack_alignment));
+
+  // r0 will point to the return address, placed by DirectCEntry.
+  __ mov(r0, sp);
+
   ExternalReference stack_guard_check =
       ExternalReference::re_check_stack_guard_state(isolate());
-  CallCFunctionUsingStub(stack_guard_check, num_arguments);
+  __ mov(ip, Operand(stack_guard_check));
+  DirectCEntryStub stub;
+  stub.GenerateCall(masm_, ip);
+
+  // Drop the return address from the stack.
+  __ add(sp, sp, Operand(stack_alignment));
+
+  ASSERT(stack_alignment != 0);
+  __ ldr(sp, MemOperand(sp, 0));
+
+  __ mov(code_pointer(), Operand(masm_->CodeObject()));
 }
 
 
@@ -1294,21 +1312,6 @@
 }
 
 
-void RegExpMacroAssemblerARM::CallCFunctionUsingStub(
-    ExternalReference function,
-    int num_arguments) {
-  // Must pass all arguments in registers. The stub pushes on the stack.
-  ASSERT(num_arguments <= 4);
-  __ mov(code_pointer(), Operand(function));
-  RegExpCEntryStub stub;
-  __ CallStub(&stub);
-  if (OS::ActivationFrameAlignment() != 0) {
-    __ ldr(sp, MemOperand(sp, 0));
-  }
-  __ mov(code_pointer(), Operand(masm_->CodeObject()));
-}
-
-
 bool RegExpMacroAssemblerARM::CanReadUnaligned() {
   return CpuFeatures::IsSupported(UNALIGNED_ACCESSES) && !slow_safe();
 }
@@ -1351,17 +1354,6 @@
 }
 
 
-void RegExpCEntryStub::Generate(MacroAssembler* masm_) {
-  int stack_alignment = OS::ActivationFrameAlignment();
-  if (stack_alignment < kPointerSize) stack_alignment = kPointerSize;
-  // Stack is already aligned for call, so decrement by alignment
-  // to make room for storing the link register.
-  __ str(lr, MemOperand(sp, stack_alignment, NegPreIndex));
-  __ mov(r0, sp);
-  __ Call(r5);
-  __ ldr(pc, MemOperand(sp, stack_alignment, PostIndex));
-}
-
 #undef __
 
 #endif  // V8_INTERPRETED_REGEXP
diff --git a/src/arm/regexp-macro-assembler-arm.h b/src/arm/regexp-macro-assembler-arm.h
index 1825752..0874ad1 100644
--- a/src/arm/regexp-macro-assembler-arm.h
+++ b/src/arm/regexp-macro-assembler-arm.h
@@ -212,14 +212,6 @@
   // and increments it by a word size.
   inline void Pop(Register target);
 
-  // Calls a C function and cleans up the frame alignment done by
-  // by FrameAlign. The called function *is* allowed to trigger a garbage
-  // collection, but may not take more than four arguments (no arguments
-  // passed on the stack), and the first argument will be a pointer to the
-  // return address.
-  inline void CallCFunctionUsingStub(ExternalReference function,
-                                     int num_arguments);
-
   Isolate* isolate() const { return masm_->isolate(); }
 
   MacroAssembler* masm_;
diff --git a/src/assembler.cc b/src/assembler.cc
index 44d5f22..fbff62d 100644
--- a/src/assembler.cc
+++ b/src/assembler.cc
@@ -43,7 +43,7 @@
 #include "deoptimizer.h"
 #include "execution.h"
 #include "ic.h"
-#include "isolate.h"
+#include "isolate-inl.h"
 #include "jsregexp.h"
 #include "lazy-instance.h"
 #include "platform.h"
@@ -119,7 +119,7 @@
       emit_debug_code_(FLAG_debug_code),
       predictable_code_size_(false) {
   if (FLAG_mask_constants_with_cookie && isolate != NULL)  {
-    jit_cookie_ = V8::RandomPrivate(isolate);
+    jit_cookie_ = isolate->random_number_generator()->NextInt();
   }
 
   if (buffer == NULL) {
diff --git a/src/ast.cc b/src/ast.cc
index 6d1dc12..823dede 100644
--- a/src/ast.cc
+++ b/src/ast.cc
@@ -599,7 +599,7 @@
     Handle<JSFunction> candidate(JSFunction::cast(cell_->value()));
     // If the function is in new space we assume it's more likely to
     // change and thus prefer the general IC code.
-    if (!HEAP->InNewSpace(*candidate)) {
+    if (!lookup->isolate()->heap()->InNewSpace(*candidate)) {
       target_ = candidate;
       return true;
     }
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index 92ff269..764c846 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -1316,13 +1316,9 @@
   Handle<FixedArray> embedder_data = factory->NewFixedArray(2);
   native_context()->set_embedder_data(*embedder_data);
 
-  {
-    // Initialize the random seed slot.
-    Handle<ByteArray> zeroed_byte_array(
-        factory->NewByteArray(kRandomStateSize));
-    native_context()->set_random_seed(*zeroed_byte_array);
-    memset(zeroed_byte_array->GetDataStartAddress(), 0, kRandomStateSize);
-  }
+  // Allocate the random seed slot.
+  Handle<ByteArray> random_seed = factory->NewByteArray(kRandomStateSize);
+  native_context()->set_random_seed(*random_seed);
 }
 
 
@@ -2647,6 +2643,14 @@
   InitializeExperimentalGlobal();
   if (!InstallExperimentalNatives()) return;
 
+  // Initially seed the per-context random number generator
+  // using the per-isolate random number generator.
+  uint32_t* state = reinterpret_cast<uint32_t*>(
+      native_context()->random_seed()->GetDataStartAddress());
+  do {
+    isolate->random_number_generator()->NextBytes(state, kRandomStateSize);
+  } while (state[0] == 0 || state[1] == 0);
+
   result_ = native_context();
 }
 
diff --git a/src/bootstrapper.h b/src/bootstrapper.h
index 3097800..e6456bd 100644
--- a/src/bootstrapper.h
+++ b/src/bootstrapper.h
@@ -45,7 +45,8 @@
   explicit SourceCodeCache(Script::Type type): type_(type), cache_(NULL) { }
 
   void Initialize(bool create_heap_objects) {
-    cache_ = create_heap_objects ? HEAP->empty_fixed_array() : NULL;
+    cache_ = create_heap_objects ?
+        Isolate::Current()->heap()->empty_fixed_array() : NULL;
   }
 
   void Iterate(ObjectVisitor* v) {
diff --git a/src/builtins.cc b/src/builtins.cc
index b7fd83e..9290852 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -303,11 +303,11 @@
   } else {
     entry_size = kDoubleSize;
   }
-  ASSERT(elms->map() != HEAP->fixed_cow_array_map());
+  ASSERT(elms->map() != heap->fixed_cow_array_map());
   // For now this trick is only applied to fixed arrays in new and paged space.
   // In large object space the object's start must coincide with chunk
   // and thus the trick is just not applicable.
-  ASSERT(!HEAP->lo_space()->Contains(elms));
+  ASSERT(!heap->lo_space()->Contains(elms));
 
   STATIC_ASSERT(FixedArrayBase::kMapOffset == 0);
   STATIC_ASSERT(FixedArrayBase::kLengthOffset == kPointerSize);
diff --git a/src/code-stubs.cc b/src/code-stubs.cc
index 6011275..5383339 100644
--- a/src/code-stubs.cc
+++ b/src/code-stubs.cc
@@ -731,8 +731,9 @@
 
 
 void ProfileEntryHookStub::EntryHookTrampoline(intptr_t function,
-                                               intptr_t stack_pointer) {
-  FunctionEntryHook entry_hook = Isolate::Current()->function_entry_hook();
+                                               intptr_t stack_pointer,
+                                               Isolate* isolate) {
+  FunctionEntryHook entry_hook = isolate->function_entry_hook();
   ASSERT(entry_hook != NULL);
   entry_hook(function, stack_pointer);
 }
diff --git a/src/code-stubs.h b/src/code-stubs.h
index 4fe4e07..207af47 100644
--- a/src/code-stubs.h
+++ b/src/code-stubs.h
@@ -102,7 +102,6 @@
   V(GetProperty)               \
   V(SetProperty)               \
   V(InvokeBuiltin)             \
-  V(RegExpCEntry)              \
   V(DirectCEntry)
 #else
 #define CODE_STUB_LIST_ARM(V)
@@ -2296,7 +2295,8 @@
 
  private:
   static void EntryHookTrampoline(intptr_t function,
-                                  intptr_t stack_pointer);
+                                  intptr_t stack_pointer,
+                                  Isolate* isolate);
 
   Major MajorKey() { return ProfileEntryHook; }
   int MinorKey() { return 0; }
diff --git a/src/compiler.cc b/src/compiler.cc
index a206066..0699602 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -358,7 +358,7 @@
   }
 
   const int locals_limit = LUnallocated::kMaxFixedSlotIndex;
-  if (!info()->osr_ast_id().IsNone() &&
+  if (info()->is_osr() &&
       scope->num_parameters() + 1 + scope->num_stack_slots() > locals_limit) {
     info()->set_bailout_reason(kTooManyParametersLocals);
     return AbortOptimization();
@@ -725,7 +725,7 @@
     }
     script->set_is_shared_cross_origin(is_shared_cross_origin);
 
-    script->set_data(script_data.is_null() ? HEAP->undefined_value()
+    script->set_data(script_data.is_null() ? isolate->heap()->undefined_value()
                                            : *script_data);
 
     // Compile the function and add it to the cache.
@@ -742,8 +742,8 @@
       compilation_cache->PutScript(source, context, result);
     }
   } else {
-    if (result->ic_age() != HEAP->global_ic_age()) {
-      result->ResetForNewContext(HEAP->global_ic_age());
+    if (result->ic_age() != isolate->heap()->global_ic_age()) {
+      result->ResetForNewContext(isolate->heap()->global_ic_age());
     }
   }
 
@@ -805,8 +805,8 @@
       }
     }
   } else {
-    if (result->ic_age() != HEAP->global_ic_age()) {
-      result->ResetForNewContext(HEAP->global_ic_age());
+    if (result->ic_age() != isolate->heap()->global_ic_age()) {
+      result->ResetForNewContext(isolate->heap()->global_ic_age());
     }
   }
 
@@ -884,7 +884,7 @@
   if (code->kind() != Code::OPTIMIZED_FUNCTION) return;  // Nothing to do.
 
   // Cache non-OSR optimized code.
-  if (FLAG_cache_optimized_code && info->osr_ast_id().IsNone()) {
+  if (FLAG_cache_optimized_code && !info->is_osr()) {
     Handle<JSFunction> function = info->closure();
     Handle<SharedFunctionInfo> shared(function->shared());
     Handle<FixedArray> literals(function->literals());
@@ -899,7 +899,7 @@
   if (!info->IsOptimizing()) return false;  // Nothing to look up.
 
   // Lookup non-OSR optimized code.
-  if (FLAG_cache_optimized_code && info->osr_ast_id().IsNone()) {
+  if (FLAG_cache_optimized_code && !info->is_osr()) {
     Handle<SharedFunctionInfo> shared = info->shared_info();
     Handle<JSFunction> function = info->closure();
     ASSERT(!function.is_null());
@@ -955,12 +955,15 @@
       InstallCodeCommon(info);
 
       if (info->IsOptimizing()) {
+        // Optimized code successfully created.
         Handle<Code> code = info->code();
         ASSERT(shared->scope_info() != ScopeInfo::Empty(isolate));
+        // TODO(titzer): Only replace the code if it was not an OSR compile.
         info->closure()->ReplaceCode(*code);
         InsertCodeIntoOptimizedCodeMap(info);
         return true;
-      } else {
+      } else if (!info->is_osr()) {
+        // Compilation failed. Replace with full code if not OSR compile.
         return InstallFullCode(info);
       }
     }
@@ -1051,7 +1054,8 @@
 }
 
 
-bool Compiler::InstallOptimizedCode(OptimizingCompiler* optimizing_compiler) {
+Handle<Code> Compiler::InstallOptimizedCode(
+    OptimizingCompiler* optimizing_compiler) {
   SmartPointer<CompilationInfo> info(optimizing_compiler->info());
   // The function may have already been optimized by OSR.  Simply continue.
   // Except when OSR already disabled optimization for some reason.
@@ -1064,7 +1068,7 @@
       PrintF(" as it has been disabled.\n");
     }
     ASSERT(!info->closure()->IsMarkedForInstallingRecompiledCode());
-    return false;
+    return Handle<Code>::null();
   }
 
   Isolate* isolate = info->isolate();
@@ -1111,7 +1115,8 @@
   // profiler ticks to prevent too soon re-opt after a deopt.
   info->shared_info()->code()->set_profiler_ticks(0);
   ASSERT(!info->closure()->IsMarkedForInstallingRecompiledCode());
-  return status == OptimizingCompiler::SUCCEEDED;
+  return (status == OptimizingCompiler::SUCCEEDED) ? info->code()
+                                                   : Handle<Code>::null();
 }
 
 
@@ -1149,10 +1154,9 @@
 }
 
 
-BailoutId Compiler::CompileForOnStackReplacement(Handle<JSFunction> function) {
+Handle<Code> Compiler::CompileForOnStackReplacement(
+      Handle<JSFunction> function) {
   Isolate* isolate = function->GetIsolate();
-  // We have hit a back edge in an unoptimized frame for a function that was
-  // selected for on-stack replacement.  Find the unoptimized code object.
   Handle<Code> unoptimized(function->shared()->code(), isolate);
 
   Deoptimizer::RevertInterruptCode(isolate, *unoptimized);
@@ -1162,47 +1166,44 @@
     PrintF("]\n");
   }
 
-  if (!IsSuitableForOnStackReplacement(isolate, function, unoptimized)) {
-    return BailoutId::None();
-  }
+  if (IsSuitableForOnStackReplacement(isolate, function, unoptimized)) {
+    // Find the PC offset in unoptimized code and translate to an AST id.
+    uint32_t pc_offset = CurrentPcOffset(isolate, function, unoptimized);
+    BailoutId ast_id = unoptimized->TranslatePcOffsetToAstId(pc_offset);
+    ASSERT(!ast_id.IsNone());
+    if (FLAG_trace_osr) {
+      PrintF("[OSR - replacing at AST id %d in ", ast_id.ToInt());
+      function->PrintName();
+      PrintF("]\n");
+    }
 
-  uint32_t pc_offset = CurrentPcOffset(isolate, function, unoptimized);
+    // Attempt OSR compilation.
+    Handle<Code> result = JSFunction::CompileOsr(
+        function, ast_id, CLEAR_EXCEPTION);
 
-  BailoutId ast_id = unoptimized->TranslatePcOffsetToAstId(pc_offset);
-  ASSERT(!ast_id.IsNone());
-  if (FLAG_trace_osr) {
-    PrintF("[OSR - replacing at AST id %d in ", ast_id.ToInt());
-    function->PrintName();
-    PrintF("]\n");
-  }
-
-  // Try to compile the optimized code.  A true return value from
-  // CompileOptimized means that compilation succeeded, not necessarily
-  // that optimization succeeded.
-  if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
-      function->IsOptimized()) {
-    DeoptimizationInputData* data = DeoptimizationInputData::cast(
-        function->code()->deoptimization_data());
-    if (data->OsrPcOffset()->value() >= 0) {
+    if (!result.is_null() && result->kind() == Code::OPTIMIZED_FUNCTION) {
+      // OSR compilation succeeded.
+      DeoptimizationInputData* data =
+          DeoptimizationInputData::cast(result->deoptimization_data());
       if (FLAG_trace_osr) {
         PrintF("[OSR - entry, offset %d in optimized code]\n",
             data->OsrPcOffset()->value());
       }
       ASSERT(BailoutId(data->OsrAstId()->value()) == ast_id);
-      return ast_id;
-    }
-  } else {
-    if (FLAG_trace_osr) {
-      PrintF("[OSR - optimization failed for ");
-      function->PrintName();
-      PrintF("]\n");
+      return result;
     }
   }
-  return BailoutId::None();
+
+  if (FLAG_trace_osr) {
+    PrintF("[OSR - attempt failed for ");
+    function->PrintName();
+    PrintF("]\n");
+  }
+  return Handle<Code>::null();
 }
 
 
-BailoutId Compiler::CompileForConcurrentOSR(Handle<JSFunction> function) {
+Handle<Code> Compiler::CompileForConcurrentOSR(Handle<JSFunction> function) {
   Isolate* isolate = function->GetIsolate();
   Handle<Code> unoptimized(function->shared()->code(), isolate);
 
@@ -1216,13 +1217,15 @@
       function->PrintName();
       PrintF("]\n");
     }
-    return BailoutId::None();
+    return Handle<Code>::null();
   }
 
   OptimizingCompiler* compiler = isolate->optimizing_compiler_thread()->
                                      FindReadyOSRCandidate(function, pc_offset);
 
   if (compiler != NULL) {
+    BailoutId ast_id = compiler->info()->osr_ast_id();
+
     if (FLAG_trace_osr) {
       PrintF("[COSR - optimization complete for ");
       function->PrintName();
@@ -1230,33 +1233,34 @@
     }
     Deoptimizer::RevertInterruptCode(isolate, *unoptimized);
 
-    BailoutId ast_id = compiler->info()->osr_ast_id();
-
-    bool succeeded = InstallOptimizedCode(compiler);
+    // TODO(titzer): don't install the OSR code into the function.
+    Handle<Code> result = InstallOptimizedCode(compiler);
 
     isolate->optimizing_compiler_thread()->RemoveStaleOSRCandidates();
 
-    if (!succeeded) {
+    if (result.is_null()) {
       if (FLAG_trace_osr) {
         PrintF("[COSR - optimization failed for ");
         function->PrintName();
         PrintF("]\n");
       }
-      return BailoutId::None();
+      return Handle<Code>::null();
     }
+    // Check the result matches our expectations, and don't use it otherwise.
+    if (result->kind() == Code::OPTIMIZED_FUNCTION) {
+      DeoptimizationInputData* data =
+          DeoptimizationInputData::cast(result->deoptimization_data());
 
-    DeoptimizationInputData* data = DeoptimizationInputData::cast(
-        function->code()->deoptimization_data());
-
-    if (data->OsrPcOffset()->value() >= 0) {
-      ASSERT(BailoutId(data->OsrAstId()->value()) == ast_id);
-      if (FLAG_trace_osr) {
-        PrintF("[COSR - entry at AST id %d, offset %d in optimized code]\n",
-               ast_id.ToInt(), data->OsrPcOffset()->value());
+      if (data->OsrPcOffset()->value() >= 0) {
+        ASSERT(BailoutId(data->OsrAstId()->value()) == ast_id);
+        if (FLAG_trace_osr) {
+          PrintF("[COSR - entry at AST id %d, offset %d in optimized code]\n",
+                 ast_id.ToInt(), data->OsrPcOffset()->value());
+        }
+        return result;
       }
-      return ast_id;
     }
-    return BailoutId::None();
+    return Handle<Code>::null();
   }
 
   if (!IsSuitableForOnStackReplacement(isolate, function, unoptimized)) {
@@ -1266,13 +1270,13 @@
       PrintF(" is unsuitable, restoring interrupt calls]\n");
     }
     Deoptimizer::RevertInterruptCode(isolate, *unoptimized);
-    return BailoutId::None();
+    return Handle<Code>::null();
   }
 
   if (!RecompileConcurrent(function, pc_offset)) {
     Deoptimizer::RevertInterruptCode(isolate, *unoptimized);
   }
-  return BailoutId::None();
+  return Handle<Code>::null();
 }
 
 
diff --git a/src/compiler.h b/src/compiler.h
index 65618dd..15c4969 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -63,7 +63,8 @@
   Isolate* isolate() const {
     return isolate_;
   }
-  Zone* zone() const { return zone_; }
+  Zone* zone() { return zone_; }
+  bool is_osr() const { return !osr_ast_id_.IsNone(); }
   bool is_lazy() const { return IsLazy::decode(flags_); }
   bool is_eval() const { return IsEval::decode(flags_); }
   bool is_global() const { return IsGlobal::decode(flags_); }
@@ -624,11 +625,11 @@
                               bool is_toplevel,
                               Handle<Script> script);
 
-  static bool InstallOptimizedCode(OptimizingCompiler* info);
+  static Handle<Code> InstallOptimizedCode(OptimizingCompiler* info);
 
-  static BailoutId CompileForOnStackReplacement(Handle<JSFunction> function);
+  static Handle<Code> CompileForOnStackReplacement(Handle<JSFunction> function);
 
-  static BailoutId CompileForConcurrentOSR(Handle<JSFunction> function);
+  static Handle<Code> CompileForConcurrentOSR(Handle<JSFunction> function);
 
 #ifdef ENABLE_DEBUGGER_SUPPORT
   static bool MakeCodeForLiveEdit(CompilationInfo* info);
diff --git a/src/cpu-profiler.cc b/src/cpu-profiler.cc
index 74e0d82..e0f7aea 100644
--- a/src/cpu-profiler.cc
+++ b/src/cpu-profiler.cc
@@ -373,7 +373,7 @@
     : isolate_(isolate),
       sampling_interval_(TimeDelta::FromMicroseconds(
           FLAG_cpu_profiler_sampling_interval)),
-      profiles_(new CpuProfilesCollection()),
+      profiles_(new CpuProfilesCollection(isolate->heap())),
       next_profile_uid_(1),
       generator_(NULL),
       processor_(NULL),
@@ -410,7 +410,7 @@
 
 void CpuProfiler::ResetProfiles() {
   delete profiles_;
-  profiles_ = new CpuProfilesCollection();
+  profiles_ = new CpuProfilesCollection(isolate()->heap());
 }
 
 
diff --git a/src/cpu.h b/src/cpu.h
index 58c7f5d..b2e9f7d 100644
--- a/src/cpu.h
+++ b/src/cpu.h
@@ -100,7 +100,7 @@
   bool has_vfp3_d32() const { return has_vfp3_d32_; }
 
   // Returns the number of processors online.
-  static int NumberOfProcessorsOnline() V8_WARN_UNUSED_RESULT;
+  static int NumberOfProcessorsOnline();
 
   // Initializes the cpu architecture support. Called once at VM startup.
   static void SetUp();
diff --git a/src/d8.cc b/src/d8.cc
index ea8b875..fb75d81 100644
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -772,7 +772,8 @@
       = i::Handle<i::JSObject>(debug->debug_context()->global_object());
   utility_context->Global()->Set(String::New("$debug"),
                                   Utils::ToLocal(js_debug));
-  debug->debug_context()->set_security_token(HEAP->undefined_value());
+  debug->debug_context()->set_security_token(
+      reinterpret_cast<i::Isolate*>(isolate)->heap()->undefined_value());
 #endif  // ENABLE_DEBUGGER_SUPPORT
 
   // Run the d8 shell utility script in the utility context
diff --git a/src/debug-agent.cc b/src/debug-agent.cc
index aad3608..51823aa 100644
--- a/src/debug-agent.cc
+++ b/src/debug-agent.cc
@@ -38,7 +38,8 @@
 // Public V8 debugger API message handler function. This function just delegates
 // to the debugger agent through it's data parameter.
 void DebuggerAgentMessageHandler(const v8::Debug::Message& message) {
-  DebuggerAgent* agent = Isolate::Current()->debugger_agent_instance();
+  Isolate* isolate = reinterpret_cast<Isolate*>(message.GetIsolate());
+  DebuggerAgent* agent = isolate->debugger_agent_instance();
   ASSERT(agent != NULL);
   agent->DebuggerMessage(message);
 }
diff --git a/src/debug.cc b/src/debug.cc
index 7624f26..3f2739e 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -3624,6 +3624,11 @@
 }
 
 
+v8::Isolate* MessageImpl::GetIsolate() const {
+  return reinterpret_cast<v8::Isolate*>(exec_state_->GetIsolate());
+}
+
+
 v8::Handle<v8::Object> MessageImpl::GetEventData() const {
   return v8::Utils::ToLocal(event_data_);
 }
diff --git a/src/debug.h b/src/debug.h
index 03ee40e..2b5f43a 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -668,6 +668,7 @@
   virtual v8::Handle<v8::String> GetJSON() const;
   virtual v8::Handle<v8::Context> GetEventContext() const;
   virtual v8::Debug::ClientData* GetClientData() const;
+  virtual v8::Isolate* GetIsolate() const;
 
  private:
   MessageImpl(bool is_event,
diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc
index 61ce780..c979a53 100644
--- a/src/deoptimizer.cc
+++ b/src/deoptimizer.cc
@@ -495,8 +495,6 @@
       return (frame_type == StackFrame::STUB)
           ? FLAG_trace_stub_failures
           : FLAG_trace_deopt;
-    case OSR:
-      return FLAG_trace_osr;
   }
   UNREACHABLE();
   return false;
@@ -509,7 +507,6 @@
     case SOFT: return "soft";
     case LAZY: return "lazy";
     case DEBUGGER: return "debugger";
-    case OSR: return "OSR";
   }
   UNREACHABLE();
   return NULL;
@@ -563,6 +560,14 @@
     }
   }
   compiled_code_ = FindOptimizedCode(function, optimized_code);
+
+#if DEBUG
+  ASSERT(compiled_code_ != NULL);
+  if (type == EAGER || type == SOFT || type == LAZY) {
+    ASSERT(compiled_code_->kind() != Code::FUNCTION);
+  }
+#endif
+
   StackFrame::Type frame_type = function == NULL
       ? StackFrame::STUB
       : StackFrame::JAVA_SCRIPT;
@@ -588,15 +593,6 @@
           ? static_cast<Code*>(isolate_->FindCodeObject(from_))
           : compiled_code;
     }
-    case Deoptimizer::OSR: {
-      // The function has already been optimized and we're transitioning
-      // from the unoptimized shared version to the optimized one in the
-      // function. The return address (from_) points to unoptimized code.
-      Code* compiled_code = function->code();
-      ASSERT(compiled_code->kind() == Code::OPTIMIZED_FUNCTION);
-      ASSERT(!compiled_code->contains(from_));
-      return compiled_code;
-    }
     case Deoptimizer::DEBUGGER:
       ASSERT(optimized_code->contains(from_));
       return optimized_code;
@@ -720,11 +716,6 @@
 // We rely on this function not causing a GC.  It is called from generated code
 // without having a real stack frame in place.
 void Deoptimizer::DoComputeOutputFrames() {
-  if (bailout_type_ == OSR) {
-    DoComputeOsrOutputFrame();
-    return;
-  }
-
   // Print some helpful diagnostic information.
   if (FLAG_log_timer_events &&
       compiled_code_->kind() == Code::OPTIMIZED_FUNCTION) {
@@ -2346,192 +2337,6 @@
 }
 
 
-bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator,
-                                        int* input_offset) {
-  disasm::NameConverter converter;
-  FrameDescription* output = output_[0];
-
-  // The input values are all part of the unoptimized frame so they
-  // are all tagged pointers.
-  uintptr_t input_value = input_->GetFrameSlot(*input_offset);
-  Object* input_object = reinterpret_cast<Object*>(input_value);
-
-  Translation::Opcode opcode =
-      static_cast<Translation::Opcode>(iterator->Next());
-
-  switch (opcode) {
-    case Translation::BEGIN:
-    case Translation::JS_FRAME:
-    case Translation::ARGUMENTS_ADAPTOR_FRAME:
-    case Translation::CONSTRUCT_STUB_FRAME:
-    case Translation::GETTER_STUB_FRAME:
-    case Translation::SETTER_STUB_FRAME:
-    case Translation::COMPILED_STUB_FRAME:
-      UNREACHABLE();  // Malformed input.
-      return false;
-
-    case Translation::REGISTER: {
-      int output_reg = iterator->Next();
-      if (FLAG_trace_osr) {
-        PrintF("    %s <- 0x%08" V8PRIxPTR " ; [sp + %d]\n",
-               converter.NameOfCPURegister(output_reg),
-               input_value,
-               *input_offset);
-      }
-      output->SetRegister(output_reg, input_value);
-      break;
-    }
-
-    case Translation::INT32_REGISTER: {
-      int32_t int32_value = 0;
-      if (!input_object->ToInt32(&int32_value)) return false;
-
-      int output_reg = iterator->Next();
-      if (FLAG_trace_osr) {
-        PrintF("    %s <- %d (int32) ; [sp + %d]\n",
-               converter.NameOfCPURegister(output_reg),
-               int32_value,
-               *input_offset);
-      }
-      output->SetRegister(output_reg, int32_value);
-      break;
-    }
-
-    case Translation::UINT32_REGISTER: {
-      uint32_t uint32_value = 0;
-      if (!input_object->ToUint32(&uint32_value)) return false;
-
-      int output_reg = iterator->Next();
-      if (FLAG_trace_osr) {
-        PrintF("    %s <- %u (uint32) ; [sp + %d]\n",
-               converter.NameOfCPURegister(output_reg),
-               uint32_value,
-               *input_offset);
-      }
-      output->SetRegister(output_reg, static_cast<int32_t>(uint32_value));
-    }
-
-
-    case Translation::DOUBLE_REGISTER: {
-      // Abort OSR if we don't have a number.
-      if (!input_object->IsNumber()) return false;
-
-      int output_reg = iterator->Next();
-      double double_value = input_object->Number();
-      if (FLAG_trace_osr) {
-        PrintF("    %s <- %g (double) ; [sp + %d]\n",
-               DoubleRegister::AllocationIndexToString(output_reg),
-               double_value,
-               *input_offset);
-      }
-      output->SetDoubleRegister(output_reg, double_value);
-      break;
-    }
-
-    case Translation::STACK_SLOT: {
-      int output_index = iterator->Next();
-      unsigned output_offset =
-          output->GetOffsetFromSlotIndex(output_index);
-      if (FLAG_trace_osr) {
-        PrintF("    [sp + %d] <- 0x%08" V8PRIxPTR " ; [sp + %d] ",
-               output_offset,
-               input_value,
-               *input_offset);
-        reinterpret_cast<Object*>(input_value)->ShortPrint();
-        PrintF("\n");
-      }
-      output->SetFrameSlot(output_offset, input_value);
-      break;
-    }
-
-    case Translation::INT32_STACK_SLOT: {
-      int32_t int32_value = 0;
-      if (!input_object->ToInt32(&int32_value)) return false;
-
-      int output_index = iterator->Next();
-      unsigned output_offset =
-          output->GetOffsetFromSlotIndex(output_index);
-      if (FLAG_trace_osr) {
-        PrintF("    [sp + %d] <- %d (int32) ; [sp + %d]\n",
-               output_offset,
-               int32_value,
-               *input_offset);
-      }
-      output->SetFrameSlot(output_offset, int32_value);
-      break;
-    }
-
-    case Translation::UINT32_STACK_SLOT: {
-      uint32_t uint32_value = 0;
-      if (!input_object->ToUint32(&uint32_value)) return false;
-
-      int output_index = iterator->Next();
-      unsigned output_offset =
-          output->GetOffsetFromSlotIndex(output_index);
-      if (FLAG_trace_osr) {
-        PrintF("    [sp + %d] <- %u (uint32) ; [sp + %d]\n",
-               output_offset,
-               uint32_value,
-               *input_offset);
-      }
-      output->SetFrameSlot(output_offset, static_cast<int32_t>(uint32_value));
-      break;
-    }
-
-    case Translation::DOUBLE_STACK_SLOT: {
-      static const int kLowerOffset = 0 * kPointerSize;
-      static const int kUpperOffset = 1 * kPointerSize;
-
-      // Abort OSR if we don't have a number.
-      if (!input_object->IsNumber()) return false;
-
-      int output_index = iterator->Next();
-      unsigned output_offset =
-          output->GetOffsetFromSlotIndex(output_index);
-      double double_value = input_object->Number();
-      uint64_t int_value = BitCast<uint64_t, double>(double_value);
-      int32_t lower = static_cast<int32_t>(int_value);
-      int32_t upper = static_cast<int32_t>(int_value >> kBitsPerInt);
-      if (FLAG_trace_osr) {
-        PrintF("    [sp + %d] <- 0x%08x (upper bits of %g) ; [sp + %d]\n",
-               output_offset + kUpperOffset,
-               upper,
-               double_value,
-               *input_offset);
-        PrintF("    [sp + %d] <- 0x%08x (lower bits of %g) ; [sp + %d]\n",
-               output_offset + kLowerOffset,
-               lower,
-               double_value,
-               *input_offset);
-      }
-      output->SetFrameSlot(output_offset + kLowerOffset, lower);
-      output->SetFrameSlot(output_offset + kUpperOffset, upper);
-      break;
-    }
-
-    case Translation::LITERAL: {
-      // Just ignore non-materialized literals.
-      iterator->Next();
-      break;
-    }
-
-    case Translation::DUPLICATED_OBJECT:
-    case Translation::ARGUMENTS_OBJECT:
-    case Translation::CAPTURED_OBJECT: {
-      // Optimized code assumes that the argument object has not been
-      // materialized and so bypasses it when doing arguments access.
-      // We should have bailed out before starting the frame
-      // translation.
-      UNREACHABLE();
-      return false;
-    }
-  }
-
-  *input_offset -= kPointerSize;
-  return true;
-}
-
-
 void Deoptimizer::PatchInterruptCode(Isolate* isolate,
                                      Code* unoptimized) {
   DisallowHeapAllocation no_gc;
@@ -2617,12 +2422,7 @@
   // into account so we have to avoid double counting them (-2).
   unsigned result = fixed_size + fp_to_sp_delta_ - (2 * kPointerSize);
 #ifdef DEBUG
-  if (bailout_type_ == OSR) {
-    // TODO(kasperl): It would be nice if we could verify that the
-    // size matches with the stack height we can compute based on the
-    // environment at the OSR entry. The code for that his built into
-    // the DoComputeOsrOutputFrame function for now.
-  } else if (compiled_code_->kind() == Code::OPTIMIZED_FUNCTION) {
+  if (compiled_code_->kind() == Code::OPTIMIZED_FUNCTION) {
     unsigned stack_slots = compiled_code_->stack_slots();
     unsigned outgoing_size = ComputeOutgoingArgumentSize();
     ASSERT(result == fixed_size + (stack_slots * kPointerSize) + outgoing_size);
diff --git a/src/deoptimizer.h b/src/deoptimizer.h
index c28b7b9..7ee5908 100644
--- a/src/deoptimizer.h
+++ b/src/deoptimizer.h
@@ -126,7 +126,6 @@
     EAGER,
     LAZY,
     SOFT,
-    OSR,
     // This last bailout type is not really a bailout, but used by the
     // debugger to deoptimize stack frames to allow inspection.
     DEBUGGER
@@ -356,7 +355,6 @@
   void DeleteFrameDescriptions();
 
   void DoComputeOutputFrames();
-  void DoComputeOsrOutputFrame();
   void DoComputeJSFrame(TranslationIterator* iterator, int frame_index);
   void DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator,
                                       int frame_index);
@@ -382,13 +380,6 @@
       unsigned output_offset,
       DeoptimizerTranslatedValueType value_type = TRANSLATED_VALUE_IS_TAGGED);
 
-  // Translate a command for OSR.  Updates the input offset to be used for
-  // the next command.  Returns false if translation of the command failed
-  // (e.g., a number conversion failed) and may or may not have updated the
-  // input offset.
-  bool DoOsrTranslateCommand(TranslationIterator* iterator,
-                             int* input_offset);
-
   unsigned ComputeInputFrameSize() const;
   unsigned ComputeFixedSize(JSFunction* function) const;
 
diff --git a/src/disassembler.cc b/src/disassembler.cc
index 30df186..dd620fb 100644
--- a/src/disassembler.cc
+++ b/src/disassembler.cc
@@ -118,7 +118,7 @@
   SealHandleScope shs(isolate);
   DisallowHeapAllocation no_alloc;
   ExternalReferenceEncoder ref_encoder(isolate);
-  Heap* heap = HEAP;
+  Heap* heap = isolate->heap();
 
   v8::internal::EmbeddedVector<char, 128> decode_buffer;
   v8::internal::EmbeddedVector<char, kOutBufferSize> out_buffer;
diff --git a/src/elements.cc b/src/elements.cc
index 3e864f4..89621cb 100644
--- a/src/elements.cc
+++ b/src/elements.cc
@@ -154,7 +154,8 @@
                                        ElementsKind to_kind,
                                        uint32_t to_start,
                                        int raw_copy_size) {
-  ASSERT(to_base->map() != HEAP->fixed_cow_array_map());
+  ASSERT(to_base->map() !=
+      from_base->GetIsolate()->heap()->fixed_cow_array_map());
   DisallowHeapAllocation no_allocation;
   int copy_size = raw_copy_size;
   if (raw_copy_size < 0) {
diff --git a/src/extensions/externalize-string-extension.cc b/src/extensions/externalize-string-extension.cc
index a3630fb..5fd821b 100644
--- a/src/extensions/externalize-string-extension.cc
+++ b/src/extensions/externalize-string-extension.cc
@@ -103,7 +103,8 @@
         reinterpret_cast<char*>(data), string->length());
     result = string->MakeExternal(resource);
     if (result && !string->IsInternalizedString()) {
-      HEAP->external_string_table()->AddString(*string);
+      i::Isolate* isolate = reinterpret_cast<i::Isolate*>(args.GetIsolate());
+      isolate->heap()->external_string_table()->AddString(*string);
     }
     if (!result) delete resource;
   } else {
@@ -113,7 +114,8 @@
         data, string->length());
     result = string->MakeExternal(resource);
     if (result && !string->IsInternalizedString()) {
-      HEAP->external_string_table()->AddString(*string);
+      i::Isolate* isolate = reinterpret_cast<i::Isolate*>(args.GetIsolate());
+      isolate->heap()->external_string_table()->AddString(*string);
     }
     if (!result) delete resource;
   }
diff --git a/src/extensions/gc-extension.cc b/src/extensions/gc-extension.cc
index 036b60c..3088791 100644
--- a/src/extensions/gc-extension.cc
+++ b/src/extensions/gc-extension.cc
@@ -39,10 +39,11 @@
 
 
 void GCExtension::GC(const v8::FunctionCallbackInfo<v8::Value>& args) {
+  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(args.GetIsolate());
   if (args[0]->BooleanValue()) {
-    HEAP->CollectGarbage(NEW_SPACE, "gc extension");
+    isolate->heap()->CollectGarbage(NEW_SPACE, "gc extension");
   } else {
-    HEAP->CollectAllGarbage(Heap::kNoGCFlags, "gc extension");
+    isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "gc extension");
   }
 }
 
diff --git a/src/factory.cc b/src/factory.cc
index c7f7806..acbaf3c 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -141,7 +141,8 @@
     PretenureFlag pretenure) {
   ASSERT(deopt_entry_count > 0);
   CALL_HEAP_FUNCTION(isolate(),
-                     DeoptimizationInputData::Allocate(deopt_entry_count,
+                     DeoptimizationInputData::Allocate(isolate(),
+                                                       deopt_entry_count,
                                                        pretenure),
                      DeoptimizationInputData);
 }
@@ -152,7 +153,8 @@
     PretenureFlag pretenure) {
   ASSERT(deopt_entry_count > 0);
   CALL_HEAP_FUNCTION(isolate(),
-                     DeoptimizationOutputData::Allocate(deopt_entry_count,
+                     DeoptimizationOutputData::Allocate(isolate(),
+                                                        deopt_entry_count,
                                                         pretenure),
                      DeoptimizationOutputData);
 }
@@ -1081,13 +1083,6 @@
 }
 
 
-void Factory::EnsureCanContainHeapObjectElements(Handle<JSArray> array) {
-  CALL_HEAP_FUNCTION_VOID(
-      isolate(),
-      array->EnsureCanContainHeapObjectElements());
-}
-
-
 void Factory::EnsureCanContainElements(Handle<JSArray> array,
                                        Handle<FixedArrayBase> elements,
                                        uint32_t length,
diff --git a/src/factory.h b/src/factory.h
index e592020..1bdf474 100644
--- a/src/factory.h
+++ b/src/factory.h
@@ -328,7 +328,6 @@
 
   void SetContent(Handle<JSArray> array, Handle<FixedArrayBase> elements);
 
-  void EnsureCanContainHeapObjectElements(Handle<JSArray> array);
   void EnsureCanContainElements(Handle<JSArray> array,
                                 Handle<FixedArrayBase> elements,
                                 uint32_t length,
@@ -640,6 +639,24 @@
         : reinterpret_cast<MaybeObject*>(Failure::RetryAfterGC());
   }
 
+  template<typename R, typename P1, typename P2, typename P3, typename P4,
+           typename P5, typename P6, typename P7>
+  MUST_USE_RESULT MaybeObject* CallWithReturnValue(
+      R (*function)(P1, P2, P3, P4, P5, P6, P7),
+      P1 p1,
+      P2 p2,
+      P3 p3,
+      P4 p4,
+      P5 p5,
+      P6 p6,
+      P7 p7) {
+    int collections = isolate_->heap()->gc_count();
+    Handle<Object> result = (*function)(p1, p2, p3, p4, p5, p6, p7);
+    return (collections == isolate_->heap()->gc_count())
+        ? *result
+        : reinterpret_cast<MaybeObject*>(Failure::RetryAfterGC());
+  }
+
  private:
   Isolate* isolate_;
 };
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index 2b4f72d..7548c01 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -240,7 +240,7 @@
 DEFINE_bool(use_gvn, true, "use hydrogen global value numbering")
 DEFINE_bool(use_canonicalizing, true, "use hydrogen instruction canonicalizing")
 DEFINE_bool(use_inlining, true, "use function inlining")
-DEFINE_bool(use_escape_analysis, false, "use hydrogen escape analysis")
+DEFINE_bool(use_escape_analysis, true, "use hydrogen escape analysis")
 DEFINE_bool(use_allocation_folding, true, "use allocation folding")
 DEFINE_int(max_inlining_levels, 5, "maximum number of inlining levels")
 DEFINE_int(max_inlined_source_size, 600,
diff --git a/src/flags.h b/src/flags.h
index f0b239b..fe182e5 100644
--- a/src/flags.h
+++ b/src/flags.h
@@ -24,9 +24,12 @@
 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 #ifndef V8_FLAGS_H_
 #define V8_FLAGS_H_
 
+#include "atomicops.h"
+
 namespace v8 {
 namespace internal {
 
diff --git a/src/frames.cc b/src/frames.cc
index 5d90f06..167277f 100644
--- a/src/frames.cc
+++ b/src/frames.cc
@@ -489,7 +489,7 @@
 
 
 Code* EntryFrame::unchecked_code() const {
-  return HEAP->js_entry_code();
+  return isolate()->heap()->js_entry_code();
 }
 
 
@@ -512,7 +512,7 @@
 
 
 Code* EntryConstructFrame::unchecked_code() const {
-  return HEAP->js_construct_entry_code();
+  return isolate()->heap()->js_construct_entry_code();
 }
 
 
diff --git a/src/globals.h b/src/globals.h
index d0a57a4..992f3a8 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -393,18 +393,6 @@
 };
 
 
-// A simple Maybe type, that can be passed by value.
-template<class T>
-struct Maybe {
-  Maybe() : has_value(false) {}
-  explicit Maybe(T t) : has_value(true), value(t) {}
-  Maybe(bool has, T t) : has_value(has), value(t) {}
-
-  bool has_value;
-  T value;
-};
-
-
 // The Strict Mode (ECMA-262 5th edition, 4.2.2).
 //
 // This flag is used in the backend to represent the language mode. So far
diff --git a/src/heap-inl.h b/src/heap-inl.h
index 8808855..86aff1a 100644
--- a/src/heap-inl.h
+++ b/src/heap-inl.h
@@ -69,7 +69,7 @@
   *(--rear_) = size;
   // Assert no overflow into live objects.
 #ifdef DEBUG
-  SemiSpace::AssertValidRange(HEAP->new_space()->top(),
+  SemiSpace::AssertValidRange(target->GetIsolate()->heap()->new_space()->top(),
                               reinterpret_cast<Address>(rear_));
 #endif
 }
@@ -508,7 +508,7 @@
 
 
 void Heap::ScavengeObject(HeapObject** p, HeapObject* object) {
-  ASSERT(HEAP->InFromSpace(object));
+  ASSERT(object->GetIsolate()->heap()->InFromSpace(object));
 
   // We use the first word (where the map pointer usually is) of a heap
   // object to record the forwarding pointer.  A forwarding pointer can
@@ -520,11 +520,13 @@
   // copied.
   if (first_word.IsForwardingAddress()) {
     HeapObject* dest = first_word.ToForwardingAddress();
-    ASSERT(HEAP->InFromSpace(*p));
+    ASSERT(object->GetIsolate()->heap()->InFromSpace(*p));
     *p = dest;
     return;
   }
 
+  // TODO(hpayer): temporary debugging code for issue 284577.
+  CHECK(object->map() != object->GetHeap()->allocation_memento_map());
   // Call the slow part of scavenge object.
   return ScavengeObjectSlow(p, object);
 }
@@ -613,10 +615,10 @@
 
 
 #ifdef DEBUG
-#define GC_GREEDY_CHECK() \
-  if (FLAG_gc_greedy) HEAP->GarbageCollectionGreedyCheck()
+#define GC_GREEDY_CHECK(ISOLATE) \
+  if (FLAG_gc_greedy) (ISOLATE)->heap()->GarbageCollectionGreedyCheck()
 #else
-#define GC_GREEDY_CHECK() { }
+#define GC_GREEDY_CHECK(ISOLATE) { }
 #endif
 
 // Calls the FUNCTION_CALL function and retries it up to three times
@@ -628,7 +630,7 @@
 
 #define CALL_AND_RETRY(ISOLATE, FUNCTION_CALL, RETURN_VALUE, RETURN_EMPTY, OOM)\
   do {                                                                         \
-    GC_GREEDY_CHECK();                                                         \
+    GC_GREEDY_CHECK(ISOLATE);                                                  \
     MaybeObject* __maybe_object__ = FUNCTION_CALL;                             \
     Object* __object__ = NULL;                                                 \
     if (__maybe_object__->ToObject(&__object__)) RETURN_VALUE;                 \
@@ -636,7 +638,7 @@
       OOM;                                                                     \
     }                                                                          \
     if (!__maybe_object__->IsRetryAfterGC()) RETURN_EMPTY;                     \
-    ISOLATE->heap()->CollectGarbage(Failure::cast(__maybe_object__)->          \
+    (ISOLATE)->heap()->CollectGarbage(Failure::cast(__maybe_object__)->        \
                                     allocation_space(),                        \
                                     "allocation failure");                     \
     __maybe_object__ = FUNCTION_CALL;                                          \
@@ -645,8 +647,8 @@
       OOM;                                                                     \
     }                                                                          \
     if (!__maybe_object__->IsRetryAfterGC()) RETURN_EMPTY;                     \
-    ISOLATE->counters()->gc_last_resort_from_handles()->Increment();           \
-    ISOLATE->heap()->CollectAllAvailableGarbage("last resort gc");             \
+    (ISOLATE)->counters()->gc_last_resort_from_handles()->Increment();         \
+    (ISOLATE)->heap()->CollectAllAvailableGarbage("last resort gc");           \
     {                                                                          \
       AlwaysAllocateScope __scope__;                                           \
       __maybe_object__ = FUNCTION_CALL;                                        \
@@ -719,12 +721,12 @@
   for (int i = 0; i < new_space_strings_.length(); ++i) {
     Object* obj = Object::cast(new_space_strings_[i]);
     ASSERT(heap_->InNewSpace(obj));
-    ASSERT(obj != HEAP->the_hole_value());
+    ASSERT(obj != heap_->the_hole_value());
   }
   for (int i = 0; i < old_space_strings_.length(); ++i) {
     Object* obj = Object::cast(old_space_strings_[i]);
     ASSERT(!heap_->InNewSpace(obj));
-    ASSERT(obj != HEAP->the_hole_value());
+    ASSERT(obj != heap_->the_hole_value());
   }
 #endif
 }
@@ -831,25 +833,29 @@
   // non-handle code to call handle code. The code still works but
   // performance will degrade, so we want to catch this situation
   // in debug mode.
-  ASSERT(HEAP->always_allocate_scope_depth_ == 0);
-  HEAP->always_allocate_scope_depth_++;
+  Isolate* isolate = Isolate::Current();
+  ASSERT(isolate->heap()->always_allocate_scope_depth_ == 0);
+  isolate->heap()->always_allocate_scope_depth_++;
 }
 
 
 AlwaysAllocateScope::~AlwaysAllocateScope() {
-  HEAP->always_allocate_scope_depth_--;
-  ASSERT(HEAP->always_allocate_scope_depth_ == 0);
+  Isolate* isolate = Isolate::Current();
+  isolate->heap()->always_allocate_scope_depth_--;
+  ASSERT(isolate->heap()->always_allocate_scope_depth_ == 0);
 }
 
 
 #ifdef VERIFY_HEAP
 NoWeakEmbeddedMapsVerificationScope::NoWeakEmbeddedMapsVerificationScope() {
-  HEAP->no_weak_embedded_maps_verification_scope_depth_++;
+  Isolate* isolate = Isolate::Current();
+  isolate->heap()->no_weak_embedded_maps_verification_scope_depth_++;
 }
 
 
 NoWeakEmbeddedMapsVerificationScope::~NoWeakEmbeddedMapsVerificationScope() {
-  HEAP->no_weak_embedded_maps_verification_scope_depth_--;
+  Isolate* isolate = Isolate::Current();
+  isolate->heap()->no_weak_embedded_maps_verification_scope_depth_--;
 }
 #endif
 
@@ -858,7 +864,7 @@
   for (Object** current = start; current < end; current++) {
     if ((*current)->IsHeapObject()) {
       HeapObject* object = HeapObject::cast(*current);
-      CHECK(HEAP->Contains(object));
+      CHECK(object->GetIsolate()->heap()->Contains(object));
       CHECK(object->map()->IsMap());
     }
   }
@@ -866,21 +872,23 @@
 
 
 double GCTracer::SizeOfHeapObjects() {
-  return (static_cast<double>(HEAP->SizeOfObjects())) / MB;
+  return (static_cast<double>(heap_->SizeOfObjects())) / MB;
 }
 
 
 DisallowAllocationFailure::DisallowAllocationFailure() {
 #ifdef DEBUG
-  old_state_ = HEAP->disallow_allocation_failure_;
-  HEAP->disallow_allocation_failure_ = true;
+  Isolate* isolate = Isolate::Current();
+  old_state_ = isolate->heap()->disallow_allocation_failure_;
+  isolate->heap()->disallow_allocation_failure_ = true;
 #endif
 }
 
 
 DisallowAllocationFailure::~DisallowAllocationFailure() {
 #ifdef DEBUG
-  HEAP->disallow_allocation_failure_ = old_state_;
+  Isolate* isolate = Isolate::Current();
+  isolate->heap()->disallow_allocation_failure_ = old_state_;
 #endif
 }
 
diff --git a/src/heap-snapshot-generator.cc b/src/heap-snapshot-generator.cc
index 6a5bb63..bd47eec 100644
--- a/src/heap-snapshot-generator.cc
+++ b/src/heap-snapshot-generator.cc
@@ -175,6 +175,8 @@
     case kHeapNumber: return "/number/";
     case kNative: return "/native/";
     case kSynthetic: return "/synthetic/";
+    case kConsString: return "/concatenated string/";
+    case kSlicedString: return "/sliced string/";
     default: return "???";
   }
 }
@@ -470,7 +472,7 @@
 
 
 void HeapObjectsMap::UpdateHeapObjectsMap() {
-  HEAP->CollectAllGarbage(Heap::kMakeHeapIterableMask,
+  heap_->CollectAllGarbage(Heap::kMakeHeapIterableMask,
                           "HeapSnapshotsCollection::UpdateHeapObjectsMap");
   HeapIterator iterator(heap_);
   for (HeapObject* obj = iterator.next();
@@ -558,12 +560,13 @@
 }
 
 
-SnapshotObjectId HeapObjectsMap::GenerateId(v8::RetainedObjectInfo* info) {
+SnapshotObjectId HeapObjectsMap::GenerateId(Heap* heap,
+                                            v8::RetainedObjectInfo* info) {
   SnapshotObjectId id = static_cast<SnapshotObjectId>(info->GetHash());
   const char* label = info->GetLabel();
   id ^= StringHasher::HashSequentialString(label,
                                            static_cast<int>(strlen(label)),
-                                           HEAP->HashSeed());
+                                           heap->HashSeed());
   intptr_t element_count = info->GetElementCount();
   if (element_count != -1)
     id ^= ComputeIntegerHash(static_cast<uint32_t>(element_count),
@@ -583,6 +586,7 @@
 
 HeapSnapshotsCollection::HeapSnapshotsCollection(Heap* heap)
     : is_tracking_objects_(false),
+      names_(heap),
       ids_(heap) {
 }
 
@@ -621,7 +625,7 @@
 Handle<HeapObject> HeapSnapshotsCollection::FindHeapObjectById(
     SnapshotObjectId id) {
   // First perform a full GC in order to avoid dead objects.
-  HEAP->CollectAllGarbage(Heap::kMakeHeapIterableMask,
+  heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
                           "HeapSnapshotsCollection::FindHeapObjectById");
   DisallowHeapAllocation no_allocation;
   HeapObject* object = NULL;
@@ -782,6 +786,15 @@
     }
     return AddEntry(object, HeapEntry::kObject, name);
   } else if (object->IsString()) {
+    String* string = String::cast(object);
+    if (string->IsConsString())
+      return AddEntry(object,
+                      HeapEntry::kConsString,
+                      "(concatenated string)");
+    if (string->IsSlicedString())
+      return AddEntry(object,
+                      HeapEntry::kSlicedString,
+                      "(sliced string)");
     return AddEntry(object,
                     HeapEntry::kString,
                     collection_->names()->GetName(String::cast(object)));
@@ -1921,7 +1934,7 @@
   return snapshot_->AddEntry(
       entries_type_,
       name,
-      HeapObjectsMap::GenerateId(info),
+      HeapObjectsMap::GenerateId(collection_->heap(), info),
       size != -1 ? static_cast<int>(size) : 0);
 }
 
@@ -2097,7 +2110,7 @@
   uint32_t hash = StringHasher::HashSequentialString(
       label_copy,
       static_cast<int>(strlen(label_copy)),
-      HEAP->HashSeed());
+      isolate_->heap()->HashSeed());
   HashMap::Entry* entry = native_groups_.Lookup(const_cast<char*>(label_copy),
                                                 hash, true);
   if (entry->value == NULL) {
@@ -2585,7 +2598,9 @@
             JSON_S("regexp") ","
             JSON_S("number") ","
             JSON_S("native") ","
-            JSON_S("synthetic")) ","
+            JSON_S("synthetic") ","
+            JSON_S("concatenated string") ","
+            JSON_S("sliced string")) ","
         JSON_S("string") ","
         JSON_S("number") ","
         JSON_S("number") ","
diff --git a/src/heap-snapshot-generator.h b/src/heap-snapshot-generator.h
index ccdcab4..7b0cf8f 100644
--- a/src/heap-snapshot-generator.h
+++ b/src/heap-snapshot-generator.h
@@ -100,7 +100,9 @@
     kRegExp = v8::HeapGraphNode::kRegExp,
     kHeapNumber = v8::HeapGraphNode::kHeapNumber,
     kNative = v8::HeapGraphNode::kNative,
-    kSynthetic = v8::HeapGraphNode::kSynthetic
+    kSynthetic = v8::HeapGraphNode::kSynthetic,
+    kConsString = v8::HeapGraphNode::kConsString,
+    kSlicedString = v8::HeapGraphNode::kSlicedString
   };
   static const int kNoEntry;
 
@@ -235,7 +237,7 @@
   SnapshotObjectId PushHeapObjectsStats(OutputStream* stream);
   size_t GetUsedMemorySize() const;
 
-  static SnapshotObjectId GenerateId(v8::RetainedObjectInfo* info);
+  static SnapshotObjectId GenerateId(Heap* heap, v8::RetainedObjectInfo* info);
   static inline SnapshotObjectId GetNthGcSubrootId(int delta);
 
   static const int kObjectIdStep = 2;
diff --git a/src/heap.cc b/src/heap.cc
index aaa3d8b..0455a84 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -38,6 +38,7 @@
 #include "global-handles.h"
 #include "heap-profiler.h"
 #include "incremental-marking.h"
+#include "isolate-inl.h"
 #include "mark-compact.h"
 #include "natives.h"
 #include "objects-visiting.h"
@@ -47,6 +48,7 @@
 #include "scopeinfo.h"
 #include "snapshot.h"
 #include "store-buffer.h"
+#include "utils/random-number-generator.h"
 #include "v8threads.h"
 #include "v8utils.h"
 #include "vm-state-inl.h"
@@ -729,7 +731,7 @@
                         int len) {
   if (len == 0) return;
 
-  ASSERT(array->map() != HEAP->fixed_cow_array_map());
+  ASSERT(array->map() != fixed_cow_array_map());
   Object** dst_objects = array->data_start() + dst_index;
   OS::MemMove(dst_objects,
               array->data_start() + src_index,
@@ -763,9 +765,9 @@
 };
 
 
-static void VerifyStringTable() {
+static void VerifyStringTable(Heap* heap) {
   StringTableVerifier verifier;
-  HEAP->string_table()->IterateElements(&verifier);
+  heap->string_table()->IterateElements(&verifier);
 }
 #endif  // VERIFY_HEAP
 
@@ -920,7 +922,7 @@
 
 #ifdef VERIFY_HEAP
   if (FLAG_verify_heap) {
-    VerifyStringTable();
+    VerifyStringTable(this);
   }
 #endif
 
@@ -1044,7 +1046,7 @@
 
 #ifdef VERIFY_HEAP
   if (FLAG_verify_heap) {
-    VerifyStringTable();
+    VerifyStringTable(this);
   }
 #endif
 
@@ -1152,29 +1154,33 @@
 // new space.
 class VerifyNonPointerSpacePointersVisitor: public ObjectVisitor {
  public:
+  explicit VerifyNonPointerSpacePointersVisitor(Heap* heap) : heap_(heap) {}
   void VisitPointers(Object** start, Object**end) {
     for (Object** current = start; current < end; current++) {
       if ((*current)->IsHeapObject()) {
-        CHECK(!HEAP->InNewSpace(HeapObject::cast(*current)));
+        CHECK(!heap_->InNewSpace(HeapObject::cast(*current)));
       }
     }
   }
+
+ private:
+  Heap* heap_;
 };
 
 
-static void VerifyNonPointerSpacePointers() {
+static void VerifyNonPointerSpacePointers(Heap* heap) {
   // Verify that there are no pointers to new space in spaces where we
   // do not expect them.
-  VerifyNonPointerSpacePointersVisitor v;
-  HeapObjectIterator code_it(HEAP->code_space());
+  VerifyNonPointerSpacePointersVisitor v(heap);
+  HeapObjectIterator code_it(heap->code_space());
   for (HeapObject* object = code_it.Next();
        object != NULL; object = code_it.Next())
     object->Iterate(&v);
 
   // The old data space was normally swept conservatively so that the iterator
   // doesn't work, so we normally skip the next bit.
-  if (!HEAP->old_data_space()->was_swept_conservatively()) {
-    HeapObjectIterator data_it(HEAP->old_data_space());
+  if (!heap->old_data_space()->was_swept_conservatively()) {
+    HeapObjectIterator data_it(heap->old_data_space());
     for (HeapObject* object = data_it.Next();
          object != NULL; object = data_it.Next())
       object->Iterate(&v);
@@ -1321,7 +1327,7 @@
   RelocationLock relocation_lock(this);
 
 #ifdef VERIFY_HEAP
-  if (FLAG_verify_heap) VerifyNonPointerSpacePointers();
+  if (FLAG_verify_heap) VerifyNonPointerSpacePointers(this);
 #endif
 
   gc_state_ = SCAVENGE;
@@ -2375,7 +2381,7 @@
 
 
 void Heap::ScavengeObjectSlow(HeapObject** p, HeapObject* object) {
-  SLOW_ASSERT(HEAP->InFromSpace(object));
+  SLOW_ASSERT(object->GetIsolate()->heap()->InFromSpace(object));
   MapWord first_word = object->map_word();
   SLOW_ASSERT(!first_word.IsForwardingAddress());
   Map* map = first_word.ToMap();
@@ -5762,7 +5768,7 @@
   int hash;
   int attempts = 0;
   do {
-    hash = V8::RandomPrivate(isolate()) & Name::kHashBitMask;
+    hash = isolate()->random_number_generator()->NextInt() & Name::kHashBitMask;
     attempts++;
   } while (hash == 0 && attempts < 30);
   if (hash == 0) hash = 1;  // never return 0
@@ -6927,8 +6933,8 @@
   ASSERT(hash_seed() == 0);
   if (FLAG_randomize_hashes) {
     if (FLAG_hash_seed == 0) {
-      set_hash_seed(
-          Smi::FromInt(V8::RandomPrivate(isolate()) & 0x3fffffff));
+      int rnd = isolate()->random_number_generator()->NextInt();
+      set_hash_seed(Smi::FromInt(rnd & Name::kHashBitMask));
     } else {
       set_hash_seed(Smi::FromInt(FLAG_hash_seed));
     }
@@ -7839,7 +7845,7 @@
 void KeyedLookupCache::Update(Map* map, Name* name, int field_offset) {
   if (!name->IsUniqueName()) {
     String* internalized_string;
-    if (!HEAP->InternalizeStringIfExists(
+    if (!map->GetIsolate()->heap()->InternalizeStringIfExists(
             String::cast(name), &internalized_string)) {
       return;
     }
@@ -7847,7 +7853,7 @@
   }
   // This cache is cleared only between mark compact passes, so we expect the
   // cache to only contain old space names.
-  ASSERT(!HEAP->InNewSpace(name));
+  ASSERT(!map->GetIsolate()->heap()->InNewSpace(name));
 
   int index = (Hash(map, name) & kHashMask);
   // After a GC there will be free slots, so we use them in order (this may
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc
index 2855e8a..4c2e308 100644
--- a/src/hydrogen-instructions.cc
+++ b/src/hydrogen-instructions.cc
@@ -1491,6 +1491,15 @@
 }
 
 
+void HUnknownOSRValue::PrintDataTo(StringStream *stream) {
+  const char* type = "expression";
+  if (environment_->is_local_index(index_)) type = "local";
+  if (environment_->is_special_index(index_)) type = "special";
+  if (environment_->is_parameter_index(index_)) type = "parameter";
+  stream->Add("%s @ %d", type, index_);
+}
+
+
 void HInstanceOf::PrintDataTo(StringStream* stream) {
   left()->PrintNameTo(stream);
   stream->Add(" ");
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index 2bfb284..aa2cdae 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -374,10 +374,6 @@
     return Combine(other).Equals(other);
   }
 
-  bool IsTagged() const {
-    return ((type_ & kTagged) == kTagged);
-  }
-
   bool IsTaggedPrimitive() const {
     return ((type_ & kTaggedPrimitive) == kTaggedPrimitive);
   }
@@ -4988,19 +4984,18 @@
 
 class HUnknownOSRValue V8_FINAL : public HTemplateInstruction<0> {
  public:
-  DECLARE_INSTRUCTION_FACTORY_P0(HUnknownOSRValue)
+  DECLARE_INSTRUCTION_FACTORY_P2(HUnknownOSRValue, HEnvironment*, int);
+
+  virtual void PrintDataTo(StringStream* stream);
 
   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
     return Representation::None();
   }
 
-  void set_incoming_value(HPhi* value) {
-    incoming_value_ = value;
-  }
-
-  HPhi* incoming_value() {
-    return incoming_value_;
-  }
+  void set_incoming_value(HPhi* value) { incoming_value_ = value; }
+  HPhi* incoming_value() { return incoming_value_; }
+  HEnvironment *environment() { return environment_; }
+  int index() { return index_; }
 
   virtual Representation KnownOptimalRepresentation() V8_OVERRIDE {
     if (incoming_value_ == NULL) return Representation::None();
@@ -5010,11 +5005,15 @@
   DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue)
 
  private:
-  HUnknownOSRValue()
-      : incoming_value_(NULL) {
+  HUnknownOSRValue(HEnvironment* environment, int index)
+      : environment_(environment),
+        index_(index),
+        incoming_value_(NULL) {
     set_representation(Representation::Tagged());
   }
 
+  HEnvironment* environment_;
+  int index_;
   HPhi* incoming_value_;
 };
 
diff --git a/src/hydrogen-osr.cc b/src/hydrogen-osr.cc
index bf6233b..6b1df1e 100644
--- a/src/hydrogen-osr.cc
+++ b/src/hydrogen-osr.cc
@@ -80,7 +80,8 @@
   osr_values_ = new(zone) ZoneList<HUnknownOSRValue*>(length, zone);
 
   for (int i = 0; i < first_expression_index; ++i) {
-    HUnknownOSRValue* osr_value = builder_->Add<HUnknownOSRValue>();
+    HUnknownOSRValue* osr_value
+        = builder_->Add<HUnknownOSRValue>(environment, i);
     environment->Bind(i, osr_value);
     osr_values_->Add(osr_value, zone);
   }
@@ -88,12 +89,21 @@
   if (first_expression_index != length) {
     environment->Drop(length - first_expression_index);
     for (int i = first_expression_index; i < length; ++i) {
-      HUnknownOSRValue* osr_value = builder_->Add<HUnknownOSRValue>();
+      HUnknownOSRValue* osr_value
+          = builder_->Add<HUnknownOSRValue>(environment, i);
       environment->Push(osr_value);
       osr_values_->Add(osr_value, zone);
     }
   }
 
+  unoptimized_frame_slots_ =
+      environment->local_count() + environment->push_count();
+
+  // Keep a copy of the old environment, since the OSR values need it
+  // to figure out where exactly they are located in the unoptimized frame.
+  environment = environment->Copy();
+  builder_->current_block()->UpdateEnvironment(environment);
+
   builder_->Add<HSimulate>(osr_entry_id);
   builder_->Add<HOsrEntry>(osr_entry_id);
   HContext* context = builder_->Add<HContext>();
diff --git a/src/hydrogen-osr.h b/src/hydrogen-osr.h
index 0c6b65d..5014a75 100644
--- a/src/hydrogen-osr.h
+++ b/src/hydrogen-osr.h
@@ -40,7 +40,8 @@
 class HOsrBuilder : public ZoneObject {
  public:
   explicit HOsrBuilder(HOptimizedGraphBuilder* builder)
-    : builder_(builder),
+    : unoptimized_frame_slots_(0),
+      builder_(builder),
       osr_entry_(NULL),
       osr_loop_entry_(NULL),
       osr_values_(NULL) { }
@@ -55,10 +56,16 @@
   // Process the OSR values and phis after initial graph optimization.
   void FinishOsrValues();
 
+  // Return the number of slots in the unoptimized frame at the entry to OSR.
+  int UnoptimizedFrameSlots() const {
+    return unoptimized_frame_slots_;
+  }
+
  private:
   HBasicBlock* BuildLoopEntry();
   bool HasOsrEntryAt(IterationStatement* statement);
 
+  int unoptimized_frame_slots_;
   HOptimizedGraphBuilder* builder_;
   HBasicBlock* osr_entry_;
   HBasicBlock* osr_loop_entry_;
diff --git a/src/hydrogen.h b/src/hydrogen.h
index 395d1cd..979a350 100644
--- a/src/hydrogen.h
+++ b/src/hydrogen.h
@@ -553,9 +553,6 @@
   void set_entry(HEnterInlined* entry) { entry_ = entry; }
 
   int length() const { return values_.length(); }
-  bool is_special_index(int i) const {
-    return i >= parameter_count() && i < parameter_count() + specials_count();
-  }
 
   int first_expression_index() const {
     return parameter_count() + specials_count() + local_count();
@@ -674,8 +671,15 @@
   }
 
   bool is_local_index(int i) const {
-    return i >= first_local_index() &&
-           i < first_expression_index();
+    return i >= first_local_index() && i < first_expression_index();
+  }
+
+  bool is_parameter_index(int i) const {
+    return i >= 0 && i < parameter_count();
+  }
+
+  bool is_special_index(int i) const {
+    return i >= parameter_count() && i < parameter_count() + specials_count();
   }
 
   void PrintTo(StringStream* stream);
diff --git a/src/ia32/assembler-ia32.cc b/src/ia32/assembler-ia32.cc
index 7ff6913..e5456da 100644
--- a/src/ia32/assembler-ia32.cc
+++ b/src/ia32/assembler-ia32.cc
@@ -1721,12 +1721,24 @@
 }
 
 
+void Assembler::fadd_i(int i) {
+  EnsureSpace ensure_space(this);
+  emit_farith(0xD8, 0xC0, i);
+}
+
+
 void Assembler::fsub(int i) {
   EnsureSpace ensure_space(this);
   emit_farith(0xDC, 0xE8, i);
 }
 
 
+void Assembler::fsub_i(int i) {
+  EnsureSpace ensure_space(this);
+  emit_farith(0xD8, 0xE0, i);
+}
+
+
 void Assembler::fisub_s(const Operand& adr) {
   EnsureSpace ensure_space(this);
   EMIT(0xDA);
@@ -1752,6 +1764,12 @@
 }
 
 
+void Assembler::fdiv_i(int i) {
+  EnsureSpace ensure_space(this);
+  emit_farith(0xD8, 0xF0, i);
+}
+
+
 void Assembler::faddp(int i) {
   EnsureSpace ensure_space(this);
   emit_farith(0xDE, 0xC0, i);
diff --git a/src/ia32/assembler-ia32.h b/src/ia32/assembler-ia32.h
index 551d031..55eff93 100644
--- a/src/ia32/assembler-ia32.h
+++ b/src/ia32/assembler-ia32.h
@@ -956,10 +956,13 @@
   void fninit();
 
   void fadd(int i);
+  void fadd_i(int i);
   void fsub(int i);
+  void fsub_i(int i);
   void fmul(int i);
   void fmul_i(int i);
   void fdiv(int i);
+  void fdiv_i(int i);
 
   void fisub_s(const Operand& adr);
 
diff --git a/src/ia32/builtins-ia32.cc b/src/ia32/builtins-ia32.cc
index c02726b..a617da7 100644
--- a/src/ia32/builtins-ia32.cc
+++ b/src/ia32/builtins-ia32.cc
@@ -1337,22 +1337,30 @@
     __ CallRuntime(Runtime::kCompileForOnStackReplacement, 1);
   }
 
-  // If the result was -1 it means that we couldn't optimize the
-  // function. Just return and continue in the unoptimized version.
   Label skip;
-  __ cmp(eax, Immediate(Smi::FromInt(-1)));
+  // If the code object is null, just return to the unoptimized code.
+  __ cmp(eax, Immediate(0));
   __ j(not_equal, &skip, Label::kNear);
   __ ret(0);
 
   __ bind(&skip);
-  // Untag the AST id and push it on the stack.
-  __ SmiUntag(eax);
-  __ push(eax);
 
-  // Generate the code for doing the frame-to-frame translation using
-  // the deoptimizer infrastructure.
-  Deoptimizer::EntryGenerator generator(masm, Deoptimizer::OSR);
-  generator.Generate();
+  // Load deoptimization data from the code object.
+  __ mov(ebx, Operand(eax, Code::kDeoptimizationDataOffset - kHeapObjectTag));
+
+  // Load the OSR entrypoint offset from the deoptimization data.
+  __ mov(ebx, Operand(ebx, FixedArray::OffsetOfElementAt(
+      DeoptimizationInputData::kOsrPcOffsetIndex) - kHeapObjectTag));
+  __ SmiUntag(ebx);
+
+  // Compute the target address = code_obj + header_size + osr_offset
+  __ lea(eax, Operand(eax, ebx, times_1, Code::kHeaderSize - kHeapObjectTag));
+
+  // Overwrite the return address on the stack.
+  __ mov(Operand(esp, 0), eax);
+
+  // And "return" to the OSR entry point of the function.
+  __ ret(0);
 }
 
 
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index 7891dc6..7133f3b 100644
--- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc
@@ -4431,7 +4431,7 @@
 
 
 bool CEntryStub::IsPregenerated() {
-  return (!save_doubles_ || ISOLATE->fp_stubs_generated()) &&
+  return (!save_doubles_ || Isolate::Current()->fp_stubs_generated()) &&
           result_size_ == 1;
 }
 
diff --git a/src/ia32/deoptimizer-ia32.cc b/src/ia32/deoptimizer-ia32.cc
index a4f7ee8..13a70af 100644
--- a/src/ia32/deoptimizer-ia32.cc
+++ b/src/ia32/deoptimizer-ia32.cc
@@ -258,192 +258,6 @@
 #endif  // DEBUG
 
 
-static int LookupBailoutId(DeoptimizationInputData* data, BailoutId ast_id) {
-  ByteArray* translations = data->TranslationByteArray();
-  int length = data->DeoptCount();
-  for (int i = 0; i < length; i++) {
-    if (data->AstId(i) == ast_id) {
-      TranslationIterator it(translations,  data->TranslationIndex(i)->value());
-      int value = it.Next();
-      ASSERT(Translation::BEGIN == static_cast<Translation::Opcode>(value));
-      // Read the number of frames.
-      value = it.Next();
-      if (value == 1) return i;
-    }
-  }
-  UNREACHABLE();
-  return -1;
-}
-
-
-void Deoptimizer::DoComputeOsrOutputFrame() {
-  DeoptimizationInputData* data = DeoptimizationInputData::cast(
-      compiled_code_->deoptimization_data());
-  unsigned ast_id = data->OsrAstId()->value();
-  // TODO(kasperl): This should not be the bailout_id_. It should be
-  // the ast id. Confusing.
-  ASSERT(bailout_id_ == ast_id);
-
-  int bailout_id = LookupBailoutId(data, BailoutId(ast_id));
-  unsigned translation_index = data->TranslationIndex(bailout_id)->value();
-  ByteArray* translations = data->TranslationByteArray();
-
-  TranslationIterator iterator(translations, translation_index);
-  Translation::Opcode opcode =
-      static_cast<Translation::Opcode>(iterator.Next());
-  ASSERT(Translation::BEGIN == opcode);
-  USE(opcode);
-  int count = iterator.Next();
-  iterator.Next();  // Drop JS frames count.
-  ASSERT(count == 1);
-  USE(count);
-
-  opcode = static_cast<Translation::Opcode>(iterator.Next());
-  USE(opcode);
-  ASSERT(Translation::JS_FRAME == opcode);
-  unsigned node_id = iterator.Next();
-  USE(node_id);
-  ASSERT(node_id == ast_id);
-  int closure_id = iterator.Next();
-  USE(closure_id);
-  ASSERT_EQ(Translation::kSelfLiteralId, closure_id);
-  unsigned height = iterator.Next();
-  unsigned height_in_bytes = height * kPointerSize;
-  USE(height_in_bytes);
-
-  unsigned fixed_size = ComputeFixedSize(function_);
-  unsigned input_frame_size = input_->GetFrameSize();
-  ASSERT(fixed_size + height_in_bytes == input_frame_size);
-
-  unsigned stack_slot_size = compiled_code_->stack_slots() * kPointerSize;
-  unsigned outgoing_height = data->ArgumentsStackHeight(bailout_id)->value();
-  unsigned outgoing_size = outgoing_height * kPointerSize;
-  unsigned output_frame_size = fixed_size + stack_slot_size + outgoing_size;
-  ASSERT(outgoing_size == 0);  // OSR does not happen in the middle of a call.
-
-  if (FLAG_trace_osr) {
-    PrintF("[on-stack replacement: begin 0x%08" V8PRIxPTR " ",
-           reinterpret_cast<intptr_t>(function_));
-    PrintFunctionName();
-    PrintF(" => node=%u, frame=%d->%d, ebp:esp=0x%08x:0x%08x]\n",
-           ast_id,
-           input_frame_size,
-           output_frame_size,
-           input_->GetRegister(ebp.code()),
-           input_->GetRegister(esp.code()));
-  }
-
-  // There's only one output frame in the OSR case.
-  output_count_ = 1;
-  output_ = new FrameDescription*[1];
-  output_[0] = new(output_frame_size) FrameDescription(
-      output_frame_size, function_);
-  output_[0]->SetFrameType(StackFrame::JAVA_SCRIPT);
-
-  // Clear the incoming parameters in the optimized frame to avoid
-  // confusing the garbage collector.
-  unsigned output_offset = output_frame_size - kPointerSize;
-  int parameter_count = function_->shared()->formal_parameter_count() + 1;
-  for (int i = 0; i < parameter_count; ++i) {
-    output_[0]->SetFrameSlot(output_offset, 0);
-    output_offset -= kPointerSize;
-  }
-
-  // Translate the incoming parameters. This may overwrite some of the
-  // incoming argument slots we've just cleared.
-  int input_offset = input_frame_size - kPointerSize;
-  bool ok = true;
-  int limit = input_offset - (parameter_count * kPointerSize);
-  while (ok && input_offset > limit) {
-    ok = DoOsrTranslateCommand(&iterator, &input_offset);
-  }
-
-  // There are no translation commands for the caller's pc and fp, the
-  // context, and the function.  Set them up explicitly.
-  for (int i =  StandardFrameConstants::kCallerPCOffset;
-       ok && i >=  StandardFrameConstants::kMarkerOffset;
-       i -= kPointerSize) {
-    uint32_t input_value = input_->GetFrameSlot(input_offset);
-    if (FLAG_trace_osr) {
-      const char* name = "UNKNOWN";
-      switch (i) {
-        case StandardFrameConstants::kCallerPCOffset:
-          name = "caller's pc";
-          break;
-        case StandardFrameConstants::kCallerFPOffset:
-          name = "fp";
-          break;
-        case StandardFrameConstants::kContextOffset:
-          name = "context";
-          break;
-        case StandardFrameConstants::kMarkerOffset:
-          name = "function";
-          break;
-      }
-      PrintF("    [sp + %d] <- 0x%08x ; [sp + %d] (fixed part - %s)\n",
-             output_offset,
-             input_value,
-             input_offset,
-             name);
-    }
-    output_[0]->SetFrameSlot(output_offset, input_->GetFrameSlot(input_offset));
-    input_offset -= kPointerSize;
-    output_offset -= kPointerSize;
-  }
-
-  // All OSR stack frames are dynamically aligned to an 8-byte boundary.
-  int frame_pointer = input_->GetRegister(ebp.code());
-  if ((frame_pointer & kPointerSize) != 0) {
-    frame_pointer -= kPointerSize;
-    has_alignment_padding_ = 1;
-  }
-
-  int32_t alignment_state = (has_alignment_padding_ == 1) ?
-    kAlignmentPaddingPushed :
-    kNoAlignmentPadding;
-  if (FLAG_trace_osr) {
-    PrintF("    [sp + %d] <- 0x%08x ; (alignment state)\n",
-           output_offset,
-           alignment_state);
-  }
-  output_[0]->SetFrameSlot(output_offset, alignment_state);
-  output_offset -= kPointerSize;
-
-  // Translate the rest of the frame.
-  while (ok && input_offset >= 0) {
-    ok = DoOsrTranslateCommand(&iterator, &input_offset);
-  }
-
-  // If translation of any command failed, continue using the input frame.
-  if (!ok) {
-    delete output_[0];
-    output_[0] = input_;
-    output_[0]->SetPc(reinterpret_cast<uint32_t>(from_));
-  } else {
-    // Set up the frame pointer and the context pointer.
-    output_[0]->SetRegister(ebp.code(), frame_pointer);
-    output_[0]->SetRegister(esi.code(), input_->GetRegister(esi.code()));
-
-    unsigned pc_offset = data->OsrPcOffset()->value();
-    uint32_t pc = reinterpret_cast<uint32_t>(
-        compiled_code_->entry() + pc_offset);
-    output_[0]->SetPc(pc);
-  }
-  Code* continuation =
-      function_->GetIsolate()->builtins()->builtin(Builtins::kNotifyOSR);
-  output_[0]->SetContinuation(
-      reinterpret_cast<uint32_t>(continuation->entry()));
-
-  if (FLAG_trace_osr) {
-    PrintF("[on-stack replacement translation %s: 0x%08" V8PRIxPTR " ",
-           ok ? "finished" : "aborted",
-           reinterpret_cast<intptr_t>(function_));
-    PrintFunctionName();
-    PrintF(" => pc=0x%0x]\n", output_[0]->GetPc());
-  }
-}
-
-
 void Deoptimizer::FillInputFrame(Address tos, JavaScriptFrame* frame) {
   // Set the register values. The values are not important as there are no
   // callee saved registers in JavaScript frames, so all registers are
@@ -611,27 +425,17 @@
   }
   __ pop(eax);
 
-  if (type() != OSR) {
-    // If frame was dynamically aligned, pop padding.
-    Label no_padding;
-    __ cmp(Operand(eax, Deoptimizer::has_alignment_padding_offset()),
-           Immediate(0));
-    __ j(equal, &no_padding);
-    __ pop(ecx);
-    if (FLAG_debug_code) {
-      __ cmp(ecx, Immediate(kAlignmentZapValue));
-      __ Assert(equal, kAlignmentMarkerExpected);
-    }
-    __ bind(&no_padding);
-  } else {
-    // If frame needs dynamic alignment push padding.
-    Label no_padding;
-    __ cmp(Operand(eax, Deoptimizer::has_alignment_padding_offset()),
-           Immediate(0));
-    __ j(equal, &no_padding);
-    __ push(Immediate(kAlignmentZapValue));
-    __ bind(&no_padding);
+  // If frame was dynamically aligned, pop padding.
+  Label no_padding;
+  __ cmp(Operand(eax, Deoptimizer::has_alignment_padding_offset()),
+         Immediate(0));
+  __ j(equal, &no_padding);
+  __ pop(ecx);
+  if (FLAG_debug_code) {
+    __ cmp(ecx, Immediate(kAlignmentZapValue));
+    __ Assert(equal, kAlignmentMarkerExpected);
   }
+  __ bind(&no_padding);
 
   // Replace the current frame with the output frames.
   Label outer_push_loop, inner_push_loop,
@@ -658,7 +462,7 @@
   __ cmp(eax, edx);
   __ j(below, &outer_push_loop);
 
-  // In case of OSR or a failed STUB, we have to restore the XMM registers.
+  // In case of a failed STUB, we have to restore the XMM registers.
   if (CpuFeatures::IsSupported(SSE2)) {
     CpuFeatureScope scope(masm(), SSE2);
     for (int i = 0; i < XMMRegister::kNumAllocatableRegisters; ++i) {
@@ -669,9 +473,7 @@
   }
 
   // Push state, pc, and continuation from the last output frame.
-  if (type() != OSR) {
-    __ push(Operand(ebx, FrameDescription::state_offset()));
-  }
+  __ push(Operand(ebx, FrameDescription::state_offset()));
   __ push(Operand(ebx, FrameDescription::pc_offset()));
   __ push(Operand(ebx, FrameDescription::continuation_offset()));
 
diff --git a/src/ia32/disasm-ia32.cc b/src/ia32/disasm-ia32.cc
index 293d428..a1d4e9d 100644
--- a/src/ia32/disasm-ia32.cc
+++ b/src/ia32/disasm-ia32.cc
@@ -743,7 +743,14 @@
 
   switch (escape_opcode) {
     case 0xD8:
-      UnimplementedInstruction();
+      has_register = true;
+      switch (modrm_byte & 0xF8) {
+        case 0xC0: mnem = "fadd_i"; break;
+        case 0xE0: mnem = "fsub_i"; break;
+        case 0xC8: mnem = "fmul_i"; break;
+        case 0xF0: mnem = "fdiv_i"; break;
+        default: UnimplementedInstruction();
+      }
       break;
 
     case 0xD9:
@@ -767,6 +774,7 @@
             case 0xEE: mnem = "fldz"; break;
             case 0xF0: mnem = "f2xm1"; break;
             case 0xF1: mnem = "fyl2x"; break;
+            case 0xF4: mnem = "fxtract"; break;
             case 0xF5: mnem = "fprem1"; break;
             case 0xF7: mnem = "fincstp"; break;
             case 0xF8: mnem = "fprem"; break;
@@ -815,6 +823,7 @@
       has_register = true;
       switch (modrm_byte & 0xF8) {
         case 0xC0: mnem = "ffree"; break;
+        case 0xD0: mnem = "fst"; break;
         case 0xD8: mnem = "fstp"; break;
         default: UnimplementedInstruction();
       }
@@ -1448,6 +1457,7 @@
         data += D1D3C1Instruction(data);
         break;
 
+      case 0xD8:  // fall through
       case 0xD9:  // fall through
       case 0xDA:  // fall through
       case 0xDB:  // fall through
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index 32c9f00..860646c 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -35,6 +35,7 @@
 #include "deoptimizer.h"
 #include "stub-cache.h"
 #include "codegen.h"
+#include "hydrogen-osr.h"
 
 namespace v8 {
 namespace internal {
@@ -332,6 +333,28 @@
 }
 
 
+void LCodeGen::GenerateOsrPrologue() {
+  // Generate the OSR entry prologue at the first unknown OSR value, or if there
+  // are none, at the OSR entrypoint instruction.
+  if (osr_pc_offset_ >= 0) return;
+
+  osr_pc_offset_ = masm()->pc_offset();
+
+  // Save the first local, which is overwritten by the alignment state.
+  Operand alignment_loc = MemOperand(ebp, -3 * kPointerSize);
+  __ push(alignment_loc);
+
+  // Set the dynamic frame alignment state to "not aligned".
+  __ mov(alignment_loc, Immediate(kNoAlignmentPadding));
+
+  // Adjust the frame size, subsuming the unoptimized frame into the
+  // optimized frame.
+  int slots = GetStackSlotCount() - graph()->osr()->UnoptimizedFrameSlots();
+  ASSERT(slots >= 1);
+  __ sub(esp, Immediate((slots - 1) * kPointerSize));
+}
+
+
 bool LCodeGen::GenerateBody() {
   ASSERT(is_generating());
   bool emit_instructions = true;
@@ -448,8 +471,8 @@
         Comment(";;; Deferred code");
       }
       code->Generate();
-      __ bind(code->done());
       if (NeedsDeferredFrame()) {
+        __ bind(code->done());
         Comment(";;; Destroy frame");
         ASSERT(frame_is_built_);
         frame_is_built_ = false;
@@ -1317,8 +1340,7 @@
 
 
 void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
-  // Record the address of the first unknown OSR value as the place to enter.
-  if (osr_pc_offset_ == -1) osr_pc_offset_ = masm()->pc_offset();
+  GenerateOsrPrologue();
 }
 
 
@@ -2210,11 +2232,36 @@
     X87Register left = ToX87Register(instr->left());
     X87Register right = ToX87Register(instr->right());
     X87Register result = ToX87Register(instr->result());
-    X87PrepareBinaryOp(left, right, result);
+    if (instr->op() != Token::MOD) {
+      X87PrepareBinaryOp(left, right, result);
+    }
     switch (instr->op()) {
+      case Token::ADD:
+        __ fadd_i(1);
+        break;
+      case Token::SUB:
+        __ fsub_i(1);
+        break;
       case Token::MUL:
         __ fmul_i(1);
         break;
+      case Token::DIV:
+        __ fdiv_i(1);
+        break;
+      case Token::MOD: {
+        // Pass two doubles as arguments on the stack.
+        __ PrepareCallCFunction(4, eax);
+        X87Mov(Operand(esp, 1 * kDoubleSize), right);
+        X87Mov(Operand(esp, 0), left);
+        X87PrepareToWrite(result);
+        __ CallCFunction(
+            ExternalReference::double_fp_operation(Token::MOD, isolate()),
+            4);
+
+        // Return value is in st(0) on ia32.
+        X87CommitWrite(result);
+        break;
+      }
       default:
         UNREACHABLE();
         break;
@@ -6214,9 +6261,7 @@
   ASSERT(!environment->HasBeenRegistered());
   RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
 
-  // Normally we record the first unknown OSR value as the entrypoint to the OSR
-  // code, but if there were none, record the entrypoint here.
-  if (osr_pc_offset_ == -1) osr_pc_offset_ = masm()->pc_offset();
+  GenerateOsrPrologue();
 }
 
 
diff --git a/src/ia32/lithium-codegen-ia32.h b/src/ia32/lithium-codegen-ia32.h
index 23b2e48..cc1747d 100644
--- a/src/ia32/lithium-codegen-ia32.h
+++ b/src/ia32/lithium-codegen-ia32.h
@@ -233,6 +233,9 @@
   bool GenerateJumpTable();
   bool GenerateSafepointTable();
 
+  // Generates the custom OSR entrypoint and sets the osr_pc_offset.
+  void GenerateOsrPrologue();
+
   enum SafepointMode {
     RECORD_SIMPLE_SAFEPOINT,
     RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS
@@ -548,7 +551,7 @@
   void SetExit(Label* exit) { external_exit_ = exit; }
   Label* entry() { return &entry_; }
   Label* exit() { return external_exit_ != NULL ? external_exit_ : &exit_; }
-  Label* done() { return &done_; }
+  Label* done() { return codegen_->NeedsDeferredFrame() ? &done_ : exit(); }
   int instruction_index() const { return instruction_index_; }
   const LCodeGen::X87Stack& x87_stack() const { return x87_stack_; }
 
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
index 8d66085..07dbf13 100644
--- a/src/ia32/lithium-ia32.cc
+++ b/src/ia32/lithium-ia32.cc
@@ -32,6 +32,7 @@
 #include "lithium-allocator-inl.h"
 #include "ia32/lithium-ia32.h"
 #include "ia32/lithium-codegen-ia32.h"
+#include "hydrogen-osr.h"
 
 namespace v8 {
 namespace internal {
@@ -483,6 +484,14 @@
     USE(alignment_state_index);
   }
 
+  // If compiling for OSR, reserve space for the unoptimized frame,
+  // which will be subsumed into this frame.
+  if (graph()->has_osr()) {
+    for (int i = graph()->osr()->UnoptimizedFrameSlots(); i > 0; i--) {
+      chunk_->GetNextSpillIndex(false);
+    }
+  }
+
   const ZoneList<HBasicBlock*>* blocks = graph()->blocks();
   for (int i = 0; i < blocks->length(); i++) {
     HBasicBlock* next = NULL;
@@ -2537,10 +2546,23 @@
 
 
 LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
-  int spill_index = chunk()->GetNextSpillIndex(false);  // Not double-width.
-  if (spill_index > LUnallocated::kMaxFixedSlotIndex) {
-    Abort(kTooManySpillSlotsNeededForOSR);
-    spill_index = 0;
+  // Use an index that corresponds to the location in the unoptimized frame,
+  // which the optimized frame will subsume.
+  int env_index = instr->index();
+  int spill_index = 0;
+  if (instr->environment()->is_parameter_index(env_index)) {
+    spill_index = chunk()->GetParameterStackSlot(env_index);
+  } else {
+    spill_index = env_index - instr->environment()->first_local_index();
+    if (spill_index > LUnallocated::kMaxFixedSlotIndex) {
+      Abort(kNotEnoughSpillSlotsForOsr);
+      spill_index = 0;
+    }
+    if (spill_index == 0) {
+      // The dynamic frame alignment state overwrites the first local.
+      // The first local is saved at the end of the unoptimized frame.
+      spill_index = graph()->osr()->UnoptimizedFrameSlots();
+    }
   }
   return DefineAsSpilled(new(zone()) LUnknownOSRValue, spill_index);
 }
diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc
index 065f02c..fbfe9dd 100644
--- a/src/ia32/macro-assembler-ia32.cc
+++ b/src/ia32/macro-assembler-ia32.cc
@@ -282,20 +282,25 @@
                                Label* conversion_failed,
                                Label::Distance dst) {
   ASSERT(!input_reg.is(scratch));
-  Label done;
   cvttsd2si(result_reg, Operand(input_reg));
   cvtsi2sd(scratch, Operand(result_reg));
   ucomisd(scratch, input_reg);
   j(not_equal, conversion_failed, dst);
   j(parity_even, conversion_failed, dst);  // NaN.
   if (minus_zero_mode == FAIL_ON_MINUS_ZERO) {
+    Label done;
+    // The integer converted back is equal to the original. We
+    // only have to test if we got -0 as an input.
     test(result_reg, Operand(result_reg));
     j(not_zero, &done, Label::kNear);
     movmskpd(result_reg, input_reg);
+    // Bit 0 contains the sign of the double in input_reg.
+    // If input was positive, we are ok and return 0, otherwise
+    // jump to conversion_failed.
     and_(result_reg, 1);
     j(not_zero, conversion_failed, dst);
+    bind(&done);
   }
-  bind(&done);
 }
 
 
diff --git a/src/isolate-inl.h b/src/isolate-inl.h
index 5e2c8c2..45076f5 100644
--- a/src/isolate-inl.h
+++ b/src/isolate-inl.h
@@ -28,9 +28,9 @@
 #ifndef V8_ISOLATE_INL_H_
 #define V8_ISOLATE_INL_H_
 
-#include "isolate.h"
-
 #include "debug.h"
+#include "isolate.h"
+#include "utils/random-number-generator.h"
 
 namespace v8 {
 namespace internal {
@@ -67,6 +67,13 @@
 }
 
 
+RandomNumberGenerator* Isolate::random_number_generator() {
+  if (random_number_generator_ == NULL) {
+    random_number_generator_ = new RandomNumberGenerator;
+  }
+  return random_number_generator_;
+}
+
 } }  // namespace v8::internal
 
 #endif  // V8_ISOLATE_INL_H_
diff --git a/src/isolate.cc b/src/isolate.cc
index 74a77c6..8e58135 100644
--- a/src/isolate.cc
+++ b/src/isolate.cc
@@ -39,7 +39,7 @@
 #include "deoptimizer.h"
 #include "heap-profiler.h"
 #include "hydrogen.h"
-#include "isolate.h"
+#include "isolate-inl.h"
 #include "lithium-allocator.h"
 #include "log.h"
 #include "marking-thread.h"
@@ -54,6 +54,7 @@
 #include "spaces.h"
 #include "stub-cache.h"
 #include "sweeper-thread.h"
+#include "utils/random-number-generator.h"
 #include "version.h"
 #include "vm-state-inl.h"
 
@@ -1772,6 +1773,10 @@
       regexp_stack_(NULL),
       date_cache_(NULL),
       code_stub_interface_descriptors_(NULL),
+      // TODO(bmeurer) Initialized lazily because it depends on flags; can
+      // be fixed once the default isolate cleanup is done.
+      random_number_generator_(NULL),
+      is_memory_constrained_(false),
       has_fatal_error_(false),
       use_crankshaft_(true),
       initialized_from_snapshot_(false),
@@ -2047,6 +2052,9 @@
   delete external_reference_table_;
   external_reference_table_ = NULL;
 
+  delete random_number_generator_;
+  random_number_generator_ = NULL;
+
 #ifdef ENABLE_DEBUGGER_SUPPORT
   delete debugger_;
   debugger_ = NULL;
diff --git a/src/isolate.h b/src/isolate.h
index f0854e5..99283c9 100644
--- a/src/isolate.h
+++ b/src/isolate.h
@@ -77,6 +77,7 @@
 class InnerPointerToCodeCache;
 class MarkingThread;
 class PreallocatedMemoryThread;
+class RandomNumberGenerator;
 class RegExpStack;
 class SaveContext;
 class UnicodeCache;
@@ -1125,9 +1126,18 @@
 
   void* stress_deopt_count_address() { return &stress_deopt_count_; }
 
+  inline RandomNumberGenerator* random_number_generator();
+
   // Given an address occupied by a live code object, return that object.
   Object* FindCodeObject(Address a);
 
+  bool is_memory_constrained() const {
+    return is_memory_constrained_;
+  }
+  void set_is_memory_constrained(bool value) {
+    is_memory_constrained_ = value;
+  }
+
  private:
   Isolate();
 
@@ -1299,6 +1309,8 @@
   DateCache* date_cache_;
   unibrow::Mapping<unibrow::Ecma262Canonicalize> interp_canonicalize_mapping_;
   CodeStubInterfaceDescriptor* code_stub_interface_descriptors_;
+  RandomNumberGenerator* random_number_generator_;
+  bool is_memory_constrained_;
 
   // True if fatal error has been signaled for this isolate.
   bool has_fatal_error_;
@@ -1506,12 +1518,6 @@
 };
 
 
-// Temporary macros for accessing current isolate and its subobjects.
-// They provide better readability, especially when used a lot in the code.
-#define HEAP (v8::internal::Isolate::Current()->heap())
-#define ISOLATE (v8::internal::Isolate::Current())
-
-
 // Tells whether the native context is marked with out of memory.
 inline bool Context::has_out_of_memory() {
   return native_context()->out_of_memory()->IsTrue();
@@ -1520,7 +1526,7 @@
 
 // Mark the native context with out of memory.
 inline void Context::mark_out_of_memory() {
-  native_context()->set_out_of_memory(HEAP->true_value());
+  native_context()->set_out_of_memory(GetIsolate()->heap()->true_value());
 }
 
 
diff --git a/src/json-stringifier.h b/src/json-stringifier.h
index 155ae5f..0d17b35 100644
--- a/src/json-stringifier.h
+++ b/src/json-stringifier.h
@@ -835,14 +835,14 @@
 void BasicJsonStringifier::SerializeString(Handle<String> object) {
   object = FlattenGetString(object);
   if (is_ascii_) {
-    if (object->IsOneByteRepresentation()) {
+    if (object->IsOneByteRepresentationUnderneath()) {
       SerializeString_<true, uint8_t>(object);
     } else {
       ChangeEncoding();
       SerializeString(object);
     }
   } else {
-    if (object->IsOneByteRepresentation()) {
+    if (object->IsOneByteRepresentationUnderneath()) {
       SerializeString_<false, uint8_t>(object);
     } else {
       SerializeString_<false, uc16>(object);
diff --git a/src/jsregexp.cc b/src/jsregexp.cc
index 5c79477..f1cb96d 100644
--- a/src/jsregexp.cc
+++ b/src/jsregexp.cc
@@ -5834,7 +5834,7 @@
         if (bm->compiler()->ignore_case()) {
           unibrow::uchar chars[unibrow::Ecma262UnCanonicalize::kMaxWidth];
           int length = GetCaseIndependentLetters(
-              ISOLATE,
+              Isolate::Current(),
               character,
               bm->max_char() == String::kMaxOneByteCharCode,
               chars);
diff --git a/src/jsregexp.h b/src/jsregexp.h
index bab8756..01ceaf4 100644
--- a/src/jsregexp.h
+++ b/src/jsregexp.h
@@ -1617,7 +1617,7 @@
   struct CompilationResult {
     explicit CompilationResult(const char* error_message)
         : error_message(error_message),
-          code(HEAP->the_hole_value()),
+          code(Isolate::Current()->heap()->the_hole_value()),
           num_registers(0) {}
     CompilationResult(Object* code, int registers)
       : error_message(NULL),
diff --git a/src/liveedit.cc b/src/liveedit.cc
index c0da38c..feaafd4 100644
--- a/src/liveedit.cc
+++ b/src/liveedit.cc
@@ -1233,7 +1233,9 @@
   DeoptimizationInputData* data =
       DeoptimizationInputData::cast(function->code()->deoptimization_data());
 
-  if (data == HEAP->empty_fixed_array()) return false;
+  if (data == function->GetIsolate()->heap()->empty_fixed_array()) {
+    return false;
+  }
 
   FixedArray* literals = data->LiteralArray();
 
@@ -1549,7 +1551,7 @@
   info->set_end_position(new_function_end);
   info->set_function_token_position(new_function_token_pos);
 
-  HEAP->EnsureHeapIsIterable();
+  info->GetIsolate()->heap()->EnsureHeapIsIterable();
 
   if (IsJSFunctionCode(info->code())) {
     // Patch relocation info section of the code.
@@ -1565,7 +1567,7 @@
     }
   }
 
-  return HEAP->undefined_value();
+  return info->GetIsolate()->heap()->undefined_value();
 }
 
 
@@ -1611,7 +1613,7 @@
   original_script->set_source(*new_source);
 
   // Drop line ends so that they will be recalculated.
-  original_script->set_line_ends(HEAP->undefined_value());
+  original_script->set_line_ends(isolate->heap()->undefined_value());
 
   return *old_script_object;
 }
diff --git a/src/log.cc b/src/log.cc
index 1b3301e..7d1861e 100644
--- a/src/log.cc
+++ b/src/log.cc
@@ -686,7 +686,7 @@
   Insert(&sample);
   Join();
 
-  LOG(ISOLATE, UncheckedStringEvent("profiler", "end"));
+  LOG(isolate_, UncheckedStringEvent("profiler", "end"));
 }
 
 
diff --git a/src/mark-compact-inl.h b/src/mark-compact-inl.h
index 10773e7..321309c 100644
--- a/src/mark-compact-inl.h
+++ b/src/mark-compact-inl.h
@@ -58,7 +58,7 @@
     mark_bit.Set();
     MemoryChunk::IncrementLiveBytesFromGC(obj->address(), obj->Size());
     ASSERT(IsMarked(obj));
-    ASSERT(HEAP->Contains(obj));
+    ASSERT(obj->GetIsolate()->heap()->Contains(obj));
     marking_deque_.PushBlack(obj);
   }
 }
diff --git a/src/mark-compact.cc b/src/mark-compact.cc
index b93460d..17ac4a8 100644
--- a/src/mark-compact.cc
+++ b/src/mark-compact.cc
@@ -79,11 +79,13 @@
 #ifdef VERIFY_HEAP
 class VerifyMarkingVisitor: public ObjectVisitor {
  public:
+  explicit VerifyMarkingVisitor(Heap* heap) : heap_(heap) {}
+
   void VisitPointers(Object** start, Object** end) {
     for (Object** current = start; current < end; current++) {
       if ((*current)->IsHeapObject()) {
         HeapObject* object = HeapObject::cast(*current);
-        CHECK(HEAP->mark_compact_collector()->IsMarked(object));
+        CHECK(heap_->mark_compact_collector()->IsMarked(object));
       }
     }
   }
@@ -97,11 +99,14 @@
       VisitPointer(rinfo->target_object_address());
     }
   }
+
+ private:
+  Heap* heap_;
 };
 
 
-static void VerifyMarking(Address bottom, Address top) {
-  VerifyMarkingVisitor visitor;
+static void VerifyMarking(Heap* heap, Address bottom, Address top) {
+  VerifyMarkingVisitor visitor(heap);
   HeapObject* object;
   Address next_object_must_be_here_or_later = bottom;
 
@@ -129,7 +134,7 @@
     NewSpacePage* page = it.next();
     Address limit = it.has_next() ? page->area_end() : end;
     CHECK(limit == end || !page->Contains(end));
-    VerifyMarking(page->area_start(), limit);
+    VerifyMarking(space->heap(), page->area_start(), limit);
   }
 }
 
@@ -139,7 +144,7 @@
 
   while (it.has_next()) {
     Page* p = it.next();
-    VerifyMarking(p->area_start(), p->area_end());
+    VerifyMarking(space->heap(), p->area_start(), p->area_end());
   }
 }
 
@@ -153,7 +158,7 @@
   VerifyMarking(heap->map_space());
   VerifyMarking(heap->new_space());
 
-  VerifyMarkingVisitor visitor;
+  VerifyMarkingVisitor visitor(heap);
 
   LargeObjectIterator it(heap->lo_space());
   for (HeapObject* obj = it.Next(); obj != NULL; obj = it.Next()) {
@@ -1409,7 +1414,7 @@
                                          HeapObject* obj)) {
 #ifdef DEBUG
     ASSERT(collector->heap()->Contains(obj));
-    ASSERT(!HEAP->mark_compact_collector()->IsMarked(obj));
+    ASSERT(!collector->heap()->mark_compact_collector()->IsMarked(obj));
 #endif
     Map* map = obj->map();
     Heap* heap = obj->GetHeap();
diff --git a/src/mips/builtins-mips.cc b/src/mips/builtins-mips.cc
index f3c219e..1a5b302 100644
--- a/src/mips/builtins-mips.cc
+++ b/src/mips/builtins-mips.cc
@@ -1009,18 +1009,26 @@
     __ CallRuntime(Runtime::kCompileForOnStackReplacement, 1);
   }
 
-  // If the result was -1 it means that we couldn't optimize the
-  // function. Just return and continue in the unoptimized version.
-  __ Ret(eq, v0, Operand(Smi::FromInt(-1)));
+  // If the code object is null, just return to the unoptimized code.
+  __ Ret(eq, v0, Operand(Smi::FromInt(0)));
 
-  // Untag the AST id and push it on the stack.
-  __ SmiUntag(v0);
-  __ push(v0);
+  // Load deoptimization data from the code object.
+  // <deopt_data> = <code>[#deoptimization_data_offset]
+  __ lw(a1, MemOperand(v0, Code::kDeoptimizationDataOffset - kHeapObjectTag));
 
-  // Generate the code for doing the frame-to-frame translation using
-  // the deoptimizer infrastructure.
-  Deoptimizer::EntryGenerator generator(masm, Deoptimizer::OSR);
-  generator.Generate();
+  // Load the OSR entrypoint offset from the deoptimization data.
+  // <osr_offset> = <deopt_data>[#header_size + #osr_pc_offset]
+  __ lw(a1, MemOperand(a1, FixedArray::OffsetOfElementAt(
+      DeoptimizationInputData::kOsrPcOffsetIndex) - kHeapObjectTag));
+  __ SmiUntag(a1);
+
+  // Compute the target address = code_obj + header_size + osr_offset
+  // <entry_addr> = <code_obj> + #header_size + <osr_offset>
+  __ addu(v0, v0, a1);
+  __ addiu(ra, v0, Code::kHeaderSize - kHeapObjectTag);
+
+  // And "return" to the OSR entry point of the function.
+  __ Ret();
 }
 
 
diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc
index ff15738..752a24c 100644
--- a/src/mips/code-stubs-mips.cc
+++ b/src/mips/code-stubs-mips.cc
@@ -2724,7 +2724,7 @@
 
 
 bool CEntryStub::IsPregenerated() {
-  return (!save_doubles_ || ISOLATE->fp_stubs_generated()) &&
+  return (!save_doubles_ || Isolate::Current()->fp_stubs_generated()) &&
           result_size_ == 1;
 }
 
diff --git a/src/mips/deoptimizer-mips.cc b/src/mips/deoptimizer-mips.cc
index bed6e12..16f75b8 100644
--- a/src/mips/deoptimizer-mips.cc
+++ b/src/mips/deoptimizer-mips.cc
@@ -160,169 +160,6 @@
 #endif  // DEBUG
 
 
-static int LookupBailoutId(DeoptimizationInputData* data, BailoutId ast_id) {
-  ByteArray* translations = data->TranslationByteArray();
-  int length = data->DeoptCount();
-  for (int i = 0; i < length; i++) {
-    if (data->AstId(i) == ast_id) {
-      TranslationIterator it(translations,  data->TranslationIndex(i)->value());
-      int value = it.Next();
-      ASSERT(Translation::BEGIN == static_cast<Translation::Opcode>(value));
-      // Read the number of frames.
-      value = it.Next();
-      if (value == 1) return i;
-    }
-  }
-  UNREACHABLE();
-  return -1;
-}
-
-
-void Deoptimizer::DoComputeOsrOutputFrame() {
-  DeoptimizationInputData* data = DeoptimizationInputData::cast(
-      compiled_code_->deoptimization_data());
-  unsigned ast_id = data->OsrAstId()->value();
-
-  int bailout_id = LookupBailoutId(data, BailoutId(ast_id));
-  unsigned translation_index = data->TranslationIndex(bailout_id)->value();
-  ByteArray* translations = data->TranslationByteArray();
-
-  TranslationIterator iterator(translations, translation_index);
-  Translation::Opcode opcode =
-      static_cast<Translation::Opcode>(iterator.Next());
-  ASSERT(Translation::BEGIN == opcode);
-  USE(opcode);
-  int count = iterator.Next();
-  iterator.Skip(1);  // Drop JS frame count.
-  ASSERT(count == 1);
-  USE(count);
-
-  opcode = static_cast<Translation::Opcode>(iterator.Next());
-  USE(opcode);
-  ASSERT(Translation::JS_FRAME == opcode);
-  unsigned node_id = iterator.Next();
-  USE(node_id);
-  ASSERT(node_id == ast_id);
-  int closure_id = iterator.Next();
-  USE(closure_id);
-  ASSERT_EQ(Translation::kSelfLiteralId, closure_id);
-  unsigned height = iterator.Next();
-  unsigned height_in_bytes = height * kPointerSize;
-  USE(height_in_bytes);
-
-  unsigned fixed_size = ComputeFixedSize(function_);
-  unsigned input_frame_size = input_->GetFrameSize();
-  ASSERT(fixed_size + height_in_bytes == input_frame_size);
-
-  unsigned stack_slot_size = compiled_code_->stack_slots() * kPointerSize;
-  unsigned outgoing_height = data->ArgumentsStackHeight(bailout_id)->value();
-  unsigned outgoing_size = outgoing_height * kPointerSize;
-  unsigned output_frame_size = fixed_size + stack_slot_size + outgoing_size;
-  ASSERT(outgoing_size == 0);  // OSR does not happen in the middle of a call.
-
-  if (FLAG_trace_osr) {
-    PrintF("[on-stack replacement: begin 0x%08" V8PRIxPTR " ",
-           reinterpret_cast<intptr_t>(function_));
-    PrintFunctionName();
-    PrintF(" => node=%u, frame=%d->%d]\n",
-           ast_id,
-           input_frame_size,
-           output_frame_size);
-  }
-
-  // There's only one output frame in the OSR case.
-  output_count_ = 1;
-  output_ = new FrameDescription*[1];
-  output_[0] = new(output_frame_size) FrameDescription(
-      output_frame_size, function_);
-  output_[0]->SetFrameType(StackFrame::JAVA_SCRIPT);
-
-  // Clear the incoming parameters in the optimized frame to avoid
-  // confusing the garbage collector.
-  unsigned output_offset = output_frame_size - kPointerSize;
-  int parameter_count = function_->shared()->formal_parameter_count() + 1;
-  for (int i = 0; i < parameter_count; ++i) {
-    output_[0]->SetFrameSlot(output_offset, 0);
-    output_offset -= kPointerSize;
-  }
-
-  // Translate the incoming parameters. This may overwrite some of the
-  // incoming argument slots we've just cleared.
-  int input_offset = input_frame_size - kPointerSize;
-  bool ok = true;
-  int limit = input_offset - (parameter_count * kPointerSize);
-  while (ok && input_offset > limit) {
-    ok = DoOsrTranslateCommand(&iterator, &input_offset);
-  }
-
-  // There are no translation commands for the caller's pc and fp, the
-  // context, and the function.  Set them up explicitly.
-  for (int i =  StandardFrameConstants::kCallerPCOffset;
-       ok && i >=  StandardFrameConstants::kMarkerOffset;
-       i -= kPointerSize) {
-    uint32_t input_value = input_->GetFrameSlot(input_offset);
-    if (FLAG_trace_osr) {
-      const char* name = "UNKNOWN";
-      switch (i) {
-        case StandardFrameConstants::kCallerPCOffset:
-          name = "caller's pc";
-          break;
-        case StandardFrameConstants::kCallerFPOffset:
-          name = "fp";
-          break;
-        case StandardFrameConstants::kContextOffset:
-          name = "context";
-          break;
-        case StandardFrameConstants::kMarkerOffset:
-          name = "function";
-          break;
-      }
-      PrintF("    [sp + %d] <- 0x%08x ; [sp + %d] (fixed part - %s)\n",
-             output_offset,
-             input_value,
-             input_offset,
-             name);
-    }
-
-    output_[0]->SetFrameSlot(output_offset, input_->GetFrameSlot(input_offset));
-    input_offset -= kPointerSize;
-    output_offset -= kPointerSize;
-  }
-
-  // Translate the rest of the frame.
-  while (ok && input_offset >= 0) {
-    ok = DoOsrTranslateCommand(&iterator, &input_offset);
-  }
-
-  // If translation of any command failed, continue using the input frame.
-  if (!ok) {
-    delete output_[0];
-    output_[0] = input_;
-    output_[0]->SetPc(reinterpret_cast<uint32_t>(from_));
-  } else {
-    // Set up the frame pointer and the context pointer.
-    output_[0]->SetRegister(fp.code(), input_->GetRegister(fp.code()));
-    output_[0]->SetRegister(cp.code(), input_->GetRegister(cp.code()));
-
-    unsigned pc_offset = data->OsrPcOffset()->value();
-    uint32_t pc = reinterpret_cast<uint32_t>(
-        compiled_code_->entry() + pc_offset);
-    output_[0]->SetPc(pc);
-  }
-  Code* continuation = isolate_->builtins()->builtin(Builtins::kNotifyOSR);
-  output_[0]->SetContinuation(
-      reinterpret_cast<uint32_t>(continuation->entry()));
-
-  if (FLAG_trace_osr) {
-    PrintF("[on-stack replacement translation %s: 0x%08" V8PRIxPTR " ",
-           ok ? "finished" : "aborted",
-           reinterpret_cast<intptr_t>(function_));
-    PrintFunctionName();
-    PrintF(" => pc=0x%0x]\n", output_[0]->GetPc());
-  }
-}
-
-
 void Deoptimizer::FillInputFrame(Address tos, JavaScriptFrame* frame) {
   // Set the register values. The values are not important as there are no
   // callee saved registers in JavaScript frames, so all registers are
@@ -537,10 +374,8 @@
   }
 
   // Push state, pc, and continuation from the last output frame.
-  if (type() != OSR) {
-    __ lw(t2, MemOperand(a2, FrameDescription::state_offset()));
-    __ push(t2);
-  }
+  __ lw(t2, MemOperand(a2, FrameDescription::state_offset()));
+  __ push(t2);
 
   __ lw(t2, MemOperand(a2, FrameDescription::pc_offset()));
   __ push(t2);
diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc
index d346428..ab713a3 100644
--- a/src/mips/lithium-codegen-mips.cc
+++ b/src/mips/lithium-codegen-mips.cc
@@ -31,6 +31,7 @@
 #include "mips/lithium-gap-resolver-mips.h"
 #include "code-stubs.h"
 #include "stub-cache.h"
+#include "hydrogen-osr.h"
 
 namespace v8 {
 namespace internal {
@@ -247,6 +248,21 @@
 }
 
 
+void LCodeGen::GenerateOsrPrologue() {
+  // Generate the OSR entry prologue at the first unknown OSR value, or if there
+  // are none, at the OSR entrypoint instruction.
+  if (osr_pc_offset_ >= 0) return;
+
+  osr_pc_offset_ = masm()->pc_offset();
+
+  // Adjust the frame size, subsuming the unoptimized frame into the
+  // optimized frame.
+  int slots = GetStackSlotCount() - graph()->osr()->UnoptimizedFrameSlots();
+  ASSERT(slots >= 0);
+  __ Subu(sp, sp, Operand(slots * kPointerSize));
+}
+
+
 bool LCodeGen::GenerateBody() {
   ASSERT(is_generating());
   bool emit_instructions = true;
@@ -1071,8 +1087,7 @@
 
 
 void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
-  // Record the address of the first unknown OSR value as the place to enter.
-  if (osr_pc_offset_ == -1) osr_pc_offset_ = masm()->pc_offset();
+  GenerateOsrPrologue();
 }
 
 
@@ -5681,9 +5696,7 @@
   ASSERT(!environment->HasBeenRegistered());
   RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
 
-  // Normally we record the first unknown OSR value as the entrypoint to the OSR
-  // code, but if there were none, record the entrypoint here.
-  if (osr_pc_offset_ == -1) osr_pc_offset_ = masm()->pc_offset();
+  GenerateOsrPrologue();
 }
 
 
diff --git a/src/mips/lithium-codegen-mips.h b/src/mips/lithium-codegen-mips.h
index 13b5804..8437435 100644
--- a/src/mips/lithium-codegen-mips.h
+++ b/src/mips/lithium-codegen-mips.h
@@ -227,6 +227,9 @@
   bool GenerateDeoptJumpTable();
   bool GenerateSafepointTable();
 
+  // Generates the custom OSR entrypoint and sets the osr_pc_offset.
+  void GenerateOsrPrologue();
+
   enum SafepointMode {
     RECORD_SIMPLE_SAFEPOINT,
     RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS
diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc
index 695a058..9476f4d 100644
--- a/src/mips/lithium-mips.cc
+++ b/src/mips/lithium-mips.cc
@@ -30,6 +30,7 @@
 #include "lithium-allocator-inl.h"
 #include "mips/lithium-mips.h"
 #include "mips/lithium-codegen-mips.h"
+#include "hydrogen-osr.h"
 
 namespace v8 {
 namespace internal {
@@ -438,6 +439,15 @@
   chunk_ = new(zone()) LPlatformChunk(info(), graph());
   LPhase phase("L_Building chunk", chunk_);
   status_ = BUILDING;
+
+  // If compiling for OSR, reserve space for the unoptimized frame,
+  // which will be subsumed into this frame.
+  if (graph()->has_osr()) {
+    for (int i = graph()->osr()->UnoptimizedFrameSlots(); i > 0; i--) {
+      chunk_->GetNextSpillIndex(false);
+    }
+  }
+
   const ZoneList<HBasicBlock*>* blocks = graph()->blocks();
   for (int i = 0; i < blocks->length(); i++) {
     HBasicBlock* next = NULL;
@@ -2341,10 +2351,18 @@
 
 
 LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
-  int spill_index = chunk()->GetNextSpillIndex(false);  // Not double-width.
-  if (spill_index > LUnallocated::kMaxFixedSlotIndex) {
-    Abort(kTooManySpillSlotsNeededForOSR);
-    spill_index = 0;
+  // Use an index that corresponds to the location in the unoptimized frame,
+  // which the optimized frame will subsume.
+  int env_index = instr->index();
+  int spill_index = 0;
+  if (instr->environment()->is_parameter_index(env_index)) {
+    spill_index = chunk()->GetParameterStackSlot(env_index);
+  } else {
+    spill_index = env_index - instr->environment()->first_local_index();
+    if (spill_index > LUnallocated::kMaxFixedSlotIndex) {
+      Abort(kTooManySpillSlotsNeededForOSR);
+      spill_index = 0;
+    }
   }
   return DefineAsSpilled(new(zone()) LUnknownOSRValue, spill_index);
 }
diff --git a/src/mksnapshot.cc b/src/mksnapshot.cc
index 156cd77..efd6e79 100644
--- a/src/mksnapshot.cc
+++ b/src/mksnapshot.cc
@@ -397,7 +397,8 @@
   }
   // If we don't do this then we end up with a stray root pointing at the
   // context even after we have disposed of the context.
-  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags, "mksnapshot");
+  internal_isolate->heap()->CollectAllGarbage(
+      i::Heap::kNoGCFlags, "mksnapshot");
   i::Object* raw_context = *v8::Utils::OpenPersistent(context);
   context.Dispose();
   CppByteSink sink(argv[1]);
diff --git a/src/object-observe.js b/src/object-observe.js
index f5e0d9d..81385c3 100644
--- a/src/object-observe.js
+++ b/src/object-observe.js
@@ -27,12 +27,41 @@
 
 "use strict";
 
+// Overview:
+//
+// This file contains all of the routing and accounting for Object.observe.
+// User code will interact with these mechanisms via the Object.observe APIs
+// and, as a side effect of mutation objects which are observed. The V8 runtime
+// (both C++ and JS) will interact with these mechanisms primarily by enqueuing
+// proper change records for objects which were mutated. The Object.observe
+// routing and accounting consists primarily of three participants
+//
+// 1) ObjectInfo. This represents the observed state of a given object. It
+//    records what callbacks are observing the object, with what options, and
+//    what "change types" are in progress on the object (i.e. via
+//    notifier.performChange).
+//
+// 2) CallbackInfo. This represents a callback used for observation. It holds
+//    the records which must be delivered to the callback, as well as the global
+//    priority of the callback (which determines delivery order between
+//    callbacks).
+//
+// 3) observationState.pendingObservers. This is the set of observers which
+//    have change records which must be delivered. During "normal" delivery
+//    (i.e. not Object.deliverChangeRecords), this is the mechanism by which
+//    callbacks are invoked in the proper order until there are no more
+//    change records pending to a callback.
+//
+// Note that in order to reduce allocation and processing costs, the
+// implementation of (1) and (2) have "optimized" states which represent
+// common cases which can be handled more efficiently.
+
 var observationState = %GetObservationState();
 if (IS_UNDEFINED(observationState.callbackInfoMap)) {
   observationState.callbackInfoMap = %ObservationWeakMapCreate();
   observationState.objectInfoMap = %ObservationWeakMapCreate();
-  observationState.notifierTargetMap = %ObservationWeakMapCreate();
-  observationState.pendingObservers = new InternalArray;
+  observationState.notifierObjectInfoMap = %ObservationWeakMapCreate();
+  observationState.pendingObservers = null;
   observationState.nextCallbackPriority = 0;
 }
 
@@ -59,126 +88,191 @@
 var callbackInfoMap =
     new ObservationWeakMap(observationState.callbackInfoMap);
 var objectInfoMap = new ObservationWeakMap(observationState.objectInfoMap);
-var notifierTargetMap =
-    new ObservationWeakMap(observationState.notifierTargetMap);
+var notifierObjectInfoMap =
+    new ObservationWeakMap(observationState.notifierObjectInfoMap);
 
-function CreateObjectInfo(object) {
-  var info = {
-    changeObservers: new InternalArray,
-    notifier: null,
-    inactiveObservers: new InternalArray,
-    performing: { __proto__: null },
-    performingCount: 0,
-  };
-  objectInfoMap.set(object, info);
-  return info;
+function TypeMapCreate() {
+  return { __proto__: null };
 }
 
-var defaultAcceptTypes = {
-  __proto__: null,
-  'new': true,
-  'updated': true,
-  'deleted': true,
-  'prototype': true,
-  'reconfigured': true
-};
-
-function CreateObserver(callback, accept) {
-  var observer = {
-    __proto__: null,
-    callback: callback,
-    accept: defaultAcceptTypes
-  };
-
-  if (IS_UNDEFINED(accept))
-    return observer;
-
-  var acceptMap = { __proto__: null };
-  for (var i = 0; i < accept.length; i++)
-    acceptMap[accept[i]] = true;
-
-  observer.accept = acceptMap;
-  return observer;
+function TypeMapAddType(typeMap, type, ignoreDuplicate) {
+  typeMap[type] = ignoreDuplicate ? 1 : (typeMap[type] || 0) + 1;
 }
 
-function ObserverIsActive(observer, objectInfo) {
-  if (objectInfo.performingCount === 0)
+function TypeMapRemoveType(typeMap, type) {
+  typeMap[type]--;
+}
+
+function TypeMapCreateFromList(typeList) {
+  var typeMap = TypeMapCreate();
+  for (var i = 0; i < typeList.length; i++) {
+    TypeMapAddType(typeMap, typeList[i], true);
+  }
+  return typeMap;
+}
+
+function TypeMapHasType(typeMap, type) {
+  return !!typeMap[type];
+}
+
+function TypeMapIsDisjointFrom(typeMap1, typeMap2) {
+  if (!typeMap1 || !typeMap2)
     return true;
 
-  var performing = objectInfo.performing;
-  for (var type in performing) {
-    if (performing[type] > 0 && observer.accept[type])
+  for (var type in typeMap1) {
+    if (TypeMapHasType(typeMap1, type) && TypeMapHasType(typeMap2, type))
       return false;
   }
 
   return true;
 }
 
-function ObserverIsInactive(observer, objectInfo) {
-  return !ObserverIsActive(observer, objectInfo);
+var defaultAcceptTypes = TypeMapCreateFromList([
+  'new',
+  'updated',
+  'deleted',
+  'prototype',
+  'reconfigured'
+]);
+
+// An Observer is a registration to observe an object by a callback with
+// a given set of accept types. If the set of accept types is the default
+// set for Object.observe, the observer is represented as a direct reference
+// to the callback. An observer never changes its accept types and thus never
+// needs to "normalize".
+function ObserverCreate(callback, acceptList) {
+  return IS_UNDEFINED(acceptList) ? callback : {
+    __proto__: null,
+    callback: callback,
+    accept: TypeMapCreateFromList(acceptList)
+  };
 }
 
-function RemoveNullElements(from) {
-  var i = 0;
-  var j = 0;
-  for (; i < from.length; i++) {
-    if (from[i] === null)
-      continue;
-    if (j < i)
-      from[j] = from[i];
-    j++;
+function ObserverGetCallback(observer) {
+  return IS_SPEC_FUNCTION(observer) ? observer : observer.callback;
+}
+
+function ObserverGetAcceptTypes(observer) {
+  return IS_SPEC_FUNCTION(observer) ? defaultAcceptTypes : observer.accept;
+}
+
+function ObserverIsActive(observer, objectInfo) {
+  return TypeMapIsDisjointFrom(ObjectInfoGetPerformingTypes(objectInfo),
+                               ObserverGetAcceptTypes(observer));
+}
+
+function ObjectInfoGet(object) {
+  var objectInfo = objectInfoMap.get(object);
+  if (IS_UNDEFINED(objectInfo)) {
+    if (!%IsJSProxy(object))
+      %SetIsObserved(object);
+
+    objectInfo = {
+      object: object,
+      changeObservers: null,
+      notifier: null,
+      performing: null,
+      performingCount: 0,
+    };
+    objectInfoMap.set(object, objectInfo);
+  }
+  return objectInfo;
+}
+
+function ObjectInfoGetFromNotifier(notifier) {
+  return notifierObjectInfoMap.get(notifier);
+}
+
+function ObjectInfoGetNotifier(objectInfo) {
+  if (IS_NULL(objectInfo.notifier)) {
+    objectInfo.notifier = { __proto__: notifierPrototype };
+    notifierObjectInfoMap.set(objectInfo.notifier, objectInfo);
   }
 
-  if (i !== j)
-    from.length = from.length - (i - j);
+  return objectInfo.notifier;
 }
 
-function RepartitionObservers(conditionFn, from, to, objectInfo) {
-  var anyRemoved = false;
-  for (var i = 0; i < from.length; i++) {
-    var observer = from[i];
-    if (conditionFn(observer, objectInfo)) {
-      anyRemoved = true;
-      from[i] = null;
-      to.push(observer);
-    }
+function ObjectInfoGetObject(objectInfo) {
+  return objectInfo.object;
+}
+
+function ChangeObserversIsOptimized(changeObservers) {
+  return typeof changeObservers === 'function' ||
+         typeof changeObservers.callback === 'function';
+}
+
+// The set of observers on an object is called 'changeObservers'. The first
+// observer is referenced directly via objectInfo.changeObservers. When a second
+// is added, changeObservers "normalizes" to become a mapping of callback
+// priority -> observer and is then stored on objectInfo.changeObservers.
+function ObjectInfoNormalizeChangeObservers(objectInfo) {
+  if (ChangeObserversIsOptimized(objectInfo.changeObservers)) {
+    var observer = objectInfo.changeObservers;
+    var callback = ObserverGetCallback(observer);
+    var callbackInfo = CallbackInfoGet(callback);
+    var priority = CallbackInfoGetPriority(callbackInfo);
+    objectInfo.changeObservers = { __proto__: null };
+    objectInfo.changeObservers[priority] = observer;
+  }
+}
+
+function ObjectInfoAddObserver(objectInfo, callback, acceptList) {
+  var callbackInfo = CallbackInfoGetOrCreate(callback);
+  var observer = ObserverCreate(callback, acceptList);
+
+  if (!objectInfo.changeObservers) {
+    objectInfo.changeObservers = observer;
+    return;
   }
 
-  if (anyRemoved)
-    RemoveNullElements(from);
+  ObjectInfoNormalizeChangeObservers(objectInfo);
+  var priority = CallbackInfoGetPriority(callbackInfo);
+  objectInfo.changeObservers[priority] = observer;
 }
 
-function BeginPerformChange(objectInfo, type) {
-  objectInfo.performing[type] = (objectInfo.performing[type] || 0) + 1;
-  objectInfo.performingCount++;
-  RepartitionObservers(ObserverIsInactive,
-                       objectInfo.changeObservers,
-                       objectInfo.inactiveObservers,
-                       objectInfo);
+function ObjectInfoRemoveObserver(objectInfo, callback) {
+  if (!objectInfo.changeObservers)
+    return;
+
+  if (ChangeObserversIsOptimized(objectInfo.changeObservers)) {
+    if (callback === ObserverGetCallback(objectInfo.changeObservers))
+      objectInfo.changeObservers = null;
+    return;
+  }
+
+  var callbackInfo = CallbackInfoGet(callback);
+  var priority = CallbackInfoGetPriority(callbackInfo);
+  delete objectInfo.changeObservers[priority];
 }
 
-function EndPerformChange(objectInfo, type) {
-  objectInfo.performing[type]--;
-  objectInfo.performingCount--;
-  RepartitionObservers(ObserverIsActive,
-                       objectInfo.inactiveObservers,
-                       objectInfo.changeObservers,
-                       objectInfo);
-}
-
-function EnsureObserverRemoved(objectInfo, callback) {
-  function remove(observerList) {
-    for (var i = 0; i < observerList.length; i++) {
-      if (observerList[i].callback === callback) {
-        observerList.splice(i, 1);
-        return true;
-      }
-    }
+function ObjectInfoHasActiveObservers(objectInfo) {
+  if (IS_UNDEFINED(objectInfo) || !objectInfo.changeObservers)
     return false;
+
+  if (ChangeObserversIsOptimized(objectInfo.changeObservers))
+    return ObserverIsActive(objectInfo.changeObservers, objectInfo);
+
+  for (var priority in objectInfo.changeObservers) {
+    if (ObserverIsActive(objectInfo.changeObservers[priority], objectInfo))
+      return true;
   }
 
-  if (!remove(objectInfo.changeObservers))
-    remove(objectInfo.inactiveObservers);
+  return false;
+}
+
+function ObjectInfoAddPerformingType(objectInfo, type) {
+  objectInfo.performing = objectInfo.performing || TypeMapCreate();
+  TypeMapAddType(objectInfo.performing, type);
+  objectInfo.performingCount++;
+}
+
+function ObjectInfoRemovePerformingType(objectInfo, type) {
+  objectInfo.performingCount--;
+  TypeMapRemoveType(objectInfo.performing, type);
+}
+
+function ObjectInfoGetPerformingTypes(objectInfo) {
+  return objectInfo.performingCount > 0 ? objectInfo.performing : null;
 }
 
 function AcceptArgIsValid(arg) {
@@ -198,12 +292,31 @@
   return true;
 }
 
-function EnsureCallbackPriority(callback) {
-  if (!callbackInfoMap.has(callback))
-    callbackInfoMap.set(callback, observationState.nextCallbackPriority++);
+// CallbackInfo's optimized state is just a number which represents its global
+// priority. When a change record must be enqueued for the callback, it
+// normalizes. When delivery clears any pending change records, it re-optimizes.
+function CallbackInfoGet(callback) {
+  return callbackInfoMap.get(callback);
 }
 
-function NormalizeCallbackInfo(callback) {
+function CallbackInfoGetOrCreate(callback) {
+  var callbackInfo = callbackInfoMap.get(callback);
+  if (!IS_UNDEFINED(callbackInfo))
+    return callbackInfo;
+
+  var priority = observationState.nextCallbackPriority++
+  callbackInfoMap.set(callback, priority);
+  return priority;
+}
+
+function CallbackInfoGetPriority(callbackInfo) {
+  if (IS_NUMBER(callbackInfo))
+    return callbackInfo;
+  else
+    return callbackInfo.priority;
+}
+
+function CallbackInfoNormalize(callback) {
   var callbackInfo = callbackInfoMap.get(callback);
   if (IS_NUMBER(callbackInfo)) {
     var priority = callbackInfo;
@@ -214,32 +327,18 @@
   return callbackInfo;
 }
 
-function ObjectObserve(object, callback, accept) {
+function ObjectObserve(object, callback, acceptList) {
   if (!IS_SPEC_OBJECT(object))
     throw MakeTypeError("observe_non_object", ["observe"]);
   if (!IS_SPEC_FUNCTION(callback))
     throw MakeTypeError("observe_non_function", ["observe"]);
   if (ObjectIsFrozen(callback))
     throw MakeTypeError("observe_callback_frozen");
-  if (!AcceptArgIsValid(accept))
+  if (!AcceptArgIsValid(acceptList))
     throw MakeTypeError("observe_accept_invalid");
 
-  EnsureCallbackPriority(callback);
-
-  var objectInfo = objectInfoMap.get(object);
-  if (IS_UNDEFINED(objectInfo)) {
-    objectInfo = CreateObjectInfo(object);
-    %SetIsObserved(object);
-  }
-
-  EnsureObserverRemoved(objectInfo, callback);
-
-  var observer = CreateObserver(callback, accept);
-  if (ObserverIsActive(observer, objectInfo))
-    objectInfo.changeObservers.push(observer);
-  else
-    objectInfo.inactiveObservers.push(observer);
-
+  var objectInfo = ObjectInfoGet(object);
+  ObjectInfoAddObserver(objectInfo, callback, acceptList);
   return object;
 }
 
@@ -253,7 +352,7 @@
   if (IS_UNDEFINED(objectInfo))
     return object;
 
-  EnsureObserverRemoved(objectInfo, callback);
+  ObjectInfoRemoveObserver(objectInfo, callback);
   return object;
 }
 
@@ -268,41 +367,52 @@
   return ObjectUnobserve(object, callback);
 }
 
-function EnqueueToCallback(callback, changeRecord) {
-  var callbackInfo = NormalizeCallbackInfo(callback);
+function ObserverEnqueueIfActive(observer, objectInfo, changeRecord) {
+  if (!ObserverIsActive(observer, objectInfo) ||
+      !TypeMapHasType(ObserverGetAcceptTypes(observer), changeRecord.type)) {
+    return;
+  }
+
+  var callback = ObserverGetCallback(observer);
+  var callbackInfo = CallbackInfoNormalize(callback);
+  if (!observationState.pendingObservers)
+    observationState.pendingObservers = { __proto__: null };
   observationState.pendingObservers[callbackInfo.priority] = callback;
   callbackInfo.push(changeRecord);
   %SetObserverDeliveryPending();
 }
 
-function EnqueueChangeRecord(changeRecord, observers) {
+function ObjectInfoEnqueueChangeRecord(objectInfo, changeRecord) {
   // TODO(rossberg): adjust once there is a story for symbols vs proxies.
   if (IS_SYMBOL(changeRecord.name)) return;
 
-  for (var i = 0; i < observers.length; i++) {
-    var observer = observers[i];
-    if (IS_UNDEFINED(observer.accept[changeRecord.type]))
-      continue;
+  if (ChangeObserversIsOptimized(objectInfo.changeObservers)) {
+    var observer = objectInfo.changeObservers;
+    ObserverEnqueueIfActive(observer, objectInfo, changeRecord);
+    return;
+  }
 
-    EnqueueToCallback(observer.callback, changeRecord);
+  for (var priority in objectInfo.changeObservers) {
+    var observer = objectInfo.changeObservers[priority];
+    ObserverEnqueueIfActive(observer, objectInfo, changeRecord);
   }
 }
 
 function BeginPerformSplice(array) {
   var objectInfo = objectInfoMap.get(array);
   if (!IS_UNDEFINED(objectInfo))
-    BeginPerformChange(objectInfo, 'splice');
+    ObjectInfoAddPerformingType(objectInfo, 'splice');
 }
 
 function EndPerformSplice(array) {
   var objectInfo = objectInfoMap.get(array);
   if (!IS_UNDEFINED(objectInfo))
-    EndPerformChange(objectInfo, 'splice');
+    ObjectInfoRemovePerformingType(objectInfo, 'splice');
 }
 
 function EnqueueSpliceRecord(array, index, removed, addedCount) {
   var objectInfo = objectInfoMap.get(array);
-  if (IS_UNDEFINED(objectInfo) || objectInfo.changeObservers.length === 0)
+  if (!ObjectInfoHasActiveObservers(objectInfo))
     return;
 
   var changeRecord = {
@@ -315,19 +425,19 @@
 
   ObjectFreeze(changeRecord);
   ObjectFreeze(changeRecord.removed);
-  EnqueueChangeRecord(changeRecord, objectInfo.changeObservers);
+  ObjectInfoEnqueueChangeRecord(objectInfo, changeRecord);
 }
 
 function NotifyChange(type, object, name, oldValue) {
   var objectInfo = objectInfoMap.get(object);
-  if (objectInfo.changeObservers.length === 0)
+  if (!ObjectInfoHasActiveObservers(objectInfo))
     return;
 
   var changeRecord = (arguments.length < 4) ?
       { type: type, object: object, name: name } :
       { type: type, object: object, name: name, oldValue: oldValue };
   ObjectFreeze(changeRecord);
-  EnqueueChangeRecord(changeRecord, objectInfo.changeObservers);
+  ObjectInfoEnqueueChangeRecord(objectInfo, changeRecord);
 }
 
 var notifierPrototype = {};
@@ -336,17 +446,16 @@
   if (!IS_SPEC_OBJECT(this))
     throw MakeTypeError("called_on_non_object", ["notify"]);
 
-  var target = notifierTargetMap.get(this);
-  if (IS_UNDEFINED(target))
+  var objectInfo = ObjectInfoGetFromNotifier(this);
+  if (IS_UNDEFINED(objectInfo))
     throw MakeTypeError("observe_notify_non_notifier");
   if (!IS_STRING(changeRecord.type))
     throw MakeTypeError("observe_type_non_string");
 
-  var objectInfo = objectInfoMap.get(target);
-  if (IS_UNDEFINED(objectInfo) || objectInfo.changeObservers.length === 0)
+  if (!ObjectInfoHasActiveObservers(objectInfo))
     return;
 
-  var newRecord = { object: target };
+  var newRecord = { object: ObjectInfoGetObject(objectInfo) };
   for (var prop in changeRecord) {
     if (prop === 'object') continue;
     %DefineOrRedefineDataProperty(newRecord, prop, changeRecord[prop],
@@ -354,15 +463,16 @@
   }
   ObjectFreeze(newRecord);
 
-  EnqueueChangeRecord(newRecord, objectInfo.changeObservers);
+  ObjectInfoEnqueueChangeRecord(objectInfo, newRecord);
 }
 
 function ObjectNotifierPerformChange(changeType, changeFn, receiver) {
   if (!IS_SPEC_OBJECT(this))
     throw MakeTypeError("called_on_non_object", ["performChange"]);
 
-  var target = notifierTargetMap.get(this);
-  if (IS_UNDEFINED(target))
+  var objectInfo = ObjectInfoGetFromNotifier(this);
+
+  if (IS_UNDEFINED(objectInfo))
     throw MakeTypeError("observe_notify_non_notifier");
   if (!IS_STRING(changeType))
     throw MakeTypeError("observe_perform_non_string");
@@ -375,15 +485,11 @@
     receiver = ToObject(receiver);
   }
 
-  var objectInfo = objectInfoMap.get(target);
-  if (IS_UNDEFINED(objectInfo))
-    return;
-
-  BeginPerformChange(objectInfo, changeType);
+  ObjectInfoAddPerformingType(objectInfo, changeType);
   try {
     %_CallFunction(receiver, changeFn);
   } finally {
-    EndPerformChange(objectInfo, changeType);
+    ObjectInfoRemovePerformingType(objectInfo, changeType);
   }
 }
 
@@ -393,18 +499,8 @@
 
   if (ObjectIsFrozen(object)) return null;
 
-  var objectInfo = objectInfoMap.get(object);
-  if (IS_UNDEFINED(objectInfo)) {
-    objectInfo = CreateObjectInfo(object);
-    %SetIsObserved(object);
-  }
-
-  if (IS_NULL(objectInfo.notifier)) {
-    objectInfo.notifier = { __proto__: notifierPrototype };
-    notifierTargetMap.set(objectInfo.notifier, object);
-  }
-
-  return objectInfo.notifier;
+  var objectInfo = ObjectInfoGet(object);
+  return ObjectInfoGetNotifier(objectInfo);
 }
 
 function CallbackDeliverPending(callback) {
@@ -417,7 +513,9 @@
   var priority = callbackInfo.priority;
   callbackInfoMap.set(callback, priority);
 
-  delete observationState.pendingObservers[priority];
+  if (observationState.pendingObservers)
+    delete observationState.pendingObservers[priority];
+
   var delivered = [];
   %MoveArrayContents(callbackInfo, delivered);
 
@@ -435,9 +533,9 @@
 }
 
 function DeliverChangeRecords() {
-  while (observationState.pendingObservers.length) {
+  while (observationState.pendingObservers) {
     var pendingObservers = observationState.pendingObservers;
-    observationState.pendingObservers = new InternalArray;
+    observationState.pendingObservers = null;
     for (var i in pendingObservers) {
       CallbackDeliverPending(pendingObservers[i]);
     }
diff --git a/src/objects-debug.cc b/src/objects-debug.cc
index 3eb7817..883afe9 100644
--- a/src/objects-debug.cc
+++ b/src/objects-debug.cc
@@ -230,7 +230,8 @@
 
 void HeapObject::VerifyHeapPointer(Object* p) {
   CHECK(p->IsHeapObject());
-  CHECK(HEAP->Contains(HeapObject::cast(p)));
+  HeapObject* ho = HeapObject::cast(p);
+  CHECK(ho->GetHeap()->Contains(ho));
 }
 
 
@@ -337,11 +338,12 @@
 
 
 void Map::MapVerify() {
-  CHECK(!HEAP->InNewSpace(this));
+  Heap* heap = GetHeap();
+  CHECK(!heap->InNewSpace(this));
   CHECK(FIRST_TYPE <= instance_type() && instance_type() <= LAST_TYPE);
   CHECK(instance_size() == kVariableSizeSentinel ||
          (kPointerSize <= instance_size() &&
-          instance_size() < HEAP->Capacity()));
+          instance_size() < heap->Capacity()));
   VerifyHeapPointer(prototype());
   VerifyHeapPointer(instance_descriptors());
   SLOW_ASSERT(instance_descriptors()->IsSortedNoDuplicates());
@@ -523,7 +525,7 @@
   CHECK(IsString());
   CHECK(length() >= 0 && length() <= Smi::kMaxValue);
   if (IsInternalizedString()) {
-    CHECK(!HEAP->InNewSpace(this));
+    CHECK(!GetHeap()->InNewSpace(this));
   }
   if (IsConsString()) {
     ConsString::cast(this)->ConsStringVerify();
@@ -615,7 +617,7 @@
   VerifyHeapPointer(to_string());
   Object* number = to_number();
   if (number->IsHeapObject()) {
-    CHECK(number == HEAP->nan_value());
+    CHECK(number == HeapObject::cast(number)->GetHeap()->nan_value());
   } else {
     CHECK(number->IsSmi());
     int value = Smi::cast(number)->value();
@@ -1043,7 +1045,7 @@
       int holes = 0;
       FixedArray* e = FixedArray::cast(elements());
       int len = e->length();
-      Heap* heap = HEAP;
+      Heap* heap = GetHeap();
       for (int i = 0; i < len; i++) {
         if (e->get(i) == heap->the_hole_value()) holes++;
       }
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 8a3cbec..c2dc750 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -1353,17 +1353,16 @@
 }
 
 
-MaybeObject* JSObject::EnsureCanContainHeapObjectElements() {
-  ValidateElements();
-  ElementsKind elements_kind = map()->elements_kind();
+void JSObject::EnsureCanContainHeapObjectElements(Handle<JSObject> object) {
+  object->ValidateElements();
+  ElementsKind elements_kind = object->map()->elements_kind();
   if (!IsFastObjectElementsKind(elements_kind)) {
     if (IsFastHoleyElementsKind(elements_kind)) {
-      return TransitionElementsKind(FAST_HOLEY_ELEMENTS);
+      TransitionElementsKind(object, FAST_HOLEY_ELEMENTS);
     } else {
-      return TransitionElementsKind(FAST_ELEMENTS);
+      TransitionElementsKind(object, FAST_ELEMENTS);
     }
   }
-  return this;
 }
 
 
@@ -1964,7 +1963,7 @@
 
 
 void FixedArray::set(int index, Smi* value) {
-  ASSERT(map() != HEAP->fixed_cow_array_map());
+  ASSERT(map() != GetHeap()->fixed_cow_array_map());
   ASSERT(index >= 0 && index < this->length());
   ASSERT(reinterpret_cast<Object*>(value)->IsSmi());
   int offset = kHeaderSize + index * kPointerSize;
@@ -1973,7 +1972,7 @@
 
 
 void FixedArray::set(int index, Object* value) {
-  ASSERT(map() != HEAP->fixed_cow_array_map());
+  ASSERT(map() != GetHeap()->fixed_cow_array_map());
   ASSERT(index >= 0 && index < this->length());
   int offset = kHeaderSize + index * kPointerSize;
   WRITE_FIELD(this, offset, value);
@@ -1999,8 +1998,8 @@
 
 
 double FixedDoubleArray::get_scalar(int index) {
-  ASSERT(map() != HEAP->fixed_cow_array_map() &&
-         map() != HEAP->fixed_array_map());
+  ASSERT(map() != GetHeap()->fixed_cow_array_map() &&
+         map() != GetHeap()->fixed_array_map());
   ASSERT(index >= 0 && index < this->length());
   double result = READ_DOUBLE_FIELD(this, kHeaderSize + index * kDoubleSize);
   ASSERT(!is_the_hole_nan(result));
@@ -2008,8 +2007,8 @@
 }
 
 int64_t FixedDoubleArray::get_representation(int index) {
-  ASSERT(map() != HEAP->fixed_cow_array_map() &&
-         map() != HEAP->fixed_array_map());
+  ASSERT(map() != GetHeap()->fixed_cow_array_map() &&
+         map() != GetHeap()->fixed_array_map());
   ASSERT(index >= 0 && index < this->length());
   return READ_INT64_FIELD(this, kHeaderSize + index * kDoubleSize);
 }
@@ -2024,8 +2023,8 @@
 
 
 void FixedDoubleArray::set(int index, double value) {
-  ASSERT(map() != HEAP->fixed_cow_array_map() &&
-         map() != HEAP->fixed_array_map());
+  ASSERT(map() != GetHeap()->fixed_cow_array_map() &&
+         map() != GetHeap()->fixed_array_map());
   int offset = kHeaderSize + index * kDoubleSize;
   if (std::isnan(value)) value = canonical_not_the_hole_nan_as_double();
   WRITE_DOUBLE_FIELD(this, offset, value);
@@ -2033,8 +2032,8 @@
 
 
 void FixedDoubleArray::set_the_hole(int index) {
-  ASSERT(map() != HEAP->fixed_cow_array_map() &&
-         map() != HEAP->fixed_array_map());
+  ASSERT(map() != GetHeap()->fixed_cow_array_map() &&
+         map() != GetHeap()->fixed_array_map());
   int offset = kHeaderSize + index * kDoubleSize;
   WRITE_DOUBLE_FIELD(this, offset, hole_nan_as_double());
 }
@@ -2058,7 +2057,7 @@
 void FixedArray::set(int index,
                      Object* value,
                      WriteBarrierMode mode) {
-  ASSERT(map() != HEAP->fixed_cow_array_map());
+  ASSERT(map() != GetHeap()->fixed_cow_array_map());
   ASSERT(index >= 0 && index < this->length());
   int offset = kHeaderSize + index * kPointerSize;
   WRITE_FIELD(this, offset, value);
@@ -2069,7 +2068,7 @@
 void FixedArray::NoIncrementalWriteBarrierSet(FixedArray* array,
                                               int index,
                                               Object* value) {
-  ASSERT(array->map() != HEAP->fixed_cow_array_map());
+  ASSERT(array->map() != array->GetHeap()->fixed_cow_array_map());
   ASSERT(index >= 0 && index < array->length());
   int offset = kHeaderSize + index * kPointerSize;
   WRITE_FIELD(array, offset, value);
@@ -2083,9 +2082,9 @@
 void FixedArray::NoWriteBarrierSet(FixedArray* array,
                                    int index,
                                    Object* value) {
-  ASSERT(array->map() != HEAP->fixed_cow_array_map());
+  ASSERT(array->map() != array->GetHeap()->fixed_cow_array_map());
   ASSERT(index >= 0 && index < array->length());
-  ASSERT(!HEAP->InNewSpace(value));
+  ASSERT(!array->GetHeap()->InNewSpace(value));
   WRITE_FIELD(array, kHeaderSize + index * kPointerSize, value);
 }
 
@@ -2110,9 +2109,9 @@
 
 
 void FixedArray::set_the_hole(int index) {
-  ASSERT(map() != HEAP->fixed_cow_array_map());
+  ASSERT(map() != GetHeap()->fixed_cow_array_map());
   ASSERT(index >= 0 && index < this->length());
-  ASSERT(!HEAP->InNewSpace(HEAP->the_hole_value()));
+  ASSERT(!GetHeap()->InNewSpace(GetHeap()->the_hole_value()));
   WRITE_FIELD(this,
               kHeaderSize + index * kPointerSize,
               GetHeap()->the_hole_value());
@@ -2131,7 +2130,7 @@
 
 bool DescriptorArray::IsEmpty() {
   ASSERT(length() >= kFirstIndex ||
-         this == HEAP->empty_descriptor_array());
+         this == GetHeap()->empty_descriptor_array());
   return length() < kFirstIndex;
 }
 
@@ -4996,7 +4995,7 @@
 
 
 void JSFunction::set_code(Code* value) {
-  ASSERT(!HEAP->InNewSpace(value));
+  ASSERT(!GetHeap()->InNewSpace(value));
   Address entry = value->entry();
   WRITE_INTPTR_FIELD(this, kCodeEntryOffset, reinterpret_cast<intptr_t>(entry));
   GetHeap()->incremental_marking()->RecordWriteOfCodeEntry(
@@ -5007,7 +5006,7 @@
 
 
 void JSFunction::set_code_no_write_barrier(Code* value) {
-  ASSERT(!HEAP->InNewSpace(value));
+  ASSERT(!GetHeap()->InNewSpace(value));
   Address entry = value->entry();
   WRITE_INTPTR_FIELD(this, kCodeEntryOffset, reinterpret_cast<intptr_t>(entry));
 }
@@ -5157,7 +5156,7 @@
                                                    Code* value) {
   ASSERT(id < kJSBuiltinsCount);  // id is unsigned.
   WRITE_FIELD(this, OffsetOfCodeWithId(id), value);
-  ASSERT(!HEAP->InNewSpace(value));
+  ASSERT(!GetHeap()->InNewSpace(value));
 }
 
 
diff --git a/src/objects.cc b/src/objects.cc
index ca10394..027506f 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -2188,9 +2188,9 @@
 
 template<RightTrimMode trim_mode>
 static void RightTrimFixedArray(Heap* heap, FixedArray* elms, int to_trim) {
-  ASSERT(elms->map() != HEAP->fixed_cow_array_map());
+  ASSERT(elms->map() != heap->fixed_cow_array_map());
   // For now this trick is only applied to fixed arrays in new and paged space.
-  ASSERT(!HEAP->lo_space()->Contains(elms));
+  ASSERT(!heap->lo_space()->Contains(elms));
 
   const int len = elms->length();
 
@@ -4029,6 +4029,29 @@
 }
 
 
+MaybeObject* JSObject::SetLocalPropertyIgnoreAttributesTrampoline(
+    Name* key,
+    Object* value,
+    PropertyAttributes attributes,
+    ValueType value_type,
+    StoreMode mode,
+    ExtensibilityCheck extensibility_check) {
+  // TODO(mstarzinger): The trampoline is a giant hack, don't use it anywhere
+  // else or handlification people will start hating you for all eternity.
+  HandleScope scope(GetIsolate());
+  IdempotentPointerToHandleCodeTrampoline trampoline(GetIsolate());
+  return trampoline.CallWithReturnValue(
+      &JSObject::SetLocalPropertyIgnoreAttributes,
+      Handle<JSObject>(this),
+      Handle<Name>(key),
+      Handle<Object>(value, GetIsolate()),
+      attributes,
+      value_type,
+      mode,
+      extensibility_check);
+}
+
+
 // Set a real local property, even if it is READ_ONLY.  If the property is not
 // present, add it with attributes NONE.  This code is an exact clone of
 // SetProperty, with the check for IsReadOnly and the check for a
@@ -4044,11 +4067,12 @@
     Handle<Object> value,
     PropertyAttributes attributes,
     ValueType value_type,
-    StoreMode mode) {
+    StoreMode mode,
+    ExtensibilityCheck extensibility_check) {
   CALL_HEAP_FUNCTION(
     object->GetIsolate(),
     object->SetLocalPropertyIgnoreAttributes(
-        *key, *value, attributes, value_type, mode),
+        *key, *value, attributes, value_type, mode, extensibility_check),
     Object);
 }
 
@@ -4458,27 +4482,17 @@
 void JSObject::UpdateMapCodeCache(Handle<JSObject> object,
                                   Handle<Name> name,
                                   Handle<Code> code) {
-  Isolate* isolate = object->GetIsolate();
-  CALL_HEAP_FUNCTION_VOID(isolate,
-                          object->UpdateMapCodeCache(*name, *code));
-}
-
-
-MaybeObject* JSObject::UpdateMapCodeCache(Name* name, Code* code) {
-  if (map()->is_shared()) {
+  Handle<Map> map(object->map());
+  if (map->is_shared()) {
     // Fast case maps are never marked as shared.
-    ASSERT(!HasFastProperties());
+    ASSERT(!object->HasFastProperties());
     // Replace the map with an identical copy that can be safely modified.
-    Object* obj;
-    { MaybeObject* maybe_obj = map()->CopyNormalized(KEEP_INOBJECT_PROPERTIES,
-                                                     UNIQUE_NORMALIZED_MAP);
-      if (!maybe_obj->ToObject(&obj)) return maybe_obj;
-    }
-    GetIsolate()->counters()->normalized_maps()->Increment();
-
-    set_map(Map::cast(obj));
+    map = Map::CopyNormalized(map, KEEP_INOBJECT_PROPERTIES,
+                              UNIQUE_NORMALIZED_MAP);
+    object->GetIsolate()->counters()->normalized_maps()->Increment();
+    object->set_map(*map);
   }
-  return map()->UpdateCodeCache(name, code);
+  Map::UpdateCodeCache(map, name, code);
 }
 
 
@@ -4729,7 +4743,7 @@
   do {
     // Generate a random 32-bit hash value but limit range to fit
     // within a smi.
-    hash_value = V8::RandomPrivate(isolate) & Smi::kMaxValue;
+    hash_value = isolate->random_number_generator()->NextInt() & Smi::kMaxValue;
     attempts++;
   } while (hash_value == 0 && attempts < 30);
   hash_value = hash_value != 0 ? hash_value : 1;  // never return 0
@@ -4961,13 +4975,13 @@
     ASSERT_EQ(hashtable, new_table);
   }
 
-  MaybeObject* store_result =
-      SetLocalPropertyIgnoreAttributes(GetHeap()->hidden_string(),
-                                       hashtable,
-                                       DONT_ENUM,
-                                       OPTIMAL_REPRESENTATION,
-                                       ALLOW_AS_CONSTANT,
-                                       OMIT_EXTENSIBILITY_CHECK);
+  MaybeObject* store_result = SetLocalPropertyIgnoreAttributesTrampoline(
+      GetHeap()->hidden_string(),
+      hashtable,
+      DONT_ENUM,
+      OPTIMAL_REPRESENTATION,
+      ALLOW_AS_CONSTANT,
+      OMIT_EXTENSIBILITY_CHECK);
   if (store_result->IsFailure()) return store_result;
   return hashtable;
 }
@@ -4994,13 +5008,13 @@
       }
     }
   }
-  MaybeObject* store_result =
-      SetLocalPropertyIgnoreAttributes(GetHeap()->hidden_string(),
-                                       value,
-                                       DONT_ENUM,
-                                       OPTIMAL_REPRESENTATION,
-                                       ALLOW_AS_CONSTANT,
-                                       OMIT_EXTENSIBILITY_CHECK);
+  MaybeObject* store_result = SetLocalPropertyIgnoreAttributesTrampoline(
+      GetHeap()->hidden_string(),
+      value,
+      DONT_ENUM,
+      OPTIMAL_REPRESENTATION,
+      ALLOW_AS_CONSTANT,
+      OMIT_EXTENSIBILITY_CHECK);
   if (store_result->IsFailure()) return store_result;
   return this;
 }
@@ -6510,6 +6524,15 @@
 }
 
 
+Handle<Map> Map::CopyNormalized(Handle<Map> map,
+                                PropertyNormalizationMode mode,
+                                NormalizedMapSharingMode sharing) {
+  CALL_HEAP_FUNCTION(map->GetIsolate(),
+                     map->CopyNormalized(mode, sharing),
+                     Map);
+}
+
+
 MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode,
                                  NormalizedMapSharingMode sharing) {
   int new_instance_size = instance_size();
@@ -7957,19 +7980,21 @@
 }
 
 
-MaybeObject* DeoptimizationInputData::Allocate(int deopt_entry_count,
+MaybeObject* DeoptimizationInputData::Allocate(Isolate* isolate,
+                                               int deopt_entry_count,
                                                PretenureFlag pretenure) {
   ASSERT(deopt_entry_count > 0);
-  return HEAP->AllocateFixedArray(LengthFor(deopt_entry_count),
-                                  pretenure);
+  return isolate->heap()->AllocateFixedArray(LengthFor(deopt_entry_count),
+                                             pretenure);
 }
 
 
-MaybeObject* DeoptimizationOutputData::Allocate(int number_of_deopt_points,
+MaybeObject* DeoptimizationOutputData::Allocate(Isolate* isolate,
+                                                int number_of_deopt_points,
                                                 PretenureFlag pretenure) {
-  if (number_of_deopt_points == 0) return HEAP->empty_fixed_array();
-  return HEAP->AllocateFixedArray(LengthOfFixedArray(number_of_deopt_points),
-                                  pretenure);
+  if (number_of_deopt_points == 0) return isolate->heap()->empty_fixed_array();
+  return isolate->heap()->AllocateFixedArray(
+      LengthOfFixedArray(number_of_deopt_points), pretenure);
 }
 
 
@@ -9493,11 +9518,25 @@
 }
 
 
-bool JSFunction::CompileOptimized(Handle<JSFunction> function,
-                                  BailoutId osr_ast_id,
-                                  ClearExceptionFlag flag) {
+Handle<Code> JSFunction::CompileOsr(Handle<JSFunction> function,
+                                    BailoutId osr_ast_id,
+                                    ClearExceptionFlag flag) {
   CompilationInfoWithZone info(function);
   info.SetOptimizing(osr_ast_id);
+  if (CompileLazyHelper(&info, flag)) {
+    // TODO(titzer): don't install the OSR code.
+    // ASSERT(function->code() != *info.code());
+    return info.code();
+  } else {
+    return Handle<Code>::null();
+  }
+}
+
+
+bool JSFunction::CompileOptimized(Handle<JSFunction> function,
+                                  ClearExceptionFlag flag) {
+  CompilationInfoWithZone info(function);
+  info.SetOptimizing(BailoutId::None());
   return CompileLazyHelper(&info, flag);
 }
 
@@ -9523,21 +9562,13 @@
 
 
 void JSObject::OptimizeAsPrototype(Handle<JSObject> object) {
-  CALL_HEAP_FUNCTION_VOID(object->GetIsolate(), object->OptimizeAsPrototype());
-}
-
-
-MaybeObject* JSObject::OptimizeAsPrototype() {
-  if (IsGlobalObject()) return this;
+  if (object->IsGlobalObject()) return;
 
   // Make sure prototypes are fast objects and their maps have the bit set
   // so they remain fast.
-  if (!HasFastProperties()) {
-    MaybeObject* new_proto = TransformToFastProperties(0);
-    if (new_proto->IsFailure()) return new_proto;
-    ASSERT(new_proto == this);
+  if (!object->HasFastProperties()) {
+    TransformToFastProperties(object, 0);
   }
-  return this;
 }
 
 
@@ -11403,8 +11434,9 @@
 
 bool DependentCode::Contains(DependencyGroup group, Code* code) {
   GroupStartIndexes starts(this);
-  int number_of_entries = starts.number_of_entries();
-  for (int i = 0; i < number_of_entries; i++) {
+  int start = starts.at(group);
+  int end = starts.at(group + 1);
+  for (int i = start; i < end; i++) {
     if (object_at(i) == code) return true;
   }
   return false;
diff --git a/src/objects.h b/src/objects.h
index 97d1e5d..af0a891 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -1214,6 +1214,8 @@
   V(kNonSmiValue, "Non-smi value")                                            \
   V(kNotEnoughVirtualRegistersForValues,                                      \
     "not enough virtual registers for values")                                \
+  V(kNotEnoughSpillSlotsForOsr,                                               \
+    "not enough spill slots for OSR")                                         \
   V(kNotEnoughVirtualRegistersRegalloc,                                       \
     "not enough virtual registers (regalloc)")                                \
   V(kObjectFoundInSmiOnlyArray, "object found in smi-only array")             \
@@ -2161,7 +2163,8 @@
       Handle<Object> value,
       PropertyAttributes attributes,
       ValueType value_type = OPTIMAL_REPRESENTATION,
-      StoreMode mode = ALLOW_AS_CONSTANT);
+      StoreMode mode = ALLOW_AS_CONSTANT,
+      ExtensibilityCheck extensibility_check = PERFORM_EXTENSIBILITY_CHECK);
 
   static inline Handle<String> ExpectedTransitionKey(Handle<Map> map);
   static inline Handle<Map> ExpectedTransitionTarget(Handle<Map> map);
@@ -2192,6 +2195,13 @@
       ValueType value_type = OPTIMAL_REPRESENTATION,
       StoreMode mode = ALLOW_AS_CONSTANT,
       ExtensibilityCheck extensibility_check = PERFORM_EXTENSIBILITY_CHECK);
+  MUST_USE_RESULT MaybeObject* SetLocalPropertyIgnoreAttributesTrampoline(
+      Name* key,
+      Object* value,
+      PropertyAttributes attributes,
+      ValueType value_type = OPTIMAL_REPRESENTATION,
+      StoreMode mode = ALLOW_AS_CONSTANT,
+      ExtensibilityCheck extensibility_check = PERFORM_EXTENSIBILITY_CHECK);
 
   // Retrieve a value in a normalized object given a lookup result.
   // Handles the special representation of JS global objects.
@@ -2220,7 +2230,6 @@
                                                      PropertyDetails details);
 
   static void OptimizeAsPrototype(Handle<JSObject> object);
-  MUST_USE_RESULT MaybeObject* OptimizeAsPrototype();
 
   // Retrieve interceptors.
   InterceptorInfo* GetNamedInterceptor();
@@ -2314,7 +2323,7 @@
   inline void ValidateElements();
 
   // Makes sure that this object can contain HeapObject as elements.
-  MUST_USE_RESULT inline MaybeObject* EnsureCanContainHeapObjectElements();
+  static inline void EnsureCanContainHeapObjectElements(Handle<JSObject> obj);
 
   // Makes sure that this object can contain the specified elements.
   MUST_USE_RESULT inline MaybeObject* EnsureCanContainElements(
@@ -2569,8 +2578,6 @@
                                  Handle<Name> name,
                                  Handle<Code> code);
 
-  MUST_USE_RESULT MaybeObject* UpdateMapCodeCache(Name* name, Code* code);
-
   // Transform slow named properties to fast variants.
   // Returns failure if allocation failed.
   static void TransformToFastProperties(Handle<JSObject> object,
@@ -4628,7 +4635,8 @@
   }
 
   // Allocates a DeoptimizationInputData.
-  MUST_USE_RESULT static MaybeObject* Allocate(int deopt_entry_count,
+  MUST_USE_RESULT static MaybeObject* Allocate(Isolate* isolate,
+                                               int deopt_entry_count,
                                                PretenureFlag pretenure);
 
   // Casting.
@@ -4674,7 +4682,8 @@
   }
 
   // Allocates a DeoptimizationOutputData.
-  MUST_USE_RESULT static MaybeObject* Allocate(int number_of_deopt_points,
+  MUST_USE_RESULT static MaybeObject* Allocate(Isolate* isolate,
+                                               int number_of_deopt_points,
                                                PretenureFlag pretenure);
 
   // Casting.
@@ -5794,6 +5803,9 @@
                                                   TransitionFlag flag);
   MUST_USE_RESULT MaybeObject* CopyForObserved();
 
+  static Handle<Map> CopyNormalized(Handle<Map> map,
+                                    PropertyNormalizationMode mode,
+                                    NormalizedMapSharingMode sharing);
   MUST_USE_RESULT MaybeObject* CopyNormalized(PropertyNormalizationMode mode,
                                               NormalizedMapSharingMode sharing);
 
@@ -6976,8 +6988,10 @@
                              ClearExceptionFlag flag);
   static bool CompileLazy(Handle<JSFunction> function,
                           ClearExceptionFlag flag);
+  static Handle<Code> CompileOsr(Handle<JSFunction> function,
+                                 BailoutId osr_ast_id,
+                                 ClearExceptionFlag flag);
   static bool CompileOptimized(Handle<JSFunction> function,
-                               BailoutId osr_ast_id,
                                ClearExceptionFlag flag);
 
   // Tells whether or not the function is already marked for lazy
diff --git a/src/platform-cygwin.cc b/src/platform-cygwin.cc
index f2154a4..9618d7e 100644
--- a/src/platform-cygwin.cc
+++ b/src/platform-cygwin.cc
@@ -80,7 +80,7 @@
   int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
   void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
   if (mbase == MAP_FAILED) {
-    LOG(ISOLATE, StringEvent("OS::Allocate", "mmap failed"));
+    LOG(Isolate::Current(), StringEvent("OS::Allocate", "mmap failed"));
     return NULL;
   }
   *allocated = msize;
@@ -152,7 +152,7 @@
   const int kLibNameLen = FILENAME_MAX + 1;
   char* lib_name = reinterpret_cast<char*>(malloc(kLibNameLen));
 
-  i::Isolate* isolate = ISOLATE;
+  i::Isolate* isolate = Isolate::Current();
   // This loop will terminate once the scanning hits an EOF.
   while (true) {
     uintptr_t start, end;
@@ -236,8 +236,9 @@
     static const intptr_t kAllocationRandomAddressMin = 0x04000000;
     static const intptr_t kAllocationRandomAddressMax = 0x3FFF0000;
 #endif
-    uintptr_t address = (V8::RandomPrivate(isolate) << kPageSizeBits)
-        | kAllocationRandomAddressMin;
+    uintptr_t address =
+        (isolate->random_number_generator()->NextInt() << kPageSizeBits) |
+        kAllocationRandomAddressMin;
     address &= kAllocationRandomAddressMax;
     return reinterpret_cast<void *>(address);
   }
@@ -344,7 +345,7 @@
   if (NULL == VirtualAlloc(address,
                            OS::CommitPageSize(),
                            MEM_COMMIT,
-                           PAGE_READONLY | PAGE_GUARD)) {
+                           PAGE_NOACCESS)) {
     return false;
   }
   return true;
@@ -366,16 +367,4 @@
   return false;
 }
 
-
-void OS::SetUp() {
-  // Seed the random number generator.
-  // Convert the current time to a 64-bit integer first, before converting it
-  // to an unsigned. Going directly can cause an overflow and the seed to be
-  // set to all ones. The seed will be identical for different instances that
-  // call this setup code within the same millisecond.
-  uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
-  srandom(static_cast<unsigned int>(seed));
-}
-
-
 } }  // namespace v8::internal
diff --git a/src/platform-freebsd.cc b/src/platform-freebsd.cc
index b21ebf7..34ed709 100644
--- a/src/platform-freebsd.cc
+++ b/src/platform-freebsd.cc
@@ -89,7 +89,7 @@
   void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
 
   if (mbase == MAP_FAILED) {
-    LOG(ISOLATE, StringEvent("OS::Allocate", "mmap failed"));
+    LOG(Isolate::Current(), StringEvent("OS::Allocate", "mmap failed"));
     return NULL;
   }
   *allocated = msize;
@@ -340,16 +340,4 @@
   return false;
 }
 
-
-void OS::SetUp() {
-  // Seed the random number generator.
-  // Convert the current time to a 64-bit integer first, before converting it
-  // to an unsigned. Going directly can cause an overflow and the seed to be
-  // set to all ones. The seed will be identical for different instances that
-  // call this setup code within the same millisecond.
-  uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
-  srandom(static_cast<unsigned int>(seed));
-}
-
-
 } }  // namespace v8::internal
diff --git a/src/platform-linux.cc b/src/platform-linux.cc
index 30825d7..39bf1cb 100644
--- a/src/platform-linux.cc
+++ b/src/platform-linux.cc
@@ -231,7 +231,7 @@
   const int kLibNameLen = FILENAME_MAX + 1;
   char* lib_name = reinterpret_cast<char*>(malloc(kLibNameLen));
 
-  i::Isolate* isolate = ISOLATE;
+  i::Isolate* isolate = Isolate::Current();
   // This loop will terminate once the scanning hits an EOF.
   while (true) {
     uintptr_t start, end;
@@ -466,12 +466,4 @@
   return true;
 }
 
-
-void OS::SetUp() {
-  // Seed the random number generator. We preserve microsecond resolution.
-  uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()) ^ (getpid() << 16);
-  srandom(static_cast<unsigned int>(seed));
-}
-
-
 } }  // namespace v8::internal
diff --git a/src/platform-macos.cc b/src/platform-macos.cc
index 5dd38b2..f618737 100644
--- a/src/platform-macos.cc
+++ b/src/platform-macos.cc
@@ -360,12 +360,4 @@
   return false;
 }
 
-
-void OS::SetUp() {
-  // Seed the random number generator. We preserve microsecond resolution.
-  uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()) ^ (getpid() << 16);
-  srandom(static_cast<unsigned int>(seed));
-}
-
-
 } }  // namespace v8::internal
diff --git a/src/platform-openbsd.cc b/src/platform-openbsd.cc
index eb48373..bb20df3 100644
--- a/src/platform-openbsd.cc
+++ b/src/platform-openbsd.cc
@@ -160,7 +160,7 @@
   const int kLibNameLen = FILENAME_MAX + 1;
   char* lib_name = reinterpret_cast<char*>(malloc(kLibNameLen));
 
-  i::Isolate* isolate = ISOLATE;
+  i::Isolate* isolate = Isolate::Current();
   // This loop will terminate once the scanning hits an EOF.
   while (true) {
     uintptr_t start, end;
@@ -397,12 +397,4 @@
   return false;
 }
 
-
-void OS::SetUp() {
-  // Seed the random number generator. We preserve microsecond resolution.
-  uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()) ^ (getpid() << 16);
-  srandom(static_cast<unsigned int>(seed));
-}
-
-
 } }  // namespace v8::internal
diff --git a/src/platform-posix.cc b/src/platform-posix.cc
index 504d140..fe27eaf 100644
--- a/src/platform-posix.cc
+++ b/src/platform-posix.cc
@@ -69,6 +69,7 @@
 #include "v8.h"
 
 #include "codegen.h"
+#include "isolate-inl.h"
 #include "platform.h"
 
 namespace v8 {
@@ -152,7 +153,7 @@
 void OS::Guard(void* address, const size_t size) {
 #if defined(__CYGWIN__)
   DWORD oldprotect;
-  VirtualProtect(address, size, PAGE_READONLY | PAGE_GUARD, &oldprotect);
+  VirtualProtect(address, size, PAGE_NOACCESS, &oldprotect);
 #else
   mprotect(address, size, PROT_NONE);
 #endif
@@ -171,17 +172,14 @@
   // CpuFeatures::Probe. We don't care about randomization in this case because
   // the code page is immediately freed.
   if (isolate != NULL) {
+    uintptr_t raw_addr;
+    isolate->random_number_generator()->NextBytes(&raw_addr, sizeof(raw_addr));
 #if V8_TARGET_ARCH_X64
-    uint64_t rnd1 = V8::RandomPrivate(isolate);
-    uint64_t rnd2 = V8::RandomPrivate(isolate);
-    uint64_t raw_addr = (rnd1 << 32) ^ rnd2;
     // Currently available CPUs have 48 bits of virtual addressing.  Truncate
     // the hint address to 46 bits to give the kernel a fighting chance of
     // fulfilling our placement request.
     raw_addr &= V8_UINT64_C(0x3ffffffff000);
 #else
-    uint32_t raw_addr = V8::RandomPrivate(isolate);
-
     raw_addr &= 0x3ffff000;
 
 # ifdef __sun
diff --git a/src/platform-solaris.cc b/src/platform-solaris.cc
index d8b60c3..512d995 100644
--- a/src/platform-solaris.cc
+++ b/src/platform-solaris.cc
@@ -104,7 +104,7 @@
   void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
 
   if (mbase == MAP_FAILED) {
-    LOG(ISOLATE, StringEvent("OS::Allocate", "mmap failed"));
+    LOG(Isolate::Current(), StringEvent("OS::Allocate", "mmap failed"));
     return NULL;
   }
   *allocated = msize;
@@ -361,16 +361,4 @@
   return false;
 }
 
-
-void OS::SetUp() {
-  // Seed the random number generator.
-  // Convert the current time to a 64-bit integer first, before converting it
-  // to an unsigned. Going directly will cause an overflow and the seed to be
-  // set to all ones. The seed will be identical for different instances that
-  // call this setup code within the same millisecond.
-  uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
-  srandom(static_cast<unsigned int>(seed));
-}
-
-
 } }  // namespace v8::internal
diff --git a/src/platform-win32.cc b/src/platform-win32.cc
index c98489f..2e82056 100644
--- a/src/platform-win32.cc
+++ b/src/platform-win32.cc
@@ -43,6 +43,7 @@
 #include "v8.h"
 
 #include "codegen.h"
+#include "isolate-inl.h"
 #include "platform.h"
 #include "simulator.h"
 #include "vm-state-inl.h"
@@ -124,13 +125,6 @@
 
 #endif  // __MINGW32__
 
-// Generate a pseudo-random number in the range 0-2^31-1. Usually
-// defined in stdlib.h. Missing in both Microsoft Visual Studio C++ and MinGW.
-int random() {
-  return rand();
-}
-
-
 namespace v8 {
 namespace internal {
 
@@ -794,8 +788,9 @@
     static const intptr_t kAllocationRandomAddressMin = 0x04000000;
     static const intptr_t kAllocationRandomAddressMax = 0x3FFF0000;
 #endif
-    uintptr_t address = (V8::RandomPrivate(isolate) << kPageSizeBits)
-        | kAllocationRandomAddressMin;
+    uintptr_t address =
+        (isolate->random_number_generator()->NextInt() << kPageSizeBits) |
+        kAllocationRandomAddressMin;
     address &= kAllocationRandomAddressMax;
     return reinterpret_cast<void *>(address);
   }
@@ -834,7 +829,7 @@
                                         prot);
 
   if (mbase == NULL) {
-    LOG(ISOLATE, StringEvent("OS::Allocate", "VirtualAlloc failed"));
+    LOG(Isolate::Current(), StringEvent("OS::Allocate", "VirtualAlloc failed"));
     return NULL;
   }
 
@@ -865,7 +860,7 @@
 
 void OS::Guard(void* address, const size_t size) {
   DWORD oldprotect;
-  VirtualProtect(address, size, PAGE_READONLY | PAGE_GUARD, &oldprotect);
+  VirtualProtect(address, size, PAGE_NOACCESS, &oldprotect);
 }
 
 
@@ -1441,7 +1436,7 @@
   if (NULL == VirtualAlloc(address,
                            OS::CommitPageSize(),
                            MEM_COMMIT,
-                           PAGE_READONLY | PAGE_GUARD)) {
+                           PAGE_NOACCESS)) {
     return false;
   }
   return true;
@@ -1580,15 +1575,4 @@
   Sleep(0);
 }
 
-
-void OS::SetUp() {
-  // Seed the random number generator.
-  // Convert the current time to a 64-bit integer first, before converting it
-  // to an unsigned. Going directly can cause an overflow and the seed to be
-  // set to all ones. The seed will be identical for different instances that
-  // call this setup code within the same millisecond.
-  uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
-  srand(static_cast<unsigned int>(seed));
-}
-
 } }  // namespace v8::internal
diff --git a/src/platform.h b/src/platform.h
index 6ae3fa0..428ba55 100644
--- a/src/platform.h
+++ b/src/platform.h
@@ -86,11 +86,6 @@
 
 #endif  // V8_CC_MSVC
 
-// Random is missing on both Visual Studio and MinGW.
-#if V8_CC_MSVC || V8_CC_MINGW
-int random();
-#endif  // V8_CC_MSVC || V8_CC_MINGW
-
 namespace v8 {
 namespace internal {
 
@@ -171,9 +166,6 @@
 
 class OS {
  public:
-  // Initializes the platform OS support. Called once at VM startup.
-  static void SetUp();
-
   // Initializes the platform OS support that depend on CPU features. This is
   // called after CPU initialization.
   static void PostSetUp();
diff --git a/src/platform/condition-variable.h b/src/platform/condition-variable.h
index 43cc529..4d8a88a 100644
--- a/src/platform/condition-variable.h
+++ b/src/platform/condition-variable.h
@@ -105,10 +105,10 @@
   };
 #endif
 
-  NativeHandle& native_handle() V8_WARN_UNUSED_RESULT {
+  NativeHandle& native_handle() {
     return native_handle_;
   }
-  const NativeHandle& native_handle() const V8_WARN_UNUSED_RESULT {
+  const NativeHandle& native_handle() const {
     return native_handle_;
   }
 
diff --git a/src/platform/elapsed-timer.h b/src/platform/elapsed-timer.h
index 773abbc..8044bd0 100644
--- a/src/platform/elapsed-timer.h
+++ b/src/platform/elapsed-timer.h
@@ -87,7 +87,7 @@
 
   // Returns the time elapsed since the previous start. This method may only
   // be called on a previously started timer.
-  TimeDelta Elapsed() const V8_WARN_UNUSED_RESULT {
+  TimeDelta Elapsed() const {
     ASSERT(IsStarted());
     TimeDelta elapsed = Now() - start_ticks_;
     ASSERT(elapsed.InMicroseconds() >= 0);
@@ -97,13 +97,13 @@
   // Returns |true| if the specified |time_delta| has elapsed since the
   // previous start, or |false| if not. This method may only be called on
   // a previously started timer.
-  bool HasExpired(TimeDelta time_delta) const V8_WARN_UNUSED_RESULT {
+  bool HasExpired(TimeDelta time_delta) const {
     ASSERT(IsStarted());
     return Elapsed() >= time_delta;
   }
 
  private:
-  V8_INLINE(static TimeTicks Now()) V8_WARN_UNUSED_RESULT {
+  V8_INLINE(static TimeTicks Now()) {
     TimeTicks now = TimeTicks::HighResNow();
     ASSERT(!now.IsNull());
     return now;
diff --git a/src/platform/mutex.h b/src/platform/mutex.h
index ff519b9..f08de4f 100644
--- a/src/platform/mutex.h
+++ b/src/platform/mutex.h
@@ -81,10 +81,10 @@
   typedef CRITICAL_SECTION NativeHandle;
 #endif
 
-  NativeHandle& native_handle() V8_WARN_UNUSED_RESULT {
+  NativeHandle& native_handle() {
     return native_handle_;
   }
-  const NativeHandle& native_handle() const V8_WARN_UNUSED_RESULT {
+  const NativeHandle& native_handle() const {
     return native_handle_;
   }
 
@@ -177,10 +177,10 @@
   // The implementation-defined native handle type.
   typedef Mutex::NativeHandle NativeHandle;
 
-  NativeHandle& native_handle() V8_WARN_UNUSED_RESULT {
+  NativeHandle& native_handle() {
     return native_handle_;
   }
-  const NativeHandle& native_handle() const V8_WARN_UNUSED_RESULT {
+  const NativeHandle& native_handle() const {
     return native_handle_;
   }
 
diff --git a/src/platform/semaphore.h b/src/platform/semaphore.h
index 221c7a3..2cfa142 100644
--- a/src/platform/semaphore.h
+++ b/src/platform/semaphore.h
@@ -80,10 +80,10 @@
   typedef HANDLE NativeHandle;
 #endif
 
-  NativeHandle& native_handle() V8_WARN_UNUSED_RESULT {
+  NativeHandle& native_handle() {
     return native_handle_;
   }
-  const NativeHandle& native_handle() const V8_WARN_UNUSED_RESULT {
+  const NativeHandle& native_handle() const {
     return native_handle_;
   }
 
diff --git a/src/platform/socket.h b/src/platform/socket.h
index 6710692..e9e2fa2 100644
--- a/src/platform/socket.h
+++ b/src/platform/socket.h
@@ -66,11 +66,11 @@
   // Set the value of the SO_REUSEADDR socket option.
   bool SetReuseAddress(bool reuse_address);
 
-  V8_INLINE(bool IsValid()) const V8_WARN_UNUSED_RESULT {
+  V8_INLINE(bool IsValid()) const {
     return native_handle_ != kInvalidNativeHandle;
   }
 
-  static int GetLastError() V8_WARN_UNUSED_RESULT;
+  static int GetLastError();
 
   // The implementation-defined native handle type.
 #if V8_OS_POSIX
@@ -81,10 +81,10 @@
   static const NativeHandle kInvalidNativeHandle = INVALID_SOCKET;
 #endif
 
-  NativeHandle& native_handle() V8_WARN_UNUSED_RESULT {
+  NativeHandle& native_handle() {
     return native_handle_;
   }
-  const NativeHandle& native_handle() const V8_WARN_UNUSED_RESULT {
+  const NativeHandle& native_handle() const {
     return native_handle_;
   }
 
diff --git a/src/platform/time.h b/src/platform/time.h
index 3fed628..2ce6cdd 100644
--- a/src/platform/time.h
+++ b/src/platform/time.h
@@ -222,6 +222,15 @@
   // with which we might compare it.
   static Time Max() { return Time(std::numeric_limits<int64_t>::max()); }
 
+  // Converts to/from internal values. The meaning of the "internal value" is
+  // completely up to the implementation, so it should be treated as opaque.
+  static Time FromInternalValue(int64_t value) {
+    return Time(value);
+  }
+  int64_t ToInternalValue() const {
+    return us_;
+  }
+
   // Converts to/from POSIX time specs.
   static Time FromTimespec(struct timespec ts);
   struct timespec ToTimespec() const;
@@ -329,6 +338,15 @@
   // Returns true if this object has not been initialized.
   bool IsNull() const { return ticks_ == 0; }
 
+  // Converts to/from internal values. The meaning of the "internal value" is
+  // completely up to the implementation, so it should be treated as opaque.
+  static TimeTicks FromInternalValue(int64_t value) {
+    return TimeTicks(value);
+  }
+  int64_t ToInternalValue() const {
+    return ticks_;
+  }
+
   TimeTicks& operator=(const TimeTicks other) {
     ticks_ = other.ticks_;
     return *this;
diff --git a/src/profile-generator.cc b/src/profile-generator.cc
index 3c11521..38c1f78 100644
--- a/src/profile-generator.cc
+++ b/src/profile-generator.cc
@@ -41,8 +41,8 @@
 namespace internal {
 
 
-StringsStorage::StringsStorage()
-    : names_(StringsMatch) {
+StringsStorage::StringsStorage(Heap* heap)
+    : hash_seed_(heap->HashSeed()), names_(StringsMatch) {
 }
 
 
@@ -61,7 +61,7 @@
   OS::StrNCpy(dst, src, len);
   dst[len] = '\0';
   uint32_t hash =
-      StringHasher::HashSequentialString(dst.start(), len, HEAP->HashSeed());
+      StringHasher::HashSequentialString(dst.start(), len, hash_seed_);
   return AddOrDisposeString(dst.start(), hash);
 }
 
@@ -95,7 +95,7 @@
     return format;
   }
   uint32_t hash = StringHasher::HashSequentialString(
-      str.start(), len, HEAP->HashSeed());
+      str.start(), len, hash_seed_);
   return AddOrDisposeString(str.start(), hash);
 }
 
@@ -443,8 +443,9 @@
 }
 
 
-CpuProfilesCollection::CpuProfilesCollection()
-    : current_profiles_semaphore_(1) {
+CpuProfilesCollection::CpuProfilesCollection(Heap* heap)
+    : function_and_resource_names_(heap),
+      current_profiles_semaphore_(1) {
 }
 
 
diff --git a/src/profile-generator.h b/src/profile-generator.h
index 9ce5f23..0a4502c 100644
--- a/src/profile-generator.h
+++ b/src/profile-generator.h
@@ -41,7 +41,7 @@
 // forever, even if they disappear from JS heap or external storage.
 class StringsStorage {
  public:
-  StringsStorage();
+  explicit StringsStorage(Heap* heap);
   ~StringsStorage();
 
   const char* GetCopy(const char* src);
@@ -63,6 +63,7 @@
   const char* AddOrDisposeString(char* str, uint32_t hash);
 
   // Mapping of strings by String::Hash to const char* strings.
+  uint32_t hash_seed_;
   HashMap names_;
 
   DISALLOW_COPY_AND_ASSIGN(StringsStorage);
@@ -277,7 +278,7 @@
 
 class CpuProfilesCollection {
  public:
-  CpuProfilesCollection();
+  explicit CpuProfilesCollection(Heap* heap);
   ~CpuProfilesCollection();
 
   bool StartProfiling(const char* title, unsigned uid, bool record_samples);
diff --git a/src/property.h b/src/property.h
index 094590e..0f78ba4 100644
--- a/src/property.h
+++ b/src/property.h
@@ -46,7 +46,8 @@
  public:
   MUST_USE_RESULT MaybeObject* KeyToUniqueName() {
     if (!key_->IsUniqueName()) {
-      MaybeObject* maybe_result = HEAP->InternalizeString(String::cast(key_));
+      MaybeObject* maybe_result =
+          key_->GetIsolate()->heap()->InternalizeString(String::cast(key_));
       if (!maybe_result->To(&key_)) return maybe_result;
     }
     return key_;
diff --git a/src/runtime.cc b/src/runtime.cc
index 56558e0..9f37411 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -6551,8 +6551,7 @@
   int part_count = indices.length();
 
   Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
-  MaybeObject* maybe_result = result->EnsureCanContainHeapObjectElements();
-  if (maybe_result->IsFailure()) return maybe_result;
+  JSObject::EnsureCanContainHeapObjectElements(result);
   result->set_length(Smi::FromInt(part_count));
 
   ASSERT(result->HasFastObjectElements());
@@ -6945,21 +6944,20 @@
 
 
 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
-  SealHandleScope shs(isolate);
+  HandleScope scope(isolate);
   ASSERT(args.length() == 3);
-  CONVERT_ARG_CHECKED(JSArray, array, 0);
+  CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
   if (!args[1]->IsSmi()) {
     isolate->context()->mark_out_of_memory();
     return Failure::OutOfMemoryException(0x14);
   }
   int array_length = args.smi_at(1);
-  CONVERT_ARG_CHECKED(String, special, 2);
+  CONVERT_ARG_HANDLE_CHECKED(String, special, 2);
 
   // This assumption is used by the slice encoding in one or two smis.
   ASSERT(Smi::kMaxValue >= String::kMaxLength);
 
-  MaybeObject* maybe_result = array->EnsureCanContainHeapObjectElements();
-  if (maybe_result->IsFailure()) return maybe_result;
+  JSObject::EnsureCanContainHeapObjectElements(array);
 
   int special_length = special->length();
   if (!array->HasFastObjectElements()) {
@@ -7041,7 +7039,7 @@
       if (!maybe_object->ToObject(&object)) return maybe_object;
     }
     SeqOneByteString* answer = SeqOneByteString::cast(object);
-    StringBuilderConcatHelper(special,
+    StringBuilderConcatHelper(*special,
                               answer->GetChars(),
                               fixed_array,
                               array_length);
@@ -7052,7 +7050,7 @@
       if (!maybe_object->ToObject(&object)) return maybe_object;
     }
     SeqTwoByteString* answer = SeqTwoByteString::cast(object);
-    StringBuilderConcatHelper(special,
+    StringBuilderConcatHelper(*special,
                               answer->GetChars(),
                               fixed_array,
                               array_length);
@@ -8318,9 +8316,7 @@
     return function->code();
   }
   function->shared()->code()->set_profiler_ticks(0);
-  if (JSFunction::CompileOptimized(function,
-                                   BailoutId::None(),
-                                   CLEAR_EXCEPTION)) {
+  if (JSFunction::CompileOptimized(function, CLEAR_EXCEPTION)) {
     return function->code();
   }
   if (FLAG_trace_opt) {
@@ -8415,6 +8411,7 @@
 
   JavaScriptFrame* frame = it.frame();
   RUNTIME_ASSERT(frame->function()->IsJSFunction());
+  ASSERT(frame->function() == *function);
 
   // Avoid doing too much work when running with --always-opt and keep
   // the optimized code around.
@@ -8592,22 +8589,29 @@
   // We're not prepared to handle a function with arguments object.
   ASSERT(!function->shared()->uses_arguments());
 
-  // If the optimization attempt succeeded, return the AST id tagged as a
-  // smi. This tells the builtin that we need to translate the unoptimized
-  // frame to an optimized one.
-  BailoutId ast_id =
+  // If the optimization attempt succeeds, return the code object which
+  // the unoptimized code can jump into.
+  Handle<Code> code =
       (FLAG_concurrent_recompilation && FLAG_concurrent_osr)
           ? Compiler::CompileForConcurrentOSR(function)
           : Compiler::CompileForOnStackReplacement(function);
-  if (!ast_id.IsNone()) {
-    ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
-    return Smi::FromInt(ast_id.ToInt());
+  if (!code.is_null()) {
+#if DEBUG
+    ASSERT(code->kind() == Code::OPTIMIZED_FUNCTION);
+    DeoptimizationInputData* data =
+        DeoptimizationInputData::cast(code->deoptimization_data());
+    ASSERT(!BailoutId(data->OsrAstId()->value()).IsNone());
+#endif
+    // TODO(titzer): this is a massive hack to make the deopt counts
+    // match. Fix heuristics for reenabling optimizations!
+    function->shared()->increment_deopt_count();
+    return *code;
   } else {
     if (function->IsMarkedForLazyRecompilation() ||
         function->IsMarkedForConcurrentRecompilation()) {
       function->ReplaceCode(function->shared()->code());
     }
-    return Smi::FromInt(-1);
+    return NULL;
   }
 }
 
@@ -9411,9 +9415,7 @@
 
   CONVERT_ARG_HANDLE_CHECKED(JSArray, output, 1);
 
-  MaybeObject* maybe_result_array =
-      output->EnsureCanContainHeapObjectElements();
-  if (maybe_result_array->IsFailure()) return maybe_result_array;
+  JSObject::EnsureCanContainHeapObjectElements(output);
   RUNTIME_ASSERT(output->HasFastObjectElements());
 
   DisallowHeapAllocation no_gc;
@@ -12948,7 +12950,7 @@
   }
   FixedArray* instances = FixedArray::cast(object);
 
-  ASSERT(HEAP->IsHeapIterable());
+  ASSERT(isolate->heap()->IsHeapIterable());
   // Fill the referencing objects.
   HeapIterator heap_iterator2(heap);
   count = DebugConstructedBy(&heap_iterator2,
diff --git a/src/scopeinfo.cc b/src/scopeinfo.cc
index 3d09d3a..ba138f2 100644
--- a/src/scopeinfo.cc
+++ b/src/scopeinfo.cc
@@ -445,7 +445,8 @@
                               int slot_index) {
   String* internalized_name;
   ASSERT(slot_index > kNotFound);
-  if (HEAP->InternalizeStringIfExists(name, &internalized_name)) {
+  if (name->GetIsolate()->heap()->InternalizeStringIfExists(
+          name, &internalized_name)) {
     int index = Hash(data, internalized_name);
     Key& key = keys_[index];
     key.data = data;
@@ -472,7 +473,8 @@
                                      InitializationFlag init_flag,
                                      int slot_index) {
   String* internalized_name;
-  if (HEAP->InternalizeStringIfExists(name, &internalized_name)) {
+  if (name->GetIsolate()->heap()->InternalizeStringIfExists(
+          name, &internalized_name)) {
     int index = Hash(data, name);
     Key& key = keys_[index];
     ASSERT(key.data == data);
diff --git a/src/serialize.cc b/src/serialize.cc
index 6f84aed..d05dd26 100644
--- a/src/serialize.cc
+++ b/src/serialize.cc
@@ -1307,7 +1307,7 @@
   // We don't support serializing installed extensions.
   CHECK(!isolate->has_installed_extensions());
 
-  HEAP->IterateStrongRoots(this, VISIT_ONLY_STRONG);
+  isolate->heap()->IterateStrongRoots(this, VISIT_ONLY_STRONG);
 }
 
 
@@ -1485,7 +1485,7 @@
   // uses to know it is done deserializing the array.
   Object* undefined = isolate()->heap()->undefined_value();
   VisitPointer(&undefined);
-  HEAP->IterateWeakRoots(this, VISIT_ALL);
+  isolate()->heap()->IterateWeakRoots(this, VISIT_ALL);
   Pad();
 }
 
@@ -1498,7 +1498,7 @@
   if (how_to_code == kPlain &&
       where_to_point == kStartOfObject &&
       root_index < kRootArrayNumberOfConstantEncodings &&
-      !HEAP->InNewSpace(object)) {
+      !isolate()->heap()->InNewSpace(object)) {
     if (skip == 0) {
       sink_->Put(kRootArrayConstants + kNoSkipDistance + root_index,
                  "RootConstant");
@@ -1631,7 +1631,7 @@
           root_index != kInvalidRootIndex &&
           root_index < kRootArrayNumberOfConstantEncodings &&
           current_contents == current[-1]) {
-        ASSERT(!HEAP->InNewSpace(current_contents));
+        ASSERT(!serializer_->isolate()->heap()->InNewSpace(current_contents));
         int repeat_count = 1;
         while (current < end - 1 && current[repeat_count] == current_contents) {
           repeat_count++;
@@ -1748,7 +1748,8 @@
   Address references_start = reinterpret_cast<Address>(resource_pointer);
   OutputRawData(references_start);
   for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
-    Object* source = HEAP->natives_source_cache()->get(i);
+    Object* source =
+        serializer_->isolate()->heap()->natives_source_cache()->get(i);
     if (!source->IsUndefined()) {
       ExternalAsciiString* string = ExternalAsciiString::cast(source);
       typedef v8::String::ExternalAsciiStringResource Resource;
@@ -1817,7 +1818,7 @@
 int Serializer::SpaceOfObject(HeapObject* object) {
   for (int i = FIRST_SPACE; i <= LAST_SPACE; i++) {
     AllocationSpace s = static_cast<AllocationSpace>(i);
-    if (HEAP->InSpace(object, s)) {
+    if (object->GetHeap()->InSpace(object, s)) {
       ASSERT(i < kNumberOfSpaces);
       return i;
     }
diff --git a/src/serialize.h b/src/serialize.h
index 0b07e1f..020a744 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -620,7 +620,8 @@
     return o->IsName() || o->IsSharedFunctionInfo() ||
            o->IsHeapNumber() || o->IsCode() ||
            o->IsScopeInfo() ||
-           o->map() == HEAP->fixed_cow_array_map();
+           o->map() ==
+               startup_serializer_->isolate()->heap()->fixed_cow_array_map();
   }
 
  private:
diff --git a/src/spaces-inl.h b/src/spaces-inl.h
index 77117b8..be2ae2a 100644
--- a/src/spaces-inl.h
+++ b/src/spaces-inl.h
@@ -194,11 +194,11 @@
 }
 
 
-MemoryChunk* MemoryChunk::FromAnyPointerAddress(Address addr) {
+MemoryChunk* MemoryChunk::FromAnyPointerAddress(Heap* heap, Address addr) {
   MemoryChunk* maybe = reinterpret_cast<MemoryChunk*>(
       OffsetFrom(addr) & ~Page::kPageAlignmentMask);
   if (maybe->owner() != NULL) return maybe;
-  LargeObjectIterator iterator(HEAP->lo_space());
+  LargeObjectIterator iterator(heap->lo_space());
   for (HeapObject* o = iterator.Next(); o != NULL; o = iterator.Next()) {
     // Fixed arrays are the only pointer-containing objects in large object
     // space.
@@ -315,12 +315,12 @@
 #ifdef DEBUG
   // If we are stressing compaction we waste some memory in new space
   // in order to get more frequent GCs.
-  if (FLAG_stress_compaction && !HEAP->linear_allocation()) {
+  if (FLAG_stress_compaction && !heap()->linear_allocation()) {
     if (allocation_info_.limit - old_top >= size_in_bytes * 4) {
       int filler_size = size_in_bytes * 4;
       for (int i = 0; i < filler_size; i += kPointerSize) {
         *(reinterpret_cast<Object**>(old_top + i)) =
-            HEAP->one_pointer_filler_map();
+            heap()->one_pointer_filler_map();
       }
       old_top += filler_size;
       allocation_info_.top += filler_size;
diff --git a/src/spaces.cc b/src/spaces.cc
index 13f80d8..2faf419 100644
--- a/src/spaces.cc
+++ b/src/spaces.cc
@@ -1950,7 +1950,7 @@
 #endif  // DEBUG
 
   if (FLAG_log_gc) {
-    Isolate* isolate = ISOLATE;
+    Isolate* isolate = heap()->isolate();
     DoReportStatistics(isolate, allocated_histogram_, "allocated");
     DoReportStatistics(isolate, promoted_histogram_, "promoted");
   }
diff --git a/src/spaces.h b/src/spaces.h
index 5b9a4e4..1ccdacb 100644
--- a/src/spaces.h
+++ b/src/spaces.h
@@ -307,7 +307,7 @@
   }
 
   // Only works for addresses in pointer spaces, not data or code spaces.
-  static inline MemoryChunk* FromAnyPointerAddress(Address addr);
+  static inline MemoryChunk* FromAnyPointerAddress(Heap* heap, Address addr);
 
   Address address() { return reinterpret_cast<Address>(this); }
 
diff --git a/src/store-buffer-inl.h b/src/store-buffer-inl.h
index bb386db..e1fcdee 100644
--- a/src/store-buffer-inl.h
+++ b/src/store-buffer-inl.h
@@ -67,7 +67,7 @@
     if (top >= old_limit_) {
       ASSERT(callback_ != NULL);
       (*callback_)(heap_,
-                   MemoryChunk::FromAnyPointerAddress(addr),
+                   MemoryChunk::FromAnyPointerAddress(heap_, addr),
                    kStoreBufferFullEvent);
     }
   }
diff --git a/src/store-buffer.cc b/src/store-buffer.cc
index 30b7f25..22a5467 100644
--- a/src/store-buffer.cc
+++ b/src/store-buffer.cc
@@ -221,7 +221,7 @@
     if (previous_chunk != NULL && previous_chunk->Contains(addr)) {
       containing_chunk = previous_chunk;
     } else {
-      containing_chunk = MemoryChunk::FromAnyPointerAddress(addr);
+      containing_chunk = MemoryChunk::FromAnyPointerAddress(heap_, addr);
     }
     int old_counter = containing_chunk->store_buffer_counter();
     if (old_counter == threshold) {
@@ -247,7 +247,7 @@
     if (previous_chunk != NULL && previous_chunk->Contains(addr)) {
       containing_chunk = previous_chunk;
     } else {
-      containing_chunk = MemoryChunk::FromAnyPointerAddress(addr);
+      containing_chunk = MemoryChunk::FromAnyPointerAddress(heap_, addr);
       previous_chunk = containing_chunk;
     }
     if (!containing_chunk->IsFlagSet(flag)) {
diff --git a/src/string-stream.cc b/src/string-stream.cc
index f34f53d..7c45e2f 100644
--- a/src/string-stream.cc
+++ b/src/string-stream.cc
@@ -270,7 +270,7 @@
 
 
 void StringStream::Log() {
-  LOG(ISOLATE, StringEvent("StackDump", buffer_));
+  LOG(Isolate::Current(), StringEvent("StackDump", buffer_));
 }
 
 
@@ -350,7 +350,7 @@
 
 void StringStream::PrintUsingMap(JSObject* js_object) {
   Map* map = js_object->map();
-  if (!HEAP->Contains(map) ||
+  if (!js_object->GetHeap()->Contains(map) ||
       !map->IsHeapObject() ||
       !map->IsMap()) {
     Add("<Invalid map>\n");
@@ -384,7 +384,7 @@
 
 
 void StringStream::PrintFixedArray(FixedArray* array, unsigned int limit) {
-  Heap* heap = HEAP;
+  Heap* heap = array->GetHeap();
   for (unsigned int i = 0; i < 10 && i < limit; i++) {
     Object* element = array->get(i);
     if (element != heap->the_hole_value()) {
@@ -491,48 +491,39 @@
 
 
 void StringStream::PrintFunction(Object* f, Object* receiver, Code** code) {
-  if (f->IsHeapObject() &&
-      HEAP->Contains(HeapObject::cast(f)) &&
-      HEAP->Contains(HeapObject::cast(f)->map()) &&
-      HeapObject::cast(f)->map()->IsMap()) {
-    if (f->IsJSFunction()) {
-      JSFunction* fun = JSFunction::cast(f);
-      // Common case: on-stack function present and resolved.
-      PrintPrototype(fun, receiver);
-      *code = fun->code();
-    } else if (f->IsInternalizedString()) {
-      // Unresolved and megamorphic calls: Instead of the function
-      // we have the function name on the stack.
-      PrintName(f);
-      Add("/* unresolved */ ");
-    } else {
-      // Unless this is the frame of a built-in function, we should always have
-      // the callee function or name on the stack. If we don't, we have a
-      // problem or a change of the stack frame layout.
-      Add("%o", f);
-      Add("/* warning: no JSFunction object or function name found */ ");
-    }
-    /* } else if (is_trampoline()) {
-       Print("trampoline ");
-    */
+  if (!f->IsHeapObject()) {
+    Add("/* warning: 'function' was not a heap object */ ");
+    return;
+  }
+  Heap* heap = HeapObject::cast(f)->GetHeap();
+  if (!heap->Contains(HeapObject::cast(f))) {
+    Add("/* warning: 'function' was not on the heap */ ");
+    return;
+  }
+  if (!heap->Contains(HeapObject::cast(f)->map())) {
+    Add("/* warning: function's map was not on the heap */ ");
+    return;
+  }
+  if (!HeapObject::cast(f)->map()->IsMap()) {
+    Add("/* warning: function's map was not a valid map */ ");
+    return;
+  }
+  if (f->IsJSFunction()) {
+    JSFunction* fun = JSFunction::cast(f);
+    // Common case: on-stack function present and resolved.
+    PrintPrototype(fun, receiver);
+    *code = fun->code();
+  } else if (f->IsInternalizedString()) {
+    // Unresolved and megamorphic calls: Instead of the function
+    // we have the function name on the stack.
+    PrintName(f);
+    Add("/* unresolved */ ");
   } else {
-    if (!f->IsHeapObject()) {
-      Add("/* warning: 'function' was not a heap object */ ");
-      return;
-    }
-    if (!HEAP->Contains(HeapObject::cast(f))) {
-      Add("/* warning: 'function' was not on the heap */ ");
-      return;
-    }
-    if (!HEAP->Contains(HeapObject::cast(f)->map())) {
-      Add("/* warning: function's map was not on the heap */ ");
-      return;
-    }
-    if (!HeapObject::cast(f)->map()->IsMap()) {
-      Add("/* warning: function's map was not a valid map */ ");
-      return;
-    }
-    Add("/* warning: Invalid JSFunction object found */ ");
+    // Unless this is the frame of a built-in function, we should always have
+    // the callee function or name on the stack. If we don't, we have a
+    // problem or a change of the stack frame layout.
+    Add("%o", f);
+    Add("/* warning: no JSFunction object or function name found */ ");
   }
 }
 
diff --git a/src/stub-cache.cc b/src/stub-cache.cc
index f83a7d2..bdfb32f 100644
--- a/src/stub-cache.cc
+++ b/src/stub-cache.cc
@@ -1309,7 +1309,7 @@
   // can't use either LoadIC or KeyedLoadIC constructors.
   IC ic(IC::NO_EXTRA_FRAME, isolate);
   ASSERT(ic.target()->is_load_stub() || ic.target()->is_keyed_load_stub());
-  if (!ic.SlowIsUndeclaredGlobal()) return HEAP->undefined_value();
+  if (!ic.SlowIsUndeclaredGlobal()) return isolate->heap()->undefined_value();
 
   // Throw a reference error.
   HandleScope scope(isolate);
diff --git a/src/utils/random-number-generator.cc b/src/utils/random-number-generator.cc
new file mode 100644
index 0000000..1e03ee2
--- /dev/null
+++ b/src/utils/random-number-generator.cc
@@ -0,0 +1,136 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "utils/random-number-generator.h"
+
+#include <cstdio>
+
+#include "flags.h"
+#include "platform/mutex.h"
+#include "platform/time.h"
+#include "utils.h"
+
+namespace v8 {
+namespace internal {
+
+static LazyMutex entropy_mutex = LAZY_MUTEX_INITIALIZER;
+static RandomNumberGenerator::EntropySource entropy_source = NULL;
+
+
+// static
+void RandomNumberGenerator::SetEntropySource(EntropySource source) {
+  LockGuard<Mutex> lock_guard(entropy_mutex.Pointer());
+  entropy_source = source;
+}
+
+
+RandomNumberGenerator::RandomNumberGenerator() {
+  // Check --random-seed flag first.
+  if (FLAG_random_seed != 0) {
+    SetSeed(FLAG_random_seed);
+    return;
+  }
+
+  // Check if embedder supplied an entropy source.
+  { LockGuard<Mutex> lock_guard(entropy_mutex.Pointer());
+    if (entropy_source != NULL) {
+      int64_t seed;
+      if (entropy_source(reinterpret_cast<unsigned char*>(&seed),
+                         sizeof(seed))) {
+        SetSeed(seed);
+        return;
+      }
+    }
+  }
+
+  // Gather entropy from /dev/urandom if available.
+  FILE* fp = fopen("/dev/urandom", "rb");
+  if (fp != NULL) {
+    int64_t seed;
+    size_t n = fread(&seed, sizeof(seed), 1, fp);
+    fclose(fp);
+    if (n == 1) {
+      SetSeed(seed);
+      return;
+    }
+  }
+
+  // We cannot assume that random() or rand() were seeded
+  // properly, so instead of relying on random() or rand(),
+  // we just seed our PRNG using timing data as fallback.
+  int64_t seed = Time::NowFromSystemTime().ToInternalValue() << 24;
+  seed ^= TimeTicks::HighResNow().ToInternalValue() << 16;
+  seed ^= TimeTicks::Now().ToInternalValue() << 8;
+  SetSeed(seed);
+}
+
+
+int RandomNumberGenerator::NextInt(int max) {
+  ASSERT_LE(0, max);
+
+  // Fast path if max is a power of 2.
+  if (IsPowerOf2(max)) {
+    return static_cast<int>((max * static_cast<int64_t>(Next(31))) >> 31);
+  }
+
+  while (true) {
+    int rnd = Next(31);
+    int val = rnd % max;
+    if (rnd - val + (max - 1) >= 0) {
+      return val;
+    }
+  }
+}
+
+
+double RandomNumberGenerator::NextDouble() {
+  return ((static_cast<int64_t>(Next(26)) << 27) + Next(27)) /
+      static_cast<double>(static_cast<int64_t>(1) << 53);
+}
+
+
+void RandomNumberGenerator::NextBytes(void* buffer, size_t buflen) {
+  for (size_t n = 0; n < buflen; ++n) {
+    static_cast<uint8_t*>(buffer)[n] = static_cast<uint8_t>(Next(8));
+  }
+}
+
+
+int RandomNumberGenerator::Next(int bits) {
+  ASSERT_LT(0, bits);
+  ASSERT_GE(32, bits);
+  int64_t seed = (seed_ * kMultiplier + kAddend) & kMask;
+  seed_ = seed;
+  return static_cast<int>(seed >> (48 - bits));
+}
+
+
+void RandomNumberGenerator::SetSeed(int64_t seed) {
+  seed_ = (seed ^ kMultiplier) & kMask;
+}
+
+} }  // namespace v8::internal
diff --git a/src/utils/random-number-generator.h b/src/utils/random-number-generator.h
new file mode 100644
index 0000000..fc14ef4
--- /dev/null
+++ b/src/utils/random-number-generator.h
@@ -0,0 +1,106 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_UTILS_RANDOM_NUMBER_GENERATOR_H_
+#define V8_UTILS_RANDOM_NUMBER_GENERATOR_H_
+
+#include "globals.h"
+
+namespace v8 {
+namespace internal {
+
+// -----------------------------------------------------------------------------
+// RandomNumberGenerator
+//
+// This class is used to generate a stream of pseudorandom numbers. The class
+// uses a 48-bit seed, which is modified using a linear congruential formula.
+// (See Donald Knuth, The Art of Computer Programming, Volume 3, Section 3.2.1.)
+// If two instances of RandomNumberGenerator are created with the same seed, and
+// the same sequence of method calls is made for each, they will generate and
+// return identical sequences of numbers.
+// This class is neither reentrant nor threadsafe.
+
+class RandomNumberGenerator V8_FINAL {
+ public:
+  // EntropySource is used as a callback function when V8 needs a source of
+  // entropy.
+  typedef bool (*EntropySource)(unsigned char* buffer, size_t buflen);
+  static void SetEntropySource(EntropySource entropy_source);
+
+  RandomNumberGenerator();
+  explicit RandomNumberGenerator(int64_t seed) { SetSeed(seed); }
+
+  // Returns the next pseudorandom, uniformly distributed int value from this
+  // random number generator's sequence. The general contract of |NextInt()| is
+  // that one int value is pseudorandomly generated and returned.
+  // All 2^32 possible integer values are produced with (approximately) equal
+  // probability.
+  V8_INLINE(int NextInt()) V8_WARN_UNUSED_RESULT {
+    return Next(32);
+  }
+
+  // Returns a pseudorandom, uniformly distributed int value between 0
+  // (inclusive) and the specified max value (exclusive), drawn from this random
+  // number generator's sequence. The general contract of |NextInt(int)| is that
+  // one int value in the specified range is pseudorandomly generated and
+  // returned. All max possible int values are produced with (approximately)
+  // equal probability.
+  int NextInt(int max) V8_WARN_UNUSED_RESULT;
+
+  // Returns the next pseudorandom, uniformly distributed boolean value from
+  // this random number generator's sequence. The general contract of
+  // |NextBoolean()| is that one boolean value is pseudorandomly generated and
+  // returned. The values true and false are produced with (approximately) equal
+  // probability.
+  V8_INLINE(bool NextBool()) V8_WARN_UNUSED_RESULT {
+    return Next(1) != 0;
+  }
+
+  // Returns the next pseudorandom, uniformly distributed double value between
+  // 0.0 and 1.0 from this random number generator's sequence.
+  // The general contract of |NextDouble()| is that one double value, chosen
+  // (approximately) uniformly from the range 0.0 (inclusive) to 1.0
+  // (exclusive), is pseudorandomly generated and returned.
+  double NextDouble() V8_WARN_UNUSED_RESULT;
+
+  // Fills the elements of a specified array of bytes with random numbers.
+  void NextBytes(void* buffer, size_t buflen);
+
+ private:
+  static const int64_t kMultiplier = V8_2PART_UINT64_C(0x5, deece66d);
+  static const int64_t kAddend = 0xb;
+  static const int64_t kMask = V8_2PART_UINT64_C(0xffff, ffffffff);
+
+  int Next(int bits) V8_WARN_UNUSED_RESULT;
+  void SetSeed(int64_t seed);
+
+  int64_t seed_;
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_UTILS_RANDOM_NUMBER_GENERATOR_H_
diff --git a/src/v8.cc b/src/v8.cc
index d9ce840..e894164 100644
--- a/src/v8.cc
+++ b/src/v8.cc
@@ -53,10 +53,6 @@
 List<CallCompletedCallback>* V8::call_completed_callbacks_ = NULL;
 v8::ArrayBuffer::Allocator* V8::array_buffer_allocator_ = NULL;
 
-static LazyMutex entropy_mutex = LAZY_MUTEX_INITIALIZER;
-
-static EntropySource entropy_source;
-
 
 bool V8::Initialize(Deserializer* des) {
   InitializeOncePerProcess();
@@ -107,41 +103,6 @@
 }
 
 
-static void seed_random(uint32_t* state) {
-  for (int i = 0; i < 2; ++i) {
-    if (FLAG_random_seed != 0) {
-      state[i] = FLAG_random_seed;
-    } else if (entropy_source != NULL) {
-      uint32_t val;
-      LockGuard<Mutex> lock_guard(entropy_mutex.Pointer());
-      entropy_source(reinterpret_cast<unsigned char*>(&val), sizeof(uint32_t));
-      state[i] = val;
-    } else {
-      state[i] = random();
-    }
-  }
-}
-
-
-// Random number generator using George Marsaglia's MWC algorithm.
-static uint32_t random_base(uint32_t* state) {
-  // Initialize seed using the system random().
-  // No non-zero seed will ever become zero again.
-  if (state[0] == 0) seed_random(state);
-
-  // Mix the bits.  Never replaces state[i] with 0 if it is nonzero.
-  state[0] = 18273 * (state[0] & 0xFFFF) + (state[0] >> 16);
-  state[1] = 36969 * (state[1] & 0xFFFF) + (state[1] >> 16);
-
-  return (state[0] << 14) + (state[1] & 0x3FFFF);
-}
-
-
-void V8::SetEntropySource(EntropySource source) {
-  entropy_source = source;
-}
-
-
 void V8::SetReturnAddressLocationResolver(
       ReturnAddressLocationResolver resolver) {
   StackFrame::SetReturnAddressLocationResolver(resolver);
@@ -152,15 +113,18 @@
 uint32_t V8::Random(Context* context) {
   ASSERT(context->IsNativeContext());
   ByteArray* seed = context->random_seed();
-  return random_base(reinterpret_cast<uint32_t*>(seed->GetDataStartAddress()));
-}
+  uint32_t* state = reinterpret_cast<uint32_t*>(seed->GetDataStartAddress());
 
+  // When we get here, the RNG must have been initialized,
+  // see the Genesis constructor in file bootstrapper.cc.
+  ASSERT_NE(0, state[0]);
+  ASSERT_NE(0, state[1]);
 
-// Used internally by the JIT and memory allocator for security
-// purposes. So, we keep a different state to prevent informations
-// leaks that could be used in an exploit.
-uint32_t V8::RandomPrivate(Isolate* isolate) {
-  return random_base(isolate->private_random_seed());
+  // Mix the bits.  Never replaces state[i] with 0 if it is nonzero.
+  state[0] = 18273 * (state[0] & 0xFFFF) + (state[0] >> 16);
+  state[1] = 36969 * (state[1] & 0xFFFF) + (state[1] >> 16);
+
+  return (state[0] << 14) + (state[1] & 0x3FFFF);
 }
 
 
@@ -282,7 +246,6 @@
     FLAG_concurrent_recompilation = false;
   }
 
-  OS::SetUp();
   Sampler::SetUp();
   CPU::SetUp();
   OS::PostSetUp();
diff --git a/src/v8.h b/src/v8.h
index 23277b3..5848f74 100644
--- a/src/v8.h
+++ b/src/v8.h
@@ -97,11 +97,6 @@
   static void SetFunctionEntryHook(FunctionEntryHook entry_hook);
   // Random number generation support. Not cryptographically safe.
   static uint32_t Random(Context* context);
-  // We use random numbers internally in memory allocation and in the
-  // compilers for security. In order to prevent information leaks we
-  // use a separate random state for internal random number
-  // generation.
-  static uint32_t RandomPrivate(Isolate* isolate);
   static Object* FillHeapNumberWithRandom(Object* heap_number,
                                           Context* context);
 
diff --git a/src/version.cc b/src/version.cc
index 1b7627f..076c7ef 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,8 +34,8 @@
 // system so their names cannot be changed without changing the scripts.
 #define MAJOR_VERSION     3
 #define MINOR_VERSION     21
-#define BUILD_NUMBER      12
-#define PATCH_LEVEL       2
+#define BUILD_NUMBER      13
+#define PATCH_LEVEL       0
 // Use 1 for candidates and 0 otherwise.
 // (Boolean macro values are not supported by all preprocessors.)
 #define IS_CANDIDATE_VERSION 0
diff --git a/src/x64/assembler-x64.cc b/src/x64/assembler-x64.cc
index 8910b07..41bf297 100644
--- a/src/x64/assembler-x64.cc
+++ b/src/x64/assembler-x64.cc
@@ -396,7 +396,7 @@
   // Some internal data structures overflow for very large buffers,
   // they must ensure that kMaximalBufferSize is not too large.
   if ((desc.buffer_size > kMaximalBufferSize) ||
-      (desc.buffer_size > HEAP->MaxOldGenerationSize())) {
+      (desc.buffer_size > isolate()->heap()->MaxOldGenerationSize())) {
     V8::FatalProcessOutOfMemory("Assembler::GrowBuffer");
   }
 
@@ -1533,7 +1533,7 @@
   } else {
     EnsureSpace ensure_space(this);
     ASSERT(value->IsHeapObject());
-    ASSERT(!HEAP->InNewSpace(*value));
+    ASSERT(!isolate()->heap()->InNewSpace(*value));
     emit_rex_64(dst);
     emit(0xB8 | dst.low_bits());
     emitp(value.location(), mode);
diff --git a/src/x64/builtins-x64.cc b/src/x64/builtins-x64.cc
index 6c83dad..4730ed1 100644
--- a/src/x64/builtins-x64.cc
+++ b/src/x64/builtins-x64.cc
@@ -1418,22 +1418,29 @@
     __ CallRuntime(Runtime::kCompileForOnStackReplacement, 1);
   }
 
-  // If the result was -1 it means that we couldn't optimize the
-  // function. Just return and continue in the unoptimized version.
   Label skip;
-  __ SmiCompare(rax, Smi::FromInt(-1));
+  // If the code object is null, just return to the unoptimized code.
+  __ cmpq(rax, Immediate(0));
   __ j(not_equal, &skip, Label::kNear);
   __ ret(0);
 
   __ bind(&skip);
-  // Untag the AST id and push it on the stack.
-  __ SmiToInteger32(rax, rax);
-  __ push(rax);
 
-  // Generate the code for doing the frame-to-frame translation using
-  // the deoptimizer infrastructure.
-  Deoptimizer::EntryGenerator generator(masm, Deoptimizer::OSR);
-  generator.Generate();
+  // Load deoptimization data from the code object.
+  __ movq(rbx, Operand(rax, Code::kDeoptimizationDataOffset - kHeapObjectTag));
+
+  // Load the OSR entrypoint offset from the deoptimization data.
+  __ SmiToInteger32(rbx, Operand(rbx, FixedArray::OffsetOfElementAt(
+      DeoptimizationInputData::kOsrPcOffsetIndex) - kHeapObjectTag));
+
+  // Compute the target address = code_obj + header_size + osr_offset
+  __ lea(rax, Operand(rax, rbx, times_1, Code::kHeaderSize - kHeapObjectTag));
+
+  // Overwrite the return address on the stack.
+  __ movq(Operand(rsp, 0), rax);
+
+  // And "return" to the OSR entry point of the function.
+  __ ret(0);
 }
 
 
diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
index 83d01a6..00c5367 100644
--- a/src/x64/code-stubs-x64.cc
+++ b/src/x64/code-stubs-x64.cc
@@ -1136,6 +1136,7 @@
   const bool tagged = (argument_type_ == TAGGED);
   if (tagged) {
     Label input_not_smi, loaded;
+
     // Test that rax is a number.
     StackArgumentsAccessor args(rsp, 1, ARGUMENTS_DONT_CONTAIN_RECEIVER);
     __ movq(rax, args.GetArgumentOperand(0));
@@ -1446,10 +1447,8 @@
   __ bind(&arg1_is_object);
   __ cmpq(FieldOperand(rdx, HeapObject::kMapOffset), heap_number_map);
   __ j(not_equal, &check_undefined_arg1);
-  // Get the untagged integer version of the rdx heap number in rcx.
-  DoubleToIStub stub1(rdx, r8, HeapNumber::kValueOffset - kHeapObjectTag,
-                      true);
-  __ call(stub1.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
+  // Get the untagged integer version of the rdx heap number in r8.
+  __ TruncateHeapNumberToI(r8, rdx);
 
   // Here r8 has the untagged integer, rax has a Smi or a heap number.
   __ bind(&load_arg2);
@@ -1469,9 +1468,7 @@
   __ cmpq(FieldOperand(rax, HeapObject::kMapOffset), heap_number_map);
   __ j(not_equal, &check_undefined_arg2);
   // Get the untagged integer version of the rax heap number in rcx.
-  DoubleToIStub stub2(rax, rcx, HeapNumber::kValueOffset - kHeapObjectTag,
-                      true);
-  __ call(stub2.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
+  __ TruncateHeapNumberToI(rcx, rax);
 
   __ bind(&done);
   __ movl(rax, r8);
@@ -1648,16 +1645,17 @@
   }
 
   if (exponent_type_ != INTEGER) {
-    Label fast_power;
+    Label fast_power, try_arithmetic_simplification;
     // Detect integer exponents stored as double.
+    __ DoubleToI(exponent, double_exponent, double_scratch,
+                 TREAT_MINUS_ZERO_AS_ZERO, &try_arithmetic_simplification);
+    __ jmp(&int_exponent);
+
+    __ bind(&try_arithmetic_simplification);
     __ cvttsd2si(exponent, double_exponent);
     // Skip to runtime if possibly NaN (indicated by the indefinite integer).
     __ cmpl(exponent, Immediate(0x80000000u));
     __ j(equal, &call_runtime);
-    __ cvtlsi2sd(double_scratch, exponent);
-    // Already ruled out NaNs for exponent.
-    __ ucomisd(double_exponent, double_scratch);
-    __ j(equal, &int_exponent);
 
     if (exponent_type_ == ON_STACK) {
       // Detect square root case.  Crankshaft detects constant +/-0.5 at
diff --git a/src/x64/deoptimizer-x64.cc b/src/x64/deoptimizer-x64.cc
index bb8acce..303b756 100644
--- a/src/x64/deoptimizer-x64.cc
+++ b/src/x64/deoptimizer-x64.cc
@@ -163,173 +163,6 @@
 #endif  // DEBUG
 
 
-static int LookupBailoutId(DeoptimizationInputData* data, BailoutId ast_id) {
-  ByteArray* translations = data->TranslationByteArray();
-  int length = data->DeoptCount();
-  for (int i = 0; i < length; i++) {
-    if (data->AstId(i) == ast_id) {
-      TranslationIterator it(translations,  data->TranslationIndex(i)->value());
-      int value = it.Next();
-      ASSERT(Translation::BEGIN == static_cast<Translation::Opcode>(value));
-      // Read the number of frames.
-      value = it.Next();
-      if (value == 1) return i;
-    }
-  }
-  UNREACHABLE();
-  return -1;
-}
-
-
-void Deoptimizer::DoComputeOsrOutputFrame() {
-  DeoptimizationInputData* data = DeoptimizationInputData::cast(
-      compiled_code_->deoptimization_data());
-  unsigned ast_id = data->OsrAstId()->value();
-  // TODO(kasperl): This should not be the bailout_id_. It should be
-  // the ast id. Confusing.
-  ASSERT(bailout_id_ == ast_id);
-
-  int bailout_id = LookupBailoutId(data, BailoutId(ast_id));
-  unsigned translation_index = data->TranslationIndex(bailout_id)->value();
-  ByteArray* translations = data->TranslationByteArray();
-
-  TranslationIterator iterator(translations, translation_index);
-  Translation::Opcode opcode =
-      static_cast<Translation::Opcode>(iterator.Next());
-  ASSERT(Translation::BEGIN == opcode);
-  USE(opcode);
-  int count = iterator.Next();
-  iterator.Skip(1);  // Drop JS frame count.
-  ASSERT(count == 1);
-  USE(count);
-
-  opcode = static_cast<Translation::Opcode>(iterator.Next());
-  USE(opcode);
-  ASSERT(Translation::JS_FRAME == opcode);
-  unsigned node_id = iterator.Next();
-  USE(node_id);
-  ASSERT(node_id == ast_id);
-  int closure_id = iterator.Next();
-  USE(closure_id);
-  ASSERT_EQ(Translation::kSelfLiteralId, closure_id);
-  unsigned height = iterator.Next();
-  unsigned height_in_bytes = height * kPointerSize;
-  USE(height_in_bytes);
-
-  unsigned fixed_size = ComputeFixedSize(function_);
-  unsigned input_frame_size = input_->GetFrameSize();
-  ASSERT(fixed_size + height_in_bytes == input_frame_size);
-
-  unsigned stack_slot_size = compiled_code_->stack_slots() * kPointerSize;
-  unsigned outgoing_height = data->ArgumentsStackHeight(bailout_id)->value();
-  unsigned outgoing_size = outgoing_height * kPointerSize;
-  unsigned output_frame_size = fixed_size + stack_slot_size + outgoing_size;
-  ASSERT(outgoing_size == 0);  // OSR does not happen in the middle of a call.
-
-  if (FLAG_trace_osr) {
-    PrintF("[on-stack replacement: begin 0x%08" V8PRIxPTR " ",
-           reinterpret_cast<intptr_t>(function_));
-    PrintFunctionName();
-    PrintF(" => node=%u, frame=%d->%d]\n",
-           ast_id,
-           input_frame_size,
-           output_frame_size);
-  }
-
-  // There's only one output frame in the OSR case.
-  output_count_ = 1;
-  output_ = new FrameDescription*[1];
-  output_[0] = new(output_frame_size) FrameDescription(
-      output_frame_size, function_);
-  output_[0]->SetFrameType(StackFrame::JAVA_SCRIPT);
-
-  // Clear the incoming parameters in the optimized frame to avoid
-  // confusing the garbage collector.
-  unsigned output_offset = output_frame_size - kPointerSize;
-  int parameter_count = function_->shared()->formal_parameter_count() + 1;
-  for (int i = 0; i < parameter_count; ++i) {
-    output_[0]->SetFrameSlot(output_offset, 0);
-    output_offset -= kPointerSize;
-  }
-
-  // Translate the incoming parameters. This may overwrite some of the
-  // incoming argument slots we've just cleared.
-  int input_offset = input_frame_size - kPointerSize;
-  bool ok = true;
-  int limit = input_offset - (parameter_count * kPointerSize);
-  while (ok && input_offset > limit) {
-    ok = DoOsrTranslateCommand(&iterator, &input_offset);
-  }
-
-  // There are no translation commands for the caller's pc and fp, the
-  // context, and the function.  Set them up explicitly.
-  for (int i = StandardFrameConstants::kCallerPCOffset;
-       ok && i >=  StandardFrameConstants::kMarkerOffset;
-       i -= kPointerSize) {
-    intptr_t input_value = input_->GetFrameSlot(input_offset);
-    if (FLAG_trace_osr) {
-      const char* name = "UNKNOWN";
-      switch (i) {
-        case StandardFrameConstants::kCallerPCOffset:
-          name = "caller's pc";
-          break;
-        case StandardFrameConstants::kCallerFPOffset:
-          name = "fp";
-          break;
-        case StandardFrameConstants::kContextOffset:
-          name = "context";
-          break;
-        case StandardFrameConstants::kMarkerOffset:
-          name = "function";
-          break;
-      }
-      PrintF("    [rsp + %d] <- 0x%08" V8PRIxPTR " ; [rsp + %d] "
-             "(fixed part - %s)\n",
-             output_offset,
-             input_value,
-             input_offset,
-             name);
-    }
-    output_[0]->SetFrameSlot(output_offset, input_->GetFrameSlot(input_offset));
-    input_offset -= kPointerSize;
-    output_offset -= kPointerSize;
-  }
-
-  // Translate the rest of the frame.
-  while (ok && input_offset >= 0) {
-    ok = DoOsrTranslateCommand(&iterator, &input_offset);
-  }
-
-  // If translation of any command failed, continue using the input frame.
-  if (!ok) {
-    delete output_[0];
-    output_[0] = input_;
-    output_[0]->SetPc(reinterpret_cast<intptr_t>(from_));
-  } else {
-    // Set up the frame pointer and the context pointer.
-    output_[0]->SetRegister(rbp.code(), input_->GetRegister(rbp.code()));
-    output_[0]->SetRegister(rsi.code(), input_->GetRegister(rsi.code()));
-
-    unsigned pc_offset = data->OsrPcOffset()->value();
-    intptr_t pc = reinterpret_cast<intptr_t>(
-        compiled_code_->entry() + pc_offset);
-    output_[0]->SetPc(pc);
-  }
-  Code* continuation =
-      function_->GetIsolate()->builtins()->builtin(Builtins::kNotifyOSR);
-  output_[0]->SetContinuation(
-      reinterpret_cast<intptr_t>(continuation->entry()));
-
-  if (FLAG_trace_osr) {
-    PrintF("[on-stack replacement translation %s: 0x%08" V8PRIxPTR " ",
-           ok ? "finished" : "aborted",
-           reinterpret_cast<intptr_t>(function_));
-    PrintFunctionName();
-    PrintF(" => pc=0x%0" V8PRIxPTR "]\n", output_[0]->GetPc());
-  }
-}
-
-
 void Deoptimizer::FillInputFrame(Address tos, JavaScriptFrame* frame) {
   // Set the register values. The values are not important as there are no
   // callee saved registers in JavaScript frames, so all registers are
@@ -526,9 +359,7 @@
   }
 
   // Push state, pc, and continuation from the last output frame.
-  if (type() != OSR) {
-    __ push(Operand(rbx, FrameDescription::state_offset()));
-  }
+  __ push(Operand(rbx, FrameDescription::state_offset()));
   __ push(Operand(rbx, FrameDescription::pc_offset()));
   __ push(Operand(rbx, FrameDescription::continuation_offset()));
 
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index f1430d7..836abe8 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -32,6 +32,7 @@
 #include "x64/lithium-codegen-x64.h"
 #include "code-stubs.h"
 #include "stub-cache.h"
+#include "hydrogen-osr.h"
 
 namespace v8 {
 namespace internal {
@@ -257,6 +258,21 @@
 }
 
 
+void LCodeGen::GenerateOsrPrologue() {
+  // Generate the OSR entry prologue at the first unknown OSR value, or if there
+  // are none, at the OSR entrypoint instruction.
+  if (osr_pc_offset_ >= 0) return;
+
+  osr_pc_offset_ = masm()->pc_offset();
+
+  // Adjust the frame size, subsuming the unoptimized frame into the
+  // optimized frame.
+  int slots = GetStackSlotCount() - graph()->osr()->UnoptimizedFrameSlots();
+  ASSERT(slots >= 0);
+  __ subq(rsp, Immediate(slots * kPointerSize));
+}
+
+
 bool LCodeGen::GenerateBody() {
   ASSERT(is_generating());
   bool emit_instructions = true;
@@ -357,6 +373,7 @@
       }
       code->Generate();
       if (NeedsDeferredFrame()) {
+        __ bind(code->done());
         Comment(";;; Destroy frame");
         ASSERT(frame_is_built_);
         frame_is_built_ = false;
@@ -979,8 +996,7 @@
 
 
 void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
-  // Record the address of the first unknown OSR value as the place to enter.
-  if (osr_pc_offset_ == -1) osr_pc_offset_ = masm()->pc_offset();
+  GenerateOsrPrologue();
 }
 
 
@@ -4683,50 +4699,35 @@
 }
 
 
-void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
-  Label done, heap_number;
+void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr, Label* done) {
+  Label heap_number;
   Register input_reg = ToRegister(instr->value());
 
-  // Heap number map check.
-  __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset),
-                 Heap::kHeapNumberMapRootIndex);
 
   if (instr->truncating()) {
+    // Heap number map check.
+    __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset),
+                   Heap::kHeapNumberMapRootIndex);
     __ j(equal, &heap_number, Label::kNear);
     // Check for undefined. Undefined is converted to zero for truncating
     // conversions.
     __ CompareRoot(input_reg, Heap::kUndefinedValueRootIndex);
     DeoptimizeIf(not_equal, instr->environment());
     __ Set(input_reg, 0);
-    __ jmp(&done, Label::kNear);
+    __ jmp(done);
 
     __ bind(&heap_number);
-
-    __ movsd(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
-    __ cvttsd2siq(input_reg, xmm0);
-    __ Set(kScratchRegister, V8_UINT64_C(0x8000000000000000));
-    __ cmpq(input_reg, kScratchRegister);
-    DeoptimizeIf(equal, instr->environment());
+    __ TruncateHeapNumberToI(input_reg, input_reg);
   } else {
-    // Deoptimize if we don't have a heap number.
-    DeoptimizeIf(not_equal, instr->environment());
-
+    Label bailout;
     XMMRegister xmm_temp = ToDoubleRegister(instr->temp());
-    __ movsd(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
-    __ cvttsd2si(input_reg, xmm0);
-    __ cvtlsi2sd(xmm_temp, input_reg);
-    __ ucomisd(xmm0, xmm_temp);
-    DeoptimizeIf(not_equal, instr->environment());
-    DeoptimizeIf(parity_even, instr->environment());  // NaN.
-    if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
-      __ testl(input_reg, input_reg);
-      __ j(not_zero, &done);
-      __ movmskpd(input_reg, xmm0);
-      __ andl(input_reg, Immediate(1));
-      DeoptimizeIf(not_zero, instr->environment());
-    }
+    __ TaggedToI(input_reg, input_reg, xmm_temp,
+        instr->hydrogen()->GetMinusZeroMode(), &bailout, Label::kNear);
+
+    __ jmp(done);
+    __ bind(&bailout);
+    DeoptimizeIf(no_condition, instr->environment());
   }
-  __ bind(&done);
 }
 
 
@@ -4736,7 +4737,7 @@
     DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr)
         : LDeferredCode(codegen), instr_(instr) { }
     virtual void Generate() V8_OVERRIDE {
-      codegen()->DoDeferredTaggedToI(instr_);
+      codegen()->DoDeferredTaggedToI(instr_, done());
     }
     virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
    private:
@@ -4786,34 +4787,16 @@
   Register result_reg = ToRegister(result);
 
   if (instr->truncating()) {
-    // Performs a truncating conversion of a floating point number as used by
-    // the JS bitwise operations.
-    __ cvttsd2siq(result_reg, input_reg);
-    __ movq(kScratchRegister,
-            V8_INT64_C(0x8000000000000000),
-            RelocInfo::NONE64);
-    __ cmpq(result_reg, kScratchRegister);
-    DeoptimizeIf(equal, instr->environment());
+    __ TruncateDoubleToI(result_reg, input_reg);
   } else {
-    __ cvttsd2si(result_reg, input_reg);
-    __ cvtlsi2sd(xmm0, result_reg);
-    __ ucomisd(xmm0, input_reg);
-    DeoptimizeIf(not_equal, instr->environment());
-    DeoptimizeIf(parity_even, instr->environment());  // NaN.
-    if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
-      Label done;
-      // The integer converted back is equal to the original. We
-      // only have to test if we got -0 as an input.
-      __ testl(result_reg, result_reg);
-      __ j(not_zero, &done, Label::kNear);
-      __ movmskpd(result_reg, input_reg);
-      // Bit 0 contains the sign of the double in input_reg.
-      // If input was positive, we are ok and return 0, otherwise
-      // deoptimize.
-      __ andl(result_reg, Immediate(1));
-      DeoptimizeIf(not_zero, instr->environment());
-      __ bind(&done);
-    }
+    Label bailout, done;
+    __ DoubleToI(result_reg, input_reg, xmm0,
+        instr->hydrogen()->GetMinusZeroMode(), &bailout, Label::kNear);
+
+    __ jmp(&done, Label::kNear);
+    __ bind(&bailout);
+    DeoptimizeIf(no_condition, instr->environment());
+    __ bind(&done);
   }
 }
 
@@ -4823,31 +4806,19 @@
   ASSERT(input->IsDoubleRegister());
   LOperand* result = instr->result();
   ASSERT(result->IsRegister());
-  CpuFeatureScope scope(masm(), SSE2);
 
   XMMRegister input_reg = ToDoubleRegister(input);
   Register result_reg = ToRegister(result);
 
-  Label done;
-  __ cvttsd2si(result_reg, input_reg);
-  __ cvtlsi2sd(xmm0, result_reg);
-  __ ucomisd(xmm0, input_reg);
-  DeoptimizeIf(not_equal, instr->environment());
-  DeoptimizeIf(parity_even, instr->environment());  // NaN.
+  Label bailout, done;
+  __ DoubleToI(result_reg, input_reg, xmm0,
+      instr->hydrogen()->GetMinusZeroMode(), &bailout, Label::kNear);
 
-  if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
-    // The integer converted back is equal to the original. We
-    // only have to test if we got -0 as an input.
-    __ testl(result_reg, result_reg);
-    __ j(not_zero, &done, Label::kNear);
-    __ movmskpd(result_reg, input_reg);
-    // Bit 0 contains the sign of the double in input_reg.
-    // If input was positive, we are ok and return 0, otherwise
-    // deoptimize.
-    __ andl(result_reg, Immediate(1));
-    DeoptimizeIf(not_zero, instr->environment());
-    __ bind(&done);
-  }
+  __ jmp(&done, Label::kNear);
+  __ bind(&bailout);
+  DeoptimizeIf(no_condition, instr->environment());
+  __ bind(&done);
+
   __ Integer32ToSmi(result_reg, result_reg);
   DeoptimizeIf(overflow, instr->environment());
 }
@@ -5457,9 +5428,7 @@
   ASSERT(!environment->HasBeenRegistered());
   RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
 
-  // Normally we record the first unknown OSR value as the entrypoint to the OSR
-  // code, but if there were none, record the entrypoint here.
-  if (osr_pc_offset_ == -1) osr_pc_offset_ = masm()->pc_offset();
+  GenerateOsrPrologue();
 }
 
 
diff --git a/src/x64/lithium-codegen-x64.h b/src/x64/lithium-codegen-x64.h
index 65c6dca..222a419 100644
--- a/src/x64/lithium-codegen-x64.h
+++ b/src/x64/lithium-codegen-x64.h
@@ -123,7 +123,7 @@
   // Deferred code support.
   void DoDeferredNumberTagD(LNumberTagD* instr);
   void DoDeferredNumberTagU(LNumberTagU* instr);
-  void DoDeferredTaggedToI(LTaggedToI* instr);
+  void DoDeferredTaggedToI(LTaggedToI* instr, Label* done);
   void DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr);
   void DoDeferredStackCheck(LStackCheck* instr);
   void DoDeferredRandom(LRandom* instr);
@@ -191,6 +191,9 @@
   bool GenerateJumpTable();
   bool GenerateSafepointTable();
 
+  // Generates the custom OSR entrypoint and sets the osr_pc_offset.
+  void GenerateOsrPrologue();
+
   enum SafepointMode {
     RECORD_SIMPLE_SAFEPOINT,
     RECORD_SAFEPOINT_WITH_REGISTERS
@@ -427,6 +430,7 @@
   void SetExit(Label* exit) { external_exit_ = exit; }
   Label* entry() { return &entry_; }
   Label* exit() { return external_exit_ != NULL ? external_exit_ : &exit_; }
+  Label* done() { return codegen_->NeedsDeferredFrame() ? &done_ : exit(); }
   int instruction_index() const { return instruction_index_; }
 
  protected:
@@ -437,6 +441,7 @@
   LCodeGen* codegen_;
   Label entry_;
   Label exit_;
+  Label done_;
   Label* external_exit_;
   int instruction_index_;
 };
diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc
index 1b4332a..ac48b09 100644
--- a/src/x64/lithium-x64.cc
+++ b/src/x64/lithium-x64.cc
@@ -32,6 +32,7 @@
 #include "lithium-allocator-inl.h"
 #include "x64/lithium-x64.h"
 #include "x64/lithium-codegen-x64.h"
+#include "hydrogen-osr.h"
 
 namespace v8 {
 namespace internal {
@@ -439,6 +440,15 @@
   chunk_ = new(zone()) LPlatformChunk(info(), graph());
   LPhase phase("L_Building chunk", chunk_);
   status_ = BUILDING;
+
+  // If compiling for OSR, reserve space for the unoptimized frame,
+  // which will be subsumed into this frame.
+  if (graph()->has_osr()) {
+    for (int i = graph()->osr()->UnoptimizedFrameSlots(); i > 0; i--) {
+      chunk_->GetNextSpillIndex(false);
+    }
+  }
+
   const ZoneList<HBasicBlock*>* blocks = graph()->blocks();
   for (int i = 0; i < blocks->length(); i++) {
     HBasicBlock* next = NULL;
@@ -2359,10 +2369,18 @@
 
 
 LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
-  int spill_index = chunk()->GetNextSpillIndex(false);  // Not double-width.
-  if (spill_index > LUnallocated::kMaxFixedSlotIndex) {
-    Abort(kTooManySpillSlotsNeededForOSR);
-    spill_index = 0;
+  // Use an index that corresponds to the location in the unoptimized frame,
+  // which the optimized frame will subsume.
+  int env_index = instr->index();
+  int spill_index = 0;
+  if (instr->environment()->is_parameter_index(env_index)) {
+    spill_index = chunk()->GetParameterStackSlot(env_index);
+  } else {
+    spill_index = env_index - instr->environment()->first_local_index();
+    if (spill_index > LUnallocated::kMaxFixedSlotIndex) {
+      Abort(kTooManySpillSlotsNeededForOSR);
+      spill_index = 0;
+    }
   }
   return DefineAsSpilled(new(zone()) LUnknownOSRValue, spill_index);
 }
diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc
index 0c605d8..69abc54 100644
--- a/src/x64/macro-assembler-x64.cc
+++ b/src/x64/macro-assembler-x64.cc
@@ -285,16 +285,17 @@
     cmpq(scratch, kScratchRegister);
     j(cc, branch, distance);
   } else {
-    ASSERT(is_int32(static_cast<int64_t>(HEAP->NewSpaceMask())));
+    ASSERT(is_int32(static_cast<int64_t>(isolate()->heap()->NewSpaceMask())));
     intptr_t new_space_start =
-        reinterpret_cast<intptr_t>(HEAP->NewSpaceStart());
+        reinterpret_cast<intptr_t>(isolate()->heap()->NewSpaceStart());
     movq(kScratchRegister, -new_space_start, RelocInfo::NONE64);
     if (scratch.is(object)) {
       addq(scratch, kScratchRegister);
     } else {
       lea(scratch, Operand(object, kScratchRegister, times_1, 0));
     }
-    and_(scratch, Immediate(static_cast<int32_t>(HEAP->NewSpaceMask())));
+    and_(scratch,
+         Immediate(static_cast<int32_t>(isolate()->heap()->NewSpaceMask())));
     j(cc, branch, distance);
   }
 }
@@ -2992,6 +2993,117 @@
 }
 
 
+void MacroAssembler::SlowTruncateToI(Register result_reg,
+                                     Register input_reg,
+                                     int offset) {
+  DoubleToIStub stub(input_reg, result_reg, offset, true);
+  call(stub.GetCode(isolate()), RelocInfo::CODE_TARGET);
+}
+
+
+void MacroAssembler::TruncateHeapNumberToI(Register result_reg,
+                                           Register input_reg) {
+  Label done;
+  movsd(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
+  cvttsd2siq(result_reg, xmm0);
+  Set(kScratchRegister, V8_UINT64_C(0x8000000000000000));
+  cmpq(result_reg, kScratchRegister);
+  j(not_equal, &done, Label::kNear);
+
+  // Slow case.
+  if (input_reg.is(result_reg)) {
+    subq(rsp, Immediate(kDoubleSize));
+    movsd(MemOperand(rsp, 0), xmm0);
+    SlowTruncateToI(result_reg, rsp, 0);
+    addq(rsp, Immediate(kDoubleSize));
+  } else {
+    SlowTruncateToI(result_reg, input_reg);
+  }
+
+  bind(&done);
+}
+
+
+void MacroAssembler::TruncateDoubleToI(Register result_reg,
+                                       XMMRegister input_reg) {
+  Label done;
+  cvttsd2siq(result_reg, input_reg);
+  movq(kScratchRegister,
+      V8_INT64_C(0x8000000000000000),
+      RelocInfo::NONE64);
+  cmpq(result_reg, kScratchRegister);
+  j(not_equal, &done, Label::kNear);
+
+  subq(rsp, Immediate(kDoubleSize));
+  movsd(MemOperand(rsp, 0), input_reg);
+  SlowTruncateToI(result_reg, rsp, 0);
+  addq(rsp, Immediate(kDoubleSize));
+
+  bind(&done);
+}
+
+
+void MacroAssembler::DoubleToI(Register result_reg,
+                               XMMRegister input_reg,
+                               XMMRegister scratch,
+                               MinusZeroMode minus_zero_mode,
+                               Label* conversion_failed,
+                               Label::Distance dst) {
+  cvttsd2si(result_reg, input_reg);
+  cvtlsi2sd(xmm0, result_reg);
+  ucomisd(xmm0, input_reg);
+  j(not_equal, conversion_failed, dst);
+  j(parity_even, conversion_failed, dst);  // NaN.
+  if (minus_zero_mode == FAIL_ON_MINUS_ZERO) {
+    Label done;
+    // The integer converted back is equal to the original. We
+    // only have to test if we got -0 as an input.
+    testl(result_reg, result_reg);
+    j(not_zero, &done, Label::kNear);
+    movmskpd(result_reg, input_reg);
+    // Bit 0 contains the sign of the double in input_reg.
+    // If input was positive, we are ok and return 0, otherwise
+    // jump to conversion_failed.
+    andl(result_reg, Immediate(1));
+    j(not_zero, conversion_failed, dst);
+    bind(&done);
+  }
+}
+
+
+void MacroAssembler::TaggedToI(Register result_reg,
+                               Register input_reg,
+                               XMMRegister temp,
+                               MinusZeroMode minus_zero_mode,
+                               Label* lost_precision,
+                               Label::Distance dst) {
+  Label done;
+  ASSERT(!temp.is(xmm0));
+
+  // Heap number map check.
+  CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset),
+              Heap::kHeapNumberMapRootIndex);
+  j(not_equal, lost_precision, dst);
+
+  movsd(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
+  cvttsd2si(result_reg, xmm0);
+  cvtlsi2sd(temp, result_reg);
+  ucomisd(xmm0, temp);
+  RecordComment("Deferred TaggedToI: lost precision");
+  j(not_equal, lost_precision, dst);
+  RecordComment("Deferred TaggedToI: NaN");
+  j(parity_even, lost_precision, dst);  // NaN.
+  if (minus_zero_mode == FAIL_ON_MINUS_ZERO) {
+    testl(result_reg, result_reg);
+    j(not_zero, &done, Label::kNear);
+    movmskpd(result_reg, xmm0);
+    andl(result_reg, Immediate(1));
+    j(not_zero, lost_precision, dst);
+  }
+  bind(&done);
+}
+
+
 void MacroAssembler::LoadInstanceDescriptors(Register map,
                                              Register descriptors) {
   movq(descriptors, FieldOperand(map, Map::kDescriptorsOffset));
diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h
index 8e30981..09c8a80 100644
--- a/src/x64/macro-assembler-x64.h
+++ b/src/x64/macro-assembler-x64.h
@@ -975,6 +975,20 @@
                           XMMRegister temp_xmm_reg,
                           Register result_reg);
 
+  void SlowTruncateToI(Register result_reg, Register input_reg,
+      int offset = HeapNumber::kValueOffset - kHeapObjectTag);
+
+  void TruncateHeapNumberToI(Register result_reg, Register input_reg);
+  void TruncateDoubleToI(Register result_reg, XMMRegister input_reg);
+
+  void DoubleToI(Register result_reg, XMMRegister input_reg,
+      XMMRegister scratch, MinusZeroMode minus_zero_mode,
+      Label* conversion_failed, Label::Distance dst = Label::kFar);
+
+  void TaggedToI(Register result_reg, Register input_reg, XMMRegister temp,
+      MinusZeroMode minus_zero_mode, Label* lost_precision,
+      Label::Distance dst = Label::kFar);
+
   void LoadUint32(XMMRegister dst, Register src, XMMRegister scratch);
 
   void LoadInstanceDescriptors(Register map, Register descriptors);
diff --git a/src/x64/regexp-macro-assembler-x64.cc b/src/x64/regexp-macro-assembler-x64.cc
index 49d9de6..999622a 100644
--- a/src/x64/regexp-macro-assembler-x64.cc
+++ b/src/x64/regexp-macro-assembler-x64.cc
@@ -998,7 +998,7 @@
 
   CodeDesc code_desc;
   masm_.GetCode(&code_desc);
-  Isolate* isolate = ISOLATE;
+  Isolate* isolate = this->isolate();
   Handle<Code> code = isolate->factory()->NewCode(
       code_desc, Code::ComputeFlags(Code::REGEXP),
       masm_.CodeObject());
diff --git a/test/cctest/cctest.gyp b/test/cctest/cctest.gyp
index 75d26b6..0775cc5 100644
--- a/test/cctest/cctest.gyp
+++ b/test/cctest/cctest.gyp
@@ -91,6 +91,7 @@
         'test-platform-tls.cc',
         'test-profile-generator.cc',
         'test-random.cc',
+        'test-random-number-generator.cc',
         'test-regexp.cc',
         'test-reloc-info.cc',
         'test-semaphore.cc',
diff --git a/test/cctest/cctest.h b/test/cctest/cctest.h
index 3365493..ceb9774 100644
--- a/test/cctest/cctest.h
+++ b/test/cctest/cctest.h
@@ -71,6 +71,10 @@
   EXTENSION_LIST(DEFINE_EXTENSION_FLAG)
 #undef DEFINE_EXTENSION_FLAG
 
+// Temporary macros for accessing current isolate and its subobjects.
+// They provide better readability, especially when used a lot in the code.
+#define HEAP (v8::internal::Isolate::Current()->heap())
+
 class CcTest {
  public:
   typedef void (TestFunction)();
diff --git a/test/cctest/test-alloc.cc b/test/cctest/test-alloc.cc
index 670da58..f4f13d0 100644
--- a/test/cctest/test-alloc.cc
+++ b/test/cctest/test-alloc.cc
@@ -90,7 +90,7 @@
 
 
 static Handle<Object> Test() {
-  CALL_HEAP_FUNCTION(ISOLATE, AllocateAfterFailures(), Object);
+  CALL_HEAP_FUNCTION(Isolate::Current(), AllocateAfterFailures(), Object);
 }
 
 
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index aaac486..6e47cd6 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -12700,7 +12700,7 @@
     CHECK_EQ(initial_handles + 3, globals->global_handles_count());
   }
   // Verify autodispose
-//  CHECK_EQ(initial_handles, globals->global_handles_count());
+  CHECK_EQ(initial_handles, globals->global_handles_count());
 }
 
 
@@ -13401,7 +13401,7 @@
           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))))->code());
 
       // Clear the compilation cache to get more wastage.
-      ISOLATE->compilation_cache()->Clear();
+      reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear();
     }
 
     // Force code movement.
@@ -19735,19 +19735,20 @@
 
 TEST(IsolateEmbedderData) {
   v8::Isolate* isolate = v8::Isolate::GetCurrent();
+  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
   CHECK_EQ(NULL, isolate->GetData());
-  CHECK_EQ(NULL, ISOLATE->GetData());
+  CHECK_EQ(NULL, i_isolate->GetData());
   static void* data1 = reinterpret_cast<void*>(0xacce55ed);
   isolate->SetData(data1);
   CHECK_EQ(data1, isolate->GetData());
-  CHECK_EQ(data1, ISOLATE->GetData());
+  CHECK_EQ(data1, i_isolate->GetData());
   static void* data2 = reinterpret_cast<void*>(0xdecea5ed);
-  ISOLATE->SetData(data2);
+  i_isolate->SetData(data2);
   CHECK_EQ(data2, isolate->GetData());
-  CHECK_EQ(data2, ISOLATE->GetData());
-  ISOLATE->TearDown();
+  CHECK_EQ(data2, i_isolate->GetData());
+  i_isolate->TearDown();
   CHECK_EQ(data2, isolate->GetData());
-  CHECK_EQ(data2, ISOLATE->GetData());
+  CHECK_EQ(data2, i_isolate->GetData());
 }
 
 
diff --git a/test/cctest/test-assembler-x64.cc b/test/cctest/test-assembler-x64.cc
index d5aaf4f..f7d2311 100644
--- a/test/cctest/test-assembler-x64.cc
+++ b/test/cctest/test-assembler-x64.cc
@@ -90,7 +90,6 @@
 
 
 TEST(AssemblerX64ReturnOperation) {
-  OS::SetUp();
   // Allocate an executable page of memory.
   size_t actual_size;
   byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
@@ -113,7 +112,6 @@
 
 
 TEST(AssemblerX64StackOperations) {
-  OS::SetUp();
   // Allocate an executable page of memory.
   size_t actual_size;
   byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
@@ -146,7 +144,6 @@
 
 
 TEST(AssemblerX64ArithmeticOperations) {
-  OS::SetUp();
   // Allocate an executable page of memory.
   size_t actual_size;
   byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
@@ -169,7 +166,6 @@
 
 
 TEST(AssemblerX64ImulOperation) {
-  OS::SetUp();
   // Allocate an executable page of memory.
   size_t actual_size;
   byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
@@ -198,7 +194,6 @@
 
 
 TEST(AssemblerX64MemoryOperands) {
-  OS::SetUp();
   // Allocate an executable page of memory.
   size_t actual_size;
   byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
@@ -233,7 +228,6 @@
 
 
 TEST(AssemblerX64ControlFlow) {
-  OS::SetUp();
   // Allocate an executable page of memory.
   size_t actual_size;
   byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
@@ -263,7 +257,6 @@
 
 
 TEST(AssemblerX64LoopImmediates) {
-  OS::SetUp();
   // Allocate an executable page of memory.
   size_t actual_size;
   byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
diff --git a/test/cctest/test-cpu-profiler.cc b/test/cctest/test-cpu-profiler.cc
index 6d66c5e..4708f50 100644
--- a/test/cctest/test-cpu-profiler.cc
+++ b/test/cctest/test-cpu-profiler.cc
@@ -49,7 +49,8 @@
 
 
 TEST(StartStop) {
-  CpuProfilesCollection profiles;
+  i::Isolate* isolate = CcTest::i_isolate();
+  CpuProfilesCollection profiles(isolate->heap());
   ProfileGenerator generator(&profiles);
   SmartPointer<ProfilerEventsProcessor> processor(new ProfilerEventsProcessor(
           &generator, NULL, TimeDelta::FromMicroseconds(100)));
@@ -140,7 +141,7 @@
   i::Code* args3_code = CreateCode(&env);
   i::Code* args4_code = CreateCode(&env);
 
-  CpuProfilesCollection* profiles = new CpuProfilesCollection;
+  CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate->heap());
   profiles->StartProfiling("", 1, false);
   ProfileGenerator generator(profiles);
   SmartPointer<ProfilerEventsProcessor> processor(new ProfilerEventsProcessor(
@@ -202,7 +203,7 @@
   i::Code* frame2_code = CreateCode(&env);
   i::Code* frame3_code = CreateCode(&env);
 
-  CpuProfilesCollection* profiles = new CpuProfilesCollection;
+  CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate->heap());
   profiles->StartProfiling("", 1, false);
   ProfileGenerator generator(profiles);
   SmartPointer<ProfilerEventsProcessor> processor(new ProfilerEventsProcessor(
@@ -271,7 +272,7 @@
 
   i::Code* code = CreateCode(&env);
 
-  CpuProfilesCollection* profiles = new CpuProfilesCollection;
+  CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate->heap());
   profiles->StartProfiling("", 1, false);
   ProfileGenerator generator(profiles);
   SmartPointer<ProfilerEventsProcessor> processor(new ProfilerEventsProcessor(
diff --git a/test/cctest/test-heap-profiler.cc b/test/cctest/test-heap-profiler.cc
index 04f6e0f..0cf9cda 100644
--- a/test/cctest/test-heap-profiler.cc
+++ b/test/cctest/test-heap-profiler.cc
@@ -404,12 +404,57 @@
   const v8::HeapGraphNode* child_string =
       GetProperty(global, v8::HeapGraphEdge::kProperty, "child_string");
   CHECK_NE(NULL, child_string);
+  CHECK_EQ(v8::HeapGraphNode::kSlicedString, child_string->GetType());
   const v8::HeapGraphNode* parent =
       GetProperty(child_string, v8::HeapGraphEdge::kInternal, "parent");
   CHECK_EQ(parent_string, parent);
+  heap_profiler->DeleteAllHeapSnapshots();
 }
 
 
+TEST(HeapSnapshotConsString) {
+  v8::Isolate* isolate = v8::Isolate::GetCurrent();
+  v8::HandleScope scope(isolate);
+  v8::Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
+  global_template->SetInternalFieldCount(1);
+  LocalContext env(NULL, global_template);
+  v8::Handle<v8::Object> global_proxy = env->Global();
+  v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
+  CHECK_EQ(1, global->InternalFieldCount());
+
+  i::Factory* factory = i::Isolate::Current()->factory();
+  i::Handle<i::String> first =
+      factory->NewStringFromAscii(i::CStrVector("0123456789"));
+  i::Handle<i::String> second =
+      factory->NewStringFromAscii(i::CStrVector("0123456789"));
+  i::Handle<i::String> cons_string = factory->NewConsString(first, second);
+
+  global->SetInternalField(0, v8::ToApiHandle<v8::String>(cons_string));
+
+  v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
+  const v8::HeapSnapshot* snapshot =
+      heap_profiler->TakeHeapSnapshot(v8_str("cons_strings"));
+  CHECK(ValidateSnapshot(snapshot));
+  const v8::HeapGraphNode* global_node = GetGlobalObject(snapshot);
+
+  const v8::HeapGraphNode* string_node =
+      GetProperty(global_node, v8::HeapGraphEdge::kInternal, "0");
+  CHECK_NE(NULL, string_node);
+  CHECK_EQ(v8::HeapGraphNode::kConsString, string_node->GetType());
+
+  const v8::HeapGraphNode* first_node =
+      GetProperty(string_node, v8::HeapGraphEdge::kInternal, "first");
+  CHECK_EQ(v8::HeapGraphNode::kString, first_node->GetType());
+
+  const v8::HeapGraphNode* second_node =
+      GetProperty(string_node, v8::HeapGraphEdge::kInternal, "second");
+  CHECK_EQ(v8::HeapGraphNode::kString, second_node->GetType());
+
+  heap_profiler->DeleteAllHeapSnapshots();
+}
+
+
+
 TEST(HeapSnapshotInternalReferences) {
   v8::Isolate* isolate = v8::Isolate::GetCurrent();
   v8::HandleScope scope(isolate);
diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc
index 95e22d4..64075d2 100644
--- a/test/cctest/test-heap.cc
+++ b/test/cctest/test-heap.cc
@@ -3422,7 +3422,7 @@
   CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   Heap* heap = isolate->heap();
-  v8::HandleScope scope;
+  v8::HandleScope scope(reinterpret_cast<v8::Isolate*>(isolate));
   v8::ImplementationUtilities::HandleScopeData* data =
       isolate->handle_scope_data();
   Handle<Object> init(heap->empty_string(), isolate);
diff --git a/test/cctest/test-mark-compact.cc b/test/cctest/test-mark-compact.cc
index 21700f7..33d9230 100644
--- a/test/cctest/test-mark-compact.cc
+++ b/test/cctest/test-mark-compact.cc
@@ -572,7 +572,7 @@
   v8::Isolate* isolate = v8::Isolate::New();
   { v8::Isolate::Scope isolate_scope(isolate);
     v8::Locker lock(isolate);
-    v8::HandleScope handle_scope;
+    v8::HandleScope handle_scope(isolate);
     v8::Local<v8::Context> context = v8::Context::New(isolate);
     CHECK(!context.IsEmpty());
   }
diff --git a/test/cctest/test-object-observe.cc b/test/cctest/test-object-observe.cc
index 44ddb6f..e7cf1e5 100644
--- a/test/cctest/test-object-observe.cc
+++ b/test/cctest/test-object-observe.cc
@@ -435,14 +435,14 @@
   i::Handle<i::JSWeakMap> objectInfoMap =
       i::Handle<i::JSWeakMap>::cast(
           i::GetProperty(observation_state, "objectInfoMap"));
-  i::Handle<i::JSWeakMap> notifierTargetMap =
+  i::Handle<i::JSWeakMap> notifierObjectInfoMap =
       i::Handle<i::JSWeakMap>::cast(
-          i::GetProperty(observation_state, "notifierTargetMap"));
+          i::GetProperty(observation_state, "notifierObjectInfoMap"));
   CHECK_EQ(1, NumberOfElements(callbackInfoMap));
   CHECK_EQ(1, NumberOfElements(objectInfoMap));
-  CHECK_EQ(1, NumberOfElements(notifierTargetMap));
+  CHECK_EQ(1, NumberOfElements(notifierObjectInfoMap));
   HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
   CHECK_EQ(0, NumberOfElements(callbackInfoMap));
   CHECK_EQ(0, NumberOfElements(objectInfoMap));
-  CHECK_EQ(0, NumberOfElements(notifierTargetMap));
+  CHECK_EQ(0, NumberOfElements(notifierObjectInfoMap));
 }
diff --git a/test/cctest/test-platform-linux.cc b/test/cctest/test-platform-linux.cc
index 34ae43c..f289e94 100644
--- a/test/cctest/test-platform-linux.cc
+++ b/test/cctest/test-platform-linux.cc
@@ -40,7 +40,6 @@
 
 
 TEST(VirtualMemory) {
-  OS::SetUp();
   VirtualMemory* vm = new VirtualMemory(1 * MB);
   CHECK(vm->IsReserved());
   void* block_addr = vm->address();
@@ -55,6 +54,5 @@
 
 
 TEST(GetCurrentProcessId) {
-  OS::SetUp();
   CHECK_EQ(static_cast<int>(getpid()), OS::GetCurrentProcessId());
 }
diff --git a/test/cctest/test-platform-win32.cc b/test/cctest/test-platform-win32.cc
index a5089d3..d7fdab1 100644
--- a/test/cctest/test-platform-win32.cc
+++ b/test/cctest/test-platform-win32.cc
@@ -39,7 +39,6 @@
 
 
 TEST(VirtualMemory) {
-  OS::SetUp();
   VirtualMemory* vm = new VirtualMemory(1 * MB);
   CHECK(vm->IsReserved());
   void* block_addr = vm->address();
@@ -54,7 +53,6 @@
 
 
 TEST(GetCurrentProcessId) {
-  OS::SetUp();
   CHECK_EQ(static_cast<int>(::GetCurrentProcessId()),
            OS::GetCurrentProcessId());
 }
diff --git a/test/cctest/test-profile-generator.cc b/test/cctest/test-profile-generator.cc
index c84003f..7504b17 100644
--- a/test/cctest/test-profile-generator.cc
+++ b/test/cctest/test-profile-generator.cc
@@ -399,7 +399,7 @@
 
 TEST(RecordTickSample) {
   TestSetup test_setup;
-  CpuProfilesCollection profiles;
+  CpuProfilesCollection profiles(CcTest::i_isolate()->heap());
   profiles.StartProfiling("", 1, false);
   ProfileGenerator generator(&profiles);
   CodeEntry* entry1 = profiles.NewCodeEntry(i::Logger::FUNCTION_TAG, "aaa");
@@ -465,7 +465,7 @@
 
 TEST(SampleIds) {
   TestSetup test_setup;
-  CpuProfilesCollection profiles;
+  CpuProfilesCollection profiles(CcTest::i_isolate()->heap());
   profiles.StartProfiling("", 1, true);
   ProfileGenerator generator(&profiles);
   CodeEntry* entry1 = profiles.NewCodeEntry(i::Logger::FUNCTION_TAG, "aaa");
@@ -513,7 +513,7 @@
 
 TEST(NoSamples) {
   TestSetup test_setup;
-  CpuProfilesCollection profiles;
+  CpuProfilesCollection profiles(CcTest::i_isolate()->heap());
   profiles.StartProfiling("", 1, false);
   ProfileGenerator generator(&profiles);
   CodeEntry* entry1 = profiles.NewCodeEntry(i::Logger::FUNCTION_TAG, "aaa");
@@ -652,7 +652,7 @@
 
 
 TEST(Issue51919) {
-  CpuProfilesCollection collection;
+  CpuProfilesCollection collection(CcTest::i_isolate()->heap());
   i::EmbeddedVector<char*,
       CpuProfilesCollection::kMaxSimultaneousProfiles> titles;
   for (int i = 0; i < CpuProfilesCollection::kMaxSimultaneousProfiles; ++i) {
diff --git a/test/cctest/test-random-number-generator.cc b/test/cctest/test-random-number-generator.cc
new file mode 100644
index 0000000..93f3257
--- /dev/null
+++ b/test/cctest/test-random-number-generator.cc
@@ -0,0 +1,92 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "cctest.h"
+#include "utils/random-number-generator.h"
+
+using namespace v8::internal;
+
+
+static const int kMaxRuns = 12345;
+static const int kRandomSeeds[] = {
+  -1, 1, 42, 100, 1234567890, 987654321
+};
+
+
+TEST(NextIntWithMaxValue) {
+  for (unsigned n = 0; n < ARRAY_SIZE(kRandomSeeds); ++n) {
+    RandomNumberGenerator rng(kRandomSeeds[n]);
+    for (int max = 1; max <= kMaxRuns; ++max) {
+      int n = rng.NextInt(max);
+      CHECK_LE(0, n);
+      CHECK_LT(n, max);
+    }
+  }
+}
+
+
+TEST(NextBoolReturnsBooleanValue) {
+  for (unsigned n = 0; n < ARRAY_SIZE(kRandomSeeds); ++n) {
+    RandomNumberGenerator rng(kRandomSeeds[n]);
+    for (int k = 0; k < kMaxRuns; ++k) {
+      bool b = rng.NextBool();
+      CHECK(b == false || b == true);
+    }
+  }
+}
+
+
+TEST(NextDoubleRange) {
+  for (unsigned n = 0; n < ARRAY_SIZE(kRandomSeeds); ++n) {
+    RandomNumberGenerator rng(kRandomSeeds[n]);
+    for (int k = 0; k < kMaxRuns; ++k) {
+      double d = rng.NextDouble();
+      CHECK_LE(0.0, d);
+      CHECK_LT(d, 1.0);
+    }
+  }
+}
+
+
+TEST(RandomSeedFlagIsUsed) {
+  for (unsigned n = 0; n < ARRAY_SIZE(kRandomSeeds); ++n) {
+    FLAG_random_seed = kRandomSeeds[n];
+    RandomNumberGenerator rng1;
+    RandomNumberGenerator rng2(kRandomSeeds[n]);
+    for (int k = 1; k <= kMaxRuns; ++k) {
+      int64_t i1, i2;
+      rng1.NextBytes(&i1, sizeof(i1));
+      rng2.NextBytes(&i2, sizeof(i2));
+      CHECK_EQ(i2, i1);
+      CHECK_EQ(rng2.NextInt(), rng1.NextInt());
+      CHECK_EQ(rng2.NextInt(k), rng1.NextInt(k));
+      CHECK_EQ(rng2.NextDouble(), rng1.NextDouble());
+    }
+  }
+}
diff --git a/test/cctest/test-random.cc b/test/cctest/test-random.cc
index 804546a..4227326 100644
--- a/test/cctest/test-random.cc
+++ b/test/cctest/test-random.cc
@@ -96,14 +96,5 @@
   // Test with some random values.
   TestSeeds(fun, context, 0xC0C0AFFE, 0x31415926);
   TestSeeds(fun, context, 0x01020304, 0xFFFFFFFF);
-  TestSeeds(fun, context, 0x00000001, 0x00000000);
-
-  // Test that we bail out to runtime when seeds are uninitialized (zeros).
-  SetSeeds(seeds, 0, 0);
-  Handle<Object> value =
-      Execution::Call(isolate, fun, global, 0, NULL, &has_pending_exception);
-  CHECK(value->IsHeapNumber());
-  CHECK(fun->IsOptimized());
-  double crankshaft_value = HeapNumber::cast(*value)->value();
-  CHECK_NE(0.0, crankshaft_value);
+  TestSeeds(fun, context, 0x00000001, 0x00000001);
 }
diff --git a/test/cctest/test-spaces.cc b/test/cctest/test-spaces.cc
index 1f362d7..3326a01 100644
--- a/test/cctest/test-spaces.cc
+++ b/test/cctest/test-spaces.cc
@@ -207,7 +207,6 @@
 
 
 TEST(MemoryChunk) {
-  OS::SetUp();
   Isolate* isolate = Isolate::Current();
   isolate->InitializeLoggingAndCounters();
   Heap* heap = isolate->heap();
@@ -264,7 +263,6 @@
 
 
 TEST(MemoryAllocator) {
-  OS::SetUp();
   Isolate* isolate = Isolate::Current();
   isolate->InitializeLoggingAndCounters();
   Heap* heap = isolate->heap();
@@ -314,7 +312,6 @@
 
 
 TEST(NewSpace) {
-  OS::SetUp();
   Isolate* isolate = Isolate::Current();
   isolate->InitializeLoggingAndCounters();
   Heap* heap = isolate->heap();
@@ -344,7 +341,6 @@
 
 
 TEST(OldSpace) {
-  OS::SetUp();
   Isolate* isolate = Isolate::Current();
   isolate->InitializeLoggingAndCounters();
   Heap* heap = isolate->heap();
diff --git a/test/cctest/test-strings.cc b/test/cctest/test-strings.cc
index 310d93c..9049df1 100644
--- a/test/cctest/test-strings.cc
+++ b/test/cctest/test-strings.cc
@@ -41,9 +41,9 @@
 #include "zone-inl.h"
 
 // Adapted from http://en.wikipedia.org/wiki/Multiply-with-carry
-class RandomNumberGenerator {
+class MyRandomNumberGenerator {
  public:
-  RandomNumberGenerator() {
+  MyRandomNumberGenerator() {
     init();
   }
 
@@ -133,7 +133,7 @@
 static void InitializeBuildingBlocks(Handle<String>* building_blocks,
                                      int bb_length,
                                      bool long_blocks,
-                                     RandomNumberGenerator* rng,
+                                     MyRandomNumberGenerator* rng,
                                      Zone* zone) {
   // A list of pointers that we don't have any interest in cleaning up.
   // If they are reachable from a root then leak detection won't complain.
@@ -276,7 +276,7 @@
   // Cached data.
   Handle<String> building_blocks_[kNumberOfBuildingBlocks];
   String* empty_string_;
-  RandomNumberGenerator rng_;
+  MyRandomNumberGenerator rng_;
   // Stats.
   ConsStringStats stats_;
   unsigned early_terminations_;
@@ -1017,6 +1017,36 @@
 }
 
 
+TEST(JSONStringifySliceMadeExternal) {
+  Isolate* isolate = Isolate::Current();
+  Zone zone(isolate);
+  CcTest::InitializeVM();
+  // Create a sliced string from a one-byte string.  The latter is turned
+  // into a two-byte external string.  Check that JSON.stringify works.
+  v8::HandleScope handle_scope(CcTest::isolate());
+  v8::Handle<v8::String> underlying =
+      CompileRun("var underlying = 'abcdefghijklmnopqrstuvwxyz';"
+                 "underlying")->ToString();
+  v8::Handle<v8::String> slice =
+      CompileRun("var slice = underlying.slice(1);"
+                 "slice")->ToString();
+  CHECK(v8::Utils::OpenHandle(*slice)->IsSlicedString());
+  CHECK(v8::Utils::OpenHandle(*underlying)->IsSeqOneByteString());
+
+  int length = underlying->Length();
+  uc16* two_byte = zone.NewArray<uc16>(length + 1);
+  underlying->Write(two_byte);
+  Resource* resource =
+      new(&zone) Resource(Vector<const uc16>(two_byte, length));
+  CHECK(underlying->MakeExternal(resource));
+  CHECK(v8::Utils::OpenHandle(*slice)->IsSlicedString());
+  CHECK(v8::Utils::OpenHandle(*underlying)->IsExternalTwoByteString());
+
+  CHECK_EQ("\"bcdefghijklmnopqrstuvwxyz\"",
+           *v8::String::Utf8Value(CompileRun("JSON.stringify(slice)")));
+}
+
+
 TEST(CachedHashOverflow) {
   // We incorrectly allowed strings to be tagged as array indices even if their
   // values didn't fit in the hash field.
diff --git a/test/cctest/test-strtod.cc b/test/cctest/test-strtod.cc
index 952f57c..237d35d 100644
--- a/test/cctest/test-strtod.cc
+++ b/test/cctest/test-strtod.cc
@@ -432,7 +432,7 @@
   static uint32_t lo = 0;
 
   // Initialization values don't have any special meaning. (They are the result
-  // of two calls to random().)
+  // of two calls to rand().)
   if (hi == 0) hi = 0xbfe166e7;
   if (lo == 0) lo = 0x64d1c3c9;
 
@@ -448,12 +448,13 @@
 static const int kLargeStrtodRandomCount = 2;
 
 TEST(RandomStrtod) {
+  srand(static_cast<unsigned int>(time(NULL)));
   char buffer[kBufferSize];
   for (int length = 1; length < 15; length++) {
     for (int i = 0; i < kShortStrtodRandomCount; ++i) {
       int pos = 0;
       for (int j = 0; j < length; ++j) {
-        buffer[pos++] = random() % 10 + '0';
+        buffer[pos++] = rand() % 10 + '0';
       }
       int exponent = DeterministicRandom() % (25*2 + 1) - 25 - length;
       buffer[pos] = '\0';
@@ -466,7 +467,7 @@
     for (int i = 0; i < kLargeStrtodRandomCount; ++i) {
       int pos = 0;
       for (int j = 0; j < length; ++j) {
-        buffer[pos++] = random() % 10 + '0';
+        buffer[pos++] = rand() % 10 + '0';
       }
       int exponent = DeterministicRandom() % (308*2 + 1) - 308 - length;
       buffer[pos] = '\0';
diff --git a/test/cctest/test-thread-termination.cc b/test/cctest/test-thread-termination.cc
index 619bce7..b89f3ef 100644
--- a/test/cctest/test-thread-termination.cc
+++ b/test/cctest/test-thread-termination.cc
@@ -324,11 +324,11 @@
 // Test that a single thread of JavaScript execution can terminate
 // itself and then resume execution.
 TEST(TerminateCancelTerminateFromThreadItself) {
-  v8::HandleScope scope;
+  v8::Isolate* isolate = v8::Isolate::GetCurrent();
+  v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> global =
       CreateGlobalTemplate(TerminateCurrentThread, DoLoopCancelTerminate);
-  v8::Handle<v8::Context> context =
-      v8::Context::New(v8::Isolate::GetCurrent(), NULL, global);
+  v8::Handle<v8::Context> context = v8::Context::New(isolate, NULL, global);
   v8::Context::Scope context_scope(context);
   CHECK(!v8::V8::IsExecutionTerminating());
   v8::Handle<v8::String> source =
@@ -336,4 +336,3 @@
   // Check that execution completed with correct return value.
   CHECK(v8::Script::Compile(source)->Run()->Equals(v8_str("completed")));
 }
-
diff --git a/test/cctest/test-utils.cc b/test/cctest/test-utils.cc
index 541c423..feff477 100644
--- a/test/cctest/test-utils.cc
+++ b/test/cctest/test-utils.cc
@@ -140,7 +140,6 @@
 
 TEST(MemMove) {
   v8::V8::Initialize();
-  OS::SetUp();
   byte* area1 = new byte[kAreaSize];
   byte* area2 = new byte[kAreaSize];
   byte* area3 = new byte[kAreaSize];
diff --git a/test/mjsunit/compiler/osr-assert.js b/test/mjsunit/compiler/osr-assert.js
new file mode 100644
index 0000000..94b901f
--- /dev/null
+++ b/test/mjsunit/compiler/osr-assert.js
@@ -0,0 +1,41 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --use-osr
+
+function f(x, b, c) {
+  var outer = 1000000;
+  var a = 1;
+  while (outer > 0) {
+    a = a + 5;
+    assertEquals(b + 1, c);
+    outer--;
+  }
+  return a + 4;
+}
+
+assertEquals(5000005, f(5, "122", "1221"));
diff --git a/test/mjsunit/compiler/osr-sar.js b/test/mjsunit/compiler/osr-sar.js
new file mode 100644
index 0000000..fd68b98
--- /dev/null
+++ b/test/mjsunit/compiler/osr-sar.js
@@ -0,0 +1,49 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax
+
+function test() {
+  // Loop to force OSR.
+  var j = 0;
+  for (var i = 0; i < 80000; i++) {
+    j++;
+  }
+
+  function SarShr(val) {
+    return val >> (-2 >>> 0);
+  }
+
+  var K3 = 0x80000000;
+  assertEquals(-2, SarShr(K3 | 0));
+  assertEquals(-2, SarShr(K3 | 0));
+  %OptimizeFunctionOnNextCall(SarShr);
+  assertEquals(-2, SarShr(K3 | 0));
+}
+
+test();
+//test();
diff --git a/test/mjsunit/compiler/osr-uint32.js b/test/mjsunit/compiler/osr-uint32.js
new file mode 100644
index 0000000..d6fcae5
--- /dev/null
+++ b/test/mjsunit/compiler/osr-uint32.js
@@ -0,0 +1,39 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Loop to force OSR.
+var j = 0;
+for (var i = 0; i < 80000; i++) {
+    j++;
+}
+
+function SarShr(val) {
+  return val >> (-2 >>> 0);
+}
+
+var K3 = 0x80000000;
+assertEquals(-2, SarShr(K3 | 0));
diff --git a/test/mjsunit/compiler/osr-warm.js b/test/mjsunit/compiler/osr-warm.js
new file mode 100644
index 0000000..65ada1e
--- /dev/null
+++ b/test/mjsunit/compiler/osr-warm.js
@@ -0,0 +1,50 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --use-osr
+
+function f1(x) {
+  while (x > 0) {
+    x--;
+  }
+  return x;
+}
+
+assertEquals(0, f1(1));
+assertEquals(0, f1(10000000));
+
+function f2(x) {
+  var sum = 1;
+  while (x > 0) {
+    x--;
+    sum++;
+  }
+  return sum;
+}
+
+assertEquals(2, f2(1));
+assertEquals(10000001, f2(10000000));
diff --git a/test/mjsunit/regress/regress-map-invalidation-2.js b/test/mjsunit/regress/regress-map-invalidation-2.js
index 789c8bf..1f896a4 100644
--- a/test/mjsunit/regress/regress-map-invalidation-2.js
+++ b/test/mjsunit/regress/regress-map-invalidation-2.js
@@ -31,13 +31,13 @@
 
 function g() {
   var outer = { foo: 1 };
-  function f() {
+  function f(b, c) {
     var n = outer.foo;
-    for (var i = 0; i < 100000; i++) {
+    for (var i = 0; i < 10; i++) {
       n += c.x + outer.foo;
     }
-    var o2 = [{ x: 1.5, y: 1 }];
-    return o2;
+    if (b) return [{ x: 1.5, y: 1 }];
+    else return c;
   }
   // Clear type feedback from previous stress runs.
   %ClearFunctionTypeFeedback(f);
@@ -45,7 +45,10 @@
 }
 
 var fun = g();
-fun();
+fun(false, c);
+fun(false, c);
+fun(false, c);
+%OptimizeFunctionOnNextCall(fun);
+fun(false, c);
+fun(true, c);
 assertOptimized(fun);
-fun();
-
diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp
index 5a5a2ae..5d4933a 100644
--- a/tools/gyp/v8.gyp
+++ b/tools/gyp/v8.gyp
@@ -531,6 +531,8 @@
         '../../src/utils-inl.h',
         '../../src/utils.cc',
         '../../src/utils.h',
+        '../../src/utils/random-number-generator.cc',
+        '../../src/utils/random-number-generator.h',
         '../../src/v8-counters.cc',
         '../../src/v8-counters.h',
         '../../src/v8.cc',