Version 2.1.2

Fix a crash bug caused by wrong assert.

Fix a bug with register names on 64-bit V8 (issue 615).

Performance improvements on all platforms.



git-svn-id: http://v8.googlecode.com/svn/trunk@3930 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/SConscript b/src/SConscript
index 1a81cc7..73de193 100755
--- a/src/SConscript
+++ b/src/SConscript
@@ -57,7 +57,6 @@
     disassembler.cc
     execution.cc
     factory.cc
-    fast-codegen.cc
     flags.cc
     frame-element.cc
     frames.cc
@@ -109,6 +108,7 @@
     zone.cc
     """),
   'arch:arm': Split("""
+    fast-codegen.cc
     arm/builtins-arm.cc
     arm/codegen-arm.cc
     arm/constants-arm.cc
@@ -133,6 +133,7 @@
     arm/assembler-thumb2.cc
     """),
   'arch:mips': Split("""
+    fast-codegen.cc
     mips/assembler-mips.cc
     mips/builtins-mips.cc
     mips/codegen-mips.cc
@@ -169,6 +170,7 @@
     ia32/virtual-frame-ia32.cc
     """),
   'arch:x64': Split("""
+    fast-codegen.cc
     x64/assembler-x64.cc
     x64/builtins-x64.cc
     x64/codegen-x64.cc
diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc
index 046d7b9..95c50f2 100644
--- a/src/arm/codegen-arm.cc
+++ b/src/arm/codegen-arm.cc
@@ -142,7 +142,7 @@
 // r1: called JS function
 // cp: callee's context
 
-void CodeGenerator::Generate(CompilationInfo* info, Mode mode) {
+void CodeGenerator::Generate(CompilationInfo* info) {
   // Record the position for debugging purposes.
   CodeForFunctionPosition(info->function());
 
@@ -174,7 +174,7 @@
     }
 #endif
 
-    if (mode == PRIMARY) {
+    if (info->mode() == CompilationInfo::PRIMARY) {
       frame_->Enter();
       // tos: code slot
 
@@ -277,6 +277,12 @@
       frame_->Adjust(4);
       allocator_->Unuse(r1);
       allocator_->Unuse(lr);
+
+      // Bind all the bailout labels to the beginning of the function.
+      List<CompilationInfo::Bailout*>* bailouts = info->bailouts();
+      for (int i = 0; i < bailouts->length(); i++) {
+        __ bind(bailouts->at(i)->label());
+      }
     }
 
     // Initialize the function return target after the locals are set
@@ -3420,6 +3426,25 @@
 }
 
 
+void CodeGenerator::GenerateIsRegExp(ZoneList<Expression*>* args) {
+  VirtualFrame::SpilledScope spilled_scope;
+  ASSERT(args->length() == 1);
+  LoadAndSpill(args->at(0));
+  JumpTarget answer;
+  // We need the CC bits to come out as not_equal in the case where the
+  // object is a smi.  This can't be done with the usual test opcode so
+  // we use XOR to get the right CC bits.
+  frame_->EmitPop(r0);
+  __ and_(r1, r0, Operand(kSmiTagMask));
+  __ eor(r1, r1, Operand(kSmiTagMask), SetCC);
+  answer.Branch(ne);
+  // It is a heap object - get the map. Check if the object is a regexp.
+  __ CompareObjectType(r0, r1, r1, JS_REGEXP_TYPE);
+  answer.Bind();
+  cc_reg_ = eq;
+}
+
+
 void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) {
   // This generates a fast version of:
   // (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp')
diff --git a/src/arm/codegen-arm.h b/src/arm/codegen-arm.h
index 10e28f4..1a2e552 100644
--- a/src/arm/codegen-arm.h
+++ b/src/arm/codegen-arm.h
@@ -150,15 +150,6 @@
 
 class CodeGenerator: public AstVisitor {
  public:
-  // Compilation mode.  Either the compiler is used as the primary
-  // compiler and needs to setup everything or the compiler is used as
-  // the secondary compiler for split compilation and has to handle
-  // bailouts.
-  enum Mode {
-    PRIMARY,
-    SECONDARY
-  };
-
   // Takes a function literal, generates code for it. This function should only
   // be called by compiler.cc.
   static Handle<Code> MakeCode(CompilationInfo* info);
@@ -244,7 +235,7 @@
   inline void VisitStatementsAndSpill(ZoneList<Statement*>* statements);
 
   // Main code generation function
-  void Generate(CompilationInfo* info, Mode mode);
+  void Generate(CompilationInfo* info);
 
   // The following are used by class Reference.
   void LoadReference(Reference* ref);
@@ -359,6 +350,7 @@
   void GenerateIsSmi(ZoneList<Expression*>* args);
   void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
   void GenerateIsArray(ZoneList<Expression*>* args);
+  void GenerateIsRegExp(ZoneList<Expression*>* args);
   void GenerateIsObject(ZoneList<Expression*>* args);
   void GenerateIsFunction(ZoneList<Expression*>* args);
   void GenerateIsUndetectableObject(ZoneList<Expression*>* args);
diff --git a/src/arm/fast-codegen-arm.cc b/src/arm/fast-codegen-arm.cc
index a07b0d2..aa7128f 100644
--- a/src/arm/fast-codegen-arm.cc
+++ b/src/arm/fast-codegen-arm.cc
@@ -148,17 +148,25 @@
     if (!destination().is(no_reg)) {
       __ orr(destination(), accumulator1(), Operand(accumulator0()));
     }
-  } else if (destination().is(no_reg)) {
-    // Result is not needed but do not clobber the operands in case of
-    // bailout.
-    __ orr(scratch0(), accumulator1(), Operand(accumulator0()));
-    __ BranchOnNotSmi(scratch0(), bailout());
   } else {
-    // Preserve the destination operand in a scratch register in case of
-    // bailout.
-    __ mov(scratch0(), destination());
-    __ orr(destination(), accumulator1(), Operand(accumulator0()));
-    __ BranchOnNotSmi(destination(), bailout());
+    // Left is in accumulator1, right in accumulator0.
+    if (destination().is(accumulator0())) {
+      __ mov(scratch0(), accumulator0());
+      __ orr(destination(), accumulator1(), Operand(accumulator1()));
+      Label* bailout =
+          info()->AddBailout(accumulator1(), scratch0());  // Left, right.
+      __ BranchOnNotSmi(destination(), bailout);
+    } else if (destination().is(accumulator1())) {
+      __ mov(scratch0(), accumulator1());
+      __ orr(destination(), accumulator1(), Operand(accumulator0()));
+      Label* bailout = info()->AddBailout(scratch0(), accumulator0());
+      __ BranchOnNotSmi(destination(), bailout);
+    } else {
+      ASSERT(destination().is(no_reg));
+      __ orr(scratch0(), accumulator1(), Operand(accumulator0()));
+      Label* bailout = info()->AddBailout(accumulator1(), accumulator0());
+      __ BranchOnNotSmi(scratch0(), bailout);
+    }
   }
 
   // If we didn't bailout, the result (in fact, both inputs too) is known to
@@ -179,6 +187,7 @@
   // Note that we keep a live register reference to cp (context) at
   // this point.
 
+  Label* bailout_to_beginning = info()->AddBailout();
   // Receiver (this) is allocated to a fixed register.
   if (info()->has_this_properties()) {
     Comment cmnt(masm(), ";; MapCheck(this)");
@@ -189,7 +198,7 @@
     Handle<HeapObject> object = Handle<HeapObject>::cast(info()->receiver());
     Handle<Map> map(object->map());
     EmitLoadReceiver();
-    __ CheckMap(receiver_reg(), scratch0(), map, bailout(), false);
+    __ CheckMap(receiver_reg(), scratch0(), map, bailout_to_beginning, false);
   }
 
   // If there is a global variable access check if the global object is the
@@ -202,7 +211,7 @@
     ASSERT(info()->has_global_object());
     Handle<Map> map(info()->global_object()->map());
     __ ldr(scratch0(), CodeGenerator::GlobalObject());
-    __ CheckMap(scratch0(), scratch1(), map, bailout(), true);
+    __ CheckMap(scratch0(), scratch1(), map, bailout_to_beginning, true);
   }
 
   VisitStatements(function()->body());
@@ -217,8 +226,6 @@
   int32_t sp_delta = (scope()->num_parameters() + 1) * kPointerSize;
   __ add(sp, sp, Operand(sp_delta));
   __ Jump(lr);
-
-  __ bind(&bailout_);
 }
 
 
diff --git a/src/ast.h b/src/ast.h
index 8e717a6..927a9f5 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -1,4 +1,4 @@
-// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Copyright 2010 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:
@@ -199,6 +199,10 @@
   // evaluated.
   virtual bool IsLeaf() { return false; }
 
+  // True if the expression has no side effects and is safe to
+  // evaluate out of order.
+  virtual bool IsTrivial() { return false; }
+
   // Mark the expression as being compiled as an expression
   // statement. This is used to transform postfix increments to
   // (faster) prefix increments.
@@ -738,6 +742,7 @@
   }
 
   virtual bool IsLeaf() { return true; }
+  virtual bool IsTrivial() { return true; }
 
   // Identity testers.
   bool IsNull() const { return handle_.is_identical_to(Factory::null_value()); }
@@ -926,6 +931,10 @@
     return var()->is_global() || var()->rewrite()->IsLeaf();
   }
 
+  // Reading from a mutable variable is a side effect, but 'this' is
+  // immutable.
+  virtual bool IsTrivial() { return is_this(); }
+
   bool IsVariable(Handle<String> n) {
     return !is_this() && name().is_identical_to(n);
   }
diff --git a/src/codegen.cc b/src/codegen.cc
index 01ee6d0..dbd1100 100644
--- a/src/codegen.cc
+++ b/src/codegen.cc
@@ -248,7 +248,7 @@
   CodeGenerator cgen(&masm);
   CodeGeneratorScope scope(&cgen);
   live_edit_tracker.RecordFunctionScope(info->function()->scope());
-  cgen.Generate(info, PRIMARY);
+  cgen.Generate(info);
   if (cgen.HasStackOverflow()) {
     ASSERT(!Top::has_pending_exception());
     return Handle<Code>::null();
@@ -360,6 +360,7 @@
   {&CodeGenerator::GenerateIsSmi, "_IsSmi"},
   {&CodeGenerator::GenerateIsNonNegativeSmi, "_IsNonNegativeSmi"},
   {&CodeGenerator::GenerateIsArray, "_IsArray"},
+  {&CodeGenerator::GenerateIsRegExp, "_IsRegExp"},
   {&CodeGenerator::GenerateIsConstructCall, "_IsConstructCall"},
   {&CodeGenerator::GenerateArgumentsLength, "_ArgumentsLength"},
   {&CodeGenerator::GenerateArgumentsAccess, "_Arguments"},
diff --git a/src/codegen.h b/src/codegen.h
index 5c10cb6..8dcde84 100644
--- a/src/codegen.h
+++ b/src/codegen.h
@@ -518,14 +518,14 @@
   }
 #endif
 
-  // Minor key encoding in 31 bits AAAAAAAAAAAAAAAAAAAAAFI A(rgs)F(lag)I(nloop).
+  // Minor key encoding in 32 bits with Bitfield <Type, shift, size>.
   class InLoopBits: public BitField<InLoopFlag, 0, 1> {};
   class FlagBits: public BitField<CallFunctionFlags, 1, 1> {};
-  class ArgcBits: public BitField<int, 2, 29> {};
+  class ArgcBits: public BitField<int, 2, 32 - 2> {};
 
   Major MajorKey() { return CallFunction; }
   int MinorKey() {
-    // Encode the parameters in a unique 31 bit value.
+    // Encode the parameters in a unique 32 bit value.
     return InLoopBits::encode(in_loop_)
            | FlagBits::encode(flags_)
            | ArgcBits::encode(argc_);
diff --git a/src/compiler.h b/src/compiler.h
index 6ee2246..f01889d 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -41,6 +41,37 @@
 // is constructed based on the resources available at compile-time.
 class CompilationInfo BASE_EMBEDDED {
  public:
+  // Compilation mode.  Either the compiler is used as the primary
+  // compiler and needs to setup everything or the compiler is used as
+  // the secondary compiler for split compilation and has to handle
+  // bailouts.
+  enum Mode {
+    PRIMARY,
+    SECONDARY
+  };
+
+  // A description of the compilation state at a bailout to the secondary
+  // code generator.
+  //
+  // The state is currently simple: there are no parameters or local
+  // variables to worry about ('this' can be found in the stack frame).
+  // There are at most two live values.
+  //
+  // There is a label that should be bound to the beginning of the bailout
+  // stub code.
+  class Bailout : public ZoneObject {
+   public:
+    Bailout(Register left, Register right) : left_(left), right_(right) {}
+
+    Label* label() { return &label_; }
+
+   private:
+    Register left_;
+    Register right_;
+    Label label_;
+  };
+
+
   // Lazy compilation of a JSFunction.
   CompilationInfo(Handle<JSFunction> closure,
                   int loop_nesting,
@@ -117,9 +148,13 @@
   int loop_nesting() { return loop_nesting_; }
   bool has_receiver() { return !receiver_.is_null(); }
   Handle<Object> receiver() { return receiver_; }
+  List<Bailout*>* bailouts() { return &bailouts_; }
 
-  // Accessors for mutable fields, possibly set by analysis passes with
+  // Accessors for mutable fields (possibly set by analysis passes) with
   // default values given by Initialize.
+  Mode mode() { return mode_; }
+  void set_mode(Mode mode) { mode_ = mode; }
+
   bool has_this_properties() { return has_this_properties_; }
   void set_has_this_properties(bool flag) { has_this_properties_ = flag; }
 
@@ -137,8 +172,19 @@
   // Derived accessors.
   Scope* scope() { return function()->scope(); }
 
+  // Add a bailout with two live values.
+  Label* AddBailout(Register left, Register right) {
+    Bailout* bailout = new Bailout(left, right);
+    bailouts_.Add(bailout);
+    return bailout->label();
+  }
+
+  // Add a bailout with no live values.
+  Label* AddBailout() { return AddBailout(no_reg, no_reg); }
+
  private:
   void Initialize() {
+    mode_ = PRIMARY;
     has_this_properties_ = false;
     has_globals_ = false;
   }
@@ -148,6 +194,7 @@
   Handle<Script> script_;
 
   FunctionLiteral* function_;
+  Mode mode_;
 
   bool is_eval_;
   int loop_nesting_;
@@ -157,6 +204,10 @@
   bool has_this_properties_;
   bool has_globals_;
 
+  // An ordered list of bailout points encountered during fast-path
+  // compilation.
+  List<Bailout*> bailouts_;
+
   DISALLOW_COPY_AND_ASSIGN(CompilationInfo);
 };
 
diff --git a/src/debug-delay.js b/src/debug-delay.js
index 754ac5d..55c25a9 100644
--- a/src/debug-delay.js
+++ b/src/debug-delay.js
@@ -1202,11 +1202,16 @@
         throw new Error('Command not specified');
       }
 
-      // TODO(yurys): remove request.arguments.compactFormat check once
-      // ChromeDevTools are switched to 'inlineRefs'
-      if (request.arguments && (request.arguments.inlineRefs ||
-                                request.arguments.compactFormat)) {
-        response.setOption('inlineRefs', true);
+      if (request.arguments) {
+        var args = request.arguments;
+        // TODO(yurys): remove request.arguments.compactFormat check once
+        // ChromeDevTools are switched to 'inlineRefs'
+        if (args.inlineRefs || args.compactFormat) {
+          response.setOption('inlineRefs', true);
+        }
+        if (!IS_UNDEFINED(args.maxStringLength)) {
+          response.setOption('maxStringLength', args.maxStringLength);
+        }
       }
 
       if (request.command == 'continue') {
diff --git a/src/fast-codegen.cc b/src/fast-codegen.cc
index ecd2652..602d6b8 100644
--- a/src/fast-codegen.cc
+++ b/src/fast-codegen.cc
@@ -456,7 +456,8 @@
   // macro assembler.
   CodeGenerator cgen(&masm);
   CodeGeneratorScope scope(&cgen);
-  cgen.Generate(info, CodeGenerator::SECONDARY);
+  info->set_mode(CompilationInfo::SECONDARY);
+  cgen.Generate(info);
   if (cgen.HasStackOverflow()) {
     ASSERT(!Top::has_pending_exception());
     return Handle<Code>::null();
diff --git a/src/fast-codegen.h b/src/fast-codegen.h
index 96ee5dd..e96daf6 100644
--- a/src/fast-codegen.h
+++ b/src/fast-codegen.h
@@ -28,10 +28,15 @@
 #ifndef V8_FAST_CODEGEN_H_
 #define V8_FAST_CODEGEN_H_
 
+#if V8_TARGET_ARCH_IA32
+#include "ia32/fast-codegen-ia32.h"
+#else
+
 #include "v8.h"
 
 #include "ast.h"
 #include "compiler.h"
+#include "list.h"
 
 namespace v8 {
 namespace internal {
@@ -76,7 +81,6 @@
  private:
   MacroAssembler* masm() { return masm_; }
   CompilationInfo* info() { return info_; }
-  Label* bailout() { return &bailout_; }
 
   Register destination() { return destination_; }
   void set_destination(Register reg) { destination_ = reg; }
@@ -142,7 +146,6 @@
 
   MacroAssembler* masm_;
   CompilationInfo* info_;
-  Label bailout_;
   Register destination_;
   uint32_t smi_bits_;
 
@@ -152,4 +155,6 @@
 
 } }  // namespace v8::internal
 
+#endif  // V8_TARGET_ARCH_IA32
+
 #endif  // V8_FAST_CODEGEN_H_
diff --git a/src/frame-element.h b/src/frame-element.h
index 3ae6d30..5762814 100644
--- a/src/frame-element.h
+++ b/src/frame-element.h
@@ -65,6 +65,9 @@
   }
 
   inline void set_number_info(NumberInfo::Type info) {
+    // Copied elements do not have number info. Instead
+    // we have to inspect their backing element in the frame.
+    ASSERT(!is_copy());
     value_ = value_ & ~NumberInfoField::mask();
     value_ = value_ | NumberInfoField::encode(info);
   }
@@ -250,7 +253,7 @@
   class CopiedField: public BitField<bool, 3, 1> {};
   class SyncedField: public BitField<bool, 4, 1> {};
   class NumberInfoField: public BitField<NumberInfo::Type, 5, 3> {};
-  class DataField: public BitField<uint32_t, 8, 32 - 9> {};
+  class DataField: public BitField<uint32_t, 8, 32 - 8> {};
 
   friend class VirtualFrame;
 };
diff --git a/src/heap.cc b/src/heap.cc
index fc4e666..cfb786a 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -4111,7 +4111,7 @@
   // Uses only lower 32 bits if pointers are larger.
   uintptr_t addr_hash =
       static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map)) >> kMapHashShift;
-  return (addr_hash ^ name->Hash()) & kCapacityMask;
+  return static_cast<uint32_t>((addr_hash ^ name->Hash()) & kCapacityMask);
 }
 
 
diff --git a/src/heap.h b/src/heap.h
index 22ab875..3f34df7 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -1383,9 +1383,9 @@
  private:
   static int Hash(DescriptorArray* array, String* name) {
     // Uses only lower 32 bits if pointers are larger.
-    uintptr_t array_hash =
+    uint32_t array_hash =
         static_cast<uint32_t>(reinterpret_cast<uintptr_t>(array)) >> 2;
-    uintptr_t name_hash =
+    uint32_t name_hash =
         static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name)) >> 2;
     return (array_hash ^ name_hash) % kLength;
   }
diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc
index 7ec3ff4..85d8ed9 100644
--- a/src/ia32/codegen-ia32.cc
+++ b/src/ia32/codegen-ia32.cc
@@ -125,7 +125,7 @@
 // edi: called JS function
 // esi: callee's context
 
-void CodeGenerator::Generate(CompilationInfo* info, Mode mode) {
+void CodeGenerator::Generate(CompilationInfo* info) {
   // Record the position for debugging purposes.
   CodeForFunctionPosition(info->function());
 
@@ -164,7 +164,7 @@
     // esi: callee's context
     allocator_->Initialize();
 
-    if (mode == PRIMARY) {
+    if (info->mode() == CompilationInfo::PRIMARY) {
       frame_->Enter();
 
       // Allocate space for locals and initialize them.
@@ -255,6 +255,12 @@
       // frame to match this state.
       frame_->Adjust(3);
       allocator_->Unuse(edi);
+
+      // Bind all the bailout labels to the beginning of the function.
+      List<CompilationInfo::Bailout*>* bailouts = info->bailouts();
+      for (int i = 0; i < bailouts->length(); i++) {
+        __ bind(bailouts->at(i)->label());
+      }
     }
 
     // Initialize the function return target after the locals are set
@@ -689,6 +695,11 @@
     // The expression is a variable proxy that does not rewrite to a
     // property.  Global variables are treated as named property references.
     if (var->is_global()) {
+      // If eax is free, the register allocator prefers it.  Thus the code
+      // generator will load the global object into eax, which is where
+      // LoadIC wants it.  Most uses of Reference call LoadIC directly
+      // after the reference is created.
+      frame_->Spill(eax);
       LoadGlobal();
       ref->set_type(Reference::NAMED);
     } else {
@@ -4307,6 +4318,10 @@
 
   // All extension objects were empty and it is safe to use a global
   // load IC call.
+  // The register allocator prefers eax if it is free, so the code generator
+  // will load the global object directly into eax, which is where the LoadIC
+  // expects it.
+  frame_->Spill(eax);
   LoadGlobal();
   frame_->Push(slot->var()->name());
   RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
@@ -4592,8 +4607,8 @@
           // Duplicate the object as the IC receiver.
           frame_->Dup();
           Load(property->value());
-          frame_->Push(key);
-          Result ignored = frame_->CallStoreIC();
+          Result dummy = frame_->CallStoreIC(Handle<String>::cast(key), false);
+          dummy.Unuse();
           break;
         }
         // Fall through
@@ -4762,26 +4777,33 @@
   Property* prop = node->target()->AsProperty();
   ASSERT(var == NULL || (prop == NULL && var->is_global()));
 
-  // Initialize name and evaluate the receiver subexpression.
+  // Initialize name and evaluate the receiver subexpression if necessary.
   Handle<String> name;
+  bool is_trivial_receiver = false;
   if (var != NULL) {
     name = var->name();
-    LoadGlobal();
   } else {
     Literal* lit = prop->key()->AsLiteral();
-    ASSERT(lit != NULL);
+    ASSERT_NOT_NULL(lit);
     name = Handle<String>::cast(lit->handle());
-    Load(prop->obj());
+    // Do not materialize the receiver on the frame if it is trivial.
+    is_trivial_receiver = prop->obj()->IsTrivial();
+    if (!is_trivial_receiver) Load(prop->obj());
   }
 
   if (node->starts_initialization_block()) {
+    ASSERT_EQ(NULL, var);
     // Change to slow case in the beginning of an initialization block to
     // avoid the quadratic behavior of repeatedly adding fast properties.
-    frame()->Dup();
+    if (is_trivial_receiver) {
+      frame()->Push(prop->obj());
+    } else {
+      frame()->Dup();
+    }
     Result ignored = frame()->CallRuntime(Runtime::kToSlowProperties, 1);
   }
 
-  if (node->ends_initialization_block()) {
+  if (node->ends_initialization_block() && !is_trivial_receiver) {
     // Add an extra copy of the receiver to the frame, so that it can be
     // converted back to fast case after the assignment.
     frame()->Dup();
@@ -4789,7 +4811,16 @@
 
   // Evaluate the right-hand side.
   if (node->is_compound()) {
-    frame()->Dup();
+    if (is_trivial_receiver) {
+      frame()->Push(prop->obj());
+    } else if (var != NULL) {
+      // The LoadIC stub expects the object in eax.
+      // Freeing eax causes the code generator to load the global into it.
+      frame_->Spill(eax);
+      LoadGlobal();
+    } else {
+      frame()->Dup();
+    }
     Result value = EmitNamedLoad(name, var != NULL);
     frame()->Push(&value);
     Load(node->value());
@@ -4806,23 +4837,34 @@
 
   // Perform the assignment.  It is safe to ignore constants here.
   ASSERT(var == NULL || var->mode() != Variable::CONST);
-  ASSERT(node->op() != Token::INIT_CONST);
+  ASSERT_NE(Token::INIT_CONST, node->op());
+  if (is_trivial_receiver) {
+    Result value = frame()->Pop();
+    frame()->Push(prop->obj());
+    frame()->Push(&value);
+  }
   CodeForSourcePosition(node->position());
-  Result answer = EmitNamedStore(name);
+  bool is_contextual = (var != NULL);
+  Result answer = EmitNamedStore(name, is_contextual);
   frame()->Push(&answer);
 
   if (node->ends_initialization_block()) {
-    // The argument to the runtime call is the extra copy of the receiver,
-    // which is below the value of the assignment.  Swap the receiver and
-    // the value of the assignment expression.
-    Result result = frame()->Pop();
-    Result receiver = frame()->Pop();
-    frame()->Push(&result);
-    frame()->Push(&receiver);
+    ASSERT_EQ(NULL, var);
+    // The argument to the runtime call is the receiver.
+    if (is_trivial_receiver) {
+      frame()->Push(prop->obj());
+    } else {
+      // A copy of the receiver is below the value of the assignment.  Swap
+      // the receiver and the value of the assignment expression.
+      Result result = frame()->Pop();
+      Result receiver = frame()->Pop();
+      frame()->Push(&result);
+      frame()->Push(&receiver);
+    }
     Result ignored = frame_->CallRuntime(Runtime::kToFastProperties, 1);
   }
 
-  ASSERT(frame()->height() == original_height + 1);
+  ASSERT_EQ(frame()->height(), original_height + 1);
 }
 
 
@@ -4832,7 +4874,7 @@
 #endif
   Comment cmnt(masm_, "[ Named Property Assignment");
   Property* prop = node->target()->AsProperty();
-  ASSERT(prop != NULL);
+  ASSERT_NOT_NULL(prop);
 
   // Evaluate the receiver subexpression.
   Load(prop->obj());
@@ -5399,6 +5441,25 @@
 }
 
 
+void CodeGenerator::GenerateIsRegExp(ZoneList<Expression*>* args) {
+  ASSERT(args->length() == 1);
+  Load(args->at(0));
+  Result value = frame_->Pop();
+  value.ToRegister();
+  ASSERT(value.is_valid());
+  __ test(value.reg(), Immediate(kSmiTagMask));
+  destination()->false_target()->Branch(equal);
+  // It is a heap object - get map.
+  Result temp = allocator()->Allocate();
+  ASSERT(temp.is_valid());
+  // Check if the object is a regexp.
+  __ CmpObjectType(value.reg(), JS_REGEXP_TYPE, temp.reg());
+  value.Unuse();
+  temp.Unuse();
+  destination()->Split(equal);
+}
+
+
 void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) {
   // This generates a fast version of:
   // (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp')
@@ -6347,13 +6408,10 @@
       __ movzx_b(temp.reg(), FieldOperand(temp.reg(), Map::kBitFieldOffset));
       __ test(temp.reg(), Immediate(1 << Map::kIsUndetectable));
       destination()->false_target()->Branch(not_zero);
-      __ mov(temp.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset));
-      __ movzx_b(temp.reg(),
-                 FieldOperand(temp.reg(), Map::kInstanceTypeOffset));
-      __ cmp(temp.reg(), FIRST_NONSTRING_TYPE);
+      __ CmpObjectType(answer.reg(), FIRST_NONSTRING_TYPE, temp.reg());
       temp.Unuse();
       answer.Unuse();
-      destination()->Split(less);
+      destination()->Split(below);
 
     } else if (check->Equals(Heap::boolean_symbol())) {
       __ cmp(answer.reg(), Factory::true_value());
@@ -6734,14 +6792,13 @@
 }
 
 
-Result CodeGenerator::EmitNamedStore(Handle<String> name) {
+Result CodeGenerator::EmitNamedStore(Handle<String> name, bool is_contextual) {
 #ifdef DEBUG
-  int original_height = frame()->height();
+  int expected_height = frame()->height() - (is_contextual ? 1 : 2);
 #endif
-  frame()->Push(name);
-  Result result = frame()->CallStoreIC();
+  Result result = frame()->CallStoreIC(name, is_contextual);
 
-  ASSERT(frame()->height() == original_height - 2);
+  ASSERT_EQ(expected_height, frame()->height());
   return result;
 }
 
@@ -7058,7 +7115,7 @@
 
     case NAMED: {
       Comment cmnt(masm, "[ Store to named Property");
-      Result answer = cgen_->EmitNamedStore(GetName());
+      Result answer = cgen_->EmitNamedStore(GetName(), false);
       cgen_->frame()->Push(&answer);
       set_unloaded();
       break;
diff --git a/src/ia32/codegen-ia32.h b/src/ia32/codegen-ia32.h
index a6cb316..99dc340 100644
--- a/src/ia32/codegen-ia32.h
+++ b/src/ia32/codegen-ia32.h
@@ -294,15 +294,6 @@
 
 class CodeGenerator: public AstVisitor {
  public:
-  // Compilation mode.  Either the compiler is used as the primary
-  // compiler and needs to setup everything or the compiler is used as
-  // the secondary compiler for split compilation and has to handle
-  // bailouts.
-  enum Mode {
-    PRIMARY,
-    SECONDARY
-  };
-
   // Takes a function literal, generates code for it. This function should only
   // be called by compiler.cc.
   static Handle<Code> MakeCode(CompilationInfo* info);
@@ -384,7 +375,7 @@
   void VisitStatementsAndSpill(ZoneList<Statement*>* statements);
 
   // Main code generation function
-  void Generate(CompilationInfo* info, Mode mode);
+  void Generate(CompilationInfo* info);
 
   // Generate the return sequence code.  Should be called no more than
   // once per compiled function, immediately after binding the return
@@ -447,8 +438,9 @@
   // Receiver is passed on the frame and consumed.
   Result EmitNamedLoad(Handle<String> name, bool is_contextual);
 
-  // Reciever and value are passed on the frame and consumed.
-  Result EmitNamedStore(Handle<String> name);
+  // If the store is contextual, value is passed on the frame and consumed.
+  // Otherwise, receiver and value are passed on the frame and consumed.
+  Result EmitNamedStore(Handle<String> name, bool is_contextual);
 
   // Receiver and key are passed on the frame and consumed.
   Result EmitKeyedLoad();
@@ -551,6 +543,7 @@
   void GenerateIsSmi(ZoneList<Expression*>* args);
   void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
   void GenerateIsArray(ZoneList<Expression*>* args);
+  void GenerateIsRegExp(ZoneList<Expression*>* args);
   void GenerateIsObject(ZoneList<Expression*>* args);
   void GenerateIsFunction(ZoneList<Expression*>* args);
   void GenerateIsUndetectableObject(ZoneList<Expression*>* args);
diff --git a/src/ia32/fast-codegen-ia32.cc b/src/ia32/fast-codegen-ia32.cc
index 9bab75a..f1c2507 100644
--- a/src/ia32/fast-codegen-ia32.cc
+++ b/src/ia32/fast-codegen-ia32.cc
@@ -29,12 +29,445 @@
 
 #include "codegen-inl.h"
 #include "fast-codegen.h"
+#include "data-flow.h"
+#include "scopes.h"
 
 namespace v8 {
 namespace internal {
 
+#define BAILOUT(reason)                         \
+  do {                                          \
+    if (FLAG_trace_bailout) {                   \
+      PrintF("%s\n", reason);                   \
+    }                                           \
+    has_supported_syntax_ = false;              \
+    return;                                     \
+  } while (false)
+
+
+#define CHECK_BAILOUT                           \
+  do {                                          \
+    if (!has_supported_syntax_) return;         \
+  } while (false)
+
+
+void FastCodeGenSyntaxChecker::Check(CompilationInfo* info) {
+  info_ = info;
+
+  // We do not specialize if we do not have a receiver or if it is not a
+  // JS object with fast mode properties.
+  if (!info->has_receiver()) BAILOUT("No receiver");
+  if (!info->receiver()->IsJSObject()) BAILOUT("Receiver is not an object");
+  Handle<JSObject> object = Handle<JSObject>::cast(info->receiver());
+  if (!object->HasFastProperties()) BAILOUT("Receiver is in dictionary mode");
+
+  // We do not support stack or heap slots (both of which require
+  // allocation).
+  Scope* scope = info->scope();
+  if (scope->num_stack_slots() > 0) {
+    BAILOUT("Function has stack-allocated locals");
+  }
+  if (scope->num_heap_slots() > 0) {
+    BAILOUT("Function has context-allocated locals");
+  }
+
+  VisitDeclarations(scope->declarations());
+  CHECK_BAILOUT;
+
+  // We do not support empty function bodies.
+  if (info->function()->body()->is_empty()) {
+    BAILOUT("Function has an empty body");
+  }
+  VisitStatements(info->function()->body());
+}
+
+
+void FastCodeGenSyntaxChecker::VisitDeclarations(
+    ZoneList<Declaration*>* decls) {
+  if (!decls->is_empty()) BAILOUT("Function has declarations");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitStatements(ZoneList<Statement*>* stmts) {
+  if (stmts->length() != 1) {
+    BAILOUT("Function body is not a singleton statement.");
+  }
+  Visit(stmts->at(0));
+}
+
+
+void FastCodeGenSyntaxChecker::VisitDeclaration(Declaration* decl) {
+  UNREACHABLE();
+}
+
+
+void FastCodeGenSyntaxChecker::VisitBlock(Block* stmt) {
+  VisitStatements(stmt->statements());
+}
+
+
+void FastCodeGenSyntaxChecker::VisitExpressionStatement(
+    ExpressionStatement* stmt) {
+  Visit(stmt->expression());
+}
+
+
+void FastCodeGenSyntaxChecker::VisitEmptyStatement(EmptyStatement* stmt) {
+  // Supported.
+}
+
+
+void FastCodeGenSyntaxChecker::VisitIfStatement(IfStatement* stmt) {
+  BAILOUT("IfStatement");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitContinueStatement(ContinueStatement* stmt) {
+  BAILOUT("Continuestatement");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitBreakStatement(BreakStatement* stmt) {
+  BAILOUT("BreakStatement");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitReturnStatement(ReturnStatement* stmt) {
+  BAILOUT("ReturnStatement");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitWithEnterStatement(
+    WithEnterStatement* stmt) {
+  BAILOUT("WithEnterStatement");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitWithExitStatement(WithExitStatement* stmt) {
+  BAILOUT("WithExitStatement");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitSwitchStatement(SwitchStatement* stmt) {
+  BAILOUT("SwitchStatement");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitDoWhileStatement(DoWhileStatement* stmt) {
+  BAILOUT("DoWhileStatement");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitWhileStatement(WhileStatement* stmt) {
+  BAILOUT("WhileStatement");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitForStatement(ForStatement* stmt) {
+  BAILOUT("ForStatement");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitForInStatement(ForInStatement* stmt) {
+  BAILOUT("ForInStatement");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitTryCatchStatement(TryCatchStatement* stmt) {
+  BAILOUT("TryCatchStatement");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitTryFinallyStatement(
+    TryFinallyStatement* stmt) {
+  BAILOUT("TryFinallyStatement");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitDebuggerStatement(
+    DebuggerStatement* stmt) {
+  BAILOUT("DebuggerStatement");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitFunctionLiteral(FunctionLiteral* expr) {
+  BAILOUT("FunctionLiteral");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitFunctionBoilerplateLiteral(
+    FunctionBoilerplateLiteral* expr) {
+  BAILOUT("FunctionBoilerplateLiteral");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitConditional(Conditional* expr) {
+  BAILOUT("Conditional");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitSlot(Slot* expr) {
+  UNREACHABLE();
+}
+
+
+void FastCodeGenSyntaxChecker::VisitVariableProxy(VariableProxy* expr) {
+  // Only global variable references are supported.
+  Variable* var = expr->var();
+  if (!var->is_global() || var->is_this()) BAILOUT("Non-global variable");
+
+  // Check if the global variable is existing and non-deletable.
+  if (info()->has_global_object()) {
+    LookupResult lookup;
+    info()->global_object()->Lookup(*expr->name(), &lookup);
+    if (!lookup.IsProperty()) {
+      BAILOUT("Non-existing global variable");
+    }
+    // We do not handle global variables with accessors or interceptors.
+    if (lookup.type() != NORMAL) {
+      BAILOUT("Global variable with accessors or interceptors.");
+    }
+    // We do not handle deletable global variables.
+    if (!lookup.IsDontDelete()) {
+      BAILOUT("Deletable global variable");
+    }
+  }
+}
+
+
+void FastCodeGenSyntaxChecker::VisitLiteral(Literal* expr) {
+  BAILOUT("Literal");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitRegExpLiteral(RegExpLiteral* expr) {
+  BAILOUT("RegExpLiteral");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitObjectLiteral(ObjectLiteral* expr) {
+  BAILOUT("ObjectLiteral");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitArrayLiteral(ArrayLiteral* expr) {
+  BAILOUT("ArrayLiteral");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitCatchExtensionObject(
+    CatchExtensionObject* expr) {
+  BAILOUT("CatchExtensionObject");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitAssignment(Assignment* expr) {
+  // Simple assignments to (named) this properties are supported.
+  if (expr->op() != Token::ASSIGN) BAILOUT("Non-simple assignment");
+
+  Property* prop = expr->target()->AsProperty();
+  if (prop == NULL) BAILOUT("Non-property assignment");
+  VariableProxy* proxy = prop->obj()->AsVariableProxy();
+  if (proxy == NULL || !proxy->var()->is_this()) {
+    BAILOUT("Non-this-property assignment");
+  }
+  if (!prop->key()->IsPropertyName()) {
+    BAILOUT("Non-named-property assignment");
+  }
+
+  // We will only specialize for fields on the object itself.
+  // Expression::IsPropertyName implies that the name is a literal
+  // symbol but we do not assume that.
+  Literal* key = prop->key()->AsLiteral();
+  if (key != NULL && key->handle()->IsString()) {
+    Handle<Object> receiver = info()->receiver();
+    Handle<String> name = Handle<String>::cast(key->handle());
+    LookupResult lookup;
+    receiver->Lookup(*name, &lookup);
+    if (!lookup.IsProperty()) {
+      BAILOUT("Assigned property not found at compile time");
+    }
+    if (lookup.holder() != *receiver) BAILOUT("Non-own property assignment");
+    if (!lookup.type() == FIELD) BAILOUT("Non-field property assignment");
+  } else {
+    UNREACHABLE();
+    BAILOUT("Unexpected non-string-literal property key");
+  }
+
+  Visit(expr->value());
+}
+
+
+void FastCodeGenSyntaxChecker::VisitThrow(Throw* expr) {
+  BAILOUT("Throw");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitProperty(Property* expr) {
+  // We support named this property references.
+  VariableProxy* proxy = expr->obj()->AsVariableProxy();
+  if (proxy == NULL || !proxy->var()->is_this()) {
+    BAILOUT("Non-this-property reference");
+  }
+  if (!expr->key()->IsPropertyName()) {
+    BAILOUT("Non-named-property reference");
+  }
+
+  // We will only specialize for fields on the object itself.
+  // Expression::IsPropertyName implies that the name is a literal
+  // symbol but we do not assume that.
+  Literal* key = expr->key()->AsLiteral();
+  if (key != NULL && key->handle()->IsString()) {
+    Handle<Object> receiver = info()->receiver();
+    Handle<String> name = Handle<String>::cast(key->handle());
+    LookupResult lookup;
+    receiver->Lookup(*name, &lookup);
+    if (!lookup.IsProperty()) {
+      BAILOUT("Referenced property not found at compile time");
+    }
+    if (lookup.holder() != *receiver) BAILOUT("Non-own property reference");
+    if (!lookup.type() == FIELD) BAILOUT("Non-field property reference");
+  } else {
+    UNREACHABLE();
+    BAILOUT("Unexpected non-string-literal property key");
+  }
+}
+
+
+void FastCodeGenSyntaxChecker::VisitCall(Call* expr) {
+  BAILOUT("Call");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitCallNew(CallNew* expr) {
+  BAILOUT("CallNew");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitCallRuntime(CallRuntime* expr) {
+  BAILOUT("CallRuntime");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitUnaryOperation(UnaryOperation* expr) {
+  BAILOUT("UnaryOperation");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitCountOperation(CountOperation* expr) {
+  BAILOUT("CountOperation");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitBinaryOperation(BinaryOperation* expr) {
+  // We support bitwise OR.
+  switch (expr->op()) {
+    case Token::COMMA:
+      BAILOUT("BinaryOperation COMMA");
+    case Token::OR:
+      BAILOUT("BinaryOperation OR");
+    case Token::AND:
+      BAILOUT("BinaryOperation AND");
+
+    case Token::BIT_OR:
+      // We support expressions nested on the left because they only require
+      // a pair of registers to keep all intermediate values in registers
+      // (i.e., the expression stack has height no more than two).
+      if (!expr->right()->IsLeaf()) BAILOUT("expression nested on right");
+
+      // We do not allow subexpressions with side effects because we
+      // (currently) bail out to the beginning of the full function.  The
+      // only expressions with side effects that we would otherwise handle
+      // are assignments.
+      if (expr->left()->AsAssignment() != NULL ||
+          expr->right()->AsAssignment() != NULL) {
+        BAILOUT("subexpression of binary operation has side effects");
+      }
+
+      Visit(expr->left());
+      CHECK_BAILOUT;
+      Visit(expr->right());
+      break;
+
+    case Token::BIT_XOR:
+      BAILOUT("BinaryOperation BIT_XOR");
+    case Token::BIT_AND:
+      BAILOUT("BinaryOperation BIT_AND");
+    case Token::SHL:
+      BAILOUT("BinaryOperation SHL");
+    case Token::SAR:
+      BAILOUT("BinaryOperation SAR");
+    case Token::SHR:
+      BAILOUT("BinaryOperation SHR");
+    case Token::ADD:
+      BAILOUT("BinaryOperation ADD");
+    case Token::SUB:
+      BAILOUT("BinaryOperation SUB");
+    case Token::MUL:
+      BAILOUT("BinaryOperation MUL");
+    case Token::DIV:
+      BAILOUT("BinaryOperation DIV");
+    case Token::MOD:
+      BAILOUT("BinaryOperation MOD");
+    default:
+      UNREACHABLE();
+  }
+}
+
+
+void FastCodeGenSyntaxChecker::VisitCompareOperation(CompareOperation* expr) {
+  BAILOUT("CompareOperation");
+}
+
+
+void FastCodeGenSyntaxChecker::VisitThisFunction(ThisFunction* expr) {
+  BAILOUT("ThisFunction");
+}
+
+#undef BAILOUT
+#undef CHECK_BAILOUT
+
+
 #define __ ACCESS_MASM(masm())
 
+Handle<Code> FastCodeGenerator::MakeCode(CompilationInfo* info) {
+  // Label the AST before calling MakeCodePrologue, so AST node numbers are
+  // printed with the AST.
+  AstLabeler labeler;
+  labeler.Label(info);
+
+  LivenessAnalyzer analyzer;
+  analyzer.Analyze(info->function());
+
+  CodeGenerator::MakeCodePrologue(info);
+
+  const int kInitialBufferSize = 4 * KB;
+  MacroAssembler masm(NULL, kInitialBufferSize);
+
+  // Generate the fast-path code.
+  FastCodeGenerator fast_cgen(&masm);
+  fast_cgen.Generate(info);
+  if (fast_cgen.HasStackOverflow()) {
+    ASSERT(!Top::has_pending_exception());
+    return Handle<Code>::null();
+  }
+
+  // Generate the full code for the function in bailout mode, using the same
+  // macro assembler.
+  CodeGenerator cgen(&masm);
+  CodeGeneratorScope scope(&cgen);
+  info->set_mode(CompilationInfo::SECONDARY);
+  cgen.Generate(info);
+  if (cgen.HasStackOverflow()) {
+    ASSERT(!Top::has_pending_exception());
+    return Handle<Code>::null();
+  }
+
+  Code::Flags flags = Code::ComputeFlags(Code::FUNCTION, NOT_IN_LOOP);
+  return CodeGenerator::MakeCodeEpilogue(&masm, flags, info);
+}
+
+
 Register FastCodeGenerator::accumulator0() { return eax; }
 Register FastCodeGenerator::accumulator1() { return edx; }
 Register FastCodeGenerator::scratch0() { return ecx; }
@@ -155,20 +588,27 @@
       // commutative.
       __ or_(destination(), Operand(other_accumulator(destination())));
     }
-  } else if (destination().is(no_reg)) {
-    // Result is not needed but do not clobber the operands in case of
-    // bailout.
-    __ mov(scratch0(), accumulator1());
-    __ or_(scratch0(), Operand(accumulator0()));
-    __ test(scratch0(), Immediate(kSmiTagMask));
-    __ j(not_zero, bailout(), not_taken);
   } else {
-    // Preserve the destination operand in a scratch register in case of
-    // bailout.
-    __ mov(scratch0(), destination());
-    __ or_(destination(), Operand(other_accumulator(destination())));
-    __ test(destination(), Immediate(kSmiTagMask));
-    __ j(not_zero, bailout(), not_taken);
+    // Left is in accumulator1, right in accumulator0.
+    Label* bailout = NULL;
+    if (destination().is(accumulator0())) {
+      __ mov(scratch0(), accumulator0());
+      __ or_(destination(), Operand(accumulator1()));  // Or is commutative.
+      __ test(destination(), Immediate(kSmiTagMask));
+      bailout = info()->AddBailout(accumulator1(), scratch0());  // Left, right.
+    } else if (destination().is(accumulator1())) {
+      __ mov(scratch0(), accumulator1());
+      __ or_(destination(), Operand(accumulator0()));
+      __ test(destination(), Immediate(kSmiTagMask));
+      bailout = info()->AddBailout(scratch0(), accumulator0());
+    } else {
+      ASSERT(destination().is(no_reg));
+      __ mov(scratch0(), accumulator1());
+      __ or_(scratch0(), Operand(accumulator0()));
+      __ test(scratch0(), Immediate(kSmiTagMask));
+      bailout = info()->AddBailout(accumulator1(), accumulator0());
+    }
+    __ j(not_zero, bailout, not_taken);
   }
 
   // If we didn't bailout, the result (in fact, both inputs too) is known to
@@ -191,6 +631,7 @@
   // Note that we keep a live register reference to esi (context) at this
   // point.
 
+  Label* bailout_to_beginning = info()->AddBailout();
   // Receiver (this) is allocated to a fixed register.
   if (info()->has_this_properties()) {
     Comment cmnt(masm(), ";; MapCheck(this)");
@@ -201,7 +642,7 @@
     Handle<HeapObject> object = Handle<HeapObject>::cast(info()->receiver());
     Handle<Map> map(object->map());
     EmitLoadReceiver();
-    __ CheckMap(receiver_reg(), map, bailout(), false);
+    __ CheckMap(receiver_reg(), map, bailout_to_beginning, false);
   }
 
   // If there is a global variable access check if the global object is the
@@ -214,7 +655,7 @@
     ASSERT(info()->has_global_object());
     Handle<Map> map(info()->global_object()->map());
     __ mov(scratch0(), CodeGenerator::GlobalObject());
-    __ CheckMap(scratch0(), map, bailout(), true);
+    __ CheckMap(scratch0(), map, bailout_to_beginning, true);
   }
 
   VisitStatements(function()->body());
@@ -227,11 +668,286 @@
   __ mov(esp, ebp);
   __ pop(ebp);
   __ ret((scope()->num_parameters() + 1) * kPointerSize);
-
-  __ bind(&bailout_);
 }
 
 
+void FastCodeGenerator::VisitDeclaration(Declaration* decl) {
+  UNREACHABLE();
+}
+
+
+void FastCodeGenerator::VisitBlock(Block* stmt) {
+  VisitStatements(stmt->statements());
+}
+
+
+void FastCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) {
+  Visit(stmt->expression());
+}
+
+
+void FastCodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) {
+  // Nothing to do.
+}
+
+
+void FastCodeGenerator::VisitIfStatement(IfStatement* stmt) {
+  UNREACHABLE();
+}
+
+
+void FastCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) {
+  UNREACHABLE();
+}
+
+
+void FastCodeGenerator::VisitBreakStatement(BreakStatement* stmt) {
+  UNREACHABLE();
+}
+
+
+void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
+  UNREACHABLE();
+}
+
+
+void FastCodeGenerator::VisitWithEnterStatement(WithEnterStatement* stmt) {
+  UNREACHABLE();
+}
+
+
+void FastCodeGenerator::VisitWithExitStatement(WithExitStatement* stmt) {
+  UNREACHABLE();
+}
+
+
+void FastCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
+  UNREACHABLE();
+}
+
+
+void FastCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
+  UNREACHABLE();
+}
+
+
+void FastCodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
+  UNREACHABLE();
+}
+
+
+void FastCodeGenerator::VisitForStatement(ForStatement* stmt) {
+  UNREACHABLE();
+}
+
+
+void FastCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
+  UNREACHABLE();
+}
+
+
+void FastCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
+  UNREACHABLE();
+}
+
+
+void FastCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
+  UNREACHABLE();
+}
+
+
+void FastCodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) {
+  UNREACHABLE();
+}
+
+
+void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
+  UNREACHABLE();
+}
+
+
+void FastCodeGenerator::VisitFunctionBoilerplateLiteral(
+    FunctionBoilerplateLiteral* expr) {
+  UNREACHABLE();
+}
+
+
+void FastCodeGenerator::VisitConditional(Conditional* expr) {
+  UNREACHABLE();
+}
+
+
+void FastCodeGenerator::VisitSlot(Slot* expr) {
+  UNREACHABLE();
+}
+
+
+void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
+  ASSERT(expr->var()->is_global() && !expr->var()->is_this());
+  // Check if we can compile a global variable load directly from the cell.
+  ASSERT(info()->has_global_object());
+  LookupResult lookup;
+  info()->global_object()->Lookup(*expr->name(), &lookup);
+  // We only support normal (non-accessor/interceptor) DontDelete properties
+  // for now.
+  ASSERT(lookup.IsProperty());
+  ASSERT_EQ(NORMAL, lookup.type());
+  ASSERT(lookup.IsDontDelete());
+  Handle<Object> cell(info()->global_object()->GetPropertyCell(&lookup));
+
+  // Global variable lookups do not have side effects, so we do not need to
+  // emit code if we are in an effect context.
+  if (!destination().is(no_reg)) {
+    Comment cmnt(masm(), ";; Global");
+    if (FLAG_print_ir) {
+      SmartPointer<char> name = expr->name()->ToCString();
+      PrintF("%d: t%d = Global(%s)  // last_use = %d\n", expr->num(),
+             expr->num(), *name, expr->var_def()->last_use()->num());
+    }
+    EmitGlobalVariableLoad(cell);
+  }
+}
+
+
+void FastCodeGenerator::VisitLiteral(Literal* expr) {
+  UNREACHABLE();
+}
+
+
+void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
+  UNREACHABLE();
+}
+
+
+void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
+  UNREACHABLE();
+}
+
+
+void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
+  UNREACHABLE();
+}
+
+
+void FastCodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* expr) {
+  UNREACHABLE();
+}
+
+
+void FastCodeGenerator::VisitAssignment(Assignment* expr) {
+  // Known to be a simple this property assignment.  Effectively a unary
+  // operation.
+  { Register my_destination = destination();
+    set_destination(accumulator0());
+    Visit(expr->value());
+    set_destination(my_destination);
+  }
+
+  Property* prop = expr->target()->AsProperty();
+  ASSERT_NOT_NULL(prop);
+  ASSERT_NOT_NULL(prop->obj()->AsVariableProxy());
+  ASSERT(prop->obj()->AsVariableProxy()->var()->is_this());
+  ASSERT(prop->key()->IsPropertyName());
+  Handle<String> name =
+      Handle<String>::cast(prop->key()->AsLiteral()->handle());
+
+  Comment cmnt(masm(), ";; Store to this");
+  if (FLAG_print_ir) {
+    SmartPointer<char> name_string = name->ToCString();
+    PrintF("%d: ", expr->num());
+    if (!destination().is(no_reg)) PrintF("t%d = ", expr->num());
+    PrintF("Store(this, \"%s\", t%d)  // last_use(this) = %d\n", *name_string,
+           expr->value()->num(),
+           expr->var_def()->last_use()->num());
+  }
+
+  EmitThisPropertyStore(name);
+}
+
+
+void FastCodeGenerator::VisitThrow(Throw* expr) {
+  UNREACHABLE();
+}
+
+
+void FastCodeGenerator::VisitProperty(Property* expr) {
+  ASSERT_NOT_NULL(expr->obj()->AsVariableProxy());
+  ASSERT(expr->obj()->AsVariableProxy()->var()->is_this());
+  ASSERT(expr->key()->IsPropertyName());
+  if (!destination().is(no_reg)) {
+    Handle<String> name =
+        Handle<String>::cast(expr->key()->AsLiteral()->handle());
+
+    Comment cmnt(masm(), ";; Load from this");
+    if (FLAG_print_ir) {
+      SmartPointer<char> name_string = name->ToCString();
+      PrintF("%d: t%d = Load(this, \"%s\")  // last_use(this) = %d\n",
+             expr->num(), expr->num(), *name_string,
+             expr->var_def()->last_use()->num());
+    }
+    EmitThisPropertyLoad(name);
+  }
+}
+
+
+void FastCodeGenerator::VisitCall(Call* expr) {
+  UNREACHABLE();
+}
+
+
+void FastCodeGenerator::VisitCallNew(CallNew* expr) {
+  UNREACHABLE();
+}
+
+
+void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
+  UNREACHABLE();
+}
+
+
+void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
+  UNREACHABLE();
+}
+
+
+void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
+  UNREACHABLE();
+}
+
+
+void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
+  // We support limited binary operations: bitwise OR only allowed to be
+  // nested on the left.
+  ASSERT(expr->op() == Token::BIT_OR);
+  ASSERT(expr->right()->IsLeaf());
+
+  { Register my_destination = destination();
+    set_destination(accumulator1());
+    Visit(expr->left());
+    set_destination(accumulator0());
+    Visit(expr->right());
+    set_destination(my_destination);
+  }
+
+  Comment cmnt(masm(), ";; BIT_OR");
+  if (FLAG_print_ir) {
+    PrintF("%d: ", expr->num());
+    if (!destination().is(no_reg)) PrintF("t%d = ", expr->num());
+    PrintF("BIT_OR(t%d, t%d)\n", expr->left()->num(), expr->right()->num());
+  }
+  EmitBitOr();
+}
+
+
+void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
+  UNREACHABLE();
+}
+
+
+void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) {
+  UNREACHABLE();
+}
+
 #undef __
 
 
diff --git a/src/ia32/fast-codegen-ia32.h b/src/ia32/fast-codegen-ia32.h
new file mode 100644
index 0000000..e0851af
--- /dev/null
+++ b/src/ia32/fast-codegen-ia32.h
@@ -0,0 +1,155 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_FAST_CODEGEN_IA32_H_
+#define V8_FAST_CODEGEN_IA32_H_
+
+#include "v8.h"
+
+#include "ast.h"
+#include "compiler.h"
+#include "list.h"
+
+namespace v8 {
+namespace internal {
+
+class FastCodeGenSyntaxChecker: public AstVisitor {
+ public:
+  explicit FastCodeGenSyntaxChecker()
+      : info_(NULL), has_supported_syntax_(true) {
+  }
+
+  void Check(CompilationInfo* info);
+
+  CompilationInfo* info() { return info_; }
+  bool has_supported_syntax() { return has_supported_syntax_; }
+
+ private:
+  void VisitDeclarations(ZoneList<Declaration*>* decls);
+  void VisitStatements(ZoneList<Statement*>* stmts);
+
+  // AST node visit functions.
+#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
+  AST_NODE_LIST(DECLARE_VISIT)
+#undef DECLARE_VISIT
+
+  CompilationInfo* info_;
+  bool has_supported_syntax_;
+
+  DISALLOW_COPY_AND_ASSIGN(FastCodeGenSyntaxChecker);
+};
+
+
+class FastCodeGenerator: public AstVisitor {
+ public:
+  explicit FastCodeGenerator(MacroAssembler* masm)
+      : masm_(masm), info_(NULL), destination_(no_reg), smi_bits_(0) {
+  }
+
+  static Handle<Code> MakeCode(CompilationInfo* info);
+
+  void Generate(CompilationInfo* compilation_info);
+
+ private:
+  MacroAssembler* masm() { return masm_; }
+  CompilationInfo* info() { return info_; }
+
+  Register destination() { return destination_; }
+  void set_destination(Register reg) { destination_ = reg; }
+
+  FunctionLiteral* function() { return info_->function(); }
+  Scope* scope() { return info_->scope(); }
+
+  // Platform-specific fixed registers, all guaranteed distinct.
+  Register accumulator0();
+  Register accumulator1();
+  Register scratch0();
+  Register scratch1();
+  Register receiver_reg();
+  Register context_reg();
+
+  Register other_accumulator(Register reg) {
+    ASSERT(reg.is(accumulator0()) || reg.is(accumulator1()));
+    return (reg.is(accumulator0())) ? accumulator1() : accumulator0();
+  }
+
+  // Flags are true if the respective register is statically known to hold a
+  // smi.  We do not track every register, only the accumulator registers.
+  bool is_smi(Register reg) {
+    ASSERT(!reg.is(no_reg));
+    return (smi_bits_ & reg.bit()) != 0;
+  }
+  void set_as_smi(Register reg) {
+    ASSERT(!reg.is(no_reg));
+    smi_bits_ = smi_bits_ | reg.bit();
+  }
+  void clear_as_smi(Register reg) {
+    ASSERT(!reg.is(no_reg));
+    smi_bits_ = smi_bits_ & ~reg.bit();
+  }
+
+  // AST node visit functions.
+#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
+  AST_NODE_LIST(DECLARE_VISIT)
+#undef DECLARE_VISIT
+
+  // Emit code to load the receiver from the stack into receiver_reg.
+  void EmitLoadReceiver();
+
+  // Emit code to load a global variable directly from a global property
+  // cell into the destination register.
+  void EmitGlobalVariableLoad(Handle<Object> cell);
+
+  // Emit a store to an own property of this.  The stored value is expected
+  // in accumulator0 and the receiver in receiver_reg.  The receiver
+  // register is preserved and the result (the stored value) is left in the
+  // destination register.
+  void EmitThisPropertyStore(Handle<String> name);
+
+  // Emit a load from an own property of this.  The receiver is expected in
+  // receiver_reg.  The receiver register is preserved and the result is
+  // left in the destination register.
+  void EmitThisPropertyLoad(Handle<String> name);
+
+  // Emit a bitwise or operation.  The left operand is in accumulator1 and
+  // the right is in accumulator0.  The result should be left in the
+  // destination register.
+  void EmitBitOr();
+
+  MacroAssembler* masm_;
+  CompilationInfo* info_;
+
+  Register destination_;
+  uint32_t smi_bits_;
+
+  DISALLOW_COPY_AND_ASSIGN(FastCodeGenerator);
+};
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_FAST_CODEGEN_IA32_H_
diff --git a/src/ia32/virtual-frame-ia32.cc b/src/ia32/virtual-frame-ia32.cc
index d248539..7df028e 100644
--- a/src/ia32/virtual-frame-ia32.cc
+++ b/src/ia32/virtual-frame-ia32.cc
@@ -948,47 +948,38 @@
 }
 
 
-Result VirtualFrame::CallStoreIC() {
-  // Name, value, and receiver are on top of the frame.  The IC
-  // expects name in ecx, value in eax, and receiver in edx.
+Result VirtualFrame::CallStoreIC(Handle<String> name, bool is_contextual) {
+  // Value and (if not contextual) receiver are on top of the frame.
+  //  The IC expects name in ecx, value in eax, and receiver in edx.
   Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
-  Result name = Pop();
   Result value = Pop();
-  Result receiver = Pop();
-  PrepareForCall(0, 0);
-
-  // Optimized for case in which name is a constant value.
-  if (name.is_register() && (name.reg().is(edx) || name.reg().is(eax))) {
-    if (!is_used(ecx)) {
-      name.ToRegister(ecx);
-    } else if (!is_used(ebx)) {
-      name.ToRegister(ebx);
-    } else {
-      ASSERT(!is_used(edi));  // Only three results are live, so edi is free.
-      name.ToRegister(edi);
-    }
-  }
-  // Now name is not in edx or eax, so we can fix them, then move name to ecx.
-  if (value.is_register() && value.reg().is(edx)) {
-    if (receiver.is_register() && receiver.reg().is(eax)) {
-      // Wrong registers.
-      __ xchg(eax, edx);
-    } else {
-      // Register eax is free for value, which frees edx for receiver.
-      value.ToRegister(eax);
-      receiver.ToRegister(edx);
-    }
-  } else {
-    // Register edx is free for receiver, which guarantees eax is free for
-    // value.
-    receiver.ToRegister(edx);
+  if (is_contextual) {
+    PrepareForCall(0, 0);
     value.ToRegister(eax);
+    __ mov(edx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
+    __ mov(ecx, name);
+  } else {
+    Result receiver = Pop();
+    PrepareForCall(0, 0);
+
+    if (value.is_register() && value.reg().is(edx)) {
+      if (receiver.is_register() && receiver.reg().is(eax)) {
+        // Wrong registers.
+        __ xchg(eax, edx);
+      } else {
+        // Register eax is free for value, which frees edx for receiver.
+        value.ToRegister(eax);
+        receiver.ToRegister(edx);
+      }
+    } else {
+      // Register edx is free for receiver, which guarantees eax is free for
+      // value.
+      receiver.ToRegister(edx);
+      value.ToRegister(eax);
+    }
   }
-  // Receiver and value are in the right place, so ecx is free for name.
-  name.ToRegister(ecx);
-  name.Unuse();
+  __ mov(ecx, name);
   value.Unuse();
-  receiver.Unuse();
   return RawCallCodeObject(ic, RelocInfo::CODE_TARGET);
 }
 
@@ -1175,6 +1166,25 @@
 }
 
 
+void VirtualFrame::Push(Expression* expr) {
+  ASSERT(expr->IsTrivial());
+
+  Literal* lit = expr->AsLiteral();
+  if (lit != NULL) {
+    Push(lit->handle());
+    return;
+  }
+
+  VariableProxy* proxy = expr->AsVariableProxy();
+  if (proxy != NULL && proxy->is_this()) {
+    PushParameterAt(-1);
+    return;
+  }
+
+  UNREACHABLE();
+}
+
+
 #undef __
 
 } }  // namespace v8::internal
diff --git a/src/ia32/virtual-frame-ia32.h b/src/ia32/virtual-frame-ia32.h
index b078ba0..7be593c 100644
--- a/src/ia32/virtual-frame-ia32.h
+++ b/src/ia32/virtual-frame-ia32.h
@@ -339,12 +339,12 @@
   Result CallLoadIC(RelocInfo::Mode mode);
 
   // Call keyed load IC.  Key and receiver are found on top of the
-  // frame.  They are not dropped.
+  // frame.  Both are dropped.
   Result CallKeyedLoadIC(RelocInfo::Mode mode);
 
-  // Call store IC.  Name, value, and receiver are found on top of the
-  // frame.  Receiver is not dropped.
-  Result CallStoreIC();
+  // Call store IC.  If the load is contextual, value is found on top of the
+  // frame.  If not, value and receiver are on the frame.  Both are dropped.
+  Result CallStoreIC(Handle<String> name, bool is_contextual);
 
   // Call keyed store IC.  Value, key, and receiver are found on top
   // of the frame.  Key and receiver are not dropped.
@@ -415,6 +415,10 @@
     result->Unuse();
   }
 
+  // Pushing an expression expects that the expression is trivial (according
+  // to Expression::IsTrivial).
+  void Push(Expression* expr);
+
   // Nip removes zero or more elements from immediately below the top
   // of the frame, leaving the previous top-of-frame value on top of
   // the frame.  Nip(k) is equivalent to x = Pop(), Drop(k), Push(x).
diff --git a/src/jump-target-inl.h b/src/jump-target-inl.h
index dcd615e..3cd9a8b 100644
--- a/src/jump-target-inl.h
+++ b/src/jump-target-inl.h
@@ -42,7 +42,7 @@
   } else if (target->is_copy()) {
     entry_frame_->elements_[target->index()].set_copied();
   }
-  if (direction_ == BIDIRECTIONAL) {
+  if (direction_ == BIDIRECTIONAL && !target->is_copy()) {
     entry_frame_->elements_[index].set_number_info(NumberInfo::kUnknown);
   }
 }
diff --git a/src/jump-target.cc b/src/jump-target.cc
index 66764e6..bce379a 100644
--- a/src/jump-target.cc
+++ b/src/jump-target.cc
@@ -105,7 +105,6 @@
         FrameElement* other = &reaching_frames_[j]->elements_[i];
         if (element != NULL && !element->is_copy()) {
           ASSERT(other != NULL);
-          ASSERT(!other->is_copy());
           // We overwrite the number information of one of the incoming frames.
           // This is safe because we only use the frame for emitting merge code.
           // The number information of incoming frames is not used anymore.
@@ -128,7 +127,6 @@
     // elements as copied exactly when they have a copy.  Undetermined
     // elements are initially recorded as if in memory.
     if (target != NULL) {
-      ASSERT(!target->is_copy());  // These initial elements are never copies.
       entry_frame_->elements_[index] = *target;
       InitializeEntryElement(index, target);
     }
diff --git a/src/macros.py b/src/macros.py
index c160b49..ccc2037 100644
--- a/src/macros.py
+++ b/src/macros.py
@@ -74,6 +74,10 @@
 const kMonthShift         = 5;
 
 # Type query macros.
+#
+# Note: We have special support for typeof(foo) === 'bar' in the compiler.
+#       It will *not* generate a runtime typeof call for the most important
+#       values of 'bar'.
 macro IS_NULL(arg)              = (arg === null);
 macro IS_NULL_OR_UNDEFINED(arg) = (arg == null);
 macro IS_UNDEFINED(arg)         = (typeof(arg) === 'undefined');
@@ -83,7 +87,7 @@
 macro IS_OBJECT(arg)            = (%_IsObject(arg));
 macro IS_ARRAY(arg)             = (%_IsArray(arg));
 macro IS_FUNCTION(arg)          = (%_IsFunction(arg));
-macro IS_REGEXP(arg)            = (%_ClassOf(arg) === 'RegExp');
+macro IS_REGEXP(arg)            = (%_IsRegExp(arg));
 macro IS_DATE(arg)              = (%_ClassOf(arg) === 'Date');
 macro IS_NUMBER_WRAPPER(arg)    = (%_ClassOf(arg) === 'Number');
 macro IS_STRING_WRAPPER(arg)    = (%_ClassOf(arg) === 'String');
@@ -97,9 +101,11 @@
 
 # Inline macros. Use %IS_VAR to make sure arg is evaluated only once.
 macro NUMBER_IS_NAN(arg) = (!%_IsSmi(%IS_VAR(arg)) && !(arg == arg));
-macro TO_INTEGER(arg)    = (%_IsSmi(%IS_VAR(arg)) ? arg : ToInteger(arg));
-macro TO_INT32(arg)      = (%_IsSmi(%IS_VAR(arg)) ? arg : (arg >> 0));
-macro TO_UINT32(arg)     = (arg >>> 0);
+macro TO_INTEGER(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : ToInteger(arg));
+macro TO_INT32(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : (arg >> 0));
+macro TO_UINT32(arg) = (arg >>> 0);
+macro TO_STRING_INLINE(arg) = (IS_STRING(%IS_VAR(arg)) ? arg : NonStringToString(arg));
+
 
 # Macros implemented in Python.
 python macro CHAR_CODE(str) = ord(str[1]);
diff --git a/src/mips/codegen-mips.cc b/src/mips/codegen-mips.cc
index 5a27c28..2de45f6 100644
--- a/src/mips/codegen-mips.cc
+++ b/src/mips/codegen-mips.cc
@@ -305,6 +305,11 @@
 }
 
 
+void CodeGenerator::GenerateIsRegExp(ZoneList<Expression*>* args) {
+  UNIMPLEMENTED_MIPS();
+}
+
+
 void CodeGenerator::GenerateIsConstructCall(ZoneList<Expression*>* args) {
   UNIMPLEMENTED_MIPS();
 }
@@ -365,6 +370,11 @@
 }
 
 
+void CodeGenerator::GenerateNumberToString(ZoneList<Expression*>* args) {
+  UNIMPLEMENTED_MIPS();
+}
+
+
 void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
   UNIMPLEMENTED_MIPS();
 }
@@ -498,4 +508,3 @@
 #undef __
 
 } }  // namespace v8::internal
-
diff --git a/src/mips/codegen-mips.h b/src/mips/codegen-mips.h
index 05138bc..147b872 100644
--- a/src/mips/codegen-mips.h
+++ b/src/mips/codegen-mips.h
@@ -210,6 +210,7 @@
   void GenerateIsSmi(ZoneList<Expression*>* args);
   void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
   void GenerateIsArray(ZoneList<Expression*>* args);
+  void GenerateIsRegExp(ZoneList<Expression*>* args);
 
   // Support for construct call checks.
   void GenerateIsConstructCall(ZoneList<Expression*>* args);
@@ -241,6 +242,8 @@
   void GenerateSubString(ZoneList<Expression*>* args);
   void GenerateStringCompare(ZoneList<Expression*>* args);
   void GenerateRegExpExec(ZoneList<Expression*>* args);
+  void GenerateNumberToString(ZoneList<Expression*>* args);
+
 
   // Fast support for Math.sin and Math.cos.
   inline void GenerateMathSin(ZoneList<Expression*>* args);
@@ -308,4 +311,3 @@
 } }  // namespace v8::internal
 
 #endif  // V8_MIPS_CODEGEN_MIPS_H_
-
diff --git a/src/mirror-delay.js b/src/mirror-delay.js
index e1bedfd..7c743ec 100644
--- a/src/mirror-delay.js
+++ b/src/mirror-delay.js
@@ -553,14 +553,16 @@
   return this.value_.length;
 };
 
+StringMirror.prototype.getTruncatedValue = function(maxLength) {
+  if (maxLength != -1 && this.length() > maxLength) {
+    return this.value_.substring(0, maxLength) +
+           '... (length: ' + this.length() + ')';
+  }
+  return this.value_;
+}
 
 StringMirror.prototype.toText = function() {
-  if (this.length() > kMaxProtocolStringLength) {
-    return this.value_.substring(0, kMaxProtocolStringLength) +
-           '... (length: ' + this.length() + ')';
-  } else {
-    return this.value_;
-  }
+  return this.getTruncatedValue(kMaxProtocolStringLength);
 }
 
 
@@ -1955,6 +1957,15 @@
 }
 
 
+JSONProtocolSerializer.prototype.maxStringLength_ = function() {
+  if (IS_UNDEFINED(this.options_) ||
+      IS_UNDEFINED(this.options_.maxStringLength)) {
+    return kMaxProtocolStringLength;
+  }
+  return this.options_.maxStringLength;
+}
+
+
 JSONProtocolSerializer.prototype.add_ = function(mirror) {
   // If this mirror is already in the list just return.
   for (var i = 0; i < this.mirrors_.length; i++) {
@@ -1987,8 +1998,7 @@
       o.value = mirror.value();
       break;
     case STRING_TYPE:
-      // Limit string length.
-      o.value = mirror.toText();
+      o.value = mirror.getTruncatedValue(this.maxStringLength_());
       break;
     case FUNCTION_TYPE:
       o.name = mirror.name();
@@ -2052,11 +2062,12 @@
 
     case STRING_TYPE:
       // String values might have their value cropped to keep down size.
-      if (mirror.length() > kMaxProtocolStringLength) {
-        var str = mirror.value().substring(0, kMaxProtocolStringLength);
+      if (this.maxStringLength_() != -1 &&
+          mirror.length() > this.maxStringLength_()) {
+        var str = mirror.getTruncatedValue(this.maxStringLength_());
         content.value = str;
         content.fromIndex = 0;
-        content.toIndex = kMaxProtocolStringLength;
+        content.toIndex = this.maxStringLength_();
       } else {
         content.value = mirror.value();
       }
diff --git a/src/objects.h b/src/objects.h
index 3ed0a70..7533892 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -179,7 +179,7 @@
   class TypeField:       public BitField<PropertyType,       0, 3> {};
   class AttributesField: public BitField<PropertyAttributes, 3, 3> {};
   class DeletedField:    public BitField<uint32_t,           6, 1> {};
-  class IndexField:      public BitField<uint32_t,           7, 31-7> {};
+  class IndexField:      public BitField<uint32_t,           7, 32-7> {};
 
   static const int kInitialIndex = 1;
  private:
diff --git a/src/register-allocator.h b/src/register-allocator.h
index 4ec0bb4..747200a 100644
--- a/src/register-allocator.h
+++ b/src/register-allocator.h
@@ -141,7 +141,7 @@
 
   class TypeField: public BitField<Type, 0, 2> {};
   class NumberInfoField : public BitField<NumberInfo::Type, 2, 3> {};
-  class DataField: public BitField<uint32_t, 5, 32 - 6> {};
+  class DataField: public BitField<uint32_t, 5, 32 - 5> {};
 
   inline void CopyTo(Result* destination) const;
 
diff --git a/src/runtime.cc b/src/runtime.cc
index 38e332b..6459aa7 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -2276,6 +2276,20 @@
   return -1;
 }
 
+
+template <typename schar>
+static int SingleCharLastIndexOf(Vector<const schar> string,
+                                 schar pattern_char,
+                                 int start_index) {
+  for (int i = start_index; i >= 0; i--) {
+    if (pattern_char == string[i]) {
+      return i;
+    }
+  }
+  return -1;
+}
+
+
 // Trivial string search for shorter strings.
 // On return, if "complete" is set to true, the return value is the
 // final result of searching for the patter in the subject.
@@ -2352,7 +2366,7 @@
   // We have an ASCII haystack and a non-ASCII needle. Check if there
   // really is a non-ASCII character in the needle and bail out if there
   // is.
-  if (sizeof(pchar) > 1 && sizeof(schar) == 1) {
+  if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
     for (int i = 0; i < pat.length(); i++) {
       uc16 c = pat[i];
       if (c > String::kMaxAsciiCharCode) {
@@ -2455,39 +2469,115 @@
 }
 
 
+template <typename schar, typename pchar>
+static int StringMatchBackwards(Vector<const schar> sub,
+                                Vector<const pchar> pat,
+                                int idx) {
+  ASSERT(pat.length() >= 1);
+  ASSERT(idx + pat.length() <= sub.length());
+
+  if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
+    for (int i = 0; i < pat.length(); i++) {
+      uc16 c = pat[i];
+      if (c > String::kMaxAsciiCharCode) {
+        return -1;
+      }
+    }
+  }
+
+  pchar pattern_first_char = pat[0];
+  for (int i = idx; i >= 0; i--) {
+    if (sub[i] != pattern_first_char) continue;
+    int j = 1;
+    while (j < pat.length()) {
+      if (pat[j] != sub[i+j]) {
+        break;
+      }
+      j++;
+    }
+    if (j == pat.length()) {
+      return i;
+    }
+  }
+  return -1;
+}
+
 static Object* Runtime_StringLastIndexOf(Arguments args) {
-  NoHandleAllocation ha;
+  HandleScope scope;  // create a new handle scope
   ASSERT(args.length() == 3);
 
-  CONVERT_CHECKED(String, sub, args[0]);
-  CONVERT_CHECKED(String, pat, args[1]);
+  CONVERT_ARG_CHECKED(String, sub, 0);
+  CONVERT_ARG_CHECKED(String, pat, 1);
+
   Object* index = args[2];
-
-  sub->TryFlattenIfNotFlat();
-  pat->TryFlattenIfNotFlat();
-
   uint32_t start_index;
   if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1);
 
-  uint32_t pattern_length = pat->length();
+  uint32_t pat_length = pat->length();
   uint32_t sub_length = sub->length();
 
-  if (start_index + pattern_length > sub_length) {
-    start_index = sub_length - pattern_length;
+  if (start_index + pat_length > sub_length) {
+    start_index = sub_length - pat_length;
   }
 
-  for (int i = start_index; i >= 0; i--) {
-    bool found = true;
-    for (uint32_t j = 0; j < pattern_length; j++) {
-      if (sub->Get(i + j) != pat->Get(j)) {
-        found = false;
-        break;
+  if (pat_length == 0) {
+    return Smi::FromInt(start_index);
+  }
+
+  if (!sub->IsFlat()) {
+    FlattenString(sub);
+  }
+
+  if (pat_length == 1) {
+    AssertNoAllocation no_heap_allocation;  // ensure vectors stay valid
+    if (sub->IsAsciiRepresentation()) {
+      uc16 pchar = pat->Get(0);
+      if (pchar > String::kMaxAsciiCharCode) {
+        return Smi::FromInt(-1);
       }
+      return Smi::FromInt(SingleCharLastIndexOf(sub->ToAsciiVector(),
+                                                static_cast<char>(pat->Get(0)),
+                                                start_index));
+    } else {
+      return Smi::FromInt(SingleCharLastIndexOf(sub->ToUC16Vector(),
+                                                pat->Get(0),
+                                                start_index));
     }
-    if (found) return Smi::FromInt(i);
   }
 
-  return Smi::FromInt(-1);
+  if (!pat->IsFlat()) {
+    FlattenString(pat);
+  }
+
+  AssertNoAllocation no_heap_allocation;  // ensure vectors stay valid
+
+  int position = -1;
+
+  if (pat->IsAsciiRepresentation()) {
+    Vector<const char> pat_vector = pat->ToAsciiVector();
+    if (sub->IsAsciiRepresentation()) {
+      position = StringMatchBackwards(sub->ToAsciiVector(),
+                                      pat_vector,
+                                      start_index);
+    } else {
+      position = StringMatchBackwards(sub->ToUC16Vector(),
+                                      pat_vector,
+                                      start_index);
+    }
+  } else {
+    Vector<const uc16> pat_vector = pat->ToUC16Vector();
+    if (sub->IsAsciiRepresentation()) {
+      position = StringMatchBackwards(sub->ToAsciiVector(),
+                                      pat_vector,
+                                      start_index);
+    } else {
+      position = StringMatchBackwards(sub->ToUC16Vector(),
+                                      pat_vector,
+                                      start_index);
+    }
+  }
+
+  return Smi::FromInt(position);
 }
 
 
diff --git a/src/runtime.js b/src/runtime.js
index 231763c..e9d9848 100644
--- a/src/runtime.js
+++ b/src/runtime.js
@@ -529,6 +529,13 @@
   return (IS_NULL(x)) ? 'null' : %ToString(%DefaultString(x));
 }
 
+function NonStringToString(x) {
+  if (IS_NUMBER(x)) return %NumberToString(x);
+  if (IS_BOOLEAN(x)) return x ? 'true' : 'false';
+  if (IS_UNDEFINED(x)) return 'undefined';
+  return (IS_NULL(x)) ? 'null' : %ToString(%DefaultString(x));
+}
+
 
 // ECMA-262, section 9.9, page 36.
 function ToObject(x) {
diff --git a/src/scopeinfo.cc b/src/scopeinfo.cc
index 8b989d7..de1841b 100644
--- a/src/scopeinfo.cc
+++ b/src/scopeinfo.cc
@@ -536,7 +536,7 @@
   // Uses only lower 32 bits if pointers are larger.
   uintptr_t addr_hash =
       static_cast<uint32_t>(reinterpret_cast<uintptr_t>(code)) >> 2;
-  return (addr_hash ^ name->Hash()) % kLength;
+  return static_cast<int>((addr_hash ^ name->Hash()) % kLength);
 }
 
 
diff --git a/src/serialize.cc b/src/serialize.cc
index bc934fb..0819ec2 100644
--- a/src/serialize.cc
+++ b/src/serialize.cc
@@ -852,10 +852,10 @@
   const int max_shift = ((kPointerSize * kBitsPerByte) / 7) * 7;
   for (int shift = max_shift; shift > 0; shift -= 7) {
     if (integer >= static_cast<uintptr_t>(1u) << shift) {
-      Put(((integer >> shift) & 0x7f) | 0x80, "IntPart");
+      Put((static_cast<int>((integer >> shift)) & 0x7f) | 0x80, "IntPart");
     }
   }
-  PutSection(integer & 0x7f, "IntLastPart");
+  PutSection(static_cast<int>(integer & 0x7f), "IntLastPart");
 }
 
 #ifdef DEBUG
diff --git a/src/spaces-inl.h b/src/spaces-inl.h
index 4fd8a6c..72f8305 100644
--- a/src/spaces-inl.h
+++ b/src/spaces-inl.h
@@ -183,7 +183,7 @@
 
 int MemoryAllocator::GetChunkId(Page* p) {
   ASSERT(p->is_valid());
-  return p->opaque_header & Page::kPageAlignmentMask;
+  return static_cast<int>(p->opaque_header & Page::kPageAlignmentMask);
 }
 
 
diff --git a/src/string.js b/src/string.js
index ba01ed6..49f403d 100644
--- a/src/string.js
+++ b/src/string.js
@@ -34,7 +34,7 @@
 
 // Set the String function and constructor.
 %SetCode($String, function(x) {
-  var value = %_ArgumentsLength() == 0 ? '' : ToString(x);
+  var value = %_ArgumentsLength() == 0 ? '' : TO_STRING_INLINE(x);
   if (%_IsConstructCall()) {
     %_SetValueOf(this, value);
   } else {
@@ -64,7 +64,7 @@
 function StringCharAt(pos) {
   var char_code = %_FastCharCodeAt(this, pos);
   if (!%_IsSmi(char_code)) {
-    var subject = ToString(this);
+    var subject = TO_STRING_INLINE(this);
     var index = TO_INTEGER(pos);
     if (index >= subject.length || index < 0) return "";
     char_code = %StringCharCodeAt(subject, index);
@@ -79,7 +79,7 @@
   if (%_IsSmi(fast_answer)) {
     return fast_answer;
   }
-  var subject = ToString(this);
+  var subject = TO_STRING_INLINE(this);
   var index = TO_INTEGER(pos);
   return %StringCharCodeAt(subject, index);
 }
@@ -88,7 +88,7 @@
 // ECMA-262, section 15.5.4.6
 function StringConcat() {
   var len = %_ArgumentsLength();
-  var this_as_string = IS_STRING(this) ? this : ToString(this);
+  var this_as_string = TO_STRING_INLINE(this);
   if (len === 1) {
     return this_as_string + %_Arguments(0);
   }
@@ -96,7 +96,7 @@
   parts[0] = this_as_string;
   for (var i = 0; i < len; i++) {
     var part = %_Arguments(i);
-    parts[i + 1] = IS_STRING(part) ? part : ToString(part);
+    parts[i + 1] = TO_STRING_INLINE(part);
   }
   return %StringBuilderConcat(parts, len + 1, "");
 }
@@ -107,8 +107,8 @@
 
 // ECMA-262 section 15.5.4.7
 function StringIndexOf(searchString /* position */) {  // length == 1
-  var subject_str = ToString(this);
-  var pattern_str = ToString(searchString);
+  var subject_str = TO_STRING_INLINE(this);
+  var pattern_str = TO_STRING_INLINE(searchString);
   var subject_str_len = subject_str.length;
   var pattern_str_len = pattern_str.length;
   var index = 0;
@@ -125,9 +125,9 @@
 
 // ECMA-262 section 15.5.4.8
 function StringLastIndexOf(searchString /* position */) {  // length == 1
-  var sub = ToString(this);
+  var sub = TO_STRING_INLINE(this);
   var subLength = sub.length;
-  var pat = ToString(searchString);
+  var pat = TO_STRING_INLINE(searchString);
   var patLength = pat.length;
   var index = subLength - patLength;
   if (%_ArgumentsLength() > 1) {
@@ -156,8 +156,8 @@
 function StringLocaleCompare(other) {
   if (%_ArgumentsLength() === 0) return 0;
 
-  var this_str = ToString(this);
-  var other_str = ToString(other);
+  var this_str = TO_STRING_INLINE(this);
+  var other_str = TO_STRING_INLINE(other);
   return %StringLocaleCompare(this_str, other_str);
 }
 
@@ -165,7 +165,7 @@
 // ECMA-262 section 15.5.4.10
 function StringMatch(regexp) {
   if (!IS_REGEXP(regexp)) regexp = new ORIGINAL_REGEXP(regexp);
-  var subject = ToString(this);
+  var subject = TO_STRING_INLINE(this);
 
   if (!regexp.global) return regexp.exec(subject);
   %_Log('regexp', 'regexp-match,%0S,%1r', [subject, regexp]);
@@ -200,7 +200,7 @@
 
 // ECMA-262, section 15.5.4.11
 function StringReplace(search, replace) {
-  var subject = IS_STRING(this) ? this : ToString(this);
+  var subject = TO_STRING_INLINE(this);
 
   // Delegate to one of the regular expression variants if necessary.
   if (IS_REGEXP(search)) {
@@ -213,7 +213,7 @@
   }
 
   // Convert the search argument to a string and search for it.
-  search = IS_STRING(search) ? search : ToString(search);
+  search = TO_STRING_INLINE(search);
   var start = %StringIndexOf(subject, search, 0);
   if (start < 0) return subject;
   var end = start + search.length;
@@ -228,7 +228,7 @@
   } else {
     reusableMatchInfo[CAPTURE0] = start;
     reusableMatchInfo[CAPTURE1] = end;
-    if (!IS_STRING(replace)) replace = ToString(replace);
+    replace = TO_STRING_INLINE(replace);
     ExpandReplacement(replace, subject, reusableMatchInfo, builder);
   }
 
@@ -241,7 +241,7 @@
 
 // Helper function for regular expressions in String.prototype.replace.
 function StringReplaceRegExp(subject, regexp, replace) {
-  replace = ToString(replace);
+  replace = TO_STRING_INLINE(replace);
   return %StringReplaceRegExpWithString(subject,
                                         regexp,
                                         replace,
@@ -462,7 +462,7 @@
 // ECMA-262 section 15.5.4.12
 function StringSearch(re) {
   var regexp = new ORIGINAL_REGEXP(re);
-  var s = ToString(this);
+  var s = TO_STRING_INLINE(this);
   var last_idx = regexp.lastIndex; // keep old lastIndex
   regexp.lastIndex = 0;            // ignore re.global property
   var result = regexp.exec(s);
@@ -476,7 +476,7 @@
 
 // ECMA-262 section 15.5.4.13
 function StringSlice(start, end) {
-  var s = ToString(this);
+  var s = TO_STRING_INLINE(this);
   var s_len = s.length;
   var start_i = TO_INTEGER(start);
   var end_i = s_len;
@@ -511,7 +511,7 @@
 
 // ECMA-262 section 15.5.4.14
 function StringSplit(separator, limit) {
-  var subject = ToString(this);
+  var subject = TO_STRING_INLINE(this);
   limit = (IS_UNDEFINED(limit)) ? 0xffffffff : TO_UINT32(limit);
   if (limit === 0) return [];
 
@@ -525,18 +525,35 @@
   }
 
   var length = subject.length;
-  if (IS_REGEXP(separator)) {
-    %_Log('regexp', 'regexp-split,%0S,%1r', [subject, separator]);
-  } else {
-    separator = ToString(separator);
+  if (!IS_REGEXP(separator)) {
+    separator = TO_STRING_INLINE(separator);
+    var separator_length = separator.length;
+
     // If the separator string is empty then return the elements in the subject.
-    if (separator.length == 0) {
+    if (separator_length === 0) {
       var result = $Array(length);
       for (var i = 0; i < length; i++) result[i] = subject[i];
       return result;
     }
+
+    var result = [];
+    var start_index = 0;
+    var index;
+    while (true) {
+      if (start_index + separator_length > length ||
+          (index = %StringIndexOf(subject, separator, start_index)) === -1) {
+        result.push(SubString(subject, start_index, length));
+        break;
+      }
+      if (result.push(SubString(subject, start_index, index)) === limit) break;
+      start_index = index + separator_length;
+    }
+
+    return result;
   }
 
+  %_Log('regexp', 'regexp-split,%0S,%1r', [subject, separator]);
+
   if (length === 0) {
     if (splitMatch(separator, subject, 0, 0) != null) return [];
     return [subject];
@@ -571,7 +588,8 @@
     result[result.length] = SubString(subject, currentIndex, matchInfo[CAPTURE0]);
     if (result.length === limit) return result;
 
-    for (var i = 2; i < NUMBER_OF_CAPTURES(matchInfo); i += 2) {
+    var num_captures = NUMBER_OF_CAPTURES(matchInfo);
+    for (var i = 2; i < num_captures; i += 2) {
       var start = matchInfo[CAPTURE(i)];
       var end = matchInfo[CAPTURE(i + 1)];
       if (start != -1 && end != -1) {
@@ -591,28 +609,18 @@
 // Helper function used by split.  This version returns the matchInfo
 // instead of allocating a new array with basically the same information.
 function splitMatch(separator, subject, current_index, start_index) {
-  if (IS_REGEXP(separator)) {
-    var matchInfo = DoRegExpExec(separator, subject, start_index);
-    if (matchInfo == null) return null;
-    // Section 15.5.4.14 paragraph two says that we do not allow zero length
-    // matches at the end of the string.
-    if (matchInfo[CAPTURE0] === subject.length) return null;
-    return matchInfo;
-  }
-
-  var separatorIndex = subject.indexOf(separator, start_index);
-  if (separatorIndex === -1) return null;
-
-  reusableMatchInfo[CAPTURE0] = separatorIndex;
-  reusableMatchInfo[CAPTURE1] = separatorIndex + separator.length;
-  return reusableMatchInfo;
-};
+  var matchInfo = DoRegExpExec(separator, subject, start_index);
+  if (matchInfo == null) return null;
+  // Section 15.5.4.14 paragraph two says that we do not allow zero length
+  // matches at the end of the string.
+  if (matchInfo[CAPTURE0] === subject.length) return null;
+  return matchInfo;
+}
 
 
 // ECMA-262 section 15.5.4.15
 function StringSubstring(start, end) {
-  var s = this;
-  if (!IS_STRING(s)) s = ToString(s);
+  var s = TO_STRING_INLINE(this);
   var s_len = s.length;
 
   var start_i = TO_INTEGER(start);
@@ -643,7 +651,7 @@
 
 // This is not a part of ECMA-262.
 function StringSubstr(start, n) {
-  var s = ToString(this);
+  var s = TO_STRING_INLINE(this);
   var len;
 
   // Correct n: If not given, set to string length; if explicitly
@@ -681,38 +689,38 @@
 
 // ECMA-262, 15.5.4.16
 function StringToLowerCase() {
-  return %StringToLowerCase(ToString(this));
+  return %StringToLowerCase(TO_STRING_INLINE(this));
 }
 
 
 // ECMA-262, 15.5.4.17
 function StringToLocaleLowerCase() {
-  return %StringToLowerCase(ToString(this));
+  return %StringToLowerCase(TO_STRING_INLINE(this));
 }
 
 
 // ECMA-262, 15.5.4.18
 function StringToUpperCase() {
-  return %StringToUpperCase(ToString(this));
+  return %StringToUpperCase(TO_STRING_INLINE(this));
 }
 
 
 // ECMA-262, 15.5.4.19
 function StringToLocaleUpperCase() {
-  return %StringToUpperCase(ToString(this));
+  return %StringToUpperCase(TO_STRING_INLINE(this));
 }
 
 // ES5, 15.5.4.20
 function StringTrim() {
-  return %StringTrim(ToString(this), true, true);
+  return %StringTrim(TO_STRING_INLINE(this), true, true);
 }
 
 function StringTrimLeft() {
-  return %StringTrim(ToString(this), true, false);
+  return %StringTrim(TO_STRING_INLINE(this), true, false);
 }
 
 function StringTrimRight() {
-  return %StringTrim(ToString(this), false, true);
+  return %StringTrim(TO_STRING_INLINE(this), false, true);
 }
 
 // ECMA-262, section 15.5.3.2
@@ -731,10 +739,10 @@
 
 // Helper function for very basic XSS protection.
 function HtmlEscape(str) {
-  return ToString(str).replace(/</g, "&lt;")
-                      .replace(/>/g, "&gt;")
-                      .replace(/"/g, "&quot;")
-                      .replace(/'/g, "&#039;");
+  return TO_STRING_INLINE(str).replace(/</g, "&lt;")
+                              .replace(/>/g, "&gt;")
+                              .replace(/"/g, "&quot;")
+                              .replace(/'/g, "&#039;");
 };
 
 
@@ -813,7 +821,7 @@
 
 
 ReplaceResultBuilder.prototype.add = function(str) {
-  if (!IS_STRING(str)) str = ToString(str);
+  str = TO_STRING_INLINE(str);
   if (str.length > 0) {
     var elements = this.elements;
     elements[elements.length] = str;
diff --git a/src/stub-cache.cc b/src/stub-cache.cc
index 3adaa40..577c2d7 100644
--- a/src/stub-cache.cc
+++ b/src/stub-cache.cc
@@ -105,7 +105,7 @@
     if (code->IsFailure()) return code;
     LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
     Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
-    if (result->IsFailure()) return code;
+    if (result->IsFailure()) return result;
   }
   return Set(name, receiver->map(), Code::cast(code));
 }
@@ -124,7 +124,7 @@
     if (code->IsFailure()) return code;
     LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
     Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
-    if (result->IsFailure()) return code;
+    if (result->IsFailure()) return result;
   }
   return Set(name, receiver->map(), Code::cast(code));
 }
@@ -143,7 +143,7 @@
     if (code->IsFailure()) return code;
     LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
     Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
-    if (result->IsFailure()) return code;
+    if (result->IsFailure()) return result;
   }
   return Set(name, receiver->map(), Code::cast(code));
 }
@@ -160,7 +160,7 @@
     if (code->IsFailure()) return code;
     LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
     Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
-    if (result->IsFailure()) return code;
+    if (result->IsFailure()) return result;
   }
   return Set(name, receiver->map(), Code::cast(code));
 }
@@ -189,7 +189,7 @@
     if (code->IsFailure()) return code;
     LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
     Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
-    if (result->IsFailure()) return code;
+    if (result->IsFailure()) return result;
   }
   return Set(name, receiver->map(), Code::cast(code));
 }
@@ -351,7 +351,7 @@
     if (code->IsFailure()) return code;
     LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
     Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
-    if (result->IsFailure()) return code;
+    if (result->IsFailure()) return result;
   }
   return Set(name, receiver->map(), Code::cast(code));
 }
@@ -566,7 +566,7 @@
     ASSERT_EQ(flags, Code::cast(code)->flags());
     LOG(CodeCreateEvent(Logger::CALL_IC_TAG, Code::cast(code), name));
     Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
-    if (result->IsFailure()) return code;
+    if (result->IsFailure()) return result;
   }
   return Set(name, receiver->map(), Code::cast(code));
 }
diff --git a/src/utils.h b/src/utils.h
index c59ca25..2fcd241 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -157,7 +157,9 @@
 
   // Returns a uint32_t mask of bit field.
   static uint32_t mask() {
-    return (1U << (size + shift)) - (1U << shift);
+    // To use all bits of a uint32 in a bitfield without compiler warnings we
+    // have to compute 2^32 without using a shift count of 32.
+    return ((1U << shift) << size) - (1U << shift);
   }
 
   // Returns a uint32_t with the bit field value encoded.
@@ -168,7 +170,7 @@
 
   // Extracts the bit field from the value.
   static T decode(uint32_t value) {
-    return static_cast<T>((value >> shift) & ((1U << (size)) - 1));
+    return static_cast<T>((value & mask()) >> shift);
   }
 };
 
diff --git a/src/version.cc b/src/version.cc
index 717bcc3..eaa63d5 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,8 +34,8 @@
 // cannot be changed without changing the SCons build script.
 #define MAJOR_VERSION     2
 #define MINOR_VERSION     1
-#define BUILD_NUMBER      1
-#define PATCH_LEVEL       1
+#define BUILD_NUMBER      2
+#define PATCH_LEVEL       0
 #define CANDIDATE_VERSION false
 
 // Define SONAME to have the SCons build the put a specific SONAME into the
diff --git a/src/x64/assembler-x64.cc b/src/x64/assembler-x64.cc
index 1f97235..a994f45 100644
--- a/src/x64/assembler-x64.cc
+++ b/src/x64/assembler-x64.cc
@@ -34,46 +34,6 @@
 namespace internal {
 
 // -----------------------------------------------------------------------------
-// Implementation of Register
-
-Register rax = { 0 };
-Register rcx = { 1 };
-Register rdx = { 2 };
-Register rbx = { 3 };
-Register rsp = { 4 };
-Register rbp = { 5 };
-Register rsi = { 6 };
-Register rdi = { 7 };
-Register r8 = { 8 };
-Register r9 = { 9 };
-Register r10 = { 10 };
-Register r11 = { 11 };
-Register r12 = { 12 };
-Register r13 = { 13 };
-Register r14 = { 14 };
-Register r15 = { 15 };
-
-Register no_reg = { -1 };
-
-XMMRegister xmm0 = { 0 };
-XMMRegister xmm1 = { 1 };
-XMMRegister xmm2 = { 2 };
-XMMRegister xmm3 = { 3 };
-XMMRegister xmm4 = { 4 };
-XMMRegister xmm5 = { 5 };
-XMMRegister xmm6 = { 6 };
-XMMRegister xmm7 = { 7 };
-XMMRegister xmm8 = { 8 };
-XMMRegister xmm9 = { 9 };
-XMMRegister xmm10 = { 10 };
-XMMRegister xmm11 = { 11 };
-XMMRegister xmm12 = { 12 };
-XMMRegister xmm13 = { 13 };
-XMMRegister xmm14 = { 14 };
-XMMRegister xmm15 = { 15 };
-
-
-// -----------------------------------------------------------------------------
 // Implementation of CpuFeatures
 
 // The required user mode extensions in X64 are (from AMD64 ABI Table A.1):
diff --git a/src/x64/assembler-x64.h b/src/x64/assembler-x64.h
index 6c6f6a3..5019525 100644
--- a/src/x64/assembler-x64.h
+++ b/src/x64/assembler-x64.h
@@ -118,51 +118,23 @@
   int code_;
 };
 
-extern Register rax;
-extern Register rcx;
-extern Register rdx;
-extern Register rbx;
-extern Register rsp;
-extern Register rbp;
-extern Register rsi;
-extern Register rdi;
-extern Register r8;
-extern Register r9;
-extern Register r10;
-extern Register r11;
-extern Register r12;
-extern Register r13;
-extern Register r14;
-extern Register r15;
-extern Register no_reg;
-
-
-struct MMXRegister {
-  bool is_valid() const  { return 0 <= code_ && code_ < 2; }
-  int code() const  {
-    ASSERT(is_valid());
-    return code_;
-  }
-
-  int code_;
-};
-
-extern MMXRegister mm0;
-extern MMXRegister mm1;
-extern MMXRegister mm2;
-extern MMXRegister mm3;
-extern MMXRegister mm4;
-extern MMXRegister mm5;
-extern MMXRegister mm6;
-extern MMXRegister mm7;
-extern MMXRegister mm8;
-extern MMXRegister mm9;
-extern MMXRegister mm10;
-extern MMXRegister mm11;
-extern MMXRegister mm12;
-extern MMXRegister mm13;
-extern MMXRegister mm14;
-extern MMXRegister mm15;
+const Register rax = { 0 };
+const Register rcx = { 1 };
+const Register rdx = { 2 };
+const Register rbx = { 3 };
+const Register rsp = { 4 };
+const Register rbp = { 5 };
+const Register rsi = { 6 };
+const Register rdi = { 7 };
+const Register r8 = { 8 };
+const Register r9 = { 9 };
+const Register r10 = { 10 };
+const Register r11 = { 11 };
+const Register r12 = { 12 };
+const Register r13 = { 13 };
+const Register r14 = { 14 };
+const Register r15 = { 15 };
+const Register no_reg = { -1 };
 
 
 struct XMMRegister {
@@ -186,22 +158,22 @@
   int code_;
 };
 
-extern XMMRegister xmm0;
-extern XMMRegister xmm1;
-extern XMMRegister xmm2;
-extern XMMRegister xmm3;
-extern XMMRegister xmm4;
-extern XMMRegister xmm5;
-extern XMMRegister xmm6;
-extern XMMRegister xmm7;
-extern XMMRegister xmm8;
-extern XMMRegister xmm9;
-extern XMMRegister xmm10;
-extern XMMRegister xmm11;
-extern XMMRegister xmm12;
-extern XMMRegister xmm13;
-extern XMMRegister xmm14;
-extern XMMRegister xmm15;
+const XMMRegister xmm0 = { 0 };
+const XMMRegister xmm1 = { 1 };
+const XMMRegister xmm2 = { 2 };
+const XMMRegister xmm3 = { 3 };
+const XMMRegister xmm4 = { 4 };
+const XMMRegister xmm5 = { 5 };
+const XMMRegister xmm6 = { 6 };
+const XMMRegister xmm7 = { 7 };
+const XMMRegister xmm8 = { 8 };
+const XMMRegister xmm9 = { 9 };
+const XMMRegister xmm10 = { 10 };
+const XMMRegister xmm11 = { 11 };
+const XMMRegister xmm12 = { 12 };
+const XMMRegister xmm13 = { 13 };
+const XMMRegister xmm14 = { 14 };
+const XMMRegister xmm15 = { 15 };
 
 enum Condition {
   // any value < 0 is considered no_condition
diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc
index 6c063f3..28a522f 100644
--- a/src/x64/codegen-x64.cc
+++ b/src/x64/codegen-x64.cc
@@ -277,7 +277,7 @@
 }
 
 
-void CodeGenerator::Generate(CompilationInfo* info, Mode mode) {
+void CodeGenerator::Generate(CompilationInfo* info) {
   // Record the position for debugging purposes.
   CodeForFunctionPosition(info->function());
 
@@ -316,7 +316,7 @@
     // rsi: callee's context
     allocator_->Initialize();
 
-    if (mode == PRIMARY) {
+    if (info->mode() == CompilationInfo::PRIMARY) {
       frame_->Enter();
 
       // Allocate space for locals and initialize them.
@@ -407,6 +407,12 @@
       // frame to match this state.
       frame_->Adjust(3);
       allocator_->Unuse(rdi);
+
+      // Bind all the bailout labels to the beginning of the function.
+      List<CompilationInfo::Bailout*>* bailouts = info->bailouts();
+      for (int i = 0; i < bailouts->length(); i++) {
+        __ bind(bailouts->at(i)->label());
+      }
     }
 
     // Initialize the function return target after the locals are set
@@ -3627,6 +3633,22 @@
 }
 
 
+void CodeGenerator::GenerateIsRegExp(ZoneList<Expression*>* args) {
+  ASSERT(args->length() == 1);
+  Load(args->at(0));
+  Result value = frame_->Pop();
+  value.ToRegister();
+  ASSERT(value.is_valid());
+  Condition is_smi = masm_->CheckSmi(value.reg());
+  destination()->false_target()->Branch(is_smi);
+  // It is a heap object - get map.
+  // Check if the object is a regexp.
+  __ CmpObjectType(value.reg(), JS_REGEXP_TYPE, kScratchRegister);
+  value.Unuse();
+  destination()->Split(equal);
+}
+
+
 void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) {
   // This generates a fast version of:
   // (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp')
diff --git a/src/x64/codegen-x64.h b/src/x64/codegen-x64.h
index 3454312..4593a28 100644
--- a/src/x64/codegen-x64.h
+++ b/src/x64/codegen-x64.h
@@ -294,15 +294,6 @@
 
 class CodeGenerator: public AstVisitor {
  public:
-  // Compilation mode.  Either the compiler is used as the primary
-  // compiler and needs to setup everything or the compiler is used as
-  // the secondary compiler for split compilation and has to handle
-  // bailouts.
-  enum Mode {
-    PRIMARY,
-    SECONDARY
-  };
-
   // Takes a function literal, generates code for it. This function should only
   // be called by compiler.cc.
   static Handle<Code> MakeCode(CompilationInfo* info);
@@ -385,7 +376,7 @@
   void VisitStatementsAndSpill(ZoneList<Statement*>* statements);
 
   // Main code generation function
-  void Generate(CompilationInfo* info, Mode mode);
+  void Generate(CompilationInfo* info);
 
   // Generate the return sequence code.  Should be called no more than
   // once per compiled function, immediately after binding the return
@@ -536,6 +527,7 @@
   void GenerateIsSmi(ZoneList<Expression*>* args);
   void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
   void GenerateIsArray(ZoneList<Expression*>* args);
+  void GenerateIsRegExp(ZoneList<Expression*>* args);
   void GenerateIsObject(ZoneList<Expression*>* args);
   void GenerateIsFunction(ZoneList<Expression*>* args);
   void GenerateIsUndetectableObject(ZoneList<Expression*>* args);
diff --git a/src/x64/fast-codegen-x64.cc b/src/x64/fast-codegen-x64.cc
index 1af7685..4dbf26a 100644
--- a/src/x64/fast-codegen-x64.cc
+++ b/src/x64/fast-codegen-x64.cc
@@ -156,21 +156,28 @@
       // commutative.
       __ or_(destination(), other_accumulator(destination()));
     }
-  } else if (destination().is(no_reg)) {
-    // Result is not needed but do not clobber the operands in case of
-    // bailout.
-    __ movq(scratch0(), accumulator1());
-    __ or_(scratch0(), accumulator0());
-    __ JumpIfNotSmi(scratch0(), bailout());
   } else {
-    // Preserve the destination operand in a scratch register in case of
-    // bailout.
-    __ movq(scratch0(), destination());
-    __ or_(destination(), other_accumulator(destination()));
-    __ JumpIfNotSmi(destination(), bailout());
+    // Left is in accumulator1, right in accumulator0.
+    if (destination().is(accumulator0())) {
+      __ movq(scratch0(), accumulator0());
+      __ or_(destination(), accumulator1());  // Or is commutative.
+      Label* bailout =
+          info()->AddBailout(accumulator1(), scratch0());  // Left, right.
+      __ JumpIfNotSmi(destination(), bailout);
+    } else if (destination().is(accumulator1())) {
+      __ movq(scratch0(), accumulator1());
+      __ or_(destination(), accumulator0());
+      Label* bailout = info()->AddBailout(scratch0(), accumulator0());
+      __ JumpIfNotSmi(destination(), bailout);
+    } else {
+      ASSERT(destination().is(no_reg));
+      __ movq(scratch0(), accumulator1());
+      __ or_(scratch0(), accumulator0());
+      Label* bailout = info()->AddBailout(accumulator1(), accumulator0());
+      __ JumpIfNotSmi(scratch0(), bailout);
+    }
   }
 
-
   // If we didn't bailout, the result (in fact, both inputs too) is known to
   // be a smi.
   set_as_smi(accumulator0());
@@ -191,6 +198,7 @@
   // Note that we keep a live register reference to esi (context) at this
   // point.
 
+  Label* bailout_to_beginning = info()->AddBailout();
   // Receiver (this) is allocated to a fixed register.
   if (info()->has_this_properties()) {
     Comment cmnt(masm(), ";; MapCheck(this)");
@@ -201,7 +209,7 @@
     Handle<HeapObject> object = Handle<HeapObject>::cast(info()->receiver());
     Handle<Map> map(object->map());
     EmitLoadReceiver();
-    __ CheckMap(receiver_reg(), map, bailout(), false);
+    __ CheckMap(receiver_reg(), map, bailout_to_beginning, false);
   }
 
   // If there is a global variable access check if the global object is the
@@ -214,7 +222,7 @@
     ASSERT(info()->has_global_object());
     Handle<Map> map(info()->global_object()->map());
     __ movq(scratch0(), CodeGenerator::GlobalObject());
-    __ CheckMap(scratch0(), map, bailout(), true);
+    __ CheckMap(scratch0(), map, bailout_to_beginning, true);
   }
 
   VisitStatements(info()->function()->body());
@@ -227,8 +235,6 @@
   __ movq(rsp, rbp);
   __ pop(rbp);
   __ ret((scope()->num_parameters() + 1) * kPointerSize);
-
-  __ bind(&bailout_);
 }
 
 
diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h
index 6deeddc..2673086 100644
--- a/src/x64/macro-assembler-x64.h
+++ b/src/x64/macro-assembler-x64.h
@@ -36,7 +36,7 @@
 // Default scratch register used by MacroAssembler (and other code that needs
 // a spare register). The register isn't callee save, and not used by the
 // function calling convention.
-static const Register kScratchRegister = r10;
+static const Register kScratchRegister = { 10 };  // r10.
 
 // Convenience for platform-independent signatures.
 typedef Operand MemOperand;