Version 3.23.8

Fixed crashes exposed though fuzzing. (Chromium issue 320948)

Deprecated v8::External::New without Isolate parameter.

Made number of available threads isolate-dependent and exposed it to ResourceConstraints. (issue 2991)

Performance and stability improvements on all platforms.

git-svn-id: http://v8.googlecode.com/svn/trunk@17897 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/ChangeLog b/ChangeLog
index 45c82ae..c545d6b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2013-11-20: Version 3.23.8
+
+        Fixed crashes exposed though fuzzing.
+        (Chromium issue 320948)
+
+        Deprecated v8::External::New without Isolate parameter.
+
+        Made number of available threads isolate-dependent and exposed it to
+        ResourceConstraints.
+        (issue 2991)
+
+        Performance and stability improvements on all platforms.
+
+
 2013-11-19: Version 3.23.7
 
         Bugfix: dependent code field in AllocationSite was keeping code objects
diff --git a/include/v8.h b/include/v8.h
index f0b627e..2f8af27 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -3074,8 +3074,7 @@
 class V8_EXPORT External : public Value {
  public:
   static Local<External> New(Isolate* isolate, void* value);
-  // Deprecated, do not use.
-  static Local<External> New(void* value);
+  V8_DEPRECATED("Will be removed", static Local<External> New(void *value));
   V8_INLINE static External* Cast(Value* obj);
   void* Value() const;
  private:
@@ -3810,24 +3809,35 @@
    *
    * \param physical_memory The total amount of physical memory on the current
    *   device, in bytes.
+   * \param number_of_processors The number of CPUs available on the current
+   *   device.
    */
-  void ConfigureDefaults(uint64_t physical_memory);
+  void ConfigureDefaults(uint64_t physical_memory,
+                         uint32_t number_of_processors);
+  V8_DEPRECATED("Will be removed",
+                void ConfigureDefaults(uint64_t physical_memory));
 
   int max_young_space_size() const { return max_young_space_size_; }
   void set_max_young_space_size(int value) { max_young_space_size_ = value; }
   int max_old_space_size() const { return max_old_space_size_; }
   void set_max_old_space_size(int value) { max_old_space_size_ = value; }
-  int max_executable_size() { return max_executable_size_; }
+  int max_executable_size() const { return max_executable_size_; }
   void set_max_executable_size(int value) { max_executable_size_ = value; }
   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; }
+  int max_available_threads() const { return max_available_threads_; }
+  // Set the number of threads available to V8, assuming at least 1.
+  void set_max_available_threads(int value) {
+    max_available_threads_ = value;
+  }
 
  private:
   int max_young_space_size_;
   int max_old_space_size_;
   int max_executable_size_;
   uint32_t* stack_limit_;
+  int max_available_threads_;
 };
 
 
diff --git a/src/api.cc b/src/api.cc
index 736f0b0..8919cca 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -563,10 +563,11 @@
   : max_young_space_size_(0),
     max_old_space_size_(0),
     max_executable_size_(0),
-    stack_limit_(NULL) { }
+    stack_limit_(NULL),
+    max_available_threads_(0) { }
 
-
-void ResourceConstraints::ConfigureDefaults(uint64_t physical_memory) {
+void ResourceConstraints::ConfigureDefaults(uint64_t physical_memory,
+                                            uint32_t number_of_processors) {
   const int lump_of_memory = (i::kPointerSize / 4) * i::MB;
 #if V8_OS_ANDROID
   // Android has higher physical memory requirements before raising the maximum
@@ -599,6 +600,13 @@
     set_max_old_space_size(700 * lump_of_memory);
     set_max_executable_size(256 * lump_of_memory);
   }
+
+  set_max_available_threads(i::Max(i::Min(number_of_processors, 4u), 1u));
+}
+
+
+void ResourceConstraints::ConfigureDefaults(uint64_t physical_memory) {
+  ConfigureDefaults(physical_memory, i::CPU::NumberOfProcessorsOnline());
 }
 
 
@@ -627,6 +635,8 @@
     uintptr_t limit = reinterpret_cast<uintptr_t>(constraints->stack_limit());
     isolate->stack_guard()->SetStackLimit(limit);
   }
+
+  isolate->set_max_available_threads(constraints->max_available_threads());
   return true;
 }
 
@@ -1264,7 +1274,7 @@
   i::Handle<i::TypeSwitchInfo> info = Utils::OpenHandle(this);
   i::FixedArray* types = i::FixedArray::cast(info->types());
   for (int i = 0; i < types->length(); i++) {
-    if (obj->IsInstanceOf(i::FunctionTemplateInfo::cast(types->get(i))))
+    if (i::FunctionTemplateInfo::cast(types->get(i))->IsTemplateFor(*obj))
       return i + 1;
   }
   return 0;
@@ -3346,7 +3356,7 @@
   ENTER_V8(isolate);
   i::JSObject* object = *Utils::OpenHandle(this);
   i::FunctionTemplateInfo* tmpl_info = *Utils::OpenHandle(*tmpl);
-  while (!object->IsInstanceOf(tmpl_info)) {
+  while (!tmpl_info->IsTemplateFor(object)) {
     i::Object* prototype = object->GetPrototype();
     if (!prototype->IsJSObject()) return Local<Object>();
     object = i::JSObject::cast(prototype);
@@ -5427,7 +5437,7 @@
   ON_BAILOUT(i::Isolate::Current(), "v8::FunctionTemplate::HasInstanceOf()",
              return false);
   i::Object* obj = *Utils::OpenHandle(*value);
-  return obj->IsInstanceOf(*Utils::OpenHandle(this));
+  return Utils::OpenHandle(this)->IsTemplateFor(obj);
 }
 
 
diff --git a/src/arm/assembler-arm.cc b/src/arm/assembler-arm.cc
index 871b419..4171f7d 100644
--- a/src/arm/assembler-arm.cc
+++ b/src/arm/assembler-arm.cc
@@ -545,6 +545,7 @@
   desc->buffer_size = buffer_size_;
   desc->instr_size = pc_offset();
   desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
+  desc->origin = this;
 }
 
 
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc
index 0cb8e46..d95055c 100644
--- a/src/arm/full-codegen-arm.cc
+++ b/src/arm/full-codegen-arm.cc
@@ -3485,31 +3485,6 @@
 }
 
 
-void FullCodeGenerator::EmitSeqStringSetCharCheck(Register string,
-                                                  Register index,
-                                                  Register value,
-                                                  uint32_t encoding_mask) {
-  __ SmiTst(index);
-  __ Check(eq, kNonSmiIndex);
-  __ SmiTst(value);
-  __ Check(eq, kNonSmiValue);
-
-  __ ldr(ip, FieldMemOperand(string, String::kLengthOffset));
-  __ cmp(index, ip);
-  __ Check(lt, kIndexIsTooLarge);
-
-  __ cmp(index, Operand(Smi::FromInt(0)));
-  __ Check(ge, kIndexIsNegative);
-
-  __ ldr(ip, FieldMemOperand(string, HeapObject::kMapOffset));
-  __ ldrb(ip, FieldMemOperand(ip, Map::kInstanceTypeOffset));
-
-  __ and_(ip, ip, Operand(kStringRepresentationMask | kStringEncodingMask));
-  __ cmp(ip, Operand(encoding_mask));
-  __ Check(eq, kUnexpectedStringType);
-}
-
-
 void FullCodeGenerator::EmitOneByteSeqStringSetChar(CallRuntime* expr) {
   ZoneList<Expression*>* args = expr->arguments();
   ASSERT_EQ(3, args->length());
@@ -3520,12 +3495,18 @@
 
   VisitForStackValue(args->at(1));  // index
   VisitForStackValue(args->at(2));  // value
-  __ Pop(index, value);
   VisitForAccumulatorValue(args->at(0));  // string
+  __ Pop(index, value);
 
   if (FLAG_debug_code) {
+    __ SmiTst(value);
+    __ ThrowIf(ne, kNonSmiValue);
+    __ SmiTst(index);
+    __ ThrowIf(ne, kNonSmiIndex);
+    __ SmiUntag(index, index);
     static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
-    EmitSeqStringSetCharCheck(string, index, value, one_byte_seq_type);
+    __ EmitSeqStringSetCharCheck(string, index, value, one_byte_seq_type);
+    __ SmiTag(index, index);
   }
 
   __ SmiUntag(value, value);
@@ -3547,12 +3528,18 @@
 
   VisitForStackValue(args->at(1));  // index
   VisitForStackValue(args->at(2));  // value
-  __ Pop(index, value);
   VisitForAccumulatorValue(args->at(0));  // string
+  __ Pop(index, value);
 
   if (FLAG_debug_code) {
+    __ SmiTst(value);
+    __ ThrowIf(ne, kNonSmiValue);
+    __ SmiTst(index);
+    __ ThrowIf(ne, kNonSmiIndex);
+    __ SmiUntag(index, index);
     static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
-    EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type);
+    __ EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type);
+    __ SmiTag(index, index);
   }
 
   __ SmiUntag(value, value);
diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc
index 71ce8f1..a6644af 100644
--- a/src/arm/lithium-arm.cc
+++ b/src/arm/lithium-arm.cc
@@ -1906,10 +1906,13 @@
 
 
 LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) {
-  LOperand* string = UseRegister(instr->string());
-  LOperand* index = UseRegisterOrConstant(instr->index());
-  LOperand* value = UseRegister(instr->value());
-  return new(zone()) LSeqStringSetChar(string, index, value);
+  LOperand* string = UseRegisterAtStart(instr->string());
+  LOperand* index = FLAG_debug_code
+      ? UseRegisterAtStart(instr->index())
+      : UseRegisterOrConstantAtStart(instr->index());
+  LOperand* value = UseRegisterAtStart(instr->value());
+  LOperand* context = FLAG_debug_code ? UseFixed(instr->context(), cp) : NULL;
+  return new(zone()) LSeqStringSetChar(context, string, index, value);
 }
 
 
diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h
index f67747b..5b9278b 100644
--- a/src/arm/lithium-arm.h
+++ b/src/arm/lithium-arm.h
@@ -1401,19 +1401,21 @@
 };
 
 
-class LSeqStringSetChar V8_FINAL : public LTemplateInstruction<1, 3, 0> {
+class LSeqStringSetChar V8_FINAL : public LTemplateInstruction<1, 4, 0> {
  public:
-  LSeqStringSetChar(LOperand* string,
+  LSeqStringSetChar(LOperand* context,
+                    LOperand* string,
                     LOperand* index,
                     LOperand* value) {
-    inputs_[0] = string;
-    inputs_[1] = index;
-    inputs_[2] = value;
+    inputs_[0] = context;
+    inputs_[1] = string;
+    inputs_[2] = index;
+    inputs_[3] = value;
   }
 
-  LOperand* string() { return inputs_[0]; }
-  LOperand* index() { return inputs_[1]; }
-  LOperand* value() { return inputs_[2]; }
+  LOperand* string() { return inputs_[1]; }
+  LOperand* index() { return inputs_[2]; }
+  LOperand* value() { return inputs_[3]; }
 
   DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar, "seq-string-set-char")
   DECLARE_HYDROGEN_ACCESSOR(SeqStringSetChar)
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index 56717a2..0d4d805 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -2027,17 +2027,13 @@
   Register value = ToRegister(instr->value());
 
   if (FLAG_debug_code) {
-    Register scratch = scratch0();
-    __ ldr(scratch, FieldMemOperand(string, HeapObject::kMapOffset));
-    __ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
-
-    __ and_(scratch, scratch,
-            Operand(kStringRepresentationMask | kStringEncodingMask));
+    Register index = ToRegister(instr->index());
     static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
     static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
-    __ cmp(scratch, Operand(encoding == String::ONE_BYTE_ENCODING
-                            ? one_byte_seq_type : two_byte_seq_type));
-    __ Check(eq, kUnexpectedStringType);
+    int encoding_mask =
+        instr->hydrogen()->encoding() == String::ONE_BYTE_ENCODING
+        ? one_byte_seq_type : two_byte_seq_type;
+    __ EmitSeqStringSetCharCheck(string, index, value, encoding_mask);
   }
 
   MemOperand operand = BuildSeqStringOperand(string, instr->index(), encoding);
diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc
index 9060195..acd398a 100644
--- a/src/arm/macro-assembler-arm.cc
+++ b/src/arm/macro-assembler-arm.cc
@@ -3391,6 +3391,42 @@
 }
 
 
+void MacroAssembler::EmitSeqStringSetCharCheck(Register string,
+                                               Register index,
+                                               Register value,
+                                               uint32_t encoding_mask) {
+  Label is_object;
+  SmiTst(string);
+  ThrowIf(eq, kNonObject);
+
+  ldr(ip, FieldMemOperand(string, HeapObject::kMapOffset));
+  ldrb(ip, FieldMemOperand(ip, Map::kInstanceTypeOffset));
+
+  and_(ip, ip, Operand(kStringRepresentationMask | kStringEncodingMask));
+  cmp(ip, Operand(encoding_mask));
+  ThrowIf(ne, kUnexpectedStringType);
+
+  // The index is assumed to be untagged coming in, tag it to compare with the
+  // string length without using a temp register, it is restored at the end of
+  // this function.
+  Label index_tag_ok, index_tag_bad;
+  TrySmiTag(index, index, &index_tag_bad);
+  b(&index_tag_ok);
+  bind(&index_tag_bad);
+  Throw(kIndexIsTooLarge);
+  bind(&index_tag_ok);
+
+  ldr(ip, FieldMemOperand(string, String::kLengthOffset));
+  cmp(index, ip);
+  ThrowIf(ge, kIndexIsTooLarge);
+
+  cmp(index, Operand(Smi::FromInt(0)));
+  ThrowIf(lt, kIndexIsNegative);
+
+  SmiUntag(index, index);
+}
+
+
 void MacroAssembler::PrepareCallCFunction(int num_reg_arguments,
                                           int num_double_arguments,
                                           Register scratch) {
@@ -3774,6 +3810,52 @@
 }
 
 
+void MacroAssembler::Throw(BailoutReason reason) {
+  Label throw_start;
+  bind(&throw_start);
+#ifdef DEBUG
+  const char* msg = GetBailoutReason(reason);
+  if (msg != NULL) {
+    RecordComment("Throw message: ");
+    RecordComment(msg);
+  }
+#endif
+
+  mov(r0, Operand(Smi::FromInt(reason)));
+  push(r0);
+  // Disable stub call restrictions to always allow calls to throw.
+  if (!has_frame_) {
+    // We don't actually want to generate a pile of code for this, so just
+    // claim there is a stack frame, without generating one.
+    FrameScope scope(this, StackFrame::NONE);
+    CallRuntime(Runtime::kThrowMessage, 1);
+  } else {
+    CallRuntime(Runtime::kThrowMessage, 1);
+  }
+  // will not return here
+  if (is_const_pool_blocked()) {
+    // If the calling code cares throw the exact number of
+    // instructions generated, we insert padding here to keep the size
+    // of the ThrowMessage macro constant.
+    static const int kExpectedThrowMessageInstructions = 10;
+    int throw_instructions = InstructionsGeneratedSince(&throw_start);
+    ASSERT(throw_instructions <= kExpectedThrowMessageInstructions);
+    while (throw_instructions++ < kExpectedThrowMessageInstructions) {
+      nop();
+    }
+  }
+}
+
+
+void MacroAssembler::ThrowIf(Condition cc, BailoutReason reason) {
+  Label L;
+  b(NegateCondition(cc), &L);
+  Throw(reason);
+  // will not return here
+  bind(&L);
+}
+
+
 void MacroAssembler::LoadInstanceDescriptors(Register map,
                                              Register descriptors) {
   ldr(descriptors, FieldMemOperand(map, Map::kDescriptorsOffset));
diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h
index 97b2575..4897064 100644
--- a/src/arm/macro-assembler-arm.h
+++ b/src/arm/macro-assembler-arm.h
@@ -661,6 +661,12 @@
   // handler chain.
   void ThrowUncatchable(Register value);
 
+  // Throw a message string as an exception.
+  void Throw(BailoutReason reason);
+
+  // Throw a message string as an exception if a condition is not true.
+  void ThrowIf(Condition cc, BailoutReason reason);
+
   // ---------------------------------------------------------------------------
   // Inline caching support
 
@@ -1341,6 +1347,11 @@
 
   void JumpIfNotUniqueName(Register reg, Label* not_unique_name);
 
+  void EmitSeqStringSetCharCheck(Register string,
+                                 Register index,
+                                 Register value,
+                                 uint32_t encoding_mask);
+
   // ---------------------------------------------------------------------------
   // Patching helpers.
 
diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc
index 2e3a0f8..7e82fd0 100644
--- a/src/arm/stub-cache-arm.cc
+++ b/src/arm/stub-cache-arm.cc
@@ -1650,7 +1650,7 @@
   GenerateMissBranch();
 
   // Return the generated code.
-  return GetCode(Code::FIELD, name);
+  return GetCode(Code::FAST, name);
 }
 
 
@@ -2681,7 +2681,7 @@
     Handle<Code> code = CompileCustomCall(object, holder,
                                           Handle<Cell>::null(),
                                           function, Handle<String>::cast(name),
-                                          Code::CONSTANT);
+                                          Code::FAST);
     // A null handle means bail out to the regular compiler code below.
     if (!code.is_null()) return code;
   }
@@ -2728,7 +2728,7 @@
   GenerateMissBranch();
 
   // Return the generated code.
-  return GetCode(Code::INTERCEPTOR, name);
+  return GetCode(Code::FAST, name);
 }
 
 
@@ -2814,7 +2814,7 @@
   __ TailCallExternalReference(store_callback_property, 4, 1);
 
   // Return the generated code.
-  return GetCode(kind(), Code::CALLBACKS, name);
+  return GetCode(kind(), Code::FAST, name);
 }
 
 
@@ -2830,7 +2830,7 @@
       masm(), call_optimization, receiver(), scratch3(), 1, values);
 
   // Return the generated code.
-  return GetCode(kind(), Code::CALLBACKS, name);
+  return GetCode(kind(), Code::FAST, name);
 }
 
 
@@ -2913,7 +2913,7 @@
   TailCallBuiltin(masm(), MissBuiltin(kind()));
 
   // Return the generated code.
-  return GetCode(kind(), Code::INTERCEPTOR, name);
+  return GetCode(kind(), Code::FAST, name);
 }
 
 
@@ -2930,7 +2930,7 @@
   __ Ret();
 
   // Return the generated code.
-  return GetCode(kind(), Code::NONEXISTENT, name);
+  return GetCode(kind(), Code::FAST, name);
 }
 
 
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index 234a211..bc52fa8 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -2426,8 +2426,8 @@
 bool Genesis::ConfigureApiObject(Handle<JSObject> object,
     Handle<ObjectTemplateInfo> object_template) {
   ASSERT(!object_template.is_null());
-  ASSERT(object->IsInstanceOf(
-      FunctionTemplateInfo::cast(object_template->constructor())));
+  ASSERT(FunctionTemplateInfo::cast(object_template->constructor())
+             ->IsTemplateFor(object->map()));;
 
   bool pending_exception = false;
   Handle<JSObject> obj =
diff --git a/src/builtins.cc b/src/builtins.cc
index 655b808..f950c59 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -1104,7 +1104,7 @@
 static inline Object* FindHidden(Heap* heap,
                                  Object* object,
                                  FunctionTemplateInfo* type) {
-  if (object->IsInstanceOf(type)) return object;
+  if (type->IsTemplateFor(object)) return object;
   Object* proto = object->GetPrototype(heap->isolate());
   if (proto->IsJSObject() &&
       JSObject::cast(proto)->map()->is_hidden_prototype()) {
diff --git a/src/code-stubs.h b/src/code-stubs.h
index 0f35eec..789983a 100644
--- a/src/code-stubs.h
+++ b/src/code-stubs.h
@@ -931,7 +931,7 @@
     return UnboxedDoubleBits::decode(bit_field_);
   }
 
-  virtual Code::StubType GetStubType() { return Code::FIELD; }
+  virtual Code::StubType GetStubType() { return Code::FAST; }
 
  protected:
   LoadFieldStub() : HandlerStub() { }
diff --git a/src/compiler.h b/src/compiler.h
index 5ebcfd9..080907e 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -302,12 +302,12 @@
   }
 
   void AbortDueToDependencyChange() {
-    ASSERT(!isolate()->optimizing_compiler_thread()->IsOptimizerThread());
+    ASSERT(!OptimizingCompilerThread::IsOptimizerThread(isolate()));
     abort_due_to_dependency_ = true;
   }
 
   bool HasAbortedDueToDependencyChange() {
-    ASSERT(!isolate()->optimizing_compiler_thread()->IsOptimizerThread());
+    ASSERT(!OptimizingCompilerThread::IsOptimizerThread(isolate()));
     return abort_due_to_dependency_;
   }
 
diff --git a/src/d8.cc b/src/d8.cc
index eaec7d3..339cc32 100644
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -62,6 +62,7 @@
 #ifndef V8_SHARED
 #include "api.h"
 #include "checks.h"
+#include "cpu.h"
 #include "d8-debug.h"
 #include "debug.h"
 #include "natives.h"
@@ -1709,7 +1710,8 @@
   Isolate* isolate = Isolate::GetCurrent();
 #ifndef V8_SHARED
   v8::ResourceConstraints constraints;
-  constraints.ConfigureDefaults(i::OS::TotalPhysicalMemory());
+  constraints.ConfigureDefaults(i::OS::TotalPhysicalMemory(),
+                                i::CPU::NumberOfProcessorsOnline());
   v8::SetResourceConstraints(isolate, &constraints);
 #endif
   DumbLineEditor dumb_line_editor(isolate);
diff --git a/src/debug.cc b/src/debug.cc
index 35970e5..6a8df7a 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -2056,7 +2056,7 @@
   // If preparing for the first break point make sure to deoptimize all
   // functions as debugging does not work with optimized code.
   if (!has_break_points_) {
-    if (FLAG_concurrent_recompilation) {
+    if (isolate_->concurrent_recompilation_enabled()) {
       isolate_->optimizing_compiler_thread()->Flush();
     }
 
diff --git a/src/execution.cc b/src/execution.cc
index 979641a..8febbbf 100644
--- a/src/execution.cc
+++ b/src/execution.cc
@@ -951,7 +951,7 @@
     Deoptimizer::DeoptimizeAll(isolate);
   }
   if (stack_guard->IsInstallCodeRequest()) {
-    ASSERT(FLAG_concurrent_recompilation);
+    ASSERT(isolate->concurrent_recompilation_enabled());
     stack_guard->Continue(INSTALL_CODE);
     isolate->optimizing_compiler_thread()->InstallOptimizedFunctions();
   }
diff --git a/src/full-codegen.h b/src/full-codegen.h
index e27662e..11d5341 100644
--- a/src/full-codegen.h
+++ b/src/full-codegen.h
@@ -497,11 +497,6 @@
   INLINE_RUNTIME_FUNCTION_LIST(EMIT_INLINE_RUNTIME_CALL)
 #undef EMIT_INLINE_RUNTIME_CALL
 
-  void EmitSeqStringSetCharCheck(Register string,
-                                 Register index,
-                                 Register value,
-                                 uint32_t encoding_mask);
-
   // Platform-specific code for resuming generators.
   void EmitGeneratorResume(Expression *generator,
                            Expression *value,
diff --git a/src/heap-profiler.cc b/src/heap-profiler.cc
index 46320b6..b45e97b 100644
--- a/src/heap-profiler.cc
+++ b/src/heap-profiler.cc
@@ -177,7 +177,7 @@
   Isolate* isolate = heap()->isolate();
   HandleScope scope(isolate);
 
-  if (FLAG_concurrent_recompilation) {
+  if (isolate->concurrent_recompilation_enabled()) {
     isolate->optimizing_compiler_thread()->Flush();
   }
 
diff --git a/src/heap.cc b/src/heap.cc
index 90bb2cd..b75f751 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -465,7 +465,7 @@
 
   store_buffer()->GCPrologue();
 
-  if (FLAG_concurrent_osr) {
+  if (isolate()->concurrent_osr_enabled()) {
     isolate()->optimizing_compiler_thread()->AgeBufferedOsrJobs();
   }
 }
@@ -662,7 +662,7 @@
   // Note: as weak callbacks can execute arbitrary code, we cannot
   // hope that eventually there will be no weak callbacks invocations.
   // Therefore stop recollecting after several attempts.
-  if (FLAG_concurrent_recompilation) {
+  if (isolate()->concurrent_recompilation_enabled()) {
     // The optimizing compiler may be unnecessarily holding on to memory.
     DisallowHeapAllocation no_recursive_gc;
     isolate()->optimizing_compiler_thread()->Flush();
@@ -763,7 +763,7 @@
 
 
 int Heap::NotifyContextDisposed() {
-  if (FLAG_concurrent_recompilation) {
+  if (isolate()->concurrent_recompilation_enabled()) {
     // Flush the queued recompilation tasks.
     isolate()->optimizing_compiler_thread()->Flush();
   }
@@ -6583,6 +6583,14 @@
 }
 
 
+bool Heap::AdvanceSweepers(int step_size) {
+  ASSERT(isolate()->num_sweeper_threads() == 0);
+  bool sweeping_complete = old_data_space()->AdvanceSweeper(step_size);
+  sweeping_complete &= old_pointer_space()->AdvanceSweeper(step_size);
+  return sweeping_complete;
+}
+
+
 intptr_t Heap::PromotedExternalMemorySize() {
   if (amount_of_external_allocated_memory_
       <= amount_of_external_allocated_memory_at_last_global_gc_) return 0;
@@ -6729,9 +6737,6 @@
   store_buffer()->SetUp();
 
   if (FLAG_concurrent_recompilation) relocation_mutex_ = new Mutex;
-#ifdef DEBUG
-  relocation_mutex_locked_by_optimizer_thread_ = false;
-#endif  // DEBUG
 
   return true;
 }
@@ -6876,6 +6881,7 @@
   isolate_->memory_allocator()->TearDown();
 
   delete relocation_mutex_;
+  relocation_mutex_ = NULL;
 }
 
 
@@ -7955,15 +7961,4 @@
   ClearObjectStats();
 }
 
-
-Heap::RelocationLock::RelocationLock(Heap* heap) : heap_(heap) {
-  if (FLAG_concurrent_recompilation) {
-    heap_->relocation_mutex_->Lock();
-#ifdef DEBUG
-    heap_->relocation_mutex_locked_by_optimizer_thread_ =
-        heap_->isolate()->optimizing_compiler_thread()->IsOptimizerThread();
-#endif  // DEBUG
-  }
-}
-
 } }  // namespace v8::internal
diff --git a/src/heap.h b/src/heap.h
index 0570557..752a1ed 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -1699,12 +1699,7 @@
            old_pointer_space()->IsLazySweepingComplete();
   }
 
-  bool AdvanceSweepers(int step_size) {
-    ASSERT(!FLAG_parallel_sweeping && !FLAG_concurrent_sweeping);
-    bool sweeping_complete = old_data_space()->AdvanceSweeper(step_size);
-    sweeping_complete &= old_pointer_space()->AdvanceSweeper(step_size);
-    return sweeping_complete;
-  }
+  bool AdvanceSweepers(int step_size);
 
   bool EnsureSweepersProgressed(int step_size) {
     bool sweeping_complete = old_data_space()->EnsureSweeperProgress(step_size);
@@ -1833,22 +1828,18 @@
   // only when FLAG_concurrent_recompilation is true.
   class RelocationLock {
    public:
-    explicit RelocationLock(Heap* heap);
-
-    ~RelocationLock() {
+    explicit RelocationLock(Heap* heap) : heap_(heap) {
       if (FLAG_concurrent_recompilation) {
-#ifdef DEBUG
-        heap_->relocation_mutex_locked_by_optimizer_thread_ = false;
-#endif  // DEBUG
-        heap_->relocation_mutex_->Unlock();
+        heap_->relocation_mutex_->Lock();
       }
     }
 
-#ifdef DEBUG
-    static bool IsLockedByOptimizerThread(Heap* heap) {
-      return heap->relocation_mutex_locked_by_optimizer_thread_;
+
+    ~RelocationLock() {
+      if (FLAG_concurrent_recompilation) {
+        heap_->relocation_mutex_->Unlock();
+      }
     }
-#endif  // DEBUG
 
    private:
     Heap* heap_;
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc
index c47351d..84949c0 100644
--- a/src/hydrogen-instructions.cc
+++ b/src/hydrogen-instructions.cc
@@ -521,19 +521,12 @@
 
 
 bool HValue::IsInteger32Constant() {
-  HValue* value_to_check = IsForceRepresentation()
-      ? HForceRepresentation::cast(this)->value()
-      : this;
-  return value_to_check->IsConstant() &&
-      HConstant::cast(value_to_check)->HasInteger32Value();
+  return IsConstant() && HConstant::cast(this)->HasInteger32Value();
 }
 
 
 int32_t HValue::GetInteger32Constant() {
-  HValue* constant_value = IsForceRepresentation()
-      ? HForceRepresentation::cast(this)->value()
-      : this;
-  return HConstant::cast(constant_value)->Integer32Value();
+  return HConstant::cast(this)->Integer32Value();
 }
 
 
@@ -1342,6 +1335,23 @@
 }
 
 
+HInstruction* HForceRepresentation::New(Zone* zone, HValue* context,
+       HValue* value, Representation required_representation) {
+  if (FLAG_fold_constants && value->IsConstant()) {
+    HConstant* c = HConstant::cast(value);
+    if (c->HasNumberValue()) {
+      double double_res = c->DoubleValue();
+      if (TypeInfo::IsInt32Double(double_res)) {
+        return HConstant::New(zone, context,
+                              static_cast<int32_t>(double_res),
+                              required_representation);
+      }
+    }
+  }
+  return new(zone) HForceRepresentation(value, required_representation);
+}
+
+
 void HForceRepresentation::PrintDataTo(StringStream* stream) {
   stream->Add("%s ", representation().Mnemonic());
   value()->PrintNameTo(stream);
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index 756ae0d..1423c72 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -1675,7 +1675,8 @@
 
 class HForceRepresentation V8_FINAL : public HTemplateInstruction<1> {
  public:
-  DECLARE_INSTRUCTION_FACTORY_P2(HForceRepresentation, HValue*, Representation);
+  static HInstruction* New(Zone* zone, HValue* context, HValue* value,
+                           Representation required_representation);
 
   HValue* value() { return OperandAt(0); }
 
@@ -7281,31 +7282,35 @@
 };
 
 
-class HSeqStringSetChar V8_FINAL : public HTemplateInstruction<3> {
+class HSeqStringSetChar V8_FINAL : public HTemplateInstruction<4> {
  public:
-  DECLARE_INSTRUCTION_FACTORY_P4(HSeqStringSetChar, String::Encoding,
-                                 HValue*, HValue*, HValue*);
+  DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(
+      HSeqStringSetChar, String::Encoding,
+      HValue*, HValue*, HValue*);
 
   String::Encoding encoding() { return encoding_; }
-  HValue* string() { return OperandAt(0); }
-  HValue* index() { return OperandAt(1); }
-  HValue* value() { return OperandAt(2); }
+  HValue* context() { return OperandAt(0); }
+  HValue* string() { return OperandAt(1); }
+  HValue* index() { return OperandAt(2); }
+  HValue* value() { return OperandAt(3); }
 
   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
-    return (index == 0) ? Representation::Tagged()
+    return (index <= 1) ? Representation::Tagged()
                         : Representation::Integer32();
   }
 
   DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar)
 
  private:
-  HSeqStringSetChar(String::Encoding encoding,
+  HSeqStringSetChar(HValue* context,
+                    String::Encoding encoding,
                     HValue* string,
                     HValue* index,
                     HValue* value) : encoding_(encoding) {
-    SetOperandAt(0, string);
-    SetOperandAt(1, index);
-    SetOperandAt(2, value);
+    SetOperandAt(0, context);
+    SetOperandAt(1, string);
+    SetOperandAt(2, index);
+    SetOperandAt(3, value);
     set_representation(Representation::Tagged());
     SetGVNFlag(kChangesStringChars);
   }
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index 431242f..22da947 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -1869,6 +1869,11 @@
           // We can safely skip the write barrier for storing map here.
           AddStoreMapConstantNoWriteBarrier(string, map);
 
+          // Length must be stored into the string before we copy characters to
+          // make debug verification code happy.
+          Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(),
+                                length);
+
           // Copy bytes from the left string.
           BuildCopySeqStringChars(
               left, graph()->GetConstant0(), String::ONE_BYTE_ENCODING,
@@ -1900,6 +1905,11 @@
           // We can safely skip the write barrier for storing map here.
           AddStoreMapConstantNoWriteBarrier(string, map);
 
+          // Length must be stored into the string before we copy characters to
+          // make debug verification code happy.
+          Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(),
+                                length);
+
           // Copy bytes from the left string.
           BuildCopySeqStringChars(
               left, graph()->GetConstant0(), String::TWO_BYTE_ENCODING,
@@ -1921,8 +1931,6 @@
         HValue* string = Pop();
         Add<HStoreNamedField>(string, HObjectAccess::ForStringHashField(),
                               Add<HConstant>(String::kEmptyHashField));
-        Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(),
-                              length);
         Push(string);
       }
       if_sameencodingandsequential.JoinContinuation(&handled);
@@ -2078,7 +2086,7 @@
   // deopt, leaving the backing store in an invalid state.
   if (is_store && IsFastSmiElementsKind(elements_kind) &&
       !val->type().IsSmi()) {
-    val = Add<HForceRepresentation>(val, Representation::Smi());
+    val = AddUncasted<HForceRepresentation>(val, Representation::Smi());
   }
 
   if (IsGrowStoreMode(store_mode)) {
@@ -2195,7 +2203,7 @@
     HValue* capacity) {
   // The HForceRepresentation is to prevent possible deopt on int-smi
   // conversion after allocation but before the new object fields are set.
-  capacity = Add<HForceRepresentation>(capacity, Representation::Smi());
+  capacity = AddUncasted<HForceRepresentation>(capacity, Representation::Smi());
   HValue* new_elements = BuildAllocateElements(kind, capacity);
   BuildInitializeElementsHeader(new_elements, kind, capacity);
   return new_elements;
@@ -2714,10 +2722,12 @@
   // These HForceRepresentations are because we store these as fields in the
   // objects we construct, and an int32-to-smi HChange could deopt. Accept
   // the deopt possibility now, before allocation occurs.
-  capacity = builder()->Add<HForceRepresentation>(capacity,
-                                                  Representation::Smi());
-  length_field = builder()->Add<HForceRepresentation>(length_field,
-                                                      Representation::Smi());
+  capacity =
+      builder()->AddUncasted<HForceRepresentation>(capacity,
+                                                   Representation::Smi());
+  length_field =
+      builder()->AddUncasted<HForceRepresentation>(length_field,
+                                                   Representation::Smi());
   // Allocate (dealing with failure appropriately)
   HAllocate* new_object = builder()->Add<HAllocate>(size_in_bytes,
       HType::JSArray(), NOT_TENURED, JS_ARRAY_TYPE);
@@ -2904,7 +2914,7 @@
 
 void HGraph::FinalizeUniqueness() {
   DisallowHeapAllocation no_gc;
-  ASSERT(!isolate()->optimizing_compiler_thread()->IsOptimizerThread());
+  ASSERT(!OptimizingCompilerThread::IsOptimizerThread(isolate()));
   for (int i = 0; i < blocks()->length(); ++i) {
     for (HInstructionIterator it(blocks()->at(i)); !it.Done(); it.Advance()) {
       it.Current()->FinalizeUniqueness();
@@ -8267,7 +8277,7 @@
     // actual HChange instruction we need is (sometimes) added in a later
     // phase, so it is not available now to be used as an input to HAdd and
     // as the return value.
-    HInstruction* number_input = Add<HForceRepresentation>(Pop(), rep);
+    HInstruction* number_input = AddUncasted<HForceRepresentation>(Pop(), rep);
     if (!rep.IsDouble()) {
       number_input->SetFlag(HInstruction::kFlexibleRepresentation);
       number_input->SetFlag(HInstruction::kCannotBeTagged);
@@ -8514,10 +8524,11 @@
 HValue* HGraphBuilder::EnforceNumberType(HValue* number,
                                          Handle<Type> expected) {
   if (expected->Is(Type::Smi())) {
-    return Add<HForceRepresentation>(number, Representation::Smi());
+    return AddUncasted<HForceRepresentation>(number, Representation::Smi());
   }
   if (expected->Is(Type::Signed32())) {
-    return Add<HForceRepresentation>(number, Representation::Integer32());
+    return AddUncasted<HForceRepresentation>(number,
+                                             Representation::Integer32());
   }
   return number;
 }
@@ -9712,9 +9723,10 @@
   HValue* value = Pop();
   HValue* index = Pop();
   HValue* string = Pop();
-  HSeqStringSetChar* result = New<HSeqStringSetChar>(
-      String::ONE_BYTE_ENCODING, string, index, value);
-  return ast_context()->ReturnInstruction(result, call->id());
+  Add<HSeqStringSetChar>(String::ONE_BYTE_ENCODING, string,
+                         index, value);
+  Add<HSimulate>(call->id(), FIXED_SIMULATE);
+  return ast_context()->ReturnValue(graph()->GetConstantUndefined());
 }
 
 
@@ -9727,9 +9739,10 @@
   HValue* value = Pop();
   HValue* index = Pop();
   HValue* string = Pop();
-  HSeqStringSetChar* result = New<HSeqStringSetChar>(
-      String::TWO_BYTE_ENCODING, string, index, value);
-  return ast_context()->ReturnInstruction(result, call->id());
+  Add<HSeqStringSetChar>(String::TWO_BYTE_ENCODING, string,
+                         index, value);
+  Add<HSimulate>(call->id(), FIXED_SIMULATE);
+  return ast_context()->ReturnValue(graph()->GetConstantUndefined());
 }
 
 
@@ -10328,7 +10341,7 @@
 
 
 void HTracer::TraceLithium(const char* name, LChunk* chunk) {
-  ASSERT(!FLAG_concurrent_recompilation);
+  ASSERT(!chunk->isolate()->concurrent_recompilation_enabled());
   AllowHandleDereference allow_deref;
   AllowDeferredHandleDereference allow_deferred_deref;
   Trace(name, chunk->graph(), chunk);
@@ -10336,7 +10349,7 @@
 
 
 void HTracer::TraceHydrogen(const char* name, HGraph* graph) {
-  ASSERT(!FLAG_concurrent_recompilation);
+  ASSERT(!graph->isolate()->concurrent_recompilation_enabled());
   AllowHandleDereference allow_deref;
   AllowDeferredHandleDereference allow_deferred_deref;
   Trace(name, graph, NULL);
diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc
index 24cb13f..bacfe83 100644
--- a/src/ia32/full-codegen-ia32.cc
+++ b/src/ia32/full-codegen-ia32.cc
@@ -3440,32 +3440,6 @@
 }
 
 
-void FullCodeGenerator::EmitSeqStringSetCharCheck(Register string,
-                                                  Register index,
-                                                  Register value,
-                                                  uint32_t encoding_mask) {
-  __ test(index, Immediate(kSmiTagMask));
-  __ Check(zero, kNonSmiIndex);
-  __ test(value, Immediate(kSmiTagMask));
-  __ Check(zero, kNonSmiValue);
-
-  __ cmp(index, FieldOperand(string, String::kLengthOffset));
-  __ Check(less, kIndexIsTooLarge);
-
-  __ cmp(index, Immediate(Smi::FromInt(0)));
-  __ Check(greater_equal, kIndexIsNegative);
-
-  __ push(value);
-  __ mov(value, FieldOperand(string, HeapObject::kMapOffset));
-  __ movzx_b(value, FieldOperand(value, Map::kInstanceTypeOffset));
-
-  __ and_(value, Immediate(kStringRepresentationMask | kStringEncodingMask));
-  __ cmp(value, Immediate(encoding_mask));
-  __ Check(equal, kUnexpectedStringType);
-  __ pop(value);
-}
-
-
 void FullCodeGenerator::EmitOneByteSeqStringSetChar(CallRuntime* expr) {
   ZoneList<Expression*>* args = expr->arguments();
   ASSERT_EQ(3, args->length());
@@ -3476,18 +3450,26 @@
 
   VisitForStackValue(args->at(1));  // index
   VisitForStackValue(args->at(2));  // value
-  __ pop(value);
-  __ pop(index);
   VisitForAccumulatorValue(args->at(0));  // string
 
+  __ pop(value);
+  __ pop(index);
 
   if (FLAG_debug_code) {
-    static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
-    EmitSeqStringSetCharCheck(string, index, value, one_byte_seq_type);
+    __ test(value, Immediate(kSmiTagMask));
+    __ ThrowIf(not_zero, kNonSmiValue);
+    __ test(index, Immediate(kSmiTagMask));
+    __ ThrowIf(not_zero, kNonSmiValue);
   }
 
   __ SmiUntag(value);
   __ SmiUntag(index);
+
+  if (FLAG_debug_code) {
+    static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
+    __ EmitSeqStringSetCharCheck(string, index, value, one_byte_seq_type);
+  }
+
   __ mov_b(FieldOperand(string, index, times_1, SeqOneByteString::kHeaderSize),
            value);
   context()->Plug(string);
@@ -3504,13 +3486,19 @@
 
   VisitForStackValue(args->at(1));  // index
   VisitForStackValue(args->at(2));  // value
+  VisitForAccumulatorValue(args->at(0));  // string
   __ pop(value);
   __ pop(index);
-  VisitForAccumulatorValue(args->at(0));  // string
 
   if (FLAG_debug_code) {
+    __ test(value, Immediate(kSmiTagMask));
+    __ ThrowIf(not_zero, kNonSmiValue);
+    __ test(index, Immediate(kSmiTagMask));
+    __ ThrowIf(not_zero, kNonSmiValue);
+    __ SmiUntag(index);
     static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
-    EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type);
+    __ EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type);
+    __ SmiTag(index);
   }
 
   __ SmiUntag(value);
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index 2a118a9..654c04d 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -2130,17 +2130,14 @@
   Register string = ToRegister(instr->string());
 
   if (FLAG_debug_code) {
-    __ push(string);
-    __ mov(string, FieldOperand(string, HeapObject::kMapOffset));
-    __ movzx_b(string, FieldOperand(string, Map::kInstanceTypeOffset));
-
-    __ and_(string, Immediate(kStringRepresentationMask | kStringEncodingMask));
+    Register value = ToRegister(instr->value());
+    Register index = ToRegister(instr->index());
     static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
     static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
-    __ cmp(string, Immediate(encoding == String::ONE_BYTE_ENCODING
-                             ? one_byte_seq_type : two_byte_seq_type));
-    __ Check(equal, kUnexpectedStringType);
-    __ pop(string);
+    int encoding_mask =
+        instr->hydrogen()->encoding() == String::ONE_BYTE_ENCODING
+        ? one_byte_seq_type : two_byte_seq_type;
+    __ EmitSeqStringSetCharCheck(string, index, value, encoding_mask);
   }
 
   Operand operand = BuildSeqStringOperand(string, instr->index(), encoding);
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
index 5a4a3bc..5fcd0a2 100644
--- a/src/ia32/lithium-ia32.cc
+++ b/src/ia32/lithium-ia32.cc
@@ -1892,13 +1892,36 @@
 }
 
 
+LOperand* LChunkBuilder::GetSeqStringSetCharOperand(HSeqStringSetChar* instr) {
+  if (instr->encoding() == String::ONE_BYTE_ENCODING) {
+    if (FLAG_debug_code) {
+      return UseFixed(instr->value(), eax);
+    } else {
+      return UseFixedOrConstant(instr->value(), eax);
+    }
+  } else {
+    if (FLAG_debug_code) {
+      return UseRegisterAtStart(instr->value());
+    } else {
+      return UseRegisterOrConstantAtStart(instr->value());
+    }
+  }
+}
+
+
 LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) {
   LOperand* string = UseRegisterAtStart(instr->string());
-  LOperand* index = UseRegisterOrConstantAtStart(instr->index());
-  LOperand* value = (instr->encoding() == String::ONE_BYTE_ENCODING)
-      ? UseFixedOrConstant(instr->value(), eax)
-      : UseRegisterOrConstantAtStart(instr->value());
-  return new(zone()) LSeqStringSetChar(string, index, value);
+  LOperand* index = FLAG_debug_code
+      ? UseRegisterAtStart(instr->index())
+      : UseRegisterOrConstantAtStart(instr->index());
+  LOperand* value = GetSeqStringSetCharOperand(instr);
+  LOperand* context = FLAG_debug_code ? UseFixed(instr->context(), esi) : NULL;
+  LInstruction* result = new(zone()) LSeqStringSetChar(context, string,
+                                                       index, value);
+  if (FLAG_debug_code) {
+    result = MarkAsCall(result, instr);
+  }
+  return result;
 }
 
 
diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h
index b0d031a..bc2b71b 100644
--- a/src/ia32/lithium-ia32.h
+++ b/src/ia32/lithium-ia32.h
@@ -1377,19 +1377,21 @@
 };
 
 
-class LSeqStringSetChar V8_FINAL : public LTemplateInstruction<1, 3, 0> {
+class LSeqStringSetChar V8_FINAL : public LTemplateInstruction<1, 4, 0> {
  public:
-  LSeqStringSetChar(LOperand* string,
+  LSeqStringSetChar(LOperand* context,
+                    LOperand* string,
                     LOperand* index,
                     LOperand* value) {
-    inputs_[0] = string;
-    inputs_[1] = index;
-    inputs_[2] = value;
+    inputs_[0] = context;
+    inputs_[1] = string;
+    inputs_[2] = index;
+    inputs_[3] = value;
   }
 
-  LOperand* string() { return inputs_[0]; }
-  LOperand* index() { return inputs_[1]; }
-  LOperand* value() { return inputs_[2]; }
+  LOperand* string() { return inputs_[1]; }
+  LOperand* index() { return inputs_[2]; }
+  LOperand* value() { return inputs_[3]; }
 
   DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar, "seq-string-set-char")
   DECLARE_HYDROGEN_ACCESSOR(SeqStringSetChar)
@@ -2917,6 +2919,8 @@
 
   enum CanDeoptimize { CAN_DEOPTIMIZE_EAGERLY, CANNOT_DEOPTIMIZE_EAGERLY };
 
+  LOperand* GetSeqStringSetCharOperand(HSeqStringSetChar* instr);
+
   // Marks a call for the register allocator.  Assigns a pointer map to
   // support GC and lazy deoptimization.  Assigns an environment to support
   // eager deoptimization if CAN_DEOPTIMIZE_EAGERLY.
diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc
index 914a4c2..d394c09 100644
--- a/src/ia32/macro-assembler-ia32.cc
+++ b/src/ia32/macro-assembler-ia32.cc
@@ -3065,6 +3065,40 @@
 }
 
 
+void MacroAssembler::Throw(BailoutReason reason) {
+#ifdef DEBUG
+  const char* msg = GetBailoutReason(reason);
+  if (msg != NULL) {
+    RecordComment("Throw message: ");
+    RecordComment(msg);
+  }
+#endif
+
+  push(eax);
+  push(Immediate(Smi::FromInt(reason)));
+  // Disable stub call restrictions to always allow calls to throw.
+  if (!has_frame_) {
+    // We don't actually want to generate a pile of code for this, so just
+    // claim there is a stack frame, without generating one.
+    FrameScope scope(this, StackFrame::NONE);
+    CallRuntime(Runtime::kThrowMessage, 1);
+  } else {
+    CallRuntime(Runtime::kThrowMessage, 1);
+  }
+  // will not return here
+  int3();
+}
+
+
+void MacroAssembler::ThrowIf(Condition cc, BailoutReason reason) {
+  Label L;
+  j(NegateCondition(cc), &L);
+  Throw(reason);
+  // will not return here
+  bind(&L);
+}
+
+
 void MacroAssembler::LoadInstanceDescriptors(Register map,
                                              Register descriptors) {
   mov(descriptors, FieldOperand(map, Map::kDescriptorsOffset));
@@ -3230,6 +3264,42 @@
 }
 
 
+void MacroAssembler::EmitSeqStringSetCharCheck(Register string,
+                                               Register index,
+                                               Register value,
+                                               uint32_t encoding_mask) {
+  Label is_object;
+  JumpIfNotSmi(string, &is_object, Label::kNear);
+  Throw(kNonObject);
+  bind(&is_object);
+
+  push(value);
+  mov(value, FieldOperand(string, HeapObject::kMapOffset));
+  movzx_b(value, FieldOperand(value, Map::kInstanceTypeOffset));
+
+  and_(value, Immediate(kStringRepresentationMask | kStringEncodingMask));
+  cmp(value, Immediate(encoding_mask));
+  pop(value);
+  ThrowIf(not_equal, kUnexpectedStringType);
+
+  // The index is assumed to be untagged coming in, tag it to compare with the
+  // string length without using a temp register, it is restored at the end of
+  // this function.
+  SmiTag(index);
+  // Can't use overflow here directly, compiler can't seem to disambiguate.
+  ThrowIf(NegateCondition(no_overflow), kIndexIsTooLarge);
+
+  cmp(index, FieldOperand(string, String::kLengthOffset));
+  ThrowIf(greater_equal, kIndexIsTooLarge);
+
+  cmp(index, Immediate(Smi::FromInt(0)));
+  ThrowIf(less, kIndexIsNegative);
+
+  // Restore the index
+  SmiUntag(index);
+}
+
+
 void MacroAssembler::PrepareCallCFunction(int num_arguments, Register scratch) {
   int frame_alignment = OS::ActivationFrameAlignment();
   if (frame_alignment != 0) {
diff --git a/src/ia32/macro-assembler-ia32.h b/src/ia32/macro-assembler-ia32.h
index 29bb78d..58e5907 100644
--- a/src/ia32/macro-assembler-ia32.h
+++ b/src/ia32/macro-assembler-ia32.h
@@ -583,6 +583,12 @@
   // Throw past all JS frames to the top JS entry frame.
   void ThrowUncatchable(Register value);
 
+  // Throw a message string as an exception.
+  void Throw(BailoutReason reason);
+
+  // Throw a message string as an exception if a condition is not true.
+  void ThrowIf(Condition cc, BailoutReason reason);
+
   // ---------------------------------------------------------------------------
   // Inline caching support
 
@@ -941,6 +947,11 @@
   void JumpIfNotUniqueName(Operand operand, Label* not_unique_name,
                            Label::Distance distance = Label::kFar);
 
+  void EmitSeqStringSetCharCheck(Register string,
+                                 Register index,
+                                 Register value,
+                                 uint32_t encoding_mask);
+
   static int SafepointRegisterStackIndex(Register reg) {
     return SafepointRegisterStackIndex(reg.code());
   }
diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc
index a3be0a7..16c2a18 100644
--- a/src/ia32/stub-cache-ia32.cc
+++ b/src/ia32/stub-cache-ia32.cc
@@ -1671,7 +1671,7 @@
   GenerateMissBranch();
 
   // Return the generated code.
-  return GetCode(Code::FIELD, name);
+  return GetCode(Code::FAST, name);
 }
 
 
@@ -2752,7 +2752,7 @@
     Handle<Code> code = CompileCustomCall(object, holder,
                                           Handle<Cell>::null(),
                                           function, Handle<String>::cast(name),
-                                          Code::CONSTANT);
+                                          Code::FAST);
     // A null handle means bail out to the regular compiler code below.
     if (!code.is_null()) return code;
   }
@@ -2820,7 +2820,7 @@
   GenerateMissBranch();
 
   // Return the generated code.
-  return GetCode(Code::INTERCEPTOR, name);
+  return GetCode(Code::FAST, name);
 }
 
 
@@ -2907,7 +2907,7 @@
   __ TailCallExternalReference(store_callback_property, 4, 1);
 
   // Return the generated code.
-  return GetCode(kind(), Code::CALLBACKS, name);
+  return GetCode(kind(), Code::FAST, name);
 }
 
 
@@ -2923,7 +2923,7 @@
       masm(), call_optimization, receiver(), scratch1(), 1, values);
 
   // Return the generated code.
-  return GetCode(kind(), Code::CALLBACKS, name);
+  return GetCode(kind(), Code::FAST, name);
 }
 
 
@@ -2990,7 +2990,7 @@
   __ TailCallExternalReference(store_ic_property, 4, 1);
 
   // Return the generated code.
-  return GetCode(kind(), Code::INTERCEPTOR, name);
+  return GetCode(kind(), Code::FAST, name);
 }
 
 
@@ -3035,7 +3035,7 @@
   __ ret(0);
 
   // Return the generated code.
-  return GetCode(kind(), Code::NONEXISTENT, name);
+  return GetCode(kind(), Code::FAST, name);
 }
 
 
diff --git a/src/isolate.cc b/src/isolate.cc
index 07bb2ae..700ca87 100644
--- a/src/isolate.cc
+++ b/src/isolate.cc
@@ -131,22 +131,6 @@
 }
 
 
-int SystemThreadManager::NumberOfParallelSystemThreads(
-    ParallelSystemComponent type) {
-  int number_of_threads = Min(CPU::NumberOfProcessorsOnline(), kMaxThreads);
-  ASSERT(number_of_threads > 0);
-  if (number_of_threads ==  1) {
-    return 0;
-  }
-  if (type == PARALLEL_SWEEPING) {
-    return number_of_threads;
-  } else if (type == CONCURRENT_SWEEPING) {
-    return number_of_threads - 1;
-  }
-  return 1;
-}
-
-
 // Create a dummy thread that will wait forever on a semaphore. The only
 // purpose for this thread is to have some stack area to save essential data
 // into for use by a stacks only core dump (aka minidump).
@@ -1790,6 +1774,8 @@
       deferred_handles_head_(NULL),
       optimizing_compiler_thread_(NULL),
       sweeper_thread_(NULL),
+      num_sweeper_threads_(0),
+      max_available_threads_(0),
       stress_deopt_count_(0) {
   id_ = NoBarrier_AtomicIncrement(&isolate_counter_, 1);
   TRACE_ISOLATE(constructor);
@@ -1882,18 +1868,20 @@
     debugger()->UnloadDebugger();
 #endif
 
-    if (FLAG_concurrent_recompilation) {
+    if (concurrent_recompilation_enabled()) {
       optimizing_compiler_thread_->Stop();
       delete optimizing_compiler_thread_;
+      optimizing_compiler_thread_ = NULL;
     }
 
-    if (FLAG_sweeper_threads > 0) {
-      for (int i = 0; i < FLAG_sweeper_threads; i++) {
-        sweeper_thread_[i]->Stop();
-        delete sweeper_thread_[i];
-      }
-      delete[] sweeper_thread_;
+    for (int i = 0; i < num_sweeper_threads_; i++) {
+      sweeper_thread_[i]->Stop();
+      delete sweeper_thread_[i];
+      sweeper_thread_[i] = NULL;
     }
+    delete[] sweeper_thread_;
+    sweeper_thread_ = NULL;
+
 
     if (FLAG_hydrogen_stats) GetHStatistics()->Print();
 
@@ -2217,11 +2205,6 @@
 
   deoptimizer_data_ = new DeoptimizerData(memory_allocator_);
 
-  if (FLAG_concurrent_recompilation) {
-    optimizing_compiler_thread_ = new OptimizingCompilerThread(this);
-    optimizing_compiler_thread_->Start();
-  }
-
   const bool create_heap_objects = (des == NULL);
   if (create_heap_objects && !heap_.CreateHeapObjects()) {
     V8::FatalProcessOutOfMemory("heap object creation");
@@ -2240,6 +2223,31 @@
 
   if (create_heap_objects) heap_.CreateStubsRequiringBuiltins();
 
+  // Set default value if not yet set.
+  // TODO(yangguo): move this to ResourceConstraints::ConfigureDefaults
+  // once ResourceConstraints becomes an argument to the Isolate constructor.
+  if (max_available_threads_ < 1) {
+    // Choose the default between 1 and 4.
+    max_available_threads_ = Max(Min(CPU::NumberOfProcessorsOnline(), 4), 1);
+  }
+
+  num_sweeper_threads_ = SweeperThread::NumberOfThreads(max_available_threads_);
+
+  if (FLAG_trace_hydrogen || FLAG_trace_hydrogen_stubs) {
+    PrintF("Concurrent recompilation has been disabled for tracing.\n");
+  } else if (OptimizingCompilerThread::Enabled(max_available_threads_)) {
+    optimizing_compiler_thread_ = new OptimizingCompilerThread(this);
+    optimizing_compiler_thread_->Start();
+  }
+
+  if (num_sweeper_threads_ > 0) {
+    sweeper_thread_ = new SweeperThread*[num_sweeper_threads_];
+    for (int i = 0; i < num_sweeper_threads_; i++) {
+      sweeper_thread_[i] = new SweeperThread(this);
+      sweeper_thread_[i]->Start();
+    }
+  }
+
   // Only preallocate on the first initialization.
   if (FLAG_preallocate_message_memory && preallocated_message_space_ == NULL) {
     // Start the thread which will set aside some memory.
@@ -2334,14 +2342,6 @@
     NewStringAddStub::InstallDescriptors(this);
   }
 
-  if (FLAG_sweeper_threads > 0) {
-    sweeper_thread_ = new SweeperThread*[FLAG_sweeper_threads];
-    for (int i = 0; i < FLAG_sweeper_threads; i++) {
-      sweeper_thread_[i] = new SweeperThread(this);
-      sweeper_thread_[i]->Start();
-    }
-  }
-
   initialized_from_snapshot_ = (des != NULL);
 
   return true;
diff --git a/src/isolate.h b/src/isolate.h
index c13714f..1d45de9 100644
--- a/src/isolate.h
+++ b/src/isolate.h
@@ -301,20 +301,6 @@
 };
 
 
-class SystemThreadManager {
- public:
-  enum ParallelSystemComponent {
-    PARALLEL_SWEEPING,
-    CONCURRENT_SWEEPING,
-    CONCURRENT_RECOMPILATION
-  };
-
-  static int NumberOfParallelSystemThreads(ParallelSystemComponent type);
-
-  static const int kMaxThreads = 4;
-};
-
-
 #ifdef ENABLE_DEBUGGER_SUPPORT
 
 #define ISOLATE_DEBUGGER_INIT_LIST(V)                                          \
@@ -1111,19 +1097,41 @@
   bool IsDeferredHandle(Object** location);
 #endif  // DEBUG
 
+  void set_max_available_threads(int value) {
+    max_available_threads_ = value;
+  }
+
+  bool concurrent_recompilation_enabled() {
+    // Thread is only available with flag enabled.
+    ASSERT(optimizing_compiler_thread_ == NULL ||
+           FLAG_concurrent_recompilation);
+    return optimizing_compiler_thread_ != NULL;
+  }
+
+  bool concurrent_osr_enabled() const {
+    // Thread is only available with flag enabled.
+    ASSERT(optimizing_compiler_thread_ == NULL ||
+           FLAG_concurrent_recompilation);
+    return optimizing_compiler_thread_ != NULL && FLAG_concurrent_osr;
+  }
+
   OptimizingCompilerThread* optimizing_compiler_thread() {
     return optimizing_compiler_thread_;
   }
 
+  int num_sweeper_threads() const {
+    return num_sweeper_threads_;
+  }
+
+  SweeperThread** sweeper_threads() {
+    return sweeper_thread_;
+  }
+
   // PreInits and returns a default isolate. Needed when a new thread tries
   // to create a Locker for the first time (the lock itself is in the isolate).
   // TODO(svenpanne) This method is on death row...
   static v8::Isolate* GetDefaultIsolateForLocking();
 
-  SweeperThread** sweeper_threads() {
-    return sweeper_thread_;
-  }
-
   int id() const { return static_cast<int>(id_); }
 
   HStatistics* GetHStatistics();
@@ -1373,6 +1381,11 @@
   DeferredHandles* deferred_handles_head_;
   OptimizingCompilerThread* optimizing_compiler_thread_;
   SweeperThread** sweeper_thread_;
+  int num_sweeper_threads_;
+
+  // TODO(yangguo): This will become obsolete once ResourceConstraints
+  // becomes an argument to Isolate constructor.
+  int max_available_threads_;
 
   // Counts deopt points if deopt_every_n_times is enabled.
   unsigned int stress_deopt_count_;
diff --git a/src/mark-compact.cc b/src/mark-compact.cc
index 6d03d43..acd36a9 100644
--- a/src/mark-compact.cc
+++ b/src/mark-compact.cc
@@ -564,7 +564,7 @@
 
 void MarkCompactCollector::StartSweeperThreads() {
   sweeping_pending_ = true;
-  for (int i = 0; i < FLAG_sweeper_threads; i++) {
+  for (int i = 0; i < isolate()->num_sweeper_threads(); i++) {
     isolate()->sweeper_threads()[i]->StartSweeping();
   }
 }
@@ -572,7 +572,7 @@
 
 void MarkCompactCollector::WaitUntilSweepingCompleted() {
   ASSERT(sweeping_pending_ == true);
-  for (int i = 0; i < FLAG_sweeper_threads; i++) {
+  for (int i = 0; i < isolate()->num_sweeper_threads(); i++) {
     isolate()->sweeper_threads()[i]->WaitForSweeperThread();
   }
   sweeping_pending_ = false;
@@ -586,7 +586,7 @@
 intptr_t MarkCompactCollector::
              StealMemoryFromSweeperThreads(PagedSpace* space) {
   intptr_t freed_bytes = 0;
-  for (int i = 0; i < FLAG_sweeper_threads; i++) {
+  for (int i = 0; i < isolate()->num_sweeper_threads(); i++) {
     freed_bytes += isolate()->sweeper_threads()[i]->StealMemory(space);
   }
   space->AddToAccountingStats(freed_bytes);
@@ -4112,8 +4112,10 @@
 #endif
   SweeperType how_to_sweep =
       FLAG_lazy_sweeping ? LAZY_CONSERVATIVE : CONSERVATIVE;
-  if (FLAG_parallel_sweeping) how_to_sweep = PARALLEL_CONSERVATIVE;
-  if (FLAG_concurrent_sweeping) how_to_sweep = CONCURRENT_CONSERVATIVE;
+  if (isolate()->num_sweeper_threads() > 0) {
+    if (FLAG_parallel_sweeping) how_to_sweep = PARALLEL_CONSERVATIVE;
+    if (FLAG_concurrent_sweeping) how_to_sweep = CONCURRENT_CONSERVATIVE;
+  }
   if (FLAG_expose_gc) how_to_sweep = CONSERVATIVE;
   if (sweep_precisely_) how_to_sweep = PRECISE;
 
diff --git a/src/mips/assembler-mips.cc b/src/mips/assembler-mips.cc
index d84315a..9aed3bd 100644
--- a/src/mips/assembler-mips.cc
+++ b/src/mips/assembler-mips.cc
@@ -326,6 +326,7 @@
   desc->buffer_size = buffer_size_;
   desc->instr_size = pc_offset();
   desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
+  desc->origin = this;
 }
 
 
diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc
index a9cf791..9d93aaf 100644
--- a/src/mips/full-codegen-mips.cc
+++ b/src/mips/full-codegen-mips.cc
@@ -3516,29 +3516,6 @@
 }
 
 
-void FullCodeGenerator::EmitSeqStringSetCharCheck(Register string,
-                                                  Register index,
-                                                  Register value,
-                                                  uint32_t encoding_mask) {
-  __ And(at, index, Operand(kSmiTagMask));
-  __ Check(eq, kNonSmiIndex, at, Operand(zero_reg));
-  __ And(at, value, Operand(kSmiTagMask));
-  __ Check(eq, kNonSmiValue, at, Operand(zero_reg));
-
-  __ lw(at, FieldMemOperand(string, String::kLengthOffset));
-  __ Check(lt, kIndexIsTooLarge, index, Operand(at));
-
-  __ Check(ge, kIndexIsNegative, index, Operand(zero_reg));
-
-  __ lw(at, FieldMemOperand(string, HeapObject::kMapOffset));
-  __ lbu(at, FieldMemOperand(at, Map::kInstanceTypeOffset));
-
-  __ And(at, at, Operand(kStringRepresentationMask | kStringEncodingMask));
-  __ Subu(at, at, Operand(encoding_mask));
-  __ Check(eq, kUnexpectedStringType, at, Operand(zero_reg));
-}
-
-
 void FullCodeGenerator::EmitOneByteSeqStringSetChar(CallRuntime* expr) {
   ZoneList<Expression*>* args = expr->arguments();
   ASSERT_EQ(3, args->length());
@@ -3549,12 +3526,20 @@
 
   VisitForStackValue(args->at(1));  // index
   VisitForStackValue(args->at(2));  // value
-  __ Pop(index, value);
   VisitForAccumulatorValue(args->at(0));  // string
+  __ Pop(index, value);
 
   if (FLAG_debug_code) {
+    __ And(at, value, Operand(kSmiTagMask));
+    __ ThrowIf(ne, kNonSmiValue, at, Operand(zero_reg));
+    __ And(at, index, Operand(kSmiTagMask));
+    __ ThrowIf(ne, kNonSmiIndex, at, Operand(zero_reg));
+    __ SmiUntag(index, index);
     static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
-    EmitSeqStringSetCharCheck(string, index, value, one_byte_seq_type);
+    Register scratch = t5;
+    __ EmitSeqStringSetCharCheck(
+        string, index, value, scratch, one_byte_seq_type);
+    __ SmiTag(index, index);
   }
 
   __ SmiUntag(value, value);
@@ -3578,12 +3563,20 @@
 
   VisitForStackValue(args->at(1));  // index
   VisitForStackValue(args->at(2));  // value
-  __ Pop(index, value);
   VisitForAccumulatorValue(args->at(0));  // string
+  __ Pop(index, value);
 
   if (FLAG_debug_code) {
+    __ And(at, value, Operand(kSmiTagMask));
+    __ ThrowIf(ne, kNonSmiValue, at, Operand(zero_reg));
+    __ And(at, index, Operand(kSmiTagMask));
+    __ ThrowIf(ne, kNonSmiIndex, at, Operand(zero_reg));
+    __ SmiUntag(index, index);
     static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
-    EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type);
+    Register scratch = t5;
+    __ EmitSeqStringSetCharCheck(
+        string, index, value, scratch, two_byte_seq_type);
+    __ SmiTag(index, index);
   }
 
   __ SmiUntag(value, value);
diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc
index d71c055..7dc341f 100644
--- a/src/mips/lithium-codegen-mips.cc
+++ b/src/mips/lithium-codegen-mips.cc
@@ -1820,16 +1820,13 @@
 
   if (FLAG_debug_code) {
     Register scratch = scratch0();
-    __ lw(scratch, FieldMemOperand(string, HeapObject::kMapOffset));
-    __ lbu(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
-
-    __ And(scratch, scratch,
-           Operand(kStringRepresentationMask | kStringEncodingMask));
+    Register index = ToRegister(instr->index());
     static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
     static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
-    __ Subu(at, scratch, Operand(encoding == String::ONE_BYTE_ENCODING
-                                ? one_byte_seq_type : two_byte_seq_type));
-    __ Check(eq, kUnexpectedStringType, at, Operand(zero_reg));
+    int encoding_mask =
+        instr->hydrogen()->encoding() == String::ONE_BYTE_ENCODING
+        ? one_byte_seq_type : two_byte_seq_type;
+    __ EmitSeqStringSetCharCheck(string, index, value, scratch, encoding_mask);
   }
 
   MemOperand operand = BuildSeqStringOperand(string, instr->index(), encoding);
diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc
index 09bae59..fb81627 100644
--- a/src/mips/lithium-mips.cc
+++ b/src/mips/lithium-mips.cc
@@ -1826,10 +1826,13 @@
 
 
 LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) {
-  LOperand* string = UseRegister(instr->string());
-  LOperand* index = UseRegisterOrConstant(instr->index());
-  LOperand* value = UseRegister(instr->value());
-  return new(zone()) LSeqStringSetChar(string, index, value);
+  LOperand* string = UseRegisterAtStart(instr->string());
+  LOperand* index = FLAG_debug_code
+      ? UseRegisterAtStart(instr->index())
+      : UseRegisterOrConstantAtStart(instr->index());
+  LOperand* value = UseRegisterAtStart(instr->value());
+  LOperand* context = FLAG_debug_code ? UseFixed(instr->context(), cp) : NULL;
+  return new(zone()) LSeqStringSetChar(context, string, index, value);
 }
 
 
diff --git a/src/mips/lithium-mips.h b/src/mips/lithium-mips.h
index 8c82a9d..452963b 100644
--- a/src/mips/lithium-mips.h
+++ b/src/mips/lithium-mips.h
@@ -1381,19 +1381,21 @@
 };
 
 
-class LSeqStringSetChar V8_FINAL : public LTemplateInstruction<1, 3, 0> {
+class LSeqStringSetChar V8_FINAL : public LTemplateInstruction<1, 4, 0> {
  public:
-  LSeqStringSetChar(LOperand* string,
+  LSeqStringSetChar(LOperand* context,
+                    LOperand* string,
                     LOperand* index,
                     LOperand* value) {
-    inputs_[0] = string;
-    inputs_[1] = index;
-    inputs_[2] = value;
+    inputs_[0] = context;
+    inputs_[1] = string;
+    inputs_[2] = index;
+    inputs_[3] = value;
   }
 
-  LOperand* string() { return inputs_[0]; }
-  LOperand* index() { return inputs_[1]; }
-  LOperand* value() { return inputs_[2]; }
+  LOperand* string() { return inputs_[1]; }
+  LOperand* index() { return inputs_[2]; }
+  LOperand* value() { return inputs_[3]; }
 
   DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar, "seq-string-set-char")
   DECLARE_HYDROGEN_ACCESSOR(SeqStringSetChar)
diff --git a/src/mips/macro-assembler-mips.cc b/src/mips/macro-assembler-mips.cc
index 5519110..930afcb 100644
--- a/src/mips/macro-assembler-mips.cc
+++ b/src/mips/macro-assembler-mips.cc
@@ -5051,6 +5051,44 @@
 }
 
 
+void MacroAssembler::EmitSeqStringSetCharCheck(Register string,
+                                               Register index,
+                                               Register value,
+                                               Register scratch,
+                                               uint32_t encoding_mask) {
+  Label is_object;
+  And(at, string, Operand(kSmiTagMask));
+  ThrowIf(eq, kNonObject, at, Operand(zero_reg));
+
+  lw(at, FieldMemOperand(string, HeapObject::kMapOffset));
+  lbu(at, FieldMemOperand(at, Map::kInstanceTypeOffset));
+
+  andi(at, at, kStringRepresentationMask | kStringEncodingMask);
+  li(scratch, Operand(encoding_mask));
+  ThrowIf(ne, kUnexpectedStringType, at, Operand(scratch));
+
+  // The index is assumed to be untagged coming in, tag it to compare with the
+  // string length without using a temp register, it is restored at the end of
+  // this function.
+  Label index_tag_ok, index_tag_bad;
+  // On ARM TrySmiTag is used here.
+  AdduAndCheckForOverflow(index, index, index, scratch);
+  BranchOnOverflow(&index_tag_bad, scratch);
+  Branch(&index_tag_ok);
+  bind(&index_tag_bad);
+  Throw(kIndexIsTooLarge);
+  bind(&index_tag_ok);
+
+  lw(at, FieldMemOperand(string, String::kLengthOffset));
+  ThrowIf(ge, kIndexIsTooLarge, index, Operand(at));
+
+  li(at, Operand(Smi::FromInt(0)));
+  ThrowIf(lt, kIndexIsNegative, index, Operand(at));
+
+  SmiUntag(index, index);
+}
+
+
 void MacroAssembler::PrepareCallCFunction(int num_reg_arguments,
                                           int num_double_arguments,
                                           Register scratch) {
@@ -5431,6 +5469,57 @@
 }
 
 
+void MacroAssembler::Throw(BailoutReason reason) {
+  Label throw_start;
+  bind(&throw_start);
+#ifdef DEBUG
+  const char* msg = GetBailoutReason(reason);
+  if (msg != NULL) {
+    RecordComment("Throw message: ");
+    RecordComment(msg);
+  }
+#endif
+
+  li(a0, Operand(Smi::FromInt(reason)));
+  push(a0);
+  // Disable stub call restrictions to always allow calls to throw.
+  if (!has_frame_) {
+    // We don't actually want to generate a pile of code for this, so just
+    // claim there is a stack frame, without generating one.
+    FrameScope scope(this, StackFrame::NONE);
+    CallRuntime(Runtime::kThrowMessage, 1);
+  } else {
+    CallRuntime(Runtime::kThrowMessage, 1);
+  }
+  // will not return here
+  if (is_trampoline_pool_blocked()) {
+    // If the calling code cares throw the exact number of
+    // instructions generated, we insert padding here to keep the size
+    // of the ThrowMessage macro constant.
+    // Currently in debug mode with debug_code enabled the number of
+    // generated instructions is 14, so we use this as a maximum value.
+    static const int kExpectedThrowMessageInstructions = 14;
+    int throw_instructions = InstructionsGeneratedSince(&throw_start);
+    ASSERT(throw_instructions <= kExpectedThrowMessageInstructions);
+    while (throw_instructions++ < kExpectedThrowMessageInstructions) {
+      nop();
+    }
+  }
+}
+
+
+void MacroAssembler::ThrowIf(Condition cc,
+                             BailoutReason reason,
+                             Register rs,
+                             Operand rt) {
+  Label L;
+  Branch(&L, NegateCondition(cc), rs, rt);
+  Throw(reason);
+  // will not return here
+  bind(&L);
+}
+
+
 void MacroAssembler::LoadInstanceDescriptors(Register map,
                                              Register descriptors) {
   lw(descriptors, FieldMemOperand(map, Map::kDescriptorsOffset));
diff --git a/src/mips/macro-assembler-mips.h b/src/mips/macro-assembler-mips.h
index a9ad5cf..d3fdbd6 100644
--- a/src/mips/macro-assembler-mips.h
+++ b/src/mips/macro-assembler-mips.h
@@ -967,6 +967,12 @@
   // handler chain.
   void ThrowUncatchable(Register value);
 
+  // Throw a message string as an exception.
+  void Throw(BailoutReason reason);
+
+  // Throw a message string as an exception if a condition is not true.
+  void ThrowIf(Condition cc, BailoutReason reason, Register rs, Operand rt);
+
   // Copies a fixed number of fields of heap objects from src to dst.
   void CopyFields(Register dst, Register src, RegList temps, int field_count);
 
@@ -1452,6 +1458,12 @@
 
   void JumpIfNotUniqueName(Register reg, Label* not_unique_name);
 
+  void EmitSeqStringSetCharCheck(Register string,
+                                 Register index,
+                                 Register value,
+                                 Register scratch,
+                                 uint32_t encoding_mask);
+
   // Test that both first and second are sequential ASCII strings.
   // Assume that they are non-smis.
   void JumpIfNonSmisNotBothSequentialAsciiStrings(Register first,
diff --git a/src/mips/stub-cache-mips.cc b/src/mips/stub-cache-mips.cc
index 437d769..921a47c 100644
--- a/src/mips/stub-cache-mips.cc
+++ b/src/mips/stub-cache-mips.cc
@@ -1637,7 +1637,7 @@
   GenerateMissBranch();
 
   // Return the generated code.
-  return GetCode(Code::FIELD, name);
+  return GetCode(Code::FAST, name);
 }
 
 
@@ -2691,7 +2691,7 @@
     Handle<Code> code = CompileCustomCall(object, holder,
                                           Handle<Cell>::null(),
                                           function, Handle<String>::cast(name),
-                                          Code::CONSTANT);
+                                          Code::FAST);
     // A null handle means bail out to the regular compiler code below.
     if (!code.is_null()) return code;
   }
@@ -2740,7 +2740,7 @@
   GenerateMissBranch();
 
   // Return the generated code.
-  return GetCode(Code::INTERCEPTOR, name);
+  return GetCode(Code::FAST, name);
 }
 
 
@@ -2828,7 +2828,7 @@
   __ TailCallExternalReference(store_callback_property, 4, 1);
 
   // Return the generated code.
-  return GetCode(kind(), Code::CALLBACKS, name);
+  return GetCode(kind(), Code::FAST, name);
 }
 
 
@@ -2844,7 +2844,7 @@
       masm(), call_optimization, receiver(), scratch3(), 1, values);
 
   // Return the generated code.
-  return GetCode(kind(), Code::CALLBACKS, name);
+  return GetCode(kind(), Code::FAST, name);
 }
 
 
@@ -2928,7 +2928,7 @@
   TailCallBuiltin(masm(), MissBuiltin(kind()));
 
   // Return the generated code.
-  return GetCode(kind(), Code::INTERCEPTOR, name);
+  return GetCode(kind(), Code::FAST, name);
 }
 
 
@@ -2944,7 +2944,7 @@
   __ Ret();
 
   // Return the generated code.
-  return GetCode(kind(), Code::NONEXISTENT, name);
+  return GetCode(kind(), Code::FAST, name);
 }
 
 
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 20a44c3..2e8c0ad 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -150,25 +150,6 @@
 }
 
 
-bool Object::IsInstanceOf(FunctionTemplateInfo* expected) {
-  // There is a constraint on the object; check.
-  if (!this->IsJSObject()) return false;
-  // Fetch the constructor function of the object.
-  Object* cons_obj = JSObject::cast(this)->map()->constructor();
-  if (!cons_obj->IsJSFunction()) return false;
-  JSFunction* fun = JSFunction::cast(cons_obj);
-  // Iterate through the chain of inheriting function templates to
-  // see if the required one occurs.
-  for (Object* type = fun->shared()->function_data();
-       type->IsFunctionTemplateInfo();
-       type = FunctionTemplateInfo::cast(type)->parent_template()) {
-    if (type == expected) return true;
-  }
-  // Didn't find the required type in the inheritance chain.
-  return false;
-}
-
-
 bool Object::IsSmi() {
   return HAS_SMI_TAG(this);
 }
@@ -5957,7 +5938,7 @@
 bool AccessorInfo::IsCompatibleReceiver(Object* receiver) {
   Object* function_template = expected_receiver_type();
   if (!function_template->IsFunctionTemplateInfo()) return true;
-  return receiver->IsInstanceOf(FunctionTemplateInfo::cast(function_template));
+  return FunctionTemplateInfo::cast(function_template)->IsTemplateFor(receiver);
 }
 
 
diff --git a/src/objects.cc b/src/objects.cc
index 6cb5e21..627d371 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -203,6 +203,31 @@
 }
 
 
+bool FunctionTemplateInfo::IsTemplateFor(Object* object) {
+  if (!object->IsHeapObject()) return false;
+  return IsTemplateFor(HeapObject::cast(object)->map());
+}
+
+
+bool FunctionTemplateInfo::IsTemplateFor(Map* map) {
+  // There is a constraint on the object; check.
+  if (!map->IsJSObjectMap()) return false;
+  // Fetch the constructor function of the object.
+  Object* cons_obj = map->constructor();
+  if (!cons_obj->IsJSFunction()) return false;
+  JSFunction* fun = JSFunction::cast(cons_obj);
+  // Iterate through the chain of inheriting function templates to
+  // see if the required one occurs.
+  for (Object* type = fun->shared()->function_data();
+       type->IsFunctionTemplateInfo();
+       type = FunctionTemplateInfo::cast(type)->parent_template()) {
+    if (type == this) return true;
+  }
+  // Didn't find the required type in the inheritance chain.
+  return false;
+}
+
+
 template<typename To>
 static inline To* CheckedCast(void *from) {
   uintptr_t temp = reinterpret_cast<uintptr_t>(from);
@@ -9498,7 +9523,7 @@
   ASSERT(!IsOptimized());
   ASSERT(shared()->allows_lazy_compilation() || code()->optimizable());
   ASSERT(!shared()->is_generator());
-  ASSERT(FLAG_concurrent_recompilation);
+  ASSERT(GetIsolate()->concurrent_recompilation_enabled());
   if (FLAG_trace_concurrent_recompilation) {
     PrintF("  ** Marking ");
     PrintName();
@@ -9516,7 +9541,7 @@
   ASSERT(!GetIsolate()->DebuggerHasBreakPoints());
   ASSERT(IsMarkedForConcurrentRecompilation() && !IsOptimized());
   ASSERT(shared()->allows_lazy_compilation() || code()->optimizable());
-  ASSERT(FLAG_concurrent_recompilation);
+  ASSERT(GetIsolate()->concurrent_recompilation_enabled());
   if (FLAG_trace_concurrent_recompilation) {
     PrintF("  ** Queueing ");
     PrintName();
@@ -11075,12 +11100,7 @@
 const char* Code::StubType2String(StubType type) {
   switch (type) {
     case NORMAL: return "NORMAL";
-    case FIELD: return "FIELD";
-    case CONSTANT: return "CONSTANT";
-    case CALLBACKS: return "CALLBACKS";
-    case INTERCEPTOR: return "INTERCEPTOR";
-    case TRANSITION: return "TRANSITION";
-    case NONEXISTENT: return "NONEXISTENT";
+    case FAST: return "FAST";
   }
   UNREACHABLE();  // keep the compiler happy
   return NULL;
diff --git a/src/objects.h b/src/objects.h
index c720c44..352edaa 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -1196,6 +1196,7 @@
   V(kNonSmiIndex, "Non-smi index")                                            \
   V(kNonSmiKeyInArrayLiteral, "Non-smi key in array literal")                 \
   V(kNonSmiValue, "Non-smi value")                                            \
+  V(kNonObject, "Non-object value")                                           \
   V(kNotEnoughVirtualRegistersForValues,                                      \
     "not enough virtual registers for values")                                \
   V(kNotEnoughSpillSlotsForOsr,                                               \
@@ -1351,10 +1352,6 @@
   inline bool IsExternal();
   inline bool IsAccessorInfo();
 
-  // Returns true if this object is an instance of the specified
-  // function template.
-  inline bool IsInstanceOf(FunctionTemplateInfo* type);
-
   inline bool IsStruct();
 #define DECLARE_STRUCT_PREDICATE(NAME, Name, name) inline bool Is##Name();
   STRUCT_LIST(DECLARE_STRUCT_PREDICATE)
@@ -5033,12 +5030,7 @@
   // Types of stubs.
   enum StubType {
     NORMAL,
-    FIELD,
-    CONSTANT,
-    CALLBACKS,
-    INTERCEPTOR,
-    TRANSITION,
-    NONEXISTENT
+    FAST
   };
 
   typedef int ExtraICState;
@@ -5464,7 +5456,7 @@
 
   // Flags layout.  BitField<type, shift, size>.
   class ICStateField: public BitField<InlineCacheState, 0, 3> {};
-  class TypeField: public BitField<StubType, 3, 3> {};
+  class TypeField: public BitField<StubType, 3, 1> {};
   class CacheHolderField: public BitField<InlineCacheHolderFlag, 6, 1> {};
   class KindField: public BitField<Kind, 7, 4> {};
   class IsPregeneratedField: public BitField<bool, 11, 1> {};
@@ -10272,6 +10264,10 @@
   static const int kLengthOffset = kFlagOffset + kPointerSize;
   static const int kSize = kLengthOffset + kPointerSize;
 
+  // Returns true if |object| is an instance of this function template.
+  bool IsTemplateFor(Object* object);
+  bool IsTemplateFor(Map* map);
+
  private:
   // Bit position in the flag, from least significant bit position.
   static const int kHiddenPrototypeBit   = 0;
diff --git a/src/optimizing-compiler-thread.cc b/src/optimizing-compiler-thread.cc
index fbc4f05..32a7f97 100644
--- a/src/optimizing-compiler-thread.cc
+++ b/src/optimizing-compiler-thread.cc
@@ -370,8 +370,13 @@
 
 
 #ifdef DEBUG
+bool OptimizingCompilerThread::IsOptimizerThread(Isolate* isolate) {
+  return isolate->concurrent_recompilation_enabled() &&
+         isolate->optimizing_compiler_thread()->IsOptimizerThread();
+}
+
+
 bool OptimizingCompilerThread::IsOptimizerThread() {
-  if (!FLAG_concurrent_recompilation) return false;
   LockGuard<Mutex> lock_guard(&thread_id_mutex_);
   return ThreadId::Current().ToInteger() == thread_id_;
 }
diff --git a/src/optimizing-compiler-thread.h b/src/optimizing-compiler-thread.h
index 754aece..795fa65 100644
--- a/src/optimizing-compiler-thread.h
+++ b/src/optimizing-compiler-thread.h
@@ -96,7 +96,12 @@
     AddToOsrBuffer(NULL);
   }
 
+  static bool Enabled(int max_available) {
+    return (FLAG_concurrent_recompilation && max_available > 1);
+  }
+
 #ifdef DEBUG
+  static bool IsOptimizerThread(Isolate* isolate);
   bool IsOptimizerThread();
 #endif
 
diff --git a/src/runtime-profiler.cc b/src/runtime-profiler.cc
index 7c900b3..691fc66 100644
--- a/src/runtime-profiler.cc
+++ b/src/runtime-profiler.cc
@@ -139,8 +139,9 @@
   }
 
 
-  if (FLAG_concurrent_recompilation && !isolate_->bootstrapper()->IsActive()) {
-    if (FLAG_concurrent_osr &&
+  if (isolate_->concurrent_recompilation_enabled() &&
+      !isolate_->bootstrapper()->IsActive()) {
+    if (isolate_->concurrent_osr_enabled() &&
         isolate_->optimizing_compiler_thread()->IsQueuedForOSR(function)) {
       // Do not attempt regular recompilation if we already queued this for OSR.
       // TODO(yangguo): This is necessary so that we don't install optimized
diff --git a/src/runtime.cc b/src/runtime.cc
index 449d8a3..b5a1081 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -8424,7 +8424,7 @@
     return isolate->heap()->undefined_value();
   }
   function->shared()->code()->set_profiler_ticks(0);
-  ASSERT(FLAG_concurrent_recompilation);
+  ASSERT(isolate->concurrent_recompilation_enabled());
   if (!Compiler::RecompileConcurrent(function)) {
     function->ReplaceCode(function->shared()->code());
   }
@@ -8561,7 +8561,7 @@
 
 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConcurrentRecompilationSupported) {
   HandleScope scope(isolate);
-  return FLAG_concurrent_recompilation
+  return isolate->concurrent_recompilation_enabled()
       ? isolate->heap()->true_value() : isolate->heap()->false_value();
 }
 
@@ -8619,7 +8619,8 @@
     }
   }
   CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
-  if (FLAG_concurrent_recompilation && sync_with_compiler_thread) {
+  if (isolate->concurrent_recompilation_enabled() &&
+      sync_with_compiler_thread) {
     while (function->IsInRecompileQueue()) {
       isolate->optimizing_compiler_thread()->InstallOptimizedFunctions();
       OS::Sleep(50);
@@ -8697,7 +8698,7 @@
   Handle<Code> result = Handle<Code>::null();
   BailoutId ast_id = BailoutId::None();
 
-  if (FLAG_concurrent_osr) {
+  if (isolate->concurrent_osr_enabled()) {
     if (isolate->optimizing_compiler_thread()->
             IsQueuedForOSR(function, pc_offset)) {
       // Still waiting for the optimizing compiler thread to finish.  Carry on.
@@ -9448,6 +9449,17 @@
 }
 
 
+RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowMessage) {
+  HandleScope scope(isolate);
+  ASSERT(args.length() == 1);
+  CONVERT_SMI_ARG_CHECKED(message_id, 0);
+  const char* message = GetBailoutReason(
+      static_cast<BailoutReason>(message_id));
+  Handle<Name> message_handle =
+      isolate->factory()->NewStringFromAscii(CStrVector(message));
+  return isolate->Throw(*message_handle);
+}
+
 
 RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
   SealHandleScope shs(isolate);
diff --git a/src/runtime.h b/src/runtime.h
index 8b650e9..4872ab5 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -408,6 +408,7 @@
   F(ReThrow, 1, 1) \
   F(ThrowReferenceError, 1, 1) \
   F(ThrowNotDateError, 0, 1) \
+  F(ThrowMessage, 1, 1) \
   F(StackGuard, 0, 1) \
   F(Interrupt, 0, 1) \
   F(PromoteScheduledException, 0, 1) \
diff --git a/src/stub-cache.cc b/src/stub-cache.cc
index f9918ed..6fdd6d9 100644
--- a/src/stub-cache.cc
+++ b/src/stub-cache.cc
@@ -292,7 +292,7 @@
   }
 
   Code::Flags flags = Code::ComputeMonomorphicFlags(
-      kind, extra_state, cache_holder, Code::CONSTANT, argc);
+      kind, extra_state, cache_holder, Code::FAST, argc);
   Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags),
                        isolate_);
   if (probe->IsCode()) return Handle<Code>::cast(probe);
@@ -334,7 +334,7 @@
   }
 
   Code::Flags flags = Code::ComputeMonomorphicFlags(
-      kind, extra_state, cache_holder, Code::FIELD, argc);
+      kind, extra_state, cache_holder, Code::FAST, argc);
   Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags),
                        isolate_);
   if (probe->IsCode()) return Handle<Code>::cast(probe);
@@ -372,7 +372,7 @@
   }
 
   Code::Flags flags = Code::ComputeMonomorphicFlags(
-      kind, extra_state, cache_holder, Code::INTERCEPTOR, argc);
+      kind, extra_state, cache_holder, Code::FAST, argc);
   Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags),
                        isolate_);
   if (probe->IsCode()) return Handle<Code>::cast(probe);
@@ -1259,7 +1259,7 @@
   TailCallBuiltin(masm(), MissBuiltin(kind()));
 
   // Return the generated code.
-  return GetCode(kind(), Code::FIELD, name);
+  return GetCode(kind(), Code::FAST, name);
 }
 
 
@@ -1272,7 +1272,7 @@
   GenerateLoadConstant(value);
 
   // Return the generated code.
-  return GetCode(kind(), Code::CONSTANT, name);
+  return GetCode(kind(), Code::FAST, name);
 }
 
 
@@ -1286,7 +1286,7 @@
   GenerateLoadCallback(reg, callback);
 
   // Return the generated code.
-  return GetCode(kind(), Code::CALLBACKS, name);
+  return GetCode(kind(), Code::FAST, name);
 }
 
 
@@ -1301,7 +1301,7 @@
   GenerateLoadCallback(call_optimization);
 
   // Return the generated code.
-  return GetCode(kind(), Code::CALLBACKS, name);
+  return GetCode(kind(), Code::FAST, name);
 }
 
 
@@ -1318,7 +1318,7 @@
   GenerateLoadInterceptor(reg, object, holder, &lookup, name);
 
   // Return the generated code.
-  return GetCode(kind(), Code::INTERCEPTOR, name);
+  return GetCode(kind(), Code::FAST, name);
 }
 
 
@@ -1378,7 +1378,7 @@
   GenerateLoadViaGetter(masm(), receiver(), getter);
 
   // Return the generated code.
-  return GetCode(kind(), Code::CALLBACKS, name);
+  return GetCode(kind(), Code::FAST, name);
 }
 
 
@@ -1435,7 +1435,7 @@
   TailCallBuiltin(masm(), SlowBuiltin(kind()));
 
   // Return the generated code.
-  return GetCode(kind(), Code::TRANSITION, name);
+  return GetCode(kind(), Code::FAST, name);
 }
 
 
@@ -1458,7 +1458,7 @@
   TailCallBuiltin(masm(), MissBuiltin(kind()));
 
   // Return the generated code.
-  return GetCode(kind(), Code::FIELD, name);
+  return GetCode(kind(), Code::FAST, name);
 }
 
 
@@ -1470,7 +1470,7 @@
   HandlerFrontend(object, receiver(), holder, name);
   GenerateStoreViaSetter(masm(), setter);
 
-  return GetCode(kind(), Code::CALLBACKS, name);
+  return GetCode(kind(), Code::FAST, name);
 }
 
 
@@ -1757,7 +1757,7 @@
   if (function->shared()->name()->IsString()) {
     function_name = Handle<String>(String::cast(function->shared()->name()));
   }
-  return GetCode(Code::CONSTANT, function_name);
+  return GetCode(Code::FAST, function_name);
 }
 
 
@@ -1785,12 +1785,12 @@
   if (expected_receiver_type_.is_null()) return 0;
   int depth = 0;
   while (!object.is_identical_to(holder)) {
-    if (object->IsInstanceOf(*expected_receiver_type_)) return depth;
+    if (expected_receiver_type_->IsTemplateFor(object->map())) return depth;
     object = Handle<JSObject>(JSObject::cast(object->GetPrototype()));
     if (!object->map()->is_hidden_prototype()) return kInvalidProtoDepth;
     ++depth;
   }
-  if (holder->IsInstanceOf(*expected_receiver_type_)) return depth;
+  if (expected_receiver_type_->IsTemplateFor(holder->map())) return depth;
   return kInvalidProtoDepth;
 }
 
diff --git a/src/stub-cache.h b/src/stub-cache.h
index adfa44a..91f3409 100644
--- a/src/stub-cache.h
+++ b/src/stub-cache.h
@@ -1037,7 +1037,7 @@
   bool IsCompatibleReceiver(Object* receiver) {
     ASSERT(is_simple_api_call());
     if (expected_receiver_type_.is_null()) return true;
-    return receiver->IsInstanceOf(*expected_receiver_type_);
+    return expected_receiver_type_->IsTemplateFor(receiver);
   }
 
  private:
diff --git a/src/sweeper-thread.cc b/src/sweeper-thread.cc
index 58c684a..6f3baed 100644
--- a/src/sweeper-thread.cc
+++ b/src/sweeper-thread.cc
@@ -105,4 +105,14 @@
 void SweeperThread::WaitForSweeperThread() {
   end_sweeping_semaphore_.Wait();
 }
+
+
+int SweeperThread::NumberOfThreads(int max_available) {
+  if (!FLAG_concurrent_sweeping && !FLAG_parallel_sweeping) return 0;
+  if (FLAG_sweeper_threads > 0) return FLAG_sweeper_threads;
+  if (FLAG_concurrent_sweeping) return max_available - 1;
+  ASSERT(FLAG_parallel_sweeping);
+  return max_available;
+}
+
 } }  // namespace v8::internal
diff --git a/src/sweeper-thread.h b/src/sweeper-thread.h
index c36cfc3..96255a0 100644
--- a/src/sweeper-thread.h
+++ b/src/sweeper-thread.h
@@ -51,6 +51,8 @@
   void WaitForSweeperThread();
   intptr_t StealMemory(PagedSpace* space);
 
+  static int NumberOfThreads(int max_available);
+
  private:
   Isolate* isolate_;
   Heap* heap_;
diff --git a/src/v8.cc b/src/v8.cc
index c35230d..17007a2 100644
--- a/src/v8.cc
+++ b/src/v8.cc
@@ -179,38 +179,6 @@
     FLAG_max_new_space_size = (1 << (kPageSizeBits - 10)) * 2;
   }
 
-  if (FLAG_concurrent_recompilation &&
-      (FLAG_trace_hydrogen || FLAG_trace_hydrogen_stubs)) {
-    FLAG_concurrent_recompilation = false;
-    FLAG_concurrent_osr = false;
-    PrintF("Concurrent recompilation has been disabled for tracing.\n");
-  }
-
-  if (FLAG_sweeper_threads <= 0) {
-    if (FLAG_concurrent_sweeping) {
-      FLAG_sweeper_threads = SystemThreadManager::
-          NumberOfParallelSystemThreads(
-              SystemThreadManager::CONCURRENT_SWEEPING);
-    } else if (FLAG_parallel_sweeping) {
-      FLAG_sweeper_threads = SystemThreadManager::
-          NumberOfParallelSystemThreads(
-              SystemThreadManager::PARALLEL_SWEEPING);
-    }
-    if (FLAG_sweeper_threads == 0) {
-      FLAG_concurrent_sweeping = false;
-      FLAG_parallel_sweeping = false;
-    }
-  } else if (!FLAG_concurrent_sweeping && !FLAG_parallel_sweeping) {
-    FLAG_sweeper_threads = 0;
-  }
-
-  if (FLAG_concurrent_recompilation &&
-      SystemThreadManager::NumberOfParallelSystemThreads(
-          SystemThreadManager::CONCURRENT_RECOMPILATION) == 0) {
-    FLAG_concurrent_recompilation = false;
-    FLAG_concurrent_osr = false;
-  }
-
   Sampler::SetUp();
   CPU::SetUp();
   OS::PostSetUp();
diff --git a/src/version.cc b/src/version.cc
index b48219d..08606aa 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,7 +34,7 @@
 // system so their names cannot be changed without changing the scripts.
 #define MAJOR_VERSION     3
 #define MINOR_VERSION     23
-#define BUILD_NUMBER      7
+#define BUILD_NUMBER      8
 #define PATCH_LEVEL       0
 // Use 1 for candidates and 0 otherwise.
 // (Boolean macro values are not supported by all preprocessors.)
diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc
index d5fa5e5..8947e2f 100644
--- a/src/x64/full-codegen-x64.cc
+++ b/src/x64/full-codegen-x64.cc
@@ -3407,30 +3407,6 @@
 }
 
 
-void FullCodeGenerator::EmitSeqStringSetCharCheck(Register string,
-                                                  Register index,
-                                                  Register value,
-                                                  uint32_t encoding_mask) {
-  __ Check(masm()->CheckSmi(index), kNonSmiIndex);
-  __ Check(masm()->CheckSmi(value), kNonSmiValue);
-
-  __ SmiCompare(index, FieldOperand(string, String::kLengthOffset));
-  __ Check(less, kIndexIsTooLarge);
-
-  __ SmiCompare(index, Smi::FromInt(0));
-  __ Check(greater_equal, kIndexIsNegative);
-
-  __ push(value);
-  __ movq(value, FieldOperand(string, HeapObject::kMapOffset));
-  __ movzxbq(value, FieldOperand(value, Map::kInstanceTypeOffset));
-
-  __ andb(value, Immediate(kStringRepresentationMask | kStringEncodingMask));
-  __ cmpq(value, Immediate(encoding_mask));
-  __ Check(equal, kUnexpectedStringType);
-  __ pop(value);
-}
-
-
 void FullCodeGenerator::EmitOneByteSeqStringSetChar(CallRuntime* expr) {
   ZoneList<Expression*>* args = expr->arguments();
   ASSERT_EQ(3, args->length());
@@ -3441,17 +3417,23 @@
 
   VisitForStackValue(args->at(1));  // index
   VisitForStackValue(args->at(2));  // value
+  VisitForAccumulatorValue(args->at(0));  // string
   __ pop(value);
   __ pop(index);
-  VisitForAccumulatorValue(args->at(0));  // string
 
   if (FLAG_debug_code) {
-    static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
-    EmitSeqStringSetCharCheck(string, index, value, one_byte_seq_type);
+    __ ThrowIf(NegateCondition(__ CheckSmi(value)), kNonSmiValue);
+    __ ThrowIf(NegateCondition(__ CheckSmi(index)), kNonSmiValue);
   }
 
   __ SmiToInteger32(value, value);
   __ SmiToInteger32(index, index);
+
+  if (FLAG_debug_code) {
+    static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
+    __ EmitSeqStringSetCharCheck(string, index, value, one_byte_seq_type);
+  }
+
   __ movb(FieldOperand(string, index, times_1, SeqOneByteString::kHeaderSize),
           value);
   context()->Plug(string);
@@ -3468,17 +3450,23 @@
 
   VisitForStackValue(args->at(1));  // index
   VisitForStackValue(args->at(2));  // value
+  VisitForAccumulatorValue(args->at(0));  // string
   __ pop(value);
   __ pop(index);
-  VisitForAccumulatorValue(args->at(0));  // string
 
   if (FLAG_debug_code) {
-    static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
-    EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type);
+    __ ThrowIf(NegateCondition(__ CheckSmi(value)), kNonSmiValue);
+    __ ThrowIf(NegateCondition(__ CheckSmi(index)), kNonSmiValue);
   }
 
   __ SmiToInteger32(value, value);
   __ SmiToInteger32(index, index);
+
+  if (FLAG_debug_code) {
+    static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
+    __ EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type);
+  }
+
   __ movw(FieldOperand(string, index, times_2, SeqTwoByteString::kHeaderSize),
           value);
   context()->Plug(rax);
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index cafde51..ba8ccc5 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -1732,17 +1732,14 @@
   Register string = ToRegister(instr->string());
 
   if (FLAG_debug_code) {
-    __ push(string);
-    __ movq(string, FieldOperand(string, HeapObject::kMapOffset));
-    __ movzxbq(string, FieldOperand(string, Map::kInstanceTypeOffset));
-
-    __ andb(string, Immediate(kStringRepresentationMask | kStringEncodingMask));
+    Register value = ToRegister(instr->value());
+    Register index = ToRegister(instr->index());
     static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
     static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
-    __ cmpq(string, Immediate(encoding == String::ONE_BYTE_ENCODING
-                              ? one_byte_seq_type : two_byte_seq_type));
-    __ Check(equal, kUnexpectedStringType);
-    __ pop(string);
+    int encoding_mask =
+        instr->hydrogen()->encoding() == String::ONE_BYTE_ENCODING
+        ? one_byte_seq_type : two_byte_seq_type;
+    __ EmitSeqStringSetCharCheck(string, index, value, encoding_mask);
   }
 
   Operand operand = BuildSeqStringOperand(string, instr->index(), encoding);
diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc
index b911c48..0b2bf82 100644
--- a/src/x64/lithium-x64.cc
+++ b/src/x64/lithium-x64.cc
@@ -1796,9 +1796,19 @@
 
 LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) {
   LOperand* string = UseRegisterAtStart(instr->string());
-  LOperand* index = UseRegisterOrConstantAtStart(instr->index());
-  LOperand* value = UseRegisterOrConstantAtStart(instr->value());
-  return new(zone()) LSeqStringSetChar(string, index, value);
+  LOperand* index = FLAG_debug_code
+      ? UseRegisterAtStart(instr->index())
+      : UseRegisterOrConstantAtStart(instr->index());
+  LOperand* value = FLAG_debug_code
+      ? UseRegisterAtStart(instr->value())
+      : UseRegisterOrConstantAtStart(instr->value());
+  LOperand* context = FLAG_debug_code ? UseFixed(instr->context(), rsi) : NULL;
+  LInstruction* result = new(zone()) LSeqStringSetChar(context, string,
+                                                       index, value);
+  if (FLAG_debug_code) {
+    result = MarkAsCall(result, instr);
+  }
+  return result;
 }
 
 
diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h
index 6e236c7..a475d8c 100644
--- a/src/x64/lithium-x64.h
+++ b/src/x64/lithium-x64.h
@@ -1339,19 +1339,21 @@
 };
 
 
-class LSeqStringSetChar V8_FINAL : public LTemplateInstruction<1, 3, 0> {
+class LSeqStringSetChar V8_FINAL : public LTemplateInstruction<1, 4, 0> {
  public:
-  LSeqStringSetChar(LOperand* string,
+  LSeqStringSetChar(LOperand* context,
+                    LOperand* string,
                     LOperand* index,
                     LOperand* value) {
-    inputs_[0] = string;
-    inputs_[1] = index;
-    inputs_[2] = value;
+    inputs_[0] = context;
+    inputs_[1] = string;
+    inputs_[2] = index;
+    inputs_[3] = value;
   }
 
-  LOperand* string() { return inputs_[0]; }
-  LOperand* index() { return inputs_[1]; }
-  LOperand* value() { return inputs_[2]; }
+  LOperand* string() { return inputs_[1]; }
+  LOperand* index() { return inputs_[2]; }
+  LOperand* value() { return inputs_[3]; }
 
   DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar, "seq-string-set-char")
   DECLARE_HYDROGEN_ACCESSOR(SeqStringSetChar)
diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc
index 5127ddf..25f4bd3 100644
--- a/src/x64/macro-assembler-x64.cc
+++ b/src/x64/macro-assembler-x64.cc
@@ -3206,6 +3206,39 @@
 }
 
 
+void MacroAssembler::Throw(BailoutReason reason) {
+#ifdef DEBUG
+  const char* msg = GetBailoutReason(reason);
+  if (msg != NULL) {
+    RecordComment("Throw message: ");
+    RecordComment(msg);
+  }
+#endif
+
+  push(rax);
+  Push(Smi::FromInt(reason));
+  if (!has_frame_) {
+    // We don't actually want to generate a pile of code for this, so just
+    // claim there is a stack frame, without generating one.
+    FrameScope scope(this, StackFrame::NONE);
+    CallRuntime(Runtime::kThrowMessage, 1);
+  } else {
+    CallRuntime(Runtime::kThrowMessage, 1);
+  }
+  // Control will not return here.
+  int3();
+}
+
+
+void MacroAssembler::ThrowIf(Condition cc, BailoutReason reason) {
+  Label L;
+  j(NegateCondition(cc), &L);
+  Throw(reason);
+  // will not return here
+  bind(&L);
+}
+
+
 void MacroAssembler::LoadInstanceDescriptors(Register map,
                                              Register descriptors) {
   movq(descriptors, FieldOperand(map, Map::kDescriptorsOffset));
@@ -4631,6 +4664,39 @@
 }
 
 
+void MacroAssembler::EmitSeqStringSetCharCheck(Register string,
+                                               Register index,
+                                               Register value,
+                                               uint32_t encoding_mask) {
+  Label is_object;
+  JumpIfNotSmi(string, &is_object);
+  Throw(kNonObject);
+  bind(&is_object);
+
+  push(value);
+  movq(value, FieldOperand(string, HeapObject::kMapOffset));
+  movzxbq(value, FieldOperand(value, Map::kInstanceTypeOffset));
+
+  andb(value, Immediate(kStringRepresentationMask | kStringEncodingMask));
+  cmpq(value, Immediate(encoding_mask));
+  pop(value);
+  ThrowIf(not_equal, kUnexpectedStringType);
+
+  // The index is assumed to be untagged coming in, tag it to compare with the
+  // string length without using a temp register, it is restored at the end of
+  // this function.
+  Integer32ToSmi(index, index);
+  SmiCompare(index, FieldOperand(string, String::kLengthOffset));
+  ThrowIf(greater_equal, kIndexIsTooLarge);
+
+  SmiCompare(index, Smi::FromInt(0));
+  ThrowIf(less, kIndexIsNegative);
+
+  // Restore the index
+  SmiToInteger32(index, index);
+}
+
+
 void MacroAssembler::PrepareCallCFunction(int num_arguments) {
   int frame_alignment = OS::ActivationFrameAlignment();
   ASSERT(frame_alignment != 0);
diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h
index 4bea461..f7bf1ca 100644
--- a/src/x64/macro-assembler-x64.h
+++ b/src/x64/macro-assembler-x64.h
@@ -792,6 +792,11 @@
       Label* on_fail,
       Label::Distance near_jump = Label::kFar);
 
+  void EmitSeqStringSetCharCheck(Register string,
+                                 Register index,
+                                 Register value,
+                                 uint32_t encoding_mask);
+
   // Checks if the given register or operand is a unique name
   void JumpIfNotUniqueName(Register reg, Label* not_unique_name,
                            Label::Distance distance = Label::kFar);
@@ -1058,6 +1063,12 @@
   // Propagate an uncatchable exception out of the current JS stack.
   void ThrowUncatchable(Register value);
 
+  // Throw a message string as an exception.
+  void Throw(BailoutReason reason);
+
+  // Throw a message string as an exception if a condition is not true.
+  void ThrowIf(Condition cc, BailoutReason reason);
+
   // ---------------------------------------------------------------------------
   // Inline caching support
 
diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc
index a1e8f21..4c61f24 100644
--- a/src/x64/stub-cache-x64.cc
+++ b/src/x64/stub-cache-x64.cc
@@ -1595,7 +1595,7 @@
   GenerateMissBranch();
 
   // Return the generated code.
-  return GetCode(Code::FIELD, name);
+  return GetCode(Code::FAST, name);
 }
 
 
@@ -2652,7 +2652,7 @@
     Handle<Code> code = CompileCustomCall(object, holder,
                                           Handle<PropertyCell>::null(),
                                           function, Handle<String>::cast(name),
-                                          Code::CONSTANT);
+                                          Code::FAST);
     // A null handle means bail out to the regular compiler code below.
     if (!code.is_null()) return code;
   }
@@ -2720,7 +2720,7 @@
   GenerateMissBranch();
 
   // Return the generated code.
-  return GetCode(Code::INTERCEPTOR, name);
+  return GetCode(Code::FAST, name);
 }
 
 
@@ -2808,7 +2808,7 @@
   __ TailCallExternalReference(store_callback_property, 4, 1);
 
   // Return the generated code.
-  return GetCode(kind(), Code::CALLBACKS, name);
+  return GetCode(kind(), Code::FAST, name);
 }
 
 
@@ -2824,7 +2824,7 @@
       masm(), call_optimization, receiver(), scratch3(), 1, values);
 
   // Return the generated code.
-  return GetCode(kind(), Code::CALLBACKS, name);
+  return GetCode(kind(), Code::FAST, name);
 }
 
 
@@ -2891,7 +2891,7 @@
   __ TailCallExternalReference(store_ic_property, 4, 1);
 
   // Return the generated code.
-  return GetCode(kind(), Code::INTERCEPTOR, name);
+  return GetCode(kind(), Code::FAST, name);
 }
 
 
@@ -2943,7 +2943,7 @@
   __ ret(0);
 
   // Return the generated code.
-  return GetCode(kind(), Code::NONEXISTENT, name);
+  return GetCode(kind(), Code::FAST, name);
 }
 
 
diff --git a/test/cctest/cctest.status b/test/cctest/cctest.status
index ad7ee91..d73399f 100644
--- a/test/cctest/cctest.status
+++ b/test/cctest/cctest.status
@@ -30,6 +30,9 @@
   # All tests prefixed with 'Bug' are expected to fail.
   'test-api/Bug*': [FAIL],
 
+  # TODO(mvstanton): reenable when I figure out why it fails on no-sse2 builds
+  'test-heap/EnsureAllocationSiteDependentCodesProcessed': [SKIP],
+
   ##############################################################################
   # BUG(382): Weird test. Can't guarantee that it never times out.
   'test-api/ApplyInterruption': [PASS, TIMEOUT],
diff --git a/test/cctest/test-deoptimization.cc b/test/cctest/test-deoptimization.cc
index 765b1ce..c9200ed 100644
--- a/test/cctest/test-deoptimization.cc
+++ b/test/cctest/test-deoptimization.cc
@@ -77,27 +77,23 @@
 
 // Utility class to set --allow-natives-syntax and --nouse-inlining when
 // constructed and return to their default state when destroyed.
-class AllowNativesSyntaxNoInliningNoConcurrent {
+class AllowNativesSyntaxNoInlining {
  public:
-  AllowNativesSyntaxNoInliningNoConcurrent()
+  AllowNativesSyntaxNoInlining()
       : allow_natives_syntax_(i::FLAG_allow_natives_syntax),
-        use_inlining_(i::FLAG_use_inlining),
-        concurrent_recompilation_(i::FLAG_concurrent_recompilation) {
+        use_inlining_(i::FLAG_use_inlining) {
     i::FLAG_allow_natives_syntax = true;
     i::FLAG_use_inlining = false;
-    i::FLAG_concurrent_recompilation = false;
   }
 
-  ~AllowNativesSyntaxNoInliningNoConcurrent() {
+  ~AllowNativesSyntaxNoInlining() {
     i::FLAG_allow_natives_syntax = allow_natives_syntax_;
     i::FLAG_use_inlining = use_inlining_;
-    i::FLAG_concurrent_recompilation = concurrent_recompilation_;
   }
 
  private:
   bool allow_natives_syntax_;
   bool use_inlining_;
-  bool concurrent_recompilation_;
 };
 
 
@@ -341,13 +337,14 @@
 
 
 TEST(DeoptimizeBinaryOperationADDString) {
+  i::FLAG_concurrent_recompilation = false;
+  AllowNativesSyntaxNoInlining options;
   LocalContext env;
   v8::HandleScope scope(env->GetIsolate());
 
   const char* f_source = "function f(x, y) { return x + y; };";
 
   {
-    AllowNativesSyntaxNoInliningNoConcurrent options;
     // Compile function f and collect to type feedback to insert binary op stub
     // call in the optimized code.
     i::FLAG_prepare_always_opt = true;
@@ -405,7 +402,7 @@
                binary_op);
   char* f_source = f_source_buffer.start();
 
-  AllowNativesSyntaxNoInliningNoConcurrent options;
+  AllowNativesSyntaxNoInlining options;
   // Compile function f and collect to type feedback to insert binary op stub
   // call in the optimized code.
   i::FLAG_prepare_always_opt = true;
@@ -431,6 +428,7 @@
 
 
 TEST(DeoptimizeBinaryOperationADD) {
+  i::FLAG_concurrent_recompilation = false;
   LocalContext env;
   v8::HandleScope scope(env->GetIsolate());
 
@@ -443,6 +441,7 @@
 
 
 TEST(DeoptimizeBinaryOperationSUB) {
+  i::FLAG_concurrent_recompilation = false;
   LocalContext env;
   v8::HandleScope scope(env->GetIsolate());
 
@@ -455,6 +454,7 @@
 
 
 TEST(DeoptimizeBinaryOperationMUL) {
+  i::FLAG_concurrent_recompilation = false;
   LocalContext env;
   v8::HandleScope scope(env->GetIsolate());
 
@@ -467,6 +467,7 @@
 
 
 TEST(DeoptimizeBinaryOperationDIV) {
+  i::FLAG_concurrent_recompilation = false;
   LocalContext env;
   v8::HandleScope scope(env->GetIsolate());
 
@@ -479,6 +480,7 @@
 
 
 TEST(DeoptimizeBinaryOperationMOD) {
+  i::FLAG_concurrent_recompilation = false;
   LocalContext env;
   v8::HandleScope scope(env->GetIsolate());
 
@@ -491,13 +493,14 @@
 
 
 TEST(DeoptimizeCompare) {
+  i::FLAG_concurrent_recompilation = false;
   LocalContext env;
   v8::HandleScope scope(env->GetIsolate());
 
   const char* f_source = "function f(x, y) { return x < y; };";
 
   {
-    AllowNativesSyntaxNoInliningNoConcurrent options;
+    AllowNativesSyntaxNoInlining options;
     // Compile function f and collect to type feedback to insert compare ic
     // call in the optimized code.
     i::FLAG_prepare_always_opt = true;
@@ -534,6 +537,7 @@
 
 
 TEST(DeoptimizeLoadICStoreIC) {
+  i::FLAG_concurrent_recompilation = false;
   LocalContext env;
   v8::HandleScope scope(env->GetIsolate());
 
@@ -544,7 +548,7 @@
   const char* g2_source = "function g2(x, y) { x[y] = 1; };";
 
   {
-    AllowNativesSyntaxNoInliningNoConcurrent options;
+    AllowNativesSyntaxNoInlining options;
     // Compile functions and collect to type feedback to insert ic
     // calls in the optimized code.
     i::FLAG_prepare_always_opt = true;
@@ -614,6 +618,7 @@
 
 
 TEST(DeoptimizeLoadICStoreICNested) {
+  i::FLAG_concurrent_recompilation = false;
   LocalContext env;
   v8::HandleScope scope(env->GetIsolate());
 
@@ -624,7 +629,7 @@
   const char* g2_source = "function g2(x, y) { x[y] = 1; };";
 
   {
-    AllowNativesSyntaxNoInliningNoConcurrent options;
+    AllowNativesSyntaxNoInlining options;
     // Compile functions and collect to type feedback to insert ic
     // calls in the optimized code.
     i::FLAG_prepare_always_opt = true;
diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc
index 799146e..448c589 100644
--- a/test/cctest/test-heap.cc
+++ b/test/cctest/test-heap.cc
@@ -2963,8 +2963,6 @@
   // after the first time the accessor is fired.  We use external string
   // to check whether the data is being released since the external string
   // resource's callback is fired when the external string is GC'ed.
-  FLAG_use_ic = false;  // ICs retain objects.
-  FLAG_concurrent_recompilation = false;
   v8::HandleScope scope(CcTest::isolate());
   SourceResource* resource = new SourceResource(i::StrDup(source));
   {
@@ -2987,6 +2985,8 @@
 
 
 TEST(ReleaseStackTraceData) {
+  FLAG_use_ic = false;  // ICs retain objects.
+  FLAG_concurrent_recompilation = false;
   CcTest::InitializeVM();
   static const char* source1 = "var error = null;            "
   /* Normal Error */           "try {                        "
@@ -3549,3 +3549,69 @@
   CcTest::heap()->EnableInlineAllocation();
   CompileRun("run()");
 }
+
+
+static int AllocationSitesCount(Heap* heap) {
+  int count = 0;
+  for (Object* site = heap->allocation_sites_list();
+       !(site->IsUndefined());
+       site = AllocationSite::cast(site)->weak_next()) {
+    count++;
+  }
+  return count;
+}
+
+
+TEST(EnsureAllocationSiteDependentCodesProcessed) {
+  if (i::FLAG_always_opt || !i::FLAG_crankshaft) return;
+  i::FLAG_allow_natives_syntax = true;
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::internal::Heap* heap = CcTest::heap();
+  GlobalHandles* global_handles = isolate->global_handles();
+
+  // The allocation site at the head of the list is ours.
+  Handle<AllocationSite> site;
+  {
+    LocalContext context;
+    v8::HandleScope scope(context->GetIsolate());
+
+    int count = AllocationSitesCount(heap);
+    CompileRun("var bar = function() { return (new Array()); };"
+               "var a = bar();"
+               "bar();"
+               "bar();");
+
+    // One allocation site should have been created.
+    int new_count = AllocationSitesCount(heap);
+    CHECK_EQ(new_count, (count + 1));
+    site = Handle<AllocationSite>::cast(
+        global_handles->Create(
+            AllocationSite::cast(heap->allocation_sites_list())));
+
+    CompileRun("%OptimizeFunctionOnNextCall(bar); bar();");
+
+    DependentCode::GroupStartIndexes starts(site->dependent_code());
+    CHECK_GE(starts.number_of_entries(), 1);
+    int index = starts.at(DependentCode::kAllocationSiteTransitionChangedGroup);
+    CHECK(site->dependent_code()->is_code_at(index));
+    Code* function_bar = site->dependent_code()->code_at(index);
+    Handle<JSFunction> bar_handle =
+        v8::Utils::OpenHandle(
+            *v8::Handle<v8::Function>::Cast(
+                CcTest::global()->Get(v8_str("bar"))));
+    CHECK_EQ(bar_handle->code(), function_bar);
+  }
+
+  // Now make sure that a gc should get rid of the function, even though we
+  // still have the allocation site alive.
+  for (int i = 0; i < 4; i++) {
+    heap->CollectAllGarbage(false);
+  }
+
+  // The site still exists because of our global handle, but the code is no
+  // longer referred to by dependent_code().
+  DependentCode::GroupStartIndexes starts(site->dependent_code());
+  int index = starts.at(DependentCode::kAllocationSiteTransitionChangedGroup);
+  CHECK(!(site->dependent_code()->is_code_at(index)));
+}
diff --git a/test/mjsunit/fuzz-natives-part1.js b/test/mjsunit/fuzz-natives-part1.js
index ffcbd1d..c30069e 100644
--- a/test/mjsunit/fuzz-natives-part1.js
+++ b/test/mjsunit/fuzz-natives-part1.js
@@ -116,6 +116,7 @@
 
 var knownProblems = {
   "Abort": true,
+  "ThrowMessage": true,
 
   // Avoid calling the concat operation, because weird lengths
   // may lead to out-of-memory.  Ditto for StringBuilderJoin.
diff --git a/test/mjsunit/fuzz-natives-part2.js b/test/mjsunit/fuzz-natives-part2.js
index f796b80..e73f3bd 100644
--- a/test/mjsunit/fuzz-natives-part2.js
+++ b/test/mjsunit/fuzz-natives-part2.js
@@ -116,6 +116,7 @@
 
 var knownProblems = {
   "Abort": true,
+  "ThrowMessage": true,
 
   // Avoid calling the concat operation, because weird lengths
   // may lead to out-of-memory.  Ditto for StringBuilderJoin.
diff --git a/test/mjsunit/fuzz-natives-part3.js b/test/mjsunit/fuzz-natives-part3.js
index 61e0211..6a73498 100644
--- a/test/mjsunit/fuzz-natives-part3.js
+++ b/test/mjsunit/fuzz-natives-part3.js
@@ -116,6 +116,7 @@
 
 var knownProblems = {
   "Abort": true,
+  "ThrowMessage": true,
 
   // Avoid calling the concat operation, because weird lengths
   // may lead to out-of-memory.  Ditto for StringBuilderJoin.
diff --git a/test/mjsunit/fuzz-natives-part4.js b/test/mjsunit/fuzz-natives-part4.js
index 831722b..edeaa87 100644
--- a/test/mjsunit/fuzz-natives-part4.js
+++ b/test/mjsunit/fuzz-natives-part4.js
@@ -116,6 +116,7 @@
 
 var knownProblems = {
   "Abort": true,
+  "ThrowMessage": true,
 
   // Avoid calling the concat operation, because weird lengths
   // may lead to out-of-memory.  Ditto for StringBuilderJoin.
diff --git a/test/mjsunit/regress/regress-320948.js b/test/mjsunit/regress/regress-320948.js
new file mode 100644
index 0000000..734031c
--- /dev/null
+++ b/test/mjsunit/regress/regress-320948.js
@@ -0,0 +1,81 @@
+// 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: --allow-natives-syntax --debug-code
+
+var one_byte = %NewString(10, true);
+var two_byte = %NewString(10, false);
+
+function foo1(s, arg1, arg2) {
+  return %_OneByteSeqStringSetChar(s, arg1, arg2)
+}
+foo1(one_byte, 0, 0);
+assertThrows("{ foo1(4, 0, 0); }");
+assertThrows("{ foo1(one_byte, new Object(), 0); }");
+assertThrows("{ foo1(one_byte, 0, new Object()); }");
+assertThrows("{ foo1(one_byte, 100000, 100; }");
+assertThrows("{ foo1(one_byte, -1, 100; }");
+
+function bar1(s, arg1, arg2) {
+  return %_OneByteSeqStringSetChar(s, arg1, arg2)
+}
+
+bar1(one_byte, 0, 0);
+bar1(one_byte, 0, 0);
+bar1(one_byte, 0, 0);
+%OptimizeFunctionOnNextCall(bar1);
+bar1(one_byte, 0, 0);
+assertThrows("{ bar1(4, 0, 0); }");
+assertThrows("{ bar1(one_byte, new Object(), 0); }");
+assertThrows("{ bar1(one_byte, 0, new Object()); }");
+assertThrows("{ bar1(one_byte, 100000, 100; }");
+assertThrows("{ bar1(one_byte, -1, 100; }");
+
+function foo2(s, arg1, arg2) {
+  return %_TwoByteSeqStringSetChar(s, arg1, arg2)
+}
+foo2(two_byte, 0, 0);
+assertThrows("{ foo2(4, 0, 0); }");
+assertThrows("{ foo2(two_byte, new Object(), 0); }");
+assertThrows("{ foo2(two_byte, 0, new Object()); }");
+assertThrows("{ foo2(two_byte, 100000, 100; }");
+assertThrows("{ foo2(two_byte, -1, 100; }");
+
+function bar2(s, arg1, arg2) {
+  return %_TwoByteSeqStringSetChar(s, arg1, arg2)
+}
+
+bar2(two_byte, 0, 0);
+bar2(two_byte, 0, 0);
+bar2(two_byte, 0, 0);
+%OptimizeFunctionOnNextCall(bar2);
+bar2(two_byte, 0, 0);
+assertThrows("{ bar2(4, 0, 0); }");
+assertThrows("{ bar2(two_byte, new Object(), 0); }");
+assertThrows("{ bar2(two_byte, 0, new Object()); }");
+assertThrows("{ bar2(two_byte, 100000, 100; }");
+assertThrows("{ bar2(two_byte, -1, 100; }");
diff --git a/test/mjsunit/regress/regress-crbug-320922.js b/test/mjsunit/regress/regress-crbug-320922.js
new file mode 100644
index 0000000..4a5b581
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-320922.js
@@ -0,0 +1,48 @@
+// 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: --allow-natives-syntax
+
+var string = "hello world";
+var expected = "Hello " + "world";
+function Capitalize() {
+  %_OneByteSeqStringSetChar(string, 0, 0x48);
+}
+Capitalize();
+assertEquals(expected, string);
+Capitalize();
+assertEquals(expected, string);
+
+var twobyte = "\u20ACello world";
+
+function TwoByteCapitalize() {
+  %_TwoByteSeqStringSetChar(twobyte, 0, 0x48);
+}
+TwoByteCapitalize();
+assertEquals(expected, twobyte);
+TwoByteCapitalize();
+assertEquals(expected, twobyte);
diff --git a/tools/push-to-trunk/common_includes.py b/tools/push-to-trunk/common_includes.py
index 06b7ebe..9547367 100644
--- a/tools/push-to-trunk/common_includes.py
+++ b/tools/push-to-trunk/common_includes.py
@@ -30,6 +30,7 @@
 import re
 import subprocess
 import sys
+import textwrap
 
 PERSISTFILE_BASENAME = "PERSISTFILE_BASENAME"
 TEMP_BRANCH = "TEMP_BRANCH"
@@ -67,6 +68,11 @@
   return re.sub(rexp, replacement, text, flags=re.MULTILINE)
 
 
+def Fill80(line):
+  return textwrap.fill(line, width=80, initial_indent="        ",
+                       subsequent_indent="        ")
+
+
 def GetLastChangeLogEntries(change_log_file):
   result = []
   for line in LinesInFile(change_log_file):
@@ -81,28 +87,56 @@
     # Add the commit's title line.
     result += "%s\n" % title.rstrip()
 
-    # Grep for "BUG=xxxx" lines in the commit message and convert them to
-    # "(issue xxxx)".
-    out = body.splitlines()
-    out = filter(lambda x: re.search(r"^BUG=", x), out)
-    out = filter(lambda x: not re.search(r"BUG=$", x), out)
-    out = filter(lambda x: not re.search(r"BUG=none$", x), out)
-
-    # TODO(machenbach): Handle multiple entries (e.g. BUG=123, 234).
-    def FormatIssue(text):
-      text = re.sub(r"BUG=v8:(.*)$", r"(issue \1)", text)
-      text = re.sub(r"BUG=chromium:(.*)$", r"(Chromium issue \1)", text)
-      text = re.sub(r"BUG=(.*)$", r"(Chromium issue \1)", text)
-      return "        %s\n" % text
-
-    for line in map(FormatIssue, out):
-      result += line
+    # Add bug references.
+    result += MakeChangeLogBugReference(body)
 
     # Append the commit's author for reference.
     result += "%s\n\n" % author.rstrip()
   return result
 
 
+def MakeChangeLogBugReference(body):
+  """Grep for "BUG=xxxx" lines in the commit message and convert them to
+  "(issue xxxx)".
+  """
+  crbugs = []
+  v8bugs = []
+
+  def AddIssues(text):
+    ref = re.match(r"^BUG[ \t]*=[ \t]*(.+)$", text.strip())
+    if not ref:
+      return
+    for bug in ref.group(1).split(","):
+      bug = bug.strip()
+      match = re.match(r"^v8:(\d+)$", bug)
+      if match: v8bugs.append(int(match.group(1)))
+      else:
+        match = re.match(r"^(?:chromium:)?(\d+)$", bug)
+        if match: crbugs.append(int(match.group(1)))
+
+  # Add issues to crbugs and v8bugs.
+  map(AddIssues, body.splitlines())
+
+  # Filter duplicates, sort, stringify.
+  crbugs = map(str, sorted(set(crbugs)))
+  v8bugs = map(str, sorted(set(v8bugs)))
+
+  bug_groups = []
+  def FormatIssues(prefix, bugs):
+    if len(bugs) > 0:
+      plural = "s" if len(bugs) > 1 else ""
+      bug_groups.append("%sissue%s %s" % (prefix, plural, ", ".join(bugs)))
+
+  FormatIssues("", v8bugs)
+  FormatIssues("Chromium ", crbugs)
+
+  if len(bug_groups) > 0:
+    # Format with 8 characters indentation and max 80 character lines.
+    return "%s\n" % Fill80("(%s)" % ", ".join(bug_groups))
+  else:
+    return ""
+
+
 # Some commands don't like the pipe, e.g. calling vi from within the script or
 # from subscripts like git cl upload.
 def Command(cmd, args="", prefix="", pipe=True):
@@ -132,6 +166,7 @@
   def __init__(self, text="", requires=None):
     self._text = text
     self._number = -1
+    self._options = None
     self._requires = requires
     self._side_effect_handler = DEFAULT_SIDE_EFFECT_HANDLER
 
@@ -168,8 +203,13 @@
   def RunStep(self):
     raise NotImplementedError
 
-  def ReadLine(self):
-    return self._side_effect_handler.ReadLine()
+  def ReadLine(self, default=None):
+    # Don't prompt in forced mode.
+    if self._options and self._options.f and default is not None:
+      print "%s (forced)" % default
+      return default
+    else:
+      return self._side_effect_handler.ReadLine()
 
   def Git(self, args="", prefix="", pipe=True):
     return self._side_effect_handler.Command("git", args, prefix, pipe)
@@ -184,9 +224,14 @@
     print "Exiting"
     raise Exception(msg)
 
+  def DieInForcedMode(self, msg=""):
+    if self._options and self._options.f:
+      msg = msg or "Not implemented in forced mode."
+      self.Die(msg)
+
   def Confirm(self, msg):
     print "%s [Y/n] " % msg,
-    answer = self.ReadLine()
+    answer = self.ReadLine(default="Y")
     return answer == "" or answer == "Y" or answer == "y"
 
   def DeleteBranch(self, name):
@@ -220,6 +265,8 @@
     if not os.path.exists(self._config[DOT_GIT_LOCATION]):
       self.Die("This is not a git checkout, this script won't work for you.")
 
+    # TODO(machenbach): Don't use EDITOR in forced mode as soon as script is
+    # well tested.
     # Cancel if EDITOR is unset or not executable.
     if (not os.environ.get("EDITOR") or
         Command("which", os.environ["EDITOR"]) is None):
@@ -291,6 +338,8 @@
     answer = ""
     while answer != "LGTM":
       print "> ",
+      # TODO(machenbach): Add default="LGTM" to avoid prompt when script is
+      # well tested and when prepare push cl has TBR flag.
       answer = self.ReadLine()
       if answer != "LGTM":
         print "That was not 'LGTM'."
@@ -299,6 +348,7 @@
     print("Applying the patch \"%s\" failed. Either type \"ABORT<Return>\", "
           "or resolve the conflicts, stage *all* touched files with "
           "'git add', and type \"RESOLVED<Return>\"")
+    self.DieInForcedMode()
     answer = ""
     while answer != "RESOLVED":
       if answer == "ABORT":
@@ -320,8 +370,13 @@
     Step.__init__(self, "Upload for code review.")
 
   def RunStep(self):
-    print "Please enter the email address of a V8 reviewer for your patch: ",
-    reviewer = self.ReadLine()
+    if self._options and self._options.r:
+      print "Using account %s for review." % self._options.r
+      reviewer = self._options.r
+    else:
+      print "Please enter the email address of a V8 reviewer for your patch: ",
+      self.DieInForcedMode("A reviewer must be specified in forced mode.")
+      reviewer = self.ReadLine()
     args = "cl upload -r \"%s\" --send-mail" % reviewer
     if self.Git(args,pipe=False) is None:
       self.Die("'git cl upload' failed, please try again.")
diff --git a/tools/push-to-trunk/push_to_trunk.py b/tools/push-to-trunk/push_to_trunk.py
index 2aa32cd..c8fdc7e 100755
--- a/tools/push-to-trunk/push_to_trunk.py
+++ b/tools/push-to-trunk/push_to_trunk.py
@@ -135,8 +135,10 @@
     print ("Please press <Return> to have your EDITOR open the ChangeLog "
            "entry, then edit its contents to your liking. When you're done, "
            "save the file and exit your EDITOR. ")
-    self.ReadLine()
+    self.ReadLine(default="")
 
+    # TODO(machenbach): Don't use EDITOR in forced mode as soon as script is
+    # well tested.
     self.Editor(self.Config(CHANGELOG_ENTRY_FILE))
     handle, new_changelog = tempfile.mkstemp()
     os.close(handle)
@@ -354,6 +356,7 @@
       print("Sorry, grepping for the SVN revision failed. Please look for it "
             "in the last command's output above and provide it manually (just "
             "the number, without the leading \"r\").")
+      self.DieInForcedMode("Can't prompt in forced mode.")
       while not trunk_revision:
         print "> ",
         trunk_revision = self.ReadLine()
@@ -380,6 +383,8 @@
   def Run(self):
     chrome_path = self._options.c
     if not chrome_path:
+      self.DieInForcedMode("Please specify the path to a Chromium checkout in "
+                          "forced mode.")
       print ("Do you have a \"NewGit\" Chromium checkout and want "
           "this script to automate creation of the roll CL? If yes, enter the "
           "path to (and including) the \"src\" directory here, otherwise just "
@@ -442,8 +447,13 @@
     ver = "%s.%s.%s" % (self._state["major"],
                         self._state["minor"],
                         self._state["build"])
-    print "Please enter the email address of a reviewer for the roll CL: ",
-    rev = self.ReadLine()
+    if self._options and self._options.r:
+      print "Using account %s for review." % self._options.r
+      rev = self._options.r
+    else:
+      print "Please enter the email address of a reviewer for the roll CL: ",
+      self.DieInForcedMode("A reviewer must be specified in forced mode.")
+      rev = self.ReadLine()
     args = "commit -am \"Update V8 to version %s.\n\nTBR=%s\"" % (ver, rev)
     if self.Git(args) is None:
       self.Die("'git commit' failed.")
@@ -523,15 +533,20 @@
 
 def BuildOptions():
   result = optparse.OptionParser()
-  result.add_option("-s", "--step", dest="s",
-                    help="Specify the step where to start work. Default: 0.",
-                    default=0, type="int")
-  result.add_option("-l", "--last-push", dest="l",
-                    help=("Manually specify the git commit ID "
-                          "of the last push to trunk."))
   result.add_option("-c", "--chromium", dest="c",
                     help=("Specify the path to your Chromium src/ "
                           "directory to automate the V8 roll."))
+  result.add_option("-f", "--force", dest="f",
+                    help="Don't prompt the user.",
+                    default=False, action="store_true")
+  result.add_option("-l", "--last-push", dest="l",
+                    help=("Manually specify the git commit ID "
+                          "of the last push to trunk."))
+  result.add_option("-r", "--reviewer", dest="r",
+                    help=("Specify the account name to be used for reviews."))
+  result.add_option("-s", "--step", dest="s",
+                    help="Specify the step where to start work. Default: 0.",
+                    default=0, type="int")
   return result
 
 
@@ -548,7 +563,7 @@
   if not ProcessOptions(options):
     parser.print_help()
     return 1
-  RunScript(CONFIG, options)
+  RunPushToTrunk(CONFIG, options)
 
 if __name__ == "__main__":
   sys.exit(Main())
diff --git a/tools/push-to-trunk/test_scripts.py b/tools/push-to-trunk/test_scripts.py
index b9d762d..6ce22de 100644
--- a/tools/push-to-trunk/test_scripts.py
+++ b/tools/push-to-trunk/test_scripts.py
@@ -52,6 +52,101 @@
 }
 
 
+class ToplevelTest(unittest.TestCase):
+  def testMakeChangeLogBodySimple(self):
+    commits = lambda: [
+          ["        Title text 1",
+           "Title text 1\n\nBUG=\n",
+           "        author1@chromium.org"],
+          ["        Title text 2",
+           "Title text 2\n\nBUG=1234\n",
+           "        author2@chromium.org"],
+        ]
+    self.assertEquals("        Title text 1\n"
+                      "        author1@chromium.org\n\n"
+                      "        Title text 2\n"
+                      "        (Chromium issue 1234)\n"
+                      "        author2@chromium.org\n\n",
+                      MakeChangeLogBody(commits))
+
+  def testMakeChangeLogBodyEmpty(self):
+    commits = lambda: []
+    self.assertEquals("", MakeChangeLogBody(commits))
+
+  def testMakeChangeLogBugReferenceEmpty(self):
+    self.assertEquals("", MakeChangeLogBugReference(""))
+    self.assertEquals("", MakeChangeLogBugReference("LOG="))
+    self.assertEquals("", MakeChangeLogBugReference(" BUG ="))
+    self.assertEquals("", MakeChangeLogBugReference("BUG=none\t"))
+
+  def testMakeChangeLogBugReferenceSimple(self):
+    self.assertEquals("        (issue 987654)\n",
+                      MakeChangeLogBugReference("BUG = v8:987654"))
+    self.assertEquals("        (Chromium issue 987654)\n",
+                      MakeChangeLogBugReference("BUG=987654 "))
+
+  def testMakeChangeLogBugReferenceFromBody(self):
+    self.assertEquals("        (Chromium issue 1234567)\n",
+                      MakeChangeLogBugReference("Title\n\nTBR=\nBUG=\n"
+                                                " BUG=\tchromium:1234567\t\n"
+                                                "R=somebody\n"))
+
+  def testMakeChangeLogBugReferenceMultiple(self):
+    # All issues should be sorted and grouped. Multiple references to the same
+    # issue should be filtered.
+    self.assertEquals("        (issues 123, 234, Chromium issue 345)\n",
+                      MakeChangeLogBugReference("Title\n\n"
+                                                "BUG=v8:234\n"
+                                                "  BUG\t= 345, \tv8:234,\n"
+                                                "BUG=v8:123\n"
+                                                "R=somebody\n"))
+    self.assertEquals("        (Chromium issues 123, 234)\n",
+                      MakeChangeLogBugReference("Title\n\n"
+                                                "BUG=234,,chromium:123 \n"
+                                                "R=somebody\n"))
+    self.assertEquals("        (Chromium issues 123, 234)\n",
+                      MakeChangeLogBugReference("Title\n\n"
+                                                "BUG=chromium:234, , 123\n"
+                                                "R=somebody\n"))
+    self.assertEquals("        (issues 345, 456)\n",
+                      MakeChangeLogBugReference("Title\n\n"
+                                                "\t\tBUG=v8:345,v8:456\n"
+                                                "R=somebody\n"))
+    self.assertEquals("        (issue 123, Chromium issues 345, 456)\n",
+                      MakeChangeLogBugReference("Title\n\n"
+                                                "BUG=chromium:456\n"
+                                                "BUG = none\n"
+                                                "R=somebody\n"
+                                                "BUG=456,v8:123, 345"))
+
+  def testMakeChangeLogBugReferenceLong(self):
+    # -----------------00--------10--------20--------30--------
+    self.assertEquals("        (issues 234, 1234567890, 1234567"
+                      "8901234567890, Chromium issues 12345678,\n"
+                      "        123456789)\n",
+                      MakeChangeLogBugReference("BUG=v8:234\n"
+                                                "BUG=v8:1234567890\n"
+                                                "BUG=v8:12345678901234567890\n"
+                                                "BUG=123456789\n"
+                                                "BUG=12345678\n"))
+    # -----------------00--------10--------20--------30--------
+    self.assertEquals("        (issues 234, 1234567890, 1234567"
+                      "8901234567890, Chromium issues\n"
+                      "        123456789, 1234567890)\n",
+                      MakeChangeLogBugReference("BUG=v8:234\n"
+                                                "BUG=v8:12345678901234567890\n"
+                                                "BUG=v8:1234567890\n"
+                                                "BUG=123456789\n"
+                                                "BUG=1234567890\n"))
+    # -----------------00--------10--------20--------30--------
+    self.assertEquals("        (Chromium issues 234, 1234567890"
+                      ", 12345678901234567,\n"
+                      "        1234567890123456789)\n",
+                      MakeChangeLogBugReference("BUG=234\n"
+                                                "BUG=12345678901234567\n"
+                                                "BUG=1234567890123456789\n"
+                                                "BUG=1234567890\n"))
+
 class ScriptTest(unittest.TestCase):
   def MakeEmptyTempFile(self):
     handle, name = tempfile.mkstemp()
@@ -335,7 +430,7 @@
     patch = FileToText(TEST_CONFIG[ PATCH_FILE])
     self.assertTrue(re.search(r"patch content", patch))
 
-  def testPushToTrunk(self):
+  def _PushToTrunk(self, force=False):
     TEST_CONFIG[DOT_GIT_LOCATION] = self.MakeEmptyTempFile()
     TEST_CONFIG[VERSION_FILE] = self.MakeTempVersionFile()
     TEST_CONFIG[CHANGELOG_ENTRY_FILE] = self.MakeEmptyTempFile()
@@ -423,6 +518,12 @@
       "Y",  # Sanity check.
       "reviewer@chromium.org",  # Chromium reviewer.
     ]
+    if force:
+      # TODO(machenbach): The lgtm for the prepare push is just temporary.
+      # There should be no user input in "force" mode.
+      self._rl_recipe = [
+        "LGTM",  # Enter LGTM for V8 CL.
+      ]
 
     class Options( object ):
       pass
@@ -430,6 +531,8 @@
     options = Options()
     options.s = 0
     options.l = None
+    options.f = force
+    options.r = "reviewer@chromium.org" if force else None
     options.c = TEST_CONFIG[CHROMIUM]
     RunPushToTrunk(TEST_CONFIG, options, self)
 
@@ -445,3 +548,9 @@
     # Note: The version file is on build number 5 again in the end of this test
     # since the git command that merges to the bleeding edge branch is mocked
     # out.
+
+  def testPushToTrunk(self):
+    self._PushToTrunk()
+
+  def testPushToTrunkForced(self):
+    self._PushToTrunk(force=True)