Version 2.1.9

Added API support for reattaching a global object to a context.

Extended debugger API with access to the internal debugger context.

Fixed Chromium crashes (issues http://crbug.com/39128 and http://crbug.com/39160)


git-svn-id: http://v8.googlecode.com/svn/trunk@4280 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/SConscript b/src/SConscript
index 51c9ba8..e7f6efd 100755
--- a/src/SConscript
+++ b/src/SConscript
@@ -113,6 +113,8 @@
     """),
   'arch:arm': Split("""
     fast-codegen.cc
+    jump-target-light.cc
+    virtual-frame-light.cc
     arm/builtins-arm.cc
     arm/codegen-arm.cc
     arm/constants-arm.cc
@@ -156,6 +158,8 @@
     mips/virtual-frame-mips.cc
     """),
   'arch:ia32': Split("""
+    jump-target-heavy.cc
+    virtual-frame-heavy.cc
     ia32/assembler-ia32.cc
     ia32/builtins-ia32.cc
     ia32/codegen-ia32.cc
@@ -175,6 +179,8 @@
     """),
   'arch:x64': Split("""
     fast-codegen.cc
+    jump-target-heavy.cc
+    virtual-frame-heavy.cc
     x64/assembler-x64.cc
     x64/builtins-x64.cc
     x64/codegen-x64.cc
diff --git a/src/api.cc b/src/api.cc
index 5f9f178..2100480 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -537,10 +537,17 @@
   LOG_API("CloseHandleScope");
 
   // Read the result before popping the handle block.
-  i::Object* result = *value;
+  i::Object* result = NULL;
+  if (value != NULL) {
+    result = *value;
+  }
   is_closed_ = true;
   i::HandleScope::Leave(&previous_);
 
+  if (value == NULL) {
+    return NULL;
+  }
+
   // Allocate a new handle on the previous handle block.
   i::Handle<i::Object> handle(result);
   return handle.location();
@@ -3078,6 +3085,16 @@
 }
 
 
+void Context::ReattachGlobal(Handle<Object> global_object) {
+  if (IsDeadCheck("v8::Context::ReattachGlobal()")) return;
+  ENTER_V8;
+  i::Object** ctx = reinterpret_cast<i::Object**>(this);
+  i::Handle<i::Context> context =
+      i::Handle<i::Context>::cast(i::Handle<i::Object>(ctx));
+  i::Bootstrapper::ReattachGlobal(context, Utils::OpenHandle(*global_object));
+}
+
+
 Local<v8::Object> ObjectTemplate::NewInstance() {
   ON_BAILOUT("v8::ObjectTemplate::NewInstance()", return Local<v8::Object>());
   LOG_API("ObjectTemplate::NewInstance");
@@ -3973,6 +3990,11 @@
   i::Execution::ProcessDebugMesssages(true);
 }
 
+Local<Context> Debug::GetDebugContext() {
+  i::EnterDebugger debugger;
+  return Utils::ToLocal(i::Debug::debug_context());
+}
+
 #endif  // ENABLE_DEBUGGER_SUPPORT
 
 namespace internal {
diff --git a/src/api.h b/src/api.h
index 2f1f77c..7b88112 100644
--- a/src/api.h
+++ b/src/api.h
@@ -247,7 +247,11 @@
 template <class T>
 v8::internal::Handle<T> v8::internal::Handle<T>::EscapeFrom(
     v8::HandleScope* scope) {
-  return Utils::OpenHandle(*scope->Close(Utils::ToLocal(*this)));
+  v8::internal::Handle<T> handle;
+  if (!is_null()) {
+    handle = *this;
+  }
+  return Utils::OpenHandle(*scope->Close(Utils::ToLocal(handle)));
 }
 
 
@@ -255,7 +259,7 @@
 
 #define MAKE_TO_LOCAL(Name, From, To)                                       \
   Local<v8::To> Utils::Name(v8::internal::Handle<v8::internal::From> obj) { \
-    ASSERT(!obj->IsTheHole());                                              \
+    ASSERT(obj.is_null() || !obj->IsTheHole());                             \
     return Local<To>(reinterpret_cast<To*>(obj.location()));                \
   }
 
diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc
index 1d67918..5e00677 100644
--- a/src/arm/codegen-arm.cc
+++ b/src/arm/codegen-arm.cc
@@ -7018,44 +7018,47 @@
 }
 
 
+// Unfortunately you have to run without snapshots to see most of these
+// names in the profile since most compare stubs end up in the snapshot.
 const char* CompareStub::GetName() {
+  if (name_ != NULL) return name_;
+  const int kMaxNameLength = 100;
+  name_ = Bootstrapper::AllocateAutoDeletedArray(kMaxNameLength);
+  if (name_ == NULL) return "OOM";
+
+  const char* cc_name;
   switch (cc_) {
-    case lt: return "CompareStub_LT";
-    case gt: return "CompareStub_GT";
-    case le: return "CompareStub_LE";
-    case ge: return "CompareStub_GE";
-    case ne: {
-      if (strict_) {
-        if (never_nan_nan_) {
-          return "CompareStub_NE_STRICT_NO_NAN";
-        } else {
-          return "CompareStub_NE_STRICT";
-        }
-      } else {
-        if (never_nan_nan_) {
-          return "CompareStub_NE_NO_NAN";
-        } else {
-          return "CompareStub_NE";
-        }
-      }
-    }
-    case eq: {
-      if (strict_) {
-        if (never_nan_nan_) {
-          return "CompareStub_EQ_STRICT_NO_NAN";
-        } else {
-          return "CompareStub_EQ_STRICT";
-        }
-      } else {
-        if (never_nan_nan_) {
-          return "CompareStub_EQ_NO_NAN";
-        } else {
-          return "CompareStub_EQ";
-        }
-      }
-    }
-    default: return "CompareStub";
+    case lt: cc_name = "LT"; break;
+    case gt: cc_name = "GT"; break;
+    case le: cc_name = "LE"; break;
+    case ge: cc_name = "GE"; break;
+    case eq: cc_name = "EQ"; break;
+    case ne: cc_name = "NE"; break;
+    default: cc_name = "UnknownCondition"; break;
   }
+
+  const char* strict_name = "";
+  if (strict_ && (cc_ == eq || cc_ == ne)) {
+    strict_name = "_STRICT";
+  }
+
+  const char* never_nan_nan_name = "";
+  if (never_nan_nan_ && (cc_ == eq || cc_ == ne)) {
+    never_nan_nan_name = "_NO_NAN";
+  }
+
+  const char* include_number_compare_name = "";
+  if (!include_number_compare_) {
+    include_number_compare_name = "_NO_NUMBER";
+  }
+
+  OS::SNPrintF(Vector<char>(name_, kMaxNameLength),
+               "CompareStub_%s%s%s%s",
+               cc_name,
+               strict_name,
+               never_nan_nan_name,
+               include_number_compare_name);
+  return name_;
 }
 
 
@@ -7063,10 +7066,11 @@
   // Encode the three parameters in a unique 16 bit value. To avoid duplicate
   // stubs the never NaN NaN condition is only taken into account if the
   // condition is equals.
-  ASSERT((static_cast<unsigned>(cc_) >> 28) < (1 << 14));
+  ASSERT((static_cast<unsigned>(cc_) >> 28) < (1 << 13));
   return ConditionField::encode(static_cast<unsigned>(cc_) >> 28)
          | StrictField::encode(strict_)
-         | NeverNanNanField::encode(cc_ == eq ? never_nan_nan_ : false);
+         | NeverNanNanField::encode(cc_ == eq ? never_nan_nan_ : false)
+         | IncludeNumberCompareField::encode(include_number_compare_);
 }
 
 
diff --git a/src/arm/jump-target-arm.cc b/src/arm/jump-target-arm.cc
index a84060d..a13de0e 100644
--- a/src/arm/jump-target-arm.cc
+++ b/src/arm/jump-target-arm.cc
@@ -173,14 +173,7 @@
 
 
 void BreakTarget::Jump(Result* arg) {
-  // On ARM we do not currently emit merge code for jumps, so we need to do
-  // it explicitly here.  The only merging necessary is to drop extra
-  // statement state from the stack.
-  ASSERT(cgen()->has_valid_frame());
-  int count = cgen()->frame()->height() - expected_height_;
-  cgen()->frame()->Drop(count);
-  cgen()->frame()->Push(arg);
-  DoJump();
+  UNIMPLEMENTED();
 }
 
 
@@ -209,27 +202,7 @@
 
 
 void BreakTarget::Bind(Result* arg) {
-#ifdef DEBUG
-  // All the forward-reaching frames should have been adjusted at the
-  // jumps to this target.
-  for (int i = 0; i < reaching_frames_.length(); i++) {
-    ASSERT(reaching_frames_[i] == NULL ||
-           reaching_frames_[i]->height() == expected_height_ + 1);
-  }
-#endif
-  // Drop leftover statement state from the frame before merging, even
-  // on the fall through.  This is so we can bind the return target
-  // with state on the frame.
-  if (cgen()->has_valid_frame()) {
-    int count = cgen()->frame()->height() - expected_height_;
-    // On ARM we do not currently emit merge code at binding sites, so we need
-    // to do it explicitly here.  The only merging necessary is to drop extra
-    // statement state from the stack.
-    cgen()->frame()->ForgetElements(count);
-    cgen()->frame()->Push(arg);
-  }
-  DoBind();
-  *arg = cgen()->frame()->Pop();
+  UNIMPLEMENTED();
 }
 
 
diff --git a/src/arm/virtual-frame-arm.cc b/src/arm/virtual-frame-arm.cc
index ab6e5f8..1e3a865 100644
--- a/src/arm/virtual-frame-arm.cc
+++ b/src/arm/virtual-frame-arm.cc
@@ -47,16 +47,6 @@
 }
 
 
-void VirtualFrame::SyncRange(int begin, int end) {
-  // All elements are in memory on ARM (ie, synced).
-#ifdef DEBUG
-  for (int i = begin; i <= end; i++) {
-    ASSERT(elements_[i].is_synced());
-  }
-#endif
-}
-
-
 void VirtualFrame::MergeTo(VirtualFrame* expected) {
   // ARM frames are currently always in memory.
   ASSERT(Equals(expected));
@@ -270,12 +260,7 @@
   }
 
   // Discard elements from the virtual frame and free any registers.
-  for (int i = 0; i < count; i++) {
-    FrameElement dropped = elements_.RemoveLast();
-    if (dropped.is_register()) {
-      Unuse(dropped.reg());
-    }
-  }
+  element_count_ -= count;
 }
 
 
@@ -288,14 +273,14 @@
 void VirtualFrame::EmitPop(Register reg) {
   ASSERT(stack_pointer_ == element_count() - 1);
   stack_pointer_--;
-  elements_.RemoveLast();
+  element_count_--;
   __ pop(reg);
 }
 
 
 void VirtualFrame::EmitPush(Register reg) {
   ASSERT(stack_pointer_ == element_count() - 1);
-  elements_.Add(FrameElement::MemoryElement(NumberInfo::Unknown()));
+  element_count_++;
   stack_pointer_++;
   __ push(reg);
 }
diff --git a/src/arm/virtual-frame-arm.h b/src/arm/virtual-frame-arm.h
index 9ac7a05..6ba1eec 100644
--- a/src/arm/virtual-frame-arm.h
+++ b/src/arm/virtual-frame-arm.h
@@ -67,12 +67,8 @@
   CodeGenerator* cgen() { return CodeGeneratorScope::Current(); }
   MacroAssembler* masm() { return cgen()->masm(); }
 
-  // Create a duplicate of an existing valid frame element.
-  FrameElement CopyElementAt(int index,
-                             NumberInfo info = NumberInfo::Unknown());
-
   // The number of elements on the virtual frame.
-  int element_count() { return elements_.length(); }
+  int element_count() { return element_count_; }
 
   // The height of the virtual expression stack.
   int height() {
@@ -115,7 +111,7 @@
     stack_pointer_ -= count;
     // On ARM, all elements are in memory, so there is no extra bookkeeping
     // (registers, copies, etc.) beyond dropping the elements.
-    elements_.Rewind(stack_pointer_ + 1);
+    element_count_ -= count;
   }
 
   // Forget count elements from the top of the frame and adjust the stack
@@ -124,7 +120,7 @@
   void ForgetElements(int count);
 
   // Spill all values from the frame to memory.
-  void SpillAll();
+  inline void SpillAll();
 
   // Spill all occurrences of a specific register from the frame.
   void Spill(Register reg) {
@@ -179,7 +175,7 @@
   // dropping all non-locals elements in the virtual frame.  This
   // avoids generating unnecessary merge code when jumping to the
   // shared return site.  Emits code for spills.
-  void PrepareForReturn();
+  inline void PrepareForReturn();
 
   // Number of local variables after when we use a loop for allocating.
   static const int kLocalVarBound = 5;
@@ -205,10 +201,6 @@
     SetElementAt(index, &temp);
   }
 
-  void PushElementAt(int index) {
-    PushFrameSlotAt(element_count() - index - 1);
-  }
-
   // A frame-allocated local as an assembly operand.
   MemOperand LocalAt(int index) {
     ASSERT(0 <= index);
@@ -216,11 +208,6 @@
     return MemOperand(fp, kLocal0Offset - index * kPointerSize);
   }
 
-  // Push a copy of the value of a local frame slot on top of the frame.
-  void PushLocalAt(int index) {
-    PushFrameSlotAt(local0_index() + index);
-  }
-
   // Push the value of a local frame slot on top of the frame and invalidate
   // the local slot.  The slot should be written to before trying to read
   // from it again.
@@ -228,21 +215,12 @@
     TakeFrameSlotAt(local0_index() + index);
   }
 
-  // Store the top value on the virtual frame into a local frame slot.  The
-  // value is left in place on top of the frame.
-  void StoreToLocalAt(int index) {
-    StoreToFrameSlotAt(local0_index() + index);
-  }
-
   // Push the address of the receiver slot on the frame.
   void PushReceiverSlotAddress();
 
   // The function frame slot.
   MemOperand Function() { return MemOperand(fp, kFunctionOffset); }
 
-  // Push the function on top of the frame.
-  void PushFunction() { PushFrameSlotAt(function_index()); }
-
   // The context frame slot.
   MemOperand Context() { return MemOperand(fp, kContextOffset); }
 
@@ -261,11 +239,6 @@
     return MemOperand(fp, (1 + parameter_count() - index) * kPointerSize);
   }
 
-  // Push a copy of the value of a parameter frame slot on top of the frame.
-  void PushParameterAt(int index) {
-    PushFrameSlotAt(param0_index() + index);
-  }
-
   // Push the value of a paramter frame slot on top of the frame and
   // invalidate the parameter slot.  The slot should be written to before
   // trying to read from it again.
@@ -323,9 +296,6 @@
   // Drop one element.
   void Drop() { Drop(1); }
 
-  // Duplicate the top element of the frame.
-  void Dup() { PushFrameSlotAt(element_count() - 1); }
-
   // Pop an element from the top of the expression stack.  Returns a
   // Result, which may be a constant or a register.
   Result Pop();
@@ -344,28 +314,16 @@
   void EmitPushMultiple(int count, int src_regs);
 
   // Push an element on the virtual frame.
-  inline void Push(Register reg, NumberInfo info = NumberInfo::Unknown());
   inline void Push(Handle<Object> value);
   inline void Push(Smi* value);
 
-  // Pushing a result invalidates it (its contents become owned by the frame).
-  void Push(Result* result) {
-    if (result->is_register()) {
-      Push(result->reg());
-    } else {
-      ASSERT(result->is_constant());
-      Push(result->handle());
-    }
-    result->Unuse();
-  }
-
   // 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).
   inline void Nip(int num_dropped);
 
-  inline void SetTypeForLocalAt(int index, NumberInfo info);
-  inline void SetTypeForParamAt(int index, NumberInfo info);
+  inline void SetTypeForLocalAt(int index, TypeInfo info);
+  inline void SetTypeForParamAt(int index, TypeInfo info);
 
  private:
   static const int kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset;
@@ -375,7 +333,8 @@
   static const int kHandlerSize = StackHandlerConstants::kSize / kPointerSize;
   static const int kPreallocatedElements = 5 + 8;  // 8 expression stack slots.
 
-  ZoneList<FrameElement> elements_;
+  // The number of elements on the stack frame.
+  int element_count_;
 
   // The index of the element that is at the processor's stack pointer
   // (the sp register).
@@ -449,19 +408,12 @@
   // Keep the element type as register or constant, and clear the dirty bit.
   void SyncElementAt(int index);
 
-  // Sync the range of elements in [begin, end] with memory.
-  void SyncRange(int begin, int end);
-
   // Sync a single unsynced element that lies beneath or at the stack pointer.
   void SyncElementBelowStackPointer(int index);
 
   // Sync a single unsynced element that lies just above the stack pointer.
   void SyncElementByPushing(int index);
 
-  // Push a copy of a frame slot (typically a local or parameter) on top of
-  // the frame.
-  inline void PushFrameSlotAt(int index);
-
   // Push a the value of a frame slot (typically a local or parameter) on
   // top of the frame and invalidate the slot.
   void TakeFrameSlotAt(int index);
@@ -505,9 +457,8 @@
 
   inline bool Equals(VirtualFrame* other);
 
-  // Classes that need raw access to the elements_ array.
-  friend class DeferredCode;
   friend class JumpTarget;
+  friend class DeferredCode;
 };
 
 
diff --git a/src/ast.cc b/src/ast.cc
index 7dd991f..9204a84 100644
--- a/src/ast.cc
+++ b/src/ast.cc
@@ -28,6 +28,7 @@
 #include "v8.h"
 
 #include "ast.h"
+#include "data-flow.h"
 #include "parser.h"
 #include "scopes.h"
 #include "string-stream.h"
@@ -171,6 +172,72 @@
 }
 
 
+bool Expression::GuaranteedSmiResult() {
+  BinaryOperation* node = AsBinaryOperation();
+  if (node == NULL) return false;
+  Token::Value op = node->op();
+  switch (op) {
+    case Token::COMMA:
+    case Token::OR:
+    case Token::AND:
+    case Token::ADD:
+    case Token::SUB:
+    case Token::MUL:
+    case Token::DIV:
+    case Token::MOD:
+    case Token::BIT_XOR:
+    case Token::SHL:
+      return false;
+      break;
+    case Token::BIT_OR:
+    case Token::BIT_AND: {
+      Literal* left = node->left()->AsLiteral();
+      Literal* right = node->right()->AsLiteral();
+      if (left != NULL && left->handle()->IsSmi()) {
+        int value = Smi::cast(*left->handle())->value();
+        if (op == Token::BIT_OR && ((value & 0xc0000000) == 0xc0000000)) {
+          // Result of bitwise or is always a negative Smi.
+          return true;
+        }
+        if (op == Token::BIT_AND && ((value & 0xc0000000) == 0)) {
+          // Result of bitwise and is always a positive Smi.
+          return true;
+        }
+      }
+      if (right != NULL && right->handle()->IsSmi()) {
+        int value = Smi::cast(*right->handle())->value();
+        if (op == Token::BIT_OR && ((value & 0xc0000000) == 0xc0000000)) {
+          // Result of bitwise or is always a negative Smi.
+          return true;
+        }
+        if (op == Token::BIT_AND && ((value & 0xc0000000) == 0)) {
+          // Result of bitwise and is always a positive Smi.
+          return true;
+        }
+      }
+      return false;
+      break;
+    }
+    case Token::SAR:
+    case Token::SHR: {
+      Literal* right = node->right()->AsLiteral();
+       if (right != NULL && right->handle()->IsSmi()) {
+        int value = Smi::cast(*right->handle())->value();
+        if ((value & 0x1F) > 1 ||
+            (op == Token::SAR && (value & 0x1F) == 1)) {
+          return true;
+        }
+       }
+       return false;
+       break;
+    }
+    default:
+      UNREACHABLE();
+      break;
+  }
+  return false;
+}
+
 // ----------------------------------------------------------------------------
 // Implementation of AstVisitor
 
@@ -600,6 +667,199 @@
 bool CompareOperation::IsPrimitive() { return true; }
 
 
+// Overridden IsCritical member functions.  IsCritical is true for AST nodes
+// whose evaluation is absolutely required (they are never dead) because
+// they are externally visible.
+
+// References to global variables or lookup slots are critical because they
+// may have getters.  All others, including parameters rewritten to explicit
+// property references, are not critical.
+bool VariableProxy::IsCritical() {
+  Variable* var = AsVariable();
+  return var != NULL &&
+      (var->slot() == NULL || var->slot()->type() == Slot::LOOKUP);
+}
+
+
+// Literals are never critical.
+bool Literal::IsCritical() { return false; }
+
+
+// Property assignments and throwing of reference errors are always
+// critical.  Assignments to escaping variables are also critical.  In
+// addition the operation of compound assignments is critical if either of
+// its operands is non-primitive (the arithmetic operations all use one of
+// ToPrimitive, ToNumber, ToInt32, or ToUint32 on each of their operands).
+// In this case, we mark the entire AST node as critical because there is
+// no binary operation node to mark.
+bool Assignment::IsCritical() {
+  Variable* var = AssignedVariable();
+  return var == NULL ||
+      !var->IsStackAllocated() ||
+      (is_compound() && (!target()->IsPrimitive() || !value()->IsPrimitive()));
+}
+
+
+// Property references are always critical, because they may have getters.
+bool Property::IsCritical() { return true; }
+
+
+// Calls are always critical.
+bool Call::IsCritical() { return true; }
+
+
+// +,- use ToNumber on the value of their operand.
+bool UnaryOperation::IsCritical() {
+  ASSERT(op() == Token::ADD || op() == Token::SUB);
+  return !expression()->IsPrimitive();
+}
+
+
+// Count operations targeting properties and reference errors are always
+// critical.  Count operations on escaping variables are critical.  Count
+// operations targeting non-primitives are also critical because they use
+// ToNumber.
+bool CountOperation::IsCritical() {
+  Variable* var = AssignedVariable();
+  return var == NULL ||
+      !var->IsStackAllocated() ||
+      !expression()->IsPrimitive();
+}
+
+
+// Arithmetic operations all use one of ToPrimitive, ToNumber, ToInt32, or
+// ToUint32 on each of their operands.
+bool BinaryOperation::IsCritical() {
+  ASSERT(op() != Token::COMMA);
+  ASSERT(op() != Token::OR);
+  ASSERT(op() != Token::AND);
+  return !left()->IsPrimitive() || !right()->IsPrimitive();
+}
+
+
+// <, >, <=, and >= all use ToPrimitive on both their operands.
+bool CompareOperation::IsCritical() {
+  ASSERT(op() != Token::EQ);
+  ASSERT(op() != Token::NE);
+  ASSERT(op() != Token::EQ_STRICT);
+  ASSERT(op() != Token::NE_STRICT);
+  ASSERT(op() != Token::INSTANCEOF);
+  ASSERT(op() != Token::IN);
+  return !left()->IsPrimitive() || !right()->IsPrimitive();
+}
+
+
+static inline void MarkIfNotLive(Expression* expr, List<AstNode*>* stack) {
+  if (!expr->is_live()) {
+    expr->mark_as_live();
+    stack->Add(expr);
+  }
+}
+
+
+// Overloaded functions for marking children of live code as live.
+void VariableProxy::ProcessNonLiveChildren(
+    List<AstNode*>* stack,
+    ZoneList<Expression*>* body_definitions,
+    int variable_count) {
+  // A reference to a stack-allocated variable depends on all the
+  // definitions reaching it.
+  BitVector* defs = reaching_definitions();
+  if (defs != NULL) {
+    ASSERT(var()->IsStackAllocated());
+    // The first variable_count definitions are the initial parameter and
+    // local declarations.
+    for (int i = variable_count; i < defs->length(); i++) {
+      if (defs->Contains(i)) {
+        MarkIfNotLive(body_definitions->at(i - variable_count), stack);
+      }
+    }
+  }
+}
+
+
+void Literal::ProcessNonLiveChildren(List<AstNode*>* stack,
+                                     ZoneList<Expression*>* body_definitions,
+                                     int variable_count) {
+  // Leaf node, no children.
+}
+
+
+void Assignment::ProcessNonLiveChildren(
+    List<AstNode*>* stack,
+    ZoneList<Expression*>* body_definitions,
+    int variable_count) {
+  Property* prop = target()->AsProperty();
+  VariableProxy* proxy = target()->AsVariableProxy();
+
+  if (prop != NULL) {
+    if (!prop->key()->IsPropertyName()) MarkIfNotLive(prop->key(), stack);
+    MarkIfNotLive(prop->obj(), stack);
+  } else if (proxy == NULL) {
+    // Must be a reference error.
+    ASSERT(!target()->IsValidLeftHandSide());
+    MarkIfNotLive(target(), stack);
+  } else if (is_compound()) {
+    // A variable assignment so lhs is an operand to the operation.
+    MarkIfNotLive(target(), stack);
+  }
+  MarkIfNotLive(value(), stack);
+}
+
+
+void Property::ProcessNonLiveChildren(List<AstNode*>* stack,
+                                      ZoneList<Expression*>* body_definitions,
+                                      int variable_count) {
+  if (!key()->IsPropertyName()) MarkIfNotLive(key(), stack);
+  MarkIfNotLive(obj(), stack);
+}
+
+
+void Call::ProcessNonLiveChildren(List<AstNode*>* stack,
+                                  ZoneList<Expression*>* body_definitions,
+                                  int variable_count) {
+  ZoneList<Expression*>* args = arguments();
+  for (int i = args->length() - 1; i >= 0; i--) {
+    MarkIfNotLive(args->at(i), stack);
+  }
+  MarkIfNotLive(expression(), stack);
+}
+
+
+void UnaryOperation::ProcessNonLiveChildren(
+    List<AstNode*>* stack,
+    ZoneList<Expression*>* body_definitions,
+    int variable_count) {
+  MarkIfNotLive(expression(), stack);
+}
+
+
+void CountOperation::ProcessNonLiveChildren(
+    List<AstNode*>* stack,
+    ZoneList<Expression*>* body_definitions,
+    int variable_count) {
+  MarkIfNotLive(expression(), stack);
+}
+
+
+void BinaryOperation::ProcessNonLiveChildren(
+    List<AstNode*>* stack,
+    ZoneList<Expression*>* body_definitions,
+    int variable_count) {
+  MarkIfNotLive(right(), stack);
+  MarkIfNotLive(left(), stack);
+}
+
+
+void CompareOperation::ProcessNonLiveChildren(
+    List<AstNode*>* stack,
+    ZoneList<Expression*>* body_definitions,
+    int variable_count) {
+  MarkIfNotLive(right(), stack);
+  MarkIfNotLive(left(), stack);
+}
+
+
 // Implementation of a copy visitor. The visitor create a deep copy
 // of ast nodes. Nodes that do not require a deep copy are copied
 // with the default copy constructor.
diff --git a/src/ast.h b/src/ast.h
index def803b..fa85eee 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -152,6 +152,13 @@
   virtual ArrayLiteral* AsArrayLiteral() { return NULL; }
   virtual CompareOperation* AsCompareOperation() { return NULL; }
 
+  // True if the AST node is critical (its execution is needed or externally
+  // visible in some way).
+  virtual bool IsCritical() {
+    UNREACHABLE();
+    return true;
+  }
+
   int num() { return num_; }
   void set_num(int n) { num_ = n; }
 
@@ -211,7 +218,7 @@
 
   virtual bool IsValidLeftHandSide() { return false; }
 
-  virtual Variable* AssignedVar() { return NULL; }
+  virtual Variable* AssignedVariable() { return NULL; }
 
   // Symbols that cannot be parsed as array indices are considered property
   // names.  We do not treat symbols that can be array indexes as property
@@ -248,6 +255,10 @@
         LoopConditionField::encode(flag);
   }
 
+  // The value of the expression is guaranteed to be a smi, because the
+  // top operation is a bit operation with a mask, or a shift.
+  bool GuaranteedSmiResult();
+
   // AST analysis results
 
   // True if the expression rooted at this node can be compiled by the
@@ -283,6 +294,19 @@
     bitfields_ |= NumBitOpsField::encode(num_bit_ops);
   }
 
+  // Functions used for dead-code elimination.  Predicate is true if the
+  // expression is not dead code.
+  int is_live() const { return LiveField::decode(bitfields_); }
+  void mark_as_live() { bitfields_ |= LiveField::encode(true); }
+
+  // Mark non-live children as live and push them on a stack for further
+  // processing.
+  virtual void ProcessNonLiveChildren(
+      List<AstNode*>* stack,
+      ZoneList<Expression*>* body_definitions,
+      int variable_count) {
+  }
+
  private:
   static const int kMaxNumBitOps = (1 << 5) - 1;
 
@@ -295,6 +319,7 @@
   class ToInt32Field : public BitField<bool, 2, 1> {};
   class NumBitOpsField : public BitField<int, 3, 5> {};
   class LoopConditionField: public BitField<bool, 8, 1> {};
+  class LiveField: public BitField<bool, 9, 1> {};
 };
 
 
@@ -881,6 +906,11 @@
   virtual bool IsLeaf() { return true; }
   virtual bool IsTrivial() { return true; }
   virtual bool IsPrimitive();
+  virtual bool IsCritical();
+  virtual void ProcessNonLiveChildren(
+      List<AstNode*>* stack,
+      ZoneList<Expression*>* body_definitions,
+      int variable_count);
 
   // Identity testers.
   bool IsNull() const { return handle_.is_identical_to(Factory::null_value()); }
@@ -1087,6 +1117,11 @@
   virtual bool IsTrivial() { return is_trivial_; }
 
   virtual bool IsPrimitive();
+  virtual bool IsCritical();
+  virtual void ProcessNonLiveChildren(
+      List<AstNode*>* stack,
+      ZoneList<Expression*>* body_definitions,
+      int variable_count);
 
   void SetIsPrimitive(bool value) { is_primitive_ = value; }
 
@@ -1224,6 +1259,11 @@
   virtual bool IsValidLeftHandSide() { return true; }
 
   virtual bool IsPrimitive();
+  virtual bool IsCritical();
+  virtual void ProcessNonLiveChildren(
+      List<AstNode*>* stack,
+      ZoneList<Expression*>* body_definitions,
+      int variable_count);
 
   Expression* obj() const { return obj_; }
   Expression* key() const { return key_; }
@@ -1258,6 +1298,11 @@
   virtual Call* AsCall() { return this; }
 
   virtual bool IsPrimitive();
+  virtual bool IsCritical();
+  virtual void ProcessNonLiveChildren(
+      List<AstNode*>* stack,
+      ZoneList<Expression*>* body_definitions,
+      int variable_count);
 
   Expression* expression() const { return expression_; }
   ZoneList<Expression*>* arguments() const { return arguments_; }
@@ -1336,6 +1381,11 @@
   virtual UnaryOperation* AsUnaryOperation() { return this; }
 
   virtual bool IsPrimitive();
+  virtual bool IsCritical();
+  virtual void ProcessNonLiveChildren(
+      List<AstNode*>* stack,
+      ZoneList<Expression*>* body_definitions,
+      int variable_count);
 
   Token::Value op() const { return op_; }
   Expression* expression() const { return expression_; }
@@ -1361,6 +1411,11 @@
   virtual BinaryOperation* AsBinaryOperation() { return this; }
 
   virtual bool IsPrimitive();
+  virtual bool IsCritical();
+  virtual void ProcessNonLiveChildren(
+      List<AstNode*>* stack,
+      ZoneList<Expression*>* body_definitions,
+      int variable_count);
 
   // True iff the result can be safely overwritten (to avoid allocation).
   // False for operations that can return one of their operands.
@@ -1412,11 +1467,16 @@
 
   virtual CountOperation* AsCountOperation() { return this; }
 
-  virtual Variable* AssignedVar() {
+  virtual Variable* AssignedVariable() {
     return expression()->AsVariableProxy()->AsVariable();
   }
 
   virtual bool IsPrimitive();
+  virtual bool IsCritical();
+  virtual void ProcessNonLiveChildren(
+      List<AstNode*>* stack,
+      ZoneList<Expression*>* body_definitions,
+      int variable_count);
 
   bool is_prefix() const { return is_prefix_; }
   bool is_postfix() const { return !is_prefix_; }
@@ -1449,6 +1509,11 @@
   virtual void Accept(AstVisitor* v);
 
   virtual bool IsPrimitive();
+  virtual bool IsCritical();
+  virtual void ProcessNonLiveChildren(
+      List<AstNode*>* stack,
+      ZoneList<Expression*>* body_definitions,
+      int variable_count);
 
   Token::Value op() const { return op_; }
   Expression* left() const { return left_; }
@@ -1502,10 +1567,15 @@
   virtual Assignment* AsAssignment() { return this; }
 
   virtual bool IsPrimitive();
+  virtual bool IsCritical();
+  virtual void ProcessNonLiveChildren(
+      List<AstNode*>* stack,
+      ZoneList<Expression*>* body_definitions,
+      int variable_count);
 
   Assignment* AsSimpleAssignment() { return !is_compound() ? this : NULL; }
 
-  virtual Variable* AssignedVar() {
+  virtual Variable* AssignedVariable() {
     return target()->AsVariableProxy()->AsVariable();
   }
 
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index 3dc2470..8a9fa4b 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -309,6 +309,17 @@
 }
 
 
+void Bootstrapper::ReattachGlobal(Handle<Context> env,
+                                  Handle<Object> global_object) {
+  ASSERT(global_object->IsJSGlobalProxy());
+  Handle<JSGlobalProxy> global = Handle<JSGlobalProxy>::cast(global_object);
+  env->global()->set_global_receiver(*global);
+  env->set_global_proxy(*global);
+  SetObjectPrototype(global, Handle<JSObject>(env->global()));
+  global->set_context(*env);
+}
+
+
 static Handle<JSFunction> InstallFunction(Handle<JSObject> target,
                                           const char* name,
                                           InstanceType type,
diff --git a/src/bootstrapper.h b/src/bootstrapper.h
index 72b438a..66b8ff4 100644
--- a/src/bootstrapper.h
+++ b/src/bootstrapper.h
@@ -68,6 +68,9 @@
   // Detach the environment from its outer global object.
   static void DetachGlobal(Handle<Context> env);
 
+  // Reattach an outer global object to an environment.
+  static void ReattachGlobal(Handle<Context> env, Handle<Object> global_object);
+
   // Traverses the pointers for memory management.
   static void Iterate(ObjectVisitor* v);
 
diff --git a/src/codegen.cc b/src/codegen.cc
index a23b54f..56d8f4b 100644
--- a/src/codegen.cc
+++ b/src/codegen.cc
@@ -66,38 +66,6 @@
 CodeGenerator* CodeGeneratorScope::top_ = NULL;
 
 
-DeferredCode::DeferredCode()
-    : masm_(CodeGeneratorScope::Current()->masm()),
-      statement_position_(masm_->current_statement_position()),
-      position_(masm_->current_position()) {
-  ASSERT(statement_position_ != RelocInfo::kNoPosition);
-  ASSERT(position_ != RelocInfo::kNoPosition);
-
-  CodeGeneratorScope::Current()->AddDeferred(this);
-#ifdef DEBUG
-  comment_ = "";
-#endif
-
-  // Copy the register locations from the code generator's frame.
-  // These are the registers that will be spilled on entry to the
-  // deferred code and restored on exit.
-  VirtualFrame* frame = CodeGeneratorScope::Current()->frame();
-  int sp_offset = frame->fp_relative(frame->stack_pointer_);
-  for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
-    int loc = frame->register_location(i);
-    if (loc == VirtualFrame::kIllegalIndex) {
-      registers_[i] = kIgnore;
-    } else if (frame->elements_[loc].is_synced()) {
-      // Needs to be restored on exit but not saved on entry.
-      registers_[i] = frame->fp_relative(loc) | kSyncedFlag;
-    } else {
-      int offset = frame->fp_relative(loc);
-      registers_[i] = (offset < sp_offset) ? kPush : offset;
-    }
-  }
-}
-
-
 void CodeGenerator::ProcessDeferred() {
   while (!deferred_.is_empty()) {
     DeferredCode* code = deferred_.RemoveLast();
diff --git a/src/codegen.h b/src/codegen.h
index d8a339d..4634f4c 100644
--- a/src/codegen.h
+++ b/src/codegen.h
@@ -31,7 +31,7 @@
 #include "ast.h"
 #include "code-stubs.h"
 #include "runtime.h"
-#include "number-info.h"
+#include "type-info.h"
 
 // Include the declaration of the architecture defined class CodeGenerator.
 // The contract  to the shared code is that the the CodeGenerator is a subclass
@@ -346,8 +346,13 @@
  public:
   CompareStub(Condition cc,
               bool strict,
-              NaNInformation nan_info = kBothCouldBeNaN) :
-      cc_(cc), strict_(strict), never_nan_nan_(nan_info == kCantBothBeNaN) { }
+              NaNInformation nan_info = kBothCouldBeNaN,
+              bool include_number_compare = true) :
+      cc_(cc),
+      strict_(strict),
+      never_nan_nan_(nan_info == kCantBothBeNaN),
+      include_number_compare_(include_number_compare),
+      name_(NULL) { }
 
   void Generate(MacroAssembler* masm);
 
@@ -360,11 +365,16 @@
   // generating the minor key for other comparisons to avoid creating more
   // stubs.
   bool never_nan_nan_;
+  // Do generate the number comparison code in the stub. Stubs without number
+  // comparison code is used when the number comparison has been inlined, and
+  // the stub will be called if one of the operands is not a number.
+  bool include_number_compare_;
 
   // Encoding of the minor key CCCCCCCCCCCCCCNS.
   class StrictField: public BitField<bool, 0, 1> {};
   class NeverNanNanField: public BitField<bool, 1, 1> {};
-  class ConditionField: public BitField<int, 2, 14> {};
+  class IncludeNumberCompareField: public BitField<bool, 2, 1> {};
+  class ConditionField: public BitField<int, 3, 13> {};
 
   Major MajorKey() { return Compare; }
 
@@ -378,12 +388,16 @@
 
   // Unfortunately you have to run without snapshots to see most of these
   // names in the profile since most compare stubs end up in the snapshot.
+  char* name_;
   const char* GetName();
 #ifdef DEBUG
   void Print() {
-    PrintF("CompareStub (cc %d), (strict %s)\n",
+    PrintF("CompareStub (cc %d), (strict %s), "
+           "(never_nan_nan %s), (number_compare %s)\n",
            static_cast<int>(cc_),
-           strict_ ? "true" : "false");
+           strict_ ? "true" : "false",
+           never_nan_nan_ ? "true" : "false",
+           include_number_compare_ ? "included" : "not included");
   }
 #endif
 };
diff --git a/src/compiler.cc b/src/compiler.cc
index a88f18a..e2021fa 100755
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -1,4 +1,4 @@
-// Copyright 2009 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:
@@ -106,6 +106,10 @@
                         variable_count,
                         function->num_parameters());
         ta.Compute();
+
+        MarkLiveCode(builder.preorder(),
+                     builder.body_definitions(),
+                     variable_count);
       }
     }
 
@@ -521,6 +525,10 @@
                           variable_count,
                           literal->num_parameters());
           ta.Compute();
+
+          MarkLiveCode(builder.preorder(),
+                       builder.body_definitions(),
+                       variable_count);
         }
       }
 
diff --git a/src/data-flow.cc b/src/data-flow.cc
index e327c57..fe4b3db 100644
--- a/src/data-flow.cc
+++ b/src/data-flow.cc
@@ -1663,9 +1663,16 @@
   PrintF("L%d: Block\n", number());
   TextInstructionPrinter printer;
   for (int i = 0, len = instructions_.length(); i < len; i++) {
+    AstNode* instr = instructions_[i];
+    // Print a star next to dead instructions.
+    if (instr->AsExpression() != NULL && instr->AsExpression()->is_live()) {
+      PrintF("  ");
+    } else {
+      PrintF("* ");
+    }
     PrintF("%d ", printer.NextNumber());
-    printer.Visit(instructions_[i]);
-    printer.AssignNumber(instructions_[i]);
+    printer.Visit(instr);
+    printer.AssignNumber(instr);
     PrintF("\n");
   }
   PrintF("goto L%d\n\n", successor_->number());
@@ -1753,7 +1760,7 @@
   for (int i = 0; i < instruction_count; i++) {
     Expression* expr = instructions_[i]->AsExpression();
     if (expr == NULL) continue;
-    Variable* var = expr->AssignedVar();
+    Variable* var = expr->AssignedVariable();
     if (var == NULL || !var->IsStackAllocated()) continue;
 
     // All definitions of this variable are killed.
@@ -1930,7 +1937,7 @@
 
     // It may instead (or also) be a definition.  If so update the running
     // value of reaching definitions for the block.
-    Variable* var = expr->AssignedVar();
+    Variable* var = expr->AssignedVariable();
     if (var == NULL || !var->IsStackAllocated()) continue;
 
     // All definitions of this variable are killed.
@@ -1961,7 +1968,7 @@
   for (int i = 0, len = body_definitions_->length(); i < len; i++) {
     // Account for each definition in the body as a definition of the
     // defined variable.
-    Variable* var = body_definitions_->at(i)->AssignedVar();
+    Variable* var = body_definitions_->at(i)->AssignedVariable();
     variables[IndexFor(var, variable_count_)]->Add(i + variable_count_);
   }
 
@@ -2046,4 +2053,50 @@
 }
 
 
+void Node::MarkCriticalInstructions(
+    List<AstNode*>* stack,
+    ZoneList<Expression*>* body_definitions,
+    int variable_count) {
+}
+
+
+void BlockNode::MarkCriticalInstructions(
+    List<AstNode*>* stack,
+    ZoneList<Expression*>* body_definitions,
+    int variable_count) {
+  for (int i = instructions_.length() - 1; i >= 0; i--) {
+    // Only expressions can appear in the flow graph for now.
+    Expression* expr = instructions_[i]->AsExpression();
+    if (expr != NULL && !expr->is_live() &&
+        (expr->is_loop_condition() || expr->IsCritical())) {
+      expr->mark_as_live();
+      expr->ProcessNonLiveChildren(stack, body_definitions, variable_count);
+    }
+  }
+}
+
+
+void MarkLiveCode(ZoneList<Node*>* nodes,
+                  ZoneList<Expression*>* body_definitions,
+                  int variable_count) {
+  List<AstNode*> stack(20);
+
+  // Mark the critical AST nodes as live; mark their dependencies and
+  // add them to the marking stack.
+  for (int i = nodes->length() - 1; i >= 0; i--) {
+    nodes->at(i)->MarkCriticalInstructions(&stack, body_definitions,
+                                           variable_count);
+  }
+
+  // Continue marking dependencies until no more.
+  while (!stack.is_empty()) {
+  // Only expressions can appear in the flow graph for now.
+    Expression* expr = stack.RemoveLast()->AsExpression();
+    if (expr != NULL) {
+      expr->ProcessNonLiveChildren(&stack, body_definitions, variable_count);
+    }
+  }
+}
+
+
 } }  // namespace v8::internal
diff --git a/src/data-flow.h b/src/data-flow.h
index 9e7e6a4..8046e42 100644
--- a/src/data-flow.h
+++ b/src/data-flow.h
@@ -241,6 +241,12 @@
   virtual void UpdateRDIn(WorkList<Node>* worklist, bool mark) = 0;
   virtual void PropagateReachingDefinitions(List<BitVector*>* variables);
 
+  // Functions used by dead-code elimination.
+  virtual void MarkCriticalInstructions(
+      List<AstNode*>* stack,
+      ZoneList<Expression*>* body_definitions,
+      int variable_count);
+
 #ifdef DEBUG
   void AssignNodeNumber();
   void PrintReachingDefinitions();
@@ -263,24 +269,24 @@
  public:
   ExitNode() : predecessors_(4) {}
 
-  bool IsExitNode() { return true; }
+  virtual bool IsExitNode() { return true; }
 
-  void AddPredecessor(Node* predecessor) {
+  virtual void AddPredecessor(Node* predecessor) {
     ASSERT(predecessor != NULL);
     predecessors_.Add(predecessor);
   }
 
-  void AddSuccessor(Node* successor) { UNREACHABLE(); }
+  virtual void AddSuccessor(Node* successor) { UNREACHABLE(); }
 
-  void Traverse(bool mark,
-                ZoneList<Node*>* preorder,
-                ZoneList<Node*>* postorder);
+  virtual void Traverse(bool mark,
+                        ZoneList<Node*>* preorder,
+                        ZoneList<Node*>* postorder);
 
-  void ComputeRDOut(BitVector* result);
-  void UpdateRDIn(WorkList<Node>* worklist, bool mark);
+  virtual void ComputeRDOut(BitVector* result);
+  virtual void UpdateRDIn(WorkList<Node>* worklist, bool mark);
 
 #ifdef DEBUG
-  void PrintText();
+  virtual void PrintText();
 #endif
 
  private:
@@ -301,18 +307,18 @@
     return reinterpret_cast<BlockNode*>(node);
   }
 
-  bool IsBlockNode() { return true; }
+  virtual bool IsBlockNode() { return true; }
 
   bool is_empty() { return instructions_.is_empty(); }
 
   ZoneList<AstNode*>* instructions() { return &instructions_; }
 
-  void AddPredecessor(Node* predecessor) {
+  virtual void AddPredecessor(Node* predecessor) {
     ASSERT(predecessor_ == NULL && predecessor != NULL);
     predecessor_ = predecessor;
   }
 
-  void AddSuccessor(Node* successor) {
+  virtual void AddSuccessor(Node* successor) {
     ASSERT(successor_ == NULL && successor != NULL);
     successor_ = successor;
   }
@@ -321,20 +327,25 @@
     instructions_.Add(instruction);
   }
 
-  void Traverse(bool mark,
-                ZoneList<Node*>* preorder,
-                ZoneList<Node*>* postorder);
+  virtual void Traverse(bool mark,
+                        ZoneList<Node*>* preorder,
+                        ZoneList<Node*>* postorder);
 
-  void InitializeReachingDefinitions(int definition_count,
-                                     List<BitVector*>* variables,
-                                     WorkList<Node>* worklist,
-                                     bool mark);
-  void ComputeRDOut(BitVector* result);
-  void UpdateRDIn(WorkList<Node>* worklist, bool mark);
-  void PropagateReachingDefinitions(List<BitVector*>* variables);
+  virtual void InitializeReachingDefinitions(int definition_count,
+                                             List<BitVector*>* variables,
+                                             WorkList<Node>* worklist,
+                                             bool mark);
+  virtual void ComputeRDOut(BitVector* result);
+  virtual void UpdateRDIn(WorkList<Node>* worklist, bool mark);
+  virtual void PropagateReachingDefinitions(List<BitVector*>* variables);
+
+  virtual void MarkCriticalInstructions(
+      List<AstNode*>* stack,
+      ZoneList<Expression*>* body_definitions,
+      int variable_count);
 
 #ifdef DEBUG
-  void PrintText();
+  virtual void PrintText();
 #endif
 
  private:
@@ -351,14 +362,14 @@
  public:
   BranchNode() : predecessor_(NULL), successor0_(NULL), successor1_(NULL) {}
 
-  bool IsBranchNode() { return true; }
+  virtual bool IsBranchNode() { return true; }
 
-  void AddPredecessor(Node* predecessor) {
+  virtual void AddPredecessor(Node* predecessor) {
     ASSERT(predecessor_ == NULL && predecessor != NULL);
     predecessor_ = predecessor;
   }
 
-  void AddSuccessor(Node* successor) {
+  virtual void AddSuccessor(Node* successor) {
     ASSERT(successor1_ == NULL && successor != NULL);
     if (successor0_ == NULL) {
       successor0_ = successor;
@@ -367,15 +378,15 @@
     }
   }
 
-  void Traverse(bool mark,
-                ZoneList<Node*>* preorder,
-                ZoneList<Node*>* postorder);
+  virtual void Traverse(bool mark,
+                        ZoneList<Node*>* preorder,
+                        ZoneList<Node*>* postorder);
 
-  void ComputeRDOut(BitVector* result);
-  void UpdateRDIn(WorkList<Node>* worklist, bool mark);
+  virtual void ComputeRDOut(BitVector* result);
+  virtual void UpdateRDIn(WorkList<Node>* worklist, bool mark);
 
 #ifdef DEBUG
-  void PrintText();
+  virtual void PrintText();
 #endif
 
  private:
@@ -397,27 +408,27 @@
     return reinterpret_cast<JoinNode*>(node);
   }
 
-  bool IsJoinNode() { return true; }
+  virtual bool IsJoinNode() { return true; }
 
-  void AddPredecessor(Node* predecessor) {
+  virtual void AddPredecessor(Node* predecessor) {
     ASSERT(predecessor != NULL);
     predecessors_.Add(predecessor);
   }
 
-  void AddSuccessor(Node* successor) {
+  virtual void AddSuccessor(Node* successor) {
     ASSERT(successor_ == NULL && successor != NULL);
     successor_ = successor;
   }
 
-  void Traverse(bool mark,
-                ZoneList<Node*>* preorder,
-                ZoneList<Node*>* postorder);
+  virtual void Traverse(bool mark,
+                        ZoneList<Node*>* preorder,
+                        ZoneList<Node*>* postorder);
 
-  void ComputeRDOut(BitVector* result);
-  void UpdateRDIn(WorkList<Node>* worklist, bool mark);
+  virtual void ComputeRDOut(BitVector* result);
+  virtual void UpdateRDIn(WorkList<Node>* worklist, bool mark);
 
 #ifdef DEBUG
-  void PrintText();
+  virtual void PrintText();
 #endif
 
  private:
@@ -499,6 +510,7 @@
   void Build(FunctionLiteral* lit);
 
   FlowGraph* graph() { return &graph_; }
+  ZoneList<Node*>* preorder() { return &preorder_; }
   ZoneList<Node*>* postorder() { return &postorder_; }
   ZoneList<Expression*>* body_definitions() { return &body_definitions_; }
 
@@ -622,7 +634,6 @@
 };
 
 
-
 class TypeAnalyzer BASE_EMBEDDED {
  public:
   TypeAnalyzer(ZoneList<Node*>* postorder,
@@ -645,8 +656,16 @@
   ZoneList<Expression*>* body_definitions_;
   int variable_count_;
   int param_count_;
+
+  DISALLOW_COPY_AND_ASSIGN(TypeAnalyzer);
 };
 
+
+void MarkLiveCode(ZoneList<Node*>* nodes,
+                  ZoneList<Expression*>* body_definitions,
+                  int variable_count);
+
+
 } }  // namespace v8::internal
 
 
diff --git a/src/debug-debugger.js b/src/debug-debugger.js
index 5ba5a3b..a81530e 100644
--- a/src/debug-debugger.js
+++ b/src/debug-debugger.js
@@ -778,6 +778,8 @@
 ExecutionState.prototype.frame = function(opt_index) {
   // If no index supplied return the selected frame.
   if (opt_index == null) opt_index = this.selected_frame;
+  if (opt_index < 0 || opt_index >= this.frameCount())
+    throw new Error('Illegal frame index.');
   return new FrameMirror(this.break_id, opt_index);
 };
 
diff --git a/src/debug.cc b/src/debug.cc
index e5d42b9..4dce4cf 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -2448,7 +2448,7 @@
 
   // Enter the debugger.
   EnterDebugger debugger;
-  if (debugger.FailedToEnter() || !debugger.HasJavaScriptFrames()) {
+  if (debugger.FailedToEnter()) {
     return Factory::undefined_value();
   }
 
@@ -2461,8 +2461,12 @@
 
   static const int kArgc = 2;
   Object** argv[kArgc] = { exec_state.location(), data.location() };
-  Handle<Object> result = Execution::Call(fun, Factory::undefined_value(),
-                                          kArgc, argv, pending_exception);
+  Handle<Object> result = Execution::Call(
+      fun,
+      Handle<Object>(Debug::debug_context_->global_proxy()),
+      kArgc,
+      argv,
+      pending_exception);
   return result;
 }
 
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index 89c4ca4..b32ee9f 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -205,6 +205,9 @@
             "Flush inline caches prior to mark compact collection.")
 DEFINE_bool(cleanup_caches_in_maps_at_gc, true,
             "Flush code caches in maps during mark compact cycle.")
+DEFINE_int(random_seed, 0,
+           "Default seed for initializing random generator "
+           "(0, the default, means to use system random).")
 
 DEFINE_bool(canonicalize_object_literal_maps, true,
             "Canonicalize maps for object literals.")
diff --git a/src/frame-element.h b/src/frame-element.h
index 2bbc288..83db5c3 100644
--- a/src/frame-element.h
+++ b/src/frame-element.h
@@ -28,7 +28,7 @@
 #ifndef V8_FRAME_ELEMENT_H_
 #define V8_FRAME_ELEMENT_H_
 
-#include "number-info.h"
+#include "type-info-inl.h"
 #include "macro-assembler.h"
 #include "zone.h"
 
@@ -54,25 +54,19 @@
     SYNCED
   };
 
-  inline NumberInfo number_info() {
-    // Copied elements do not have number info. Instead
+  inline TypeInfo type_info() {
+    // Copied elements do not have type info. Instead
     // we have to inspect their backing element in the frame.
     ASSERT(!is_copy());
-    if (!is_constant()) {
-      return NumberInfo::FromInt(NumberInfoField::decode(value_));
-    }
-    Handle<Object> value = handle();
-    if (value->IsSmi()) return NumberInfo::Smi();
-    if (value->IsHeapNumber()) return NumberInfo::HeapNumber();
-    return NumberInfo::Unknown();
+    return TypeInfo::FromInt(TypeInfoField::decode(value_));
   }
 
-  inline void set_number_info(NumberInfo info) {
-    // Copied elements do not have number info. Instead
+  inline void set_type_info(TypeInfo info) {
+    // Copied elements do not have type info. Instead
     // we have to inspect their backing element in the frame.
     ASSERT(!is_copy());
-    value_ = value_ & ~NumberInfoField::mask();
-    value_ = value_ | NumberInfoField::encode(info.ToInt());
+    value_ = value_ & ~TypeInfoField::mask();
+    value_ = value_ | TypeInfoField::encode(info.ToInt());
   }
 
   // The default constructor creates an invalid frame element.
@@ -80,7 +74,7 @@
     value_ = TypeField::encode(INVALID)
         | CopiedField::encode(false)
         | SyncedField::encode(false)
-        | NumberInfoField::encode(NumberInfo::Uninitialized().ToInt())
+        | TypeInfoField::encode(TypeInfo::Uninitialized().ToInt())
         | DataField::encode(0);
   }
 
@@ -91,7 +85,7 @@
   }
 
   // Factory function to construct an in-memory frame element.
-  static FrameElement MemoryElement(NumberInfo info) {
+  static FrameElement MemoryElement(TypeInfo info) {
     FrameElement result(MEMORY, no_reg, SYNCED, info);
     return result;
   }
@@ -99,7 +93,7 @@
   // Factory function to construct an in-register frame element.
   static FrameElement RegisterElement(Register reg,
                                       SyncFlag is_synced,
-                                      NumberInfo info) {
+                                      TypeInfo info) {
     return FrameElement(REGISTER, reg, is_synced, info);
   }
 
@@ -107,7 +101,8 @@
   // compile time.
   static FrameElement ConstantElement(Handle<Object> value,
                                       SyncFlag is_synced) {
-    FrameElement result(value, is_synced);
+    TypeInfo info = TypeInfo::TypeFromValue(value);
+    FrameElement result(value, is_synced, info);
     return result;
   }
 
@@ -223,20 +218,20 @@
   FrameElement(Type type,
                Register reg,
                SyncFlag is_synced,
-               NumberInfo info) {
+               TypeInfo info) {
     value_ = TypeField::encode(type)
         | CopiedField::encode(false)
         | SyncedField::encode(is_synced != NOT_SYNCED)
-        | NumberInfoField::encode(info.ToInt())
+        | TypeInfoField::encode(info.ToInt())
         | DataField::encode(reg.code_ > 0 ? reg.code_ : 0);
   }
 
   // Used to construct constant elements.
-  FrameElement(Handle<Object> value, SyncFlag is_synced) {
+  FrameElement(Handle<Object> value, SyncFlag is_synced, TypeInfo info) {
     value_ = TypeField::encode(CONSTANT)
         | CopiedField::encode(false)
         | SyncedField::encode(is_synced != NOT_SYNCED)
-        | NumberInfoField::encode(NumberInfo::Uninitialized().ToInt())
+        | TypeInfoField::encode(info.ToInt())
         | DataField::encode(ConstantList()->length());
     ConstantList()->Add(value);
   }
@@ -262,12 +257,13 @@
   // Encode type, copied, synced and data in one 32 bit integer.
   uint32_t value_;
 
+  // Declare BitFields with template parameters <type, start, size>.
   class TypeField: public BitField<Type, 0, 3> {};
   class CopiedField: public BitField<bool, 3, 1> {};
   class SyncedField: public BitField<bool, 4, 1> {};
   class UntaggedInt32Field: public BitField<bool, 5, 1> {};
-  class NumberInfoField: public BitField<int, 6, 4> {};
-  class DataField: public BitField<uint32_t, 10, 32 - 10> {};
+  class TypeInfoField: public BitField<int, 6, 6> {};
+  class DataField: public BitField<uint32_t, 12, 32 - 12> {};
 
   friend class VirtualFrame;
 };
diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc
index d71b639..20b6463 100644
--- a/src/ia32/codegen-ia32.cc
+++ b/src/ia32/codegen-ia32.cc
@@ -490,7 +490,11 @@
   Load(expr);
   Result value = frame_->Pop();
   ASSERT(frame_->HasNoUntaggedInt32Elements());
-  ConvertInt32ResultToNumber(&value);
+  if (expr->GuaranteedSmiResult()) {
+    ConvertInt32ResultToSmi(&value);
+  } else {
+    ConvertInt32ResultToNumber(&value);
+  }
   set_in_safe_int32_mode(false);
   set_unsafe_bailout(NULL);
   frame_->Push(&value);
@@ -504,6 +508,19 @@
 }
 
 
+void CodeGenerator::ConvertInt32ResultToSmi(Result* value) {
+  ASSERT(value->is_untagged_int32());
+  if (value->is_register()) {
+    __ add(value->reg(), Operand(value->reg()));
+  } else {
+    ASSERT(value->is_constant());
+    ASSERT(value->handle()->IsSmi());
+  }
+  value->set_untagged_int32(false);
+  value->set_type_info(TypeInfo::Smi());
+}
+
+
 void CodeGenerator::ConvertInt32ResultToNumber(Result* value) {
   ASSERT(value->is_untagged_int32());
   if (value->is_register()) {
@@ -552,6 +569,7 @@
     ASSERT(value->is_constant());
   }
   value->set_untagged_int32(false);
+  value->set_type_info(TypeInfo::Integer32());
 }
 
 
@@ -850,7 +868,7 @@
     dest->Split(not_zero);
   } else if (value.is_number()) {
     Comment cmnt(masm_, "ONLY_NUMBER");
-    // Fast case if NumberInfo indicates only numbers.
+    // Fast case if TypeInfo indicates only numbers.
     if (FLAG_debug_code) {
       __ AbortIfNotNumber(value.reg());
     }
@@ -911,6 +929,7 @@
   // operand in register number. Returns operand as floating point number
   // on FPU stack.
   static void LoadFloatOperand(MacroAssembler* masm, Register number);
+
   // Code pattern for loading floating point values. Input values must
   // be either smi or heap number objects (fp values). Requirements:
   // operand_1 on TOS+1 or in edx, operand_2 on TOS+2 or in eax.
@@ -929,14 +948,15 @@
   static void CheckFloatOperands(MacroAssembler* masm,
                                  Label* non_float,
                                  Register scratch);
+
   // Takes the operands in edx and eax and loads them as integers in eax
   // and ecx.
   static void LoadAsIntegers(MacroAssembler* masm,
-                             NumberInfo number_info,
+                             TypeInfo type_info,
                              bool use_sse3,
                              Label* operand_conversion_failure);
   static void LoadNumbersAsIntegers(MacroAssembler* masm,
-                                    NumberInfo number_info,
+                                    TypeInfo type_info,
                                     bool use_sse3,
                                     Label* operand_conversion_failure);
   static void LoadUnknownsAsIntegers(MacroAssembler* masm,
@@ -947,6 +967,7 @@
   // into xmm0 and xmm1 if they are. Operands are in edx and eax.
   // Leaves operands unchanged.
   static void LoadSSE2Operands(MacroAssembler* masm);
+
   // Test if operands are numbers (smi or HeapNumber objects), and load
   // them into xmm0 and xmm1 if they are.  Jump to label not_numbers if
   // either operand is not a number.  Operands are in edx and eax.
@@ -993,8 +1014,8 @@
                                 Register dst,
                                 Register left,
                                 Register right,
-                                NumberInfo left_info,
-                                NumberInfo right_info,
+                                TypeInfo left_info,
+                                TypeInfo right_info,
                                 OverwriteMode mode)
       : op_(op), dst_(dst), left_(left), right_(right),
         left_info_(left_info), right_info_(right_info), mode_(mode) {
@@ -1008,8 +1029,8 @@
   Register dst_;
   Register left_;
   Register right_;
-  NumberInfo left_info_;
-  NumberInfo right_info_;
+  TypeInfo left_info_;
+  TypeInfo right_info_;
   OverwriteMode mode_;
 };
 
@@ -1103,23 +1124,23 @@
   GenericBinaryOpStub stub(op_,
                            mode_,
                            NO_SMI_CODE_IN_STUB,
-                           NumberInfo::Combine(left_info_, right_info_));
+                           TypeInfo::Combine(left_info_, right_info_));
   stub.GenerateCall(masm_, left_, right_);
   if (!dst_.is(eax)) __ mov(dst_, eax);
   __ bind(&done);
 }
 
 
-static NumberInfo CalculateNumberInfo(NumberInfo operands_type,
+static TypeInfo CalculateTypeInfo(TypeInfo operands_type,
                                       Token::Value op,
                                       const Result& right,
                                       const Result& left) {
-  // Set NumberInfo of result according to the operation performed.
+  // Set TypeInfo of result according to the operation performed.
   // Rely on the fact that smis have a 31 bit payload on ia32.
   ASSERT(kSmiValueSize == 31);
   switch (op) {
     case Token::COMMA:
-      return right.number_info();
+      return right.type_info();
     case Token::OR:
     case Token::AND:
       // Result type can be either of the two input types.
@@ -1128,74 +1149,74 @@
       // Anding with positive Smis will give you a Smi.
       if (right.is_constant() && right.handle()->IsSmi() &&
           Smi::cast(*right.handle())->value() >= 0) {
-        return NumberInfo::Smi();
+        return TypeInfo::Smi();
       } else if (left.is_constant() && left.handle()->IsSmi() &&
           Smi::cast(*left.handle())->value() >= 0) {
-        return NumberInfo::Smi();
+        return TypeInfo::Smi();
       }
       return (operands_type.IsSmi())
-          ? NumberInfo::Smi()
-          : NumberInfo::Integer32();
+          ? TypeInfo::Smi()
+          : TypeInfo::Integer32();
     }
     case Token::BIT_OR: {
       // Oring with negative Smis will give you a Smi.
       if (right.is_constant() && right.handle()->IsSmi() &&
           Smi::cast(*right.handle())->value() < 0) {
-        return NumberInfo::Smi();
+        return TypeInfo::Smi();
       } else if (left.is_constant() && left.handle()->IsSmi() &&
           Smi::cast(*left.handle())->value() < 0) {
-        return NumberInfo::Smi();
+        return TypeInfo::Smi();
       }
       return (operands_type.IsSmi())
-          ? NumberInfo::Smi()
-          : NumberInfo::Integer32();
+          ? TypeInfo::Smi()
+          : TypeInfo::Integer32();
     }
     case Token::BIT_XOR:
       // Result is always a 32 bit integer. Smi property of inputs is preserved.
       return (operands_type.IsSmi())
-          ? NumberInfo::Smi()
-          : NumberInfo::Integer32();
+          ? TypeInfo::Smi()
+          : TypeInfo::Integer32();
     case Token::SAR:
-      if (left.is_smi()) return NumberInfo::Smi();
+      if (left.is_smi()) return TypeInfo::Smi();
       // Result is a smi if we shift by a constant >= 1, otherwise an integer32.
       return (right.is_constant() && right.handle()->IsSmi()
                      && Smi::cast(*right.handle())->value() >= 1)
-          ? NumberInfo::Smi()
-          : NumberInfo::Integer32();
+          ? TypeInfo::Smi()
+          : TypeInfo::Integer32();
     case Token::SHR:
       // Result is a smi if we shift by a constant >= 2, otherwise an integer32.
       return (right.is_constant() && right.handle()->IsSmi()
                      && Smi::cast(*right.handle())->value() >= 2)
-          ? NumberInfo::Smi()
-          : NumberInfo::Integer32();
+          ? TypeInfo::Smi()
+          : TypeInfo::Integer32();
     case Token::ADD:
       if (operands_type.IsSmi()) {
         // The Integer32 range is big enough to take the sum of any two Smis.
-        return NumberInfo::Integer32();
+        return TypeInfo::Integer32();
       } else {
         // Result could be a string or a number. Check types of inputs.
         return operands_type.IsNumber()
-            ? NumberInfo::Number()
-            : NumberInfo::Unknown();
+            ? TypeInfo::Number()
+            : TypeInfo::Unknown();
       }
     case Token::SHL:
-      return NumberInfo::Integer32();
+      return TypeInfo::Integer32();
     case Token::SUB:
       // The Integer32 range is big enough to take the difference of any two
       // Smis.
       return (operands_type.IsSmi()) ?
-                    NumberInfo::Integer32() :
-                    NumberInfo::Number();
+                    TypeInfo::Integer32() :
+                    TypeInfo::Number();
     case Token::MUL:
     case Token::DIV:
     case Token::MOD:
       // Result is always a number.
-      return NumberInfo::Number();
+      return TypeInfo::Number();
     default:
       UNREACHABLE();
   }
   UNREACHABLE();
-  return NumberInfo::Unknown();
+  return TypeInfo::Unknown();
 }
 
 
@@ -1255,10 +1276,10 @@
   }
 
   // Get number type of left and right sub-expressions.
-  NumberInfo operands_type =
-      NumberInfo::Combine(left.number_info(), right.number_info());
+  TypeInfo operands_type =
+      TypeInfo::Combine(left.type_info(), right.type_info());
 
-  NumberInfo result_type = CalculateNumberInfo(operands_type, op, right, left);
+  TypeInfo result_type = CalculateTypeInfo(operands_type, op, right, left);
 
   Result answer;
   if (left_is_non_smi_constant || right_is_non_smi_constant) {
@@ -1297,7 +1318,7 @@
     }
   }
 
-  answer.set_number_info(result_type);
+  answer.set_type_info(result_type);
   frame_->Push(&answer);
 }
 
@@ -1385,7 +1406,7 @@
 
 static void CheckTwoForSminess(MacroAssembler* masm,
                                Register left, Register right, Register scratch,
-                               NumberInfo left_info, NumberInfo right_info,
+                               TypeInfo left_info, TypeInfo right_info,
                                DeferredInlineBinaryOperation* deferred);
 
 
@@ -1470,8 +1491,8 @@
                                           (op == Token::DIV) ? eax : edx,
                                           left->reg(),
                                           right->reg(),
-                                          left->number_info(),
-                                          right->number_info(),
+                                          left->type_info(),
+                                          right->type_info(),
                                           overwrite_mode);
     if (left->reg().is(right->reg())) {
       __ test(left->reg(), Immediate(kSmiTagMask));
@@ -1574,18 +1595,18 @@
                                           answer.reg(),
                                           left->reg(),
                                           ecx,
-                                          left->number_info(),
-                                          right->number_info(),
+                                          left->type_info(),
+                                          right->type_info(),
                                           overwrite_mode);
 
     Label do_op, left_nonsmi;
     // If right is a smi we make a fast case if left is either a smi
     // or a heapnumber.
-    if (CpuFeatures::IsSupported(SSE2) && right->number_info().IsSmi()) {
+    if (CpuFeatures::IsSupported(SSE2) && right->type_info().IsSmi()) {
       CpuFeatures::Scope use_sse2(SSE2);
       __ mov(answer.reg(), left->reg());
       // Fast case - both are actually smis.
-      if (!left->number_info().IsSmi()) {
+      if (!left->type_info().IsSmi()) {
         __ test(answer.reg(), Immediate(kSmiTagMask));
         __ j(not_zero, &left_nonsmi);
       } else {
@@ -1609,7 +1630,7 @@
       deferred->Branch(negative);
     } else {
       CheckTwoForSminess(masm_, left->reg(), right->reg(), answer.reg(),
-                         left->number_info(), right->number_info(), deferred);
+                         left->type_info(), right->type_info(), deferred);
 
       // Untag both operands.
       __ mov(answer.reg(), left->reg());
@@ -1682,11 +1703,11 @@
                                         answer.reg(),
                                         left->reg(),
                                         right->reg(),
-                                        left->number_info(),
-                                        right->number_info(),
+                                        left->type_info(),
+                                        right->type_info(),
                                         overwrite_mode);
   CheckTwoForSminess(masm_, left->reg(), right->reg(), answer.reg(),
-                     left->number_info(), right->number_info(), deferred);
+                     left->type_info(), right->type_info(), deferred);
 
   __ mov(answer.reg(), left->reg());
   switch (op) {
@@ -1758,16 +1779,16 @@
   DeferredInlineSmiOperation(Token::Value op,
                              Register dst,
                              Register src,
-                             NumberInfo number_info,
+                             TypeInfo type_info,
                              Smi* value,
                              OverwriteMode overwrite_mode)
       : op_(op),
         dst_(dst),
         src_(src),
-        number_info_(number_info),
+        type_info_(type_info),
         value_(value),
         overwrite_mode_(overwrite_mode) {
-    if (number_info.IsSmi()) overwrite_mode_ = NO_OVERWRITE;
+    if (type_info.IsSmi()) overwrite_mode_ = NO_OVERWRITE;
     set_comment("[ DeferredInlineSmiOperation");
   }
 
@@ -1777,7 +1798,7 @@
   Token::Value op_;
   Register dst_;
   Register src_;
-  NumberInfo number_info_;
+  TypeInfo type_info_;
   Smi* value_;
   OverwriteMode overwrite_mode_;
 };
@@ -1789,7 +1810,7 @@
       op_,
       overwrite_mode_,
       (op_ == Token::MOD) ? NO_GENERIC_BINARY_FLAGS : NO_SMI_CODE_IN_STUB,
-      NumberInfo::Combine(NumberInfo::Smi(), number_info_));
+      TypeInfo::Combine(TypeInfo::Smi(), type_info_));
   stub.GenerateCall(masm_, src_, value_);
   if (!dst_.is(eax)) __ mov(dst_, eax);
 }
@@ -1803,11 +1824,11 @@
                                      Register dst,
                                      Smi* value,
                                      Register src,
-                                     NumberInfo number_info,
+                                     TypeInfo type_info,
                                      OverwriteMode overwrite_mode)
       : op_(op),
         dst_(dst),
-        number_info_(number_info),
+        type_info_(type_info),
         value_(value),
         src_(src),
         overwrite_mode_(overwrite_mode) {
@@ -1819,7 +1840,7 @@
  private:
   Token::Value op_;
   Register dst_;
-  NumberInfo number_info_;
+  TypeInfo type_info_;
   Smi* value_;
   Register src_;
   OverwriteMode overwrite_mode_;
@@ -1831,7 +1852,7 @@
       op_,
       overwrite_mode_,
       NO_SMI_CODE_IN_STUB,
-      NumberInfo::Combine(NumberInfo::Smi(), number_info_));
+      TypeInfo::Combine(TypeInfo::Smi(), type_info_));
   igostub.GenerateCall(masm_, value_, src_);
   if (!dst_.is(eax)) __ mov(dst_, eax);
 }
@@ -1843,14 +1864,14 @@
 class DeferredInlineSmiAdd: public DeferredCode {
  public:
   DeferredInlineSmiAdd(Register dst,
-                       NumberInfo number_info,
+                       TypeInfo type_info,
                        Smi* value,
                        OverwriteMode overwrite_mode)
       : dst_(dst),
-        number_info_(number_info),
+        type_info_(type_info),
         value_(value),
         overwrite_mode_(overwrite_mode) {
-    if (number_info_.IsSmi()) overwrite_mode_ = NO_OVERWRITE;
+    if (type_info_.IsSmi()) overwrite_mode_ = NO_OVERWRITE;
     set_comment("[ DeferredInlineSmiAdd");
   }
 
@@ -1858,7 +1879,7 @@
 
  private:
   Register dst_;
-  NumberInfo number_info_;
+  TypeInfo type_info_;
   Smi* value_;
   OverwriteMode overwrite_mode_;
 };
@@ -1871,7 +1892,7 @@
       Token::ADD,
       overwrite_mode_,
       NO_SMI_CODE_IN_STUB,
-      NumberInfo::Combine(NumberInfo::Smi(), number_info_));
+      TypeInfo::Combine(TypeInfo::Smi(), type_info_));
   igostub.GenerateCall(masm_, dst_, value_);
   if (!dst_.is(eax)) __ mov(dst_, eax);
 }
@@ -1883,11 +1904,11 @@
 class DeferredInlineSmiAddReversed: public DeferredCode {
  public:
   DeferredInlineSmiAddReversed(Register dst,
-                               NumberInfo number_info,
+                               TypeInfo type_info,
                                Smi* value,
                                OverwriteMode overwrite_mode)
       : dst_(dst),
-        number_info_(number_info),
+        type_info_(type_info),
         value_(value),
         overwrite_mode_(overwrite_mode) {
     set_comment("[ DeferredInlineSmiAddReversed");
@@ -1897,7 +1918,7 @@
 
  private:
   Register dst_;
-  NumberInfo number_info_;
+  TypeInfo type_info_;
   Smi* value_;
   OverwriteMode overwrite_mode_;
 };
@@ -1910,7 +1931,7 @@
       Token::ADD,
       overwrite_mode_,
       NO_SMI_CODE_IN_STUB,
-      NumberInfo::Combine(NumberInfo::Smi(), number_info_));
+      TypeInfo::Combine(TypeInfo::Smi(), type_info_));
   igostub.GenerateCall(masm_, value_, dst_);
   if (!dst_.is(eax)) __ mov(dst_, eax);
 }
@@ -1923,14 +1944,14 @@
 class DeferredInlineSmiSub: public DeferredCode {
  public:
   DeferredInlineSmiSub(Register dst,
-                       NumberInfo number_info,
+                       TypeInfo type_info,
                        Smi* value,
                        OverwriteMode overwrite_mode)
       : dst_(dst),
-        number_info_(number_info),
+        type_info_(type_info),
         value_(value),
         overwrite_mode_(overwrite_mode) {
-    if (number_info.IsSmi()) overwrite_mode_ = NO_OVERWRITE;
+    if (type_info.IsSmi()) overwrite_mode_ = NO_OVERWRITE;
     set_comment("[ DeferredInlineSmiSub");
   }
 
@@ -1938,7 +1959,7 @@
 
  private:
   Register dst_;
-  NumberInfo number_info_;
+  TypeInfo type_info_;
   Smi* value_;
   OverwriteMode overwrite_mode_;
 };
@@ -1951,7 +1972,7 @@
       Token::SUB,
       overwrite_mode_,
       NO_SMI_CODE_IN_STUB,
-      NumberInfo::Combine(NumberInfo::Smi(), number_info_));
+      TypeInfo::Combine(TypeInfo::Smi(), type_info_));
   igostub.GenerateCall(masm_, dst_, value_);
   if (!dst_.is(eax)) __ mov(dst_, eax);
 }
@@ -1996,18 +2017,18 @@
       DeferredCode* deferred = NULL;
       if (reversed) {
         deferred = new DeferredInlineSmiAddReversed(operand->reg(),
-                                                    operand->number_info(),
+                                                    operand->type_info(),
                                                     smi_value,
                                                     overwrite_mode);
       } else {
         deferred = new DeferredInlineSmiAdd(operand->reg(),
-                                            operand->number_info(),
+                                            operand->type_info(),
                                             smi_value,
                                             overwrite_mode);
       }
       __ add(Operand(operand->reg()), Immediate(value));
       deferred->Branch(overflow);
-      if (!operand->number_info().IsSmi()) {
+      if (!operand->type_info().IsSmi()) {
         __ test(operand->reg(), Immediate(kSmiTagMask));
         deferred->Branch(not_zero);
       } else {
@@ -2032,7 +2053,7 @@
                                                    answer.reg(),
                                                    smi_value,
                                                    operand->reg(),
-                                                   operand->number_info(),
+                                                   operand->type_info(),
                                                    overwrite_mode);
         __ sub(answer.reg(), Operand(operand->reg()));
       } else {
@@ -2040,13 +2061,13 @@
         frame_->Spill(operand->reg());
         answer = *operand;
         deferred = new DeferredInlineSmiSub(operand->reg(),
-                                            operand->number_info(),
+                                            operand->type_info(),
                                             smi_value,
                                             overwrite_mode);
         __ sub(Operand(operand->reg()), Immediate(value));
       }
       deferred->Branch(overflow);
-      if (!operand->number_info().IsSmi()) {
+      if (!operand->type_info().IsSmi()) {
         __ test(answer.reg(), Immediate(kSmiTagMask));
         deferred->Branch(not_zero);
       } else {
@@ -2068,12 +2089,12 @@
         int shift_value = int_value & 0x1f;
         operand->ToRegister();
         frame_->Spill(operand->reg());
-        if (!operand->number_info().IsSmi()) {
+        if (!operand->type_info().IsSmi()) {
           DeferredInlineSmiOperation* deferred =
               new DeferredInlineSmiOperation(op,
                                              operand->reg(),
                                              operand->reg(),
-                                             operand->number_info(),
+                                             operand->type_info(),
                                              smi_value,
                                              overwrite_mode);
           __ test(operand->reg(), Immediate(kSmiTagMask));
@@ -2110,10 +2131,10 @@
             new DeferredInlineSmiOperation(op,
                                            answer.reg(),
                                            operand->reg(),
-                                           operand->number_info(),
+                                           operand->type_info(),
                                            smi_value,
                                            overwrite_mode);
-        if (!operand->number_info().IsSmi()) {
+        if (!operand->type_info().IsSmi()) {
           __ test(operand->reg(), Immediate(kSmiTagMask));
           deferred->Branch(not_zero);
         } else {
@@ -2160,11 +2181,11 @@
                                                    answer.reg(),
                                                    smi_value,
                                                    right.reg(),
-                                                   right.number_info(),
+                                                   right.type_info(),
                                                    overwrite_mode);
         __ mov(answer.reg(), Immediate(int_value));
         __ sar(ecx, kSmiTagSize);
-        if (!right.number_info().IsSmi()) {
+        if (!right.type_info().IsSmi()) {
           deferred->Branch(carry);
         } else {
           if (FLAG_debug_code) __ AbortIfNotSmi(right.reg());
@@ -2187,7 +2208,7 @@
               new DeferredInlineSmiOperation(op,
                                              operand->reg(),
                                              operand->reg(),
-                                             operand->number_info(),
+                                             operand->type_info(),
                                              smi_value,
                                              overwrite_mode);
           __ test(operand->reg(), Immediate(kSmiTagMask));
@@ -2202,10 +2223,10 @@
               new DeferredInlineSmiOperation(op,
                                              answer.reg(),
                                              operand->reg(),
-                                             operand->number_info(),
+                                             operand->type_info(),
                                              smi_value,
                                              overwrite_mode);
-          if (!operand->number_info().IsSmi()) {
+          if (!operand->type_info().IsSmi()) {
             __ test(operand->reg(), Immediate(kSmiTagMask));
             deferred->Branch(not_zero);
           } else {
@@ -2239,17 +2260,17 @@
                                                    operand->reg(),
                                                    smi_value,
                                                    operand->reg(),
-                                                   operand->number_info(),
+                                                   operand->type_info(),
                                                    overwrite_mode);
       } else {
         deferred =  new DeferredInlineSmiOperation(op,
                                                    operand->reg(),
                                                    operand->reg(),
-                                                   operand->number_info(),
+                                                   operand->type_info(),
                                                    smi_value,
                                                    overwrite_mode);
       }
-      if (!operand->number_info().IsSmi()) {
+      if (!operand->type_info().IsSmi()) {
         __ test(operand->reg(), Immediate(kSmiTagMask));
         deferred->Branch(not_zero);
       } else {
@@ -2281,7 +2302,7 @@
             new DeferredInlineSmiOperation(op,
                                            operand->reg(),
                                            operand->reg(),
-                                           operand->number_info(),
+                                           operand->type_info(),
                                            smi_value,
                                            overwrite_mode);
         // Check that lowest log2(value) bits of operand are zero, and test
@@ -2317,7 +2338,7 @@
             new DeferredInlineSmiOperation(op,
                                            operand->reg(),
                                            operand->reg(),
-                                           operand->number_info(),
+                                           operand->type_info(),
                                            smi_value,
                                            overwrite_mode);
         // Check for negative or non-Smi left hand side.
@@ -2353,14 +2374,30 @@
 
 
 static bool CouldBeNaN(const Result& result) {
-  if (result.number_info().IsSmi()) return false;
-  if (result.number_info().IsInteger32()) return false;
+  if (result.type_info().IsSmi()) return false;
+  if (result.type_info().IsInteger32()) return false;
   if (!result.is_constant()) return true;
   if (!result.handle()->IsHeapNumber()) return false;
   return isnan(HeapNumber::cast(*result.handle())->value());
 }
 
 
+// Convert from signed to unsigned comparison to match the way EFLAGS are set
+// by FPU and XMM compare instructions.
+static Condition DoubleCondition(Condition cc) {
+  switch (cc) {
+    case less:          return below;
+    case equal:         return equal;
+    case less_equal:    return below_equal;
+    case greater:       return above;
+    case greater_equal: return above_equal;
+    default:            UNREACHABLE();
+  }
+  UNREACHABLE();
+  return equal;
+}
+
+
 void CodeGenerator::Comparison(AstNode* node,
                                Condition cc,
                                bool strict,
@@ -2431,7 +2468,7 @@
         left_side = right_side;
         right_side = temp;
         cc = ReverseCondition(cc);
-        // This may reintroduce greater or less_equal as the value of cc.
+        // This may re-introduce greater or less_equal as the value of cc.
         // CompareStub and the inline code both support all values of cc.
       }
       // Implement comparison against a constant Smi, inlining the case
@@ -2480,16 +2517,7 @@
           // Jump to builtin for NaN.
           not_number.Branch(parity_even, &left_side);
           left_side.Unuse();
-          Condition double_cc = cc;
-          switch (cc) {
-            case less:          double_cc = below;       break;
-            case equal:         double_cc = equal;       break;
-            case less_equal:    double_cc = below_equal; break;
-            case greater:       double_cc = above;       break;
-            case greater_equal: double_cc = above_equal; break;
-            default: UNREACHABLE();
-          }
-          dest->true_target()->Branch(double_cc);
+          dest->true_target()->Branch(DoubleCondition(cc));
           dest->false_target()->Jump();
           not_number.Bind(&left_side);
         }
@@ -2688,21 +2716,53 @@
       dest->Split(cc);
     }
   } else {
-    // Neither side is a constant Smi or null.
-    // If either side is a non-smi constant, skip the smi check.
+    // Neither side is a constant Smi, constant 1-char string or constant null.
+    // If either side is a non-smi constant, or known to be a heap number skip
+    // the smi check.
     bool known_non_smi =
         (left_side.is_constant() && !left_side.handle()->IsSmi()) ||
-        (right_side.is_constant() && !right_side.handle()->IsSmi());
+        (right_side.is_constant() && !right_side.handle()->IsSmi()) ||
+        left_side.type_info().IsDouble() ||
+        right_side.type_info().IsDouble();
     NaNInformation nan_info =
         (CouldBeNaN(left_side) && CouldBeNaN(right_side)) ?
         kBothCouldBeNaN :
         kCantBothBeNaN;
+
+    // Inline number comparison handling any combination of smi's and heap
+    // numbers if:
+    //   code is in a loop
+    //   the compare operation is different from equal
+    //   compare is not a for-loop comparison
+    // The reason for excluding equal is that it will most likely be done
+    // with smi's (not heap numbers) and the code to comparing smi's is inlined
+    // separately. The same reason applies for for-loop comparison which will
+    // also most likely be smi comparisons.
+    bool is_loop_condition = (node->AsExpression() != NULL)
+        && node->AsExpression()->is_loop_condition();
+    bool inline_number_compare =
+        loop_nesting() > 0 && cc != equal && !is_loop_condition;
+
+    // Left and right needed in registers for the following code.
     left_side.ToRegister();
     right_side.ToRegister();
 
     if (known_non_smi) {
-      // When non-smi, call out to the compare stub.
-      CompareStub stub(cc, strict, nan_info);
+      // Inline the equality check if both operands can't be a NaN. If both
+      // objects are the same they are equal.
+      if (nan_info == kCantBothBeNaN && cc == equal) {
+        __ cmp(left_side.reg(), Operand(right_side.reg()));
+        dest->true_target()->Branch(equal);
+      }
+
+      // Inline number comparison.
+      if (inline_number_compare) {
+        GenerateInlineNumberComparison(&left_side, &right_side, cc, dest);
+      }
+
+      // End of in-line compare, call out to the compare stub. Don't include
+      // number comparison in the stub if it was inlined.
+      CompareStub stub(cc, strict, nan_info, !inline_number_compare);
       Result answer = frame_->CallStub(&stub, &left_side, &right_side);
       if (cc == equal) {
         __ test(answer.reg(), Operand(answer.reg()));
@@ -2721,6 +2781,7 @@
       Register left_reg = left_side.reg();
       Register right_reg = right_side.reg();
 
+      // In-line check for comparing two smis.
       Result temp = allocator_->Allocate();
       ASSERT(temp.is_valid());
       __ mov(temp.reg(), left_side.reg());
@@ -2728,8 +2789,22 @@
       __ test(temp.reg(), Immediate(kSmiTagMask));
       temp.Unuse();
       is_smi.Branch(zero, taken);
-      // When non-smi, call out to the compare stub.
-      CompareStub stub(cc, strict, nan_info);
+
+      // Inline the equality check if both operands can't be a NaN. If both
+      // objects are the same they are equal.
+      if (nan_info == kCantBothBeNaN && cc == equal) {
+        __ cmp(left_side.reg(), Operand(right_side.reg()));
+        dest->true_target()->Branch(equal);
+      }
+
+      // Inline number comparison.
+      if (inline_number_compare) {
+        GenerateInlineNumberComparison(&left_side, &right_side, cc, dest);
+      }
+
+      // End of in-line compare, call out to the compare stub. Don't include
+      // number comparison in the stub if it was inlined.
+      CompareStub stub(cc, strict, nan_info, !inline_number_compare);
       Result answer = frame_->CallStub(&stub, &left_side, &right_side);
       if (cc == equal) {
         __ test(answer.reg(), Operand(answer.reg()));
@@ -2752,6 +2827,148 @@
 }
 
 
+// Check that the comparison operand is a number. Jump to not_numbers jump
+// target passing the left and right result if the operand is not a number.
+static void CheckComparisonOperand(MacroAssembler* masm_,
+                                   Result* operand,
+                                   Result* left_side,
+                                   Result* right_side,
+                                   JumpTarget* not_numbers) {
+  // Perform check if operand is not known to be a number.
+  if (!operand->type_info().IsNumber()) {
+    Label done;
+    __ test(operand->reg(), Immediate(kSmiTagMask));
+    __ j(zero, &done);
+    __ cmp(FieldOperand(operand->reg(), HeapObject::kMapOffset),
+           Immediate(Factory::heap_number_map()));
+    not_numbers->Branch(not_equal, left_side, right_side, not_taken);
+    __ bind(&done);
+  }
+}
+
+
+// Load a comparison operand to the FPU stack. This assumes that the operand has
+// already been checked and is a number.
+static void LoadComparisonOperand(MacroAssembler* masm_,
+                                  Result* operand) {
+  Label done;
+  if (operand->type_info().IsDouble()) {
+    // Operand is known to be a heap number, just load it.
+    __ fld_d(FieldOperand(operand->reg(), HeapNumber::kValueOffset));
+  } else if (operand->type_info().IsSmi()) {
+    // Operand is known to be a smi. Convert it to double and keep the original
+    // smi.
+    __ SmiUntag(operand->reg());
+    __ push(operand->reg());
+    __ fild_s(Operand(esp, 0));
+    __ pop(operand->reg());
+    __ SmiTag(operand->reg());
+  } else {
+    // Operand type not known, check for smi otherwise assume heap number.
+    Label smi;
+    __ test(operand->reg(), Immediate(kSmiTagMask));
+    __ j(zero, &smi);
+    __ fld_d(FieldOperand(operand->reg(), HeapNumber::kValueOffset));
+    __ jmp(&done);
+    __ bind(&smi);
+    __ SmiUntag(operand->reg());
+    __ push(operand->reg());
+    __ fild_s(Operand(esp, 0));
+    __ pop(operand->reg());
+    __ SmiTag(operand->reg());
+    __ jmp(&done);
+  }
+  __ bind(&done);
+}
+
+
+// Load a comparison operand into into a XMM register. Jump to not_numbers jump
+// target passing the left and right result if the operand is not a number.
+static void LoadComparisonOperandSSE2(MacroAssembler* masm_,
+                                      Result* operand,
+                                      XMMRegister reg,
+                                      Result* left_side,
+                                      Result* right_side,
+                                      JumpTarget* not_numbers) {
+  Label done;
+  if (operand->type_info().IsDouble()) {
+    // Operand is known to be a heap number, just load it.
+    __ movdbl(reg, FieldOperand(operand->reg(), HeapNumber::kValueOffset));
+  } else if (operand->type_info().IsSmi()) {
+    // Operand is known to be a smi. Convert it to double and keep the original
+    // smi.
+    __ SmiUntag(operand->reg());
+    __ cvtsi2sd(reg, Operand(operand->reg()));
+    __ SmiTag(operand->reg());
+  } else {
+    // Operand type not known, check for smi or heap number.
+    Label smi;
+    __ test(operand->reg(), Immediate(kSmiTagMask));
+    __ j(zero, &smi);
+    if (!operand->type_info().IsNumber()) {
+      __ cmp(FieldOperand(operand->reg(), HeapObject::kMapOffset),
+             Immediate(Factory::heap_number_map()));
+      not_numbers->Branch(not_equal, left_side, right_side, taken);
+    }
+    __ movdbl(reg, FieldOperand(operand->reg(), HeapNumber::kValueOffset));
+    __ jmp(&done);
+
+    __ bind(&smi);
+    // Comvert smi to float and keep the original smi.
+    __ SmiUntag(operand->reg());
+    __ cvtsi2sd(reg, Operand(operand->reg()));
+    __ SmiTag(operand->reg());
+    __ jmp(&done);
+  }
+  __ bind(&done);
+}
+
+
+void CodeGenerator::GenerateInlineNumberComparison(Result* left_side,
+                                                   Result* right_side,
+                                                   Condition cc,
+                                                   ControlDestination* dest) {
+  ASSERT(left_side->is_register());
+  ASSERT(right_side->is_register());
+
+  JumpTarget not_numbers;
+  if (CpuFeatures::IsSupported(SSE2)) {
+    CpuFeatures::Scope use_sse2(SSE2);
+
+    // Load left and right operand into registers xmm0 and xmm1 and compare.
+    LoadComparisonOperandSSE2(masm_, left_side, xmm0, left_side, right_side,
+                              &not_numbers);
+    LoadComparisonOperandSSE2(masm_, right_side, xmm1, left_side, right_side,
+                              &not_numbers);
+    __ comisd(xmm0, xmm1);
+  } else {
+    Label check_right, compare;
+
+    // Make sure that both comparison operands are numbers.
+    CheckComparisonOperand(masm_, left_side, left_side, right_side,
+                           &not_numbers);
+    CheckComparisonOperand(masm_, right_side, left_side, right_side,
+                           &not_numbers);
+
+    // Load right and left operand to FPU stack and compare.
+    LoadComparisonOperand(masm_, right_side);
+    LoadComparisonOperand(masm_, left_side);
+    __ FCmp();
+  }
+
+  // Bail out if a NaN is involved.
+  not_numbers.Branch(parity_even, left_side, right_side, not_taken);
+
+  // Split to destination targets based on comparison.
+  left_side->Unuse();
+  right_side->Unuse();
+  dest->true_target()->Branch(DoubleCondition(cc));
+  dest->false_target()->Jump();
+
+  not_numbers.Bind(left_side, right_side);
+}
+
+
 // Call the function just below TOS on the stack with the given
 // arguments. The receiver is the TOS.
 void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args,
@@ -3652,7 +3869,7 @@
 }
 
 
-void CodeGenerator::SetTypeForStackSlot(Slot* slot, NumberInfo info) {
+void CodeGenerator::SetTypeForStackSlot(Slot* slot, TypeInfo info) {
   ASSERT(slot->type() == Slot::LOCAL || slot->type() == Slot::PARAMETER);
   if (slot->type() == Slot::LOCAL) {
     frame_->SetTypeForLocalAt(slot->index(), info);
@@ -3772,7 +3989,7 @@
   // the bottom check of the loop condition.
   if (node->is_fast_smi_loop()) {
     // Set number type of the loop variable to smi.
-    SetTypeForStackSlot(node->loop_variable()->slot(), NumberInfo::Smi());
+    SetTypeForStackSlot(node->loop_variable()->slot(), TypeInfo::Smi());
   }
 
   Visit(node->body());
@@ -3798,7 +4015,7 @@
   // expression if we are in a fast smi loop condition.
   if (node->is_fast_smi_loop() && has_valid_frame()) {
     // Set number type of the loop variable to smi.
-    SetTypeForStackSlot(node->loop_variable()->slot(), NumberInfo::Smi());
+    SetTypeForStackSlot(node->loop_variable()->slot(), TypeInfo::Smi());
   }
 
   // Based on the condition analysis, compile the backward jump as
@@ -6701,7 +6918,7 @@
           GenericUnaryOpStub stub(Token::SUB, overwrite);
           Result operand = frame_->Pop();
           Result answer = frame_->CallStub(&stub, &operand);
-          answer.set_number_info(NumberInfo::Number());
+          answer.set_type_info(TypeInfo::Number());
           frame_->Push(&answer);
           break;
         }
@@ -6710,7 +6927,7 @@
           JumpTarget smi_label;
           JumpTarget continue_label;
           Result operand = frame_->Pop();
-          NumberInfo operand_info = operand.number_info();
+          TypeInfo operand_info = operand.type_info();
           operand.ToRegister();
           if (operand_info.IsSmi()) {
             if (FLAG_debug_code) __ AbortIfNotSmi(operand.reg());
@@ -6719,7 +6936,7 @@
             __ lea(operand.reg(), Operand(operand.reg(), kSmiTagMask));
             __ not_(operand.reg());
             Result answer = operand;
-            answer.set_number_info(NumberInfo::Smi());
+            answer.set_type_info(TypeInfo::Smi());
             frame_->Push(&answer);
           } else {
             __ test(operand.reg(), Immediate(kSmiTagMask));
@@ -6738,9 +6955,9 @@
 
             continue_label.Bind(&answer);
             if (operand_info.IsInteger32()) {
-              answer.set_number_info(NumberInfo::Integer32());
+              answer.set_type_info(TypeInfo::Integer32());
             } else {
-              answer.set_number_info(NumberInfo::Number());
+              answer.set_type_info(TypeInfo::Number());
             }
             frame_->Push(&answer);
           }
@@ -6750,7 +6967,7 @@
           // Smi check.
           JumpTarget continue_label;
           Result operand = frame_->Pop();
-          NumberInfo operand_info = operand.number_info();
+          TypeInfo operand_info = operand.type_info();
           operand.ToRegister();
           __ test(operand.reg(), Immediate(kSmiTagMask));
           continue_label.Branch(zero, &operand, taken);
@@ -6761,11 +6978,11 @@
 
           continue_label.Bind(&answer);
           if (operand_info.IsSmi()) {
-            answer.set_number_info(NumberInfo::Smi());
+            answer.set_type_info(TypeInfo::Smi());
           } else if (operand_info.IsInteger32()) {
-            answer.set_number_info(NumberInfo::Integer32());
+            answer.set_type_info(TypeInfo::Integer32());
           } else {
-            answer.set_number_info(NumberInfo::Number());
+            answer.set_type_info(TypeInfo::Number());
           }
           frame_->Push(&answer);
           break;
@@ -6905,7 +7122,7 @@
 
       // The return value for postfix operations is the
       // same as the input, and has the same number info.
-      old_value.set_number_info(new_value.number_info());
+      old_value.set_type_info(new_value.type_info());
     }
 
     // Ensure the new value is writable.
@@ -6972,9 +7189,9 @@
     // The result of ++ or -- is an Integer32 if the
     // input is a smi. Otherwise it is a number.
     if (new_value.is_smi()) {
-      new_value.set_number_info(NumberInfo::Integer32());
+      new_value.set_type_info(TypeInfo::Integer32());
     } else {
-      new_value.set_number_info(NumberInfo::Number());
+      new_value.set_type_info(TypeInfo::Number());
     }
 
     // Postfix: store the old value in the allocated slot under the
@@ -7188,14 +7405,14 @@
           unsafe_bailout_->Branch(negative);
           __ bind(&not_negative_zero);
         }
-        Result edx_result(edx, NumberInfo::Integer32());
+        Result edx_result(edx, TypeInfo::Integer32());
         edx_result.set_untagged_int32(true);
         frame_->Push(&edx_result);
       } else {
         ASSERT(op == Token::DIV);
         __ test(edx, Operand(edx));
         unsafe_bailout_->Branch(not_equal);
-        Result eax_result(eax, NumberInfo::Integer32());
+        Result eax_result(eax, TypeInfo::Integer32());
         eax_result.set_untagged_int32(true);
         frame_->Push(&eax_result);
       }
@@ -8082,7 +8299,7 @@
 
 static void CheckTwoForSminess(MacroAssembler* masm,
                                Register left, Register right, Register scratch,
-                               NumberInfo left_info, NumberInfo right_info,
+                               TypeInfo left_info, TypeInfo right_info,
                                DeferredInlineBinaryOperation* deferred) {
   if (left.is(right)) {
     if (!left_info.IsSmi()) {
@@ -9583,14 +9800,14 @@
 // trashed registers.
 void IntegerConvert(MacroAssembler* masm,
                     Register source,
-                    NumberInfo number_info,
+                    TypeInfo type_info,
                     bool use_sse3,
                     Label* conversion_failure) {
   ASSERT(!source.is(ecx) && !source.is(edi) && !source.is(ebx));
   Label done, right_exponent, normal_exponent;
   Register scratch = ebx;
   Register scratch2 = edi;
-  if (!number_info.IsInteger32() || !use_sse3) {
+  if (!type_info.IsInteger32() || !use_sse3) {
     // Get exponent word.
     __ mov(scratch, FieldOperand(source, HeapNumber::kExponentOffset));
     // Get exponent alone in scratch2.
@@ -9599,7 +9816,7 @@
   }
   if (use_sse3) {
     CpuFeatures::Scope scope(SSE3);
-    if (!number_info.IsInteger32()) {
+    if (!type_info.IsInteger32()) {
       // Check whether the exponent is too big for a 64 bit signed integer.
       static const uint32_t kTooBigExponent =
           (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
@@ -9720,7 +9937,7 @@
 // Input: edx, eax are the left and right objects of a bit op.
 // Output: eax, ecx are left and right integers for a bit op.
 void FloatingPointHelper::LoadNumbersAsIntegers(MacroAssembler* masm,
-                                                NumberInfo number_info,
+                                                TypeInfo type_info,
                                                 bool use_sse3,
                                                 Label* conversion_failure) {
   // Check float operands.
@@ -9728,8 +9945,8 @@
   Label arg2_is_object, check_undefined_arg2;
   Label load_arg2, done;
 
-  if (!number_info.IsHeapNumber()) {
-    if (!number_info.IsSmi()) {
+  if (!type_info.IsDouble()) {
+    if (!type_info.IsSmi()) {
       __ test(edx, Immediate(kSmiTagMask));
       __ j(not_zero, &arg1_is_object);
     } else {
@@ -9742,14 +9959,14 @@
   __ bind(&arg1_is_object);
 
   // Get the untagged integer version of the edx heap number in ecx.
-  IntegerConvert(masm, edx, number_info, use_sse3, conversion_failure);
+  IntegerConvert(masm, edx, type_info, use_sse3, conversion_failure);
   __ mov(edx, ecx);
 
   // Here edx has the untagged integer, eax has a Smi or a heap number.
   __ bind(&load_arg2);
-  if (!number_info.IsHeapNumber()) {
+  if (!type_info.IsDouble()) {
     // Test if arg2 is a Smi.
-    if (!number_info.IsSmi()) {
+    if (!type_info.IsSmi()) {
       __ test(eax, Immediate(kSmiTagMask));
       __ j(not_zero, &arg2_is_object);
     } else {
@@ -9763,7 +9980,7 @@
   __ bind(&arg2_is_object);
 
   // Get the untagged integer version of the eax heap number in ecx.
-  IntegerConvert(masm, eax, number_info, use_sse3, conversion_failure);
+  IntegerConvert(masm, eax, type_info, use_sse3, conversion_failure);
   __ bind(&done);
   __ mov(eax, edx);
 }
@@ -9801,7 +10018,7 @@
   // Get the untagged integer version of the edx heap number in ecx.
   IntegerConvert(masm,
                  edx,
-                 NumberInfo::Unknown(),
+                 TypeInfo::Unknown(),
                  use_sse3,
                  conversion_failure);
   __ mov(edx, ecx);
@@ -9832,7 +10049,7 @@
   // Get the untagged integer version of the eax heap number in ecx.
   IntegerConvert(masm,
                  eax,
-                 NumberInfo::Unknown(),
+                 TypeInfo::Unknown(),
                  use_sse3,
                  conversion_failure);
   __ bind(&done);
@@ -9841,11 +10058,11 @@
 
 
 void FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm,
-                                         NumberInfo number_info,
+                                         TypeInfo type_info,
                                          bool use_sse3,
                                          Label* conversion_failure) {
-  if (number_info.IsNumber()) {
-    LoadNumbersAsIntegers(masm, number_info, use_sse3, conversion_failure);
+  if (type_info.IsNumber()) {
+    LoadNumbersAsIntegers(masm, type_info, use_sse3, conversion_failure);
   } else {
     LoadUnknownsAsIntegers(masm, use_sse3, conversion_failure);
   }
@@ -10090,7 +10307,7 @@
     // Convert the heap number in eax to an untagged integer in ecx.
     IntegerConvert(masm,
                    eax,
-                   NumberInfo::Unknown(),
+                   TypeInfo::Unknown(),
                    CpuFeatures::IsSupported(SSE3),
                    &slow);
 
@@ -10877,63 +11094,70 @@
   __ push(edx);
   __ push(ecx);
 
-  // Inlined floating point compare.
-  // Call builtin if operands are not floating point or smi.
-  Label check_for_symbols;
-  Label unordered;
-  if (CpuFeatures::IsSupported(SSE2)) {
-    CpuFeatures::Scope use_sse2(SSE2);
-    CpuFeatures::Scope use_cmov(CMOV);
+  // Generate the number comparison code.
+  if (include_number_compare_) {
+    Label non_number_comparison;
+    Label unordered;
+    if (CpuFeatures::IsSupported(SSE2)) {
+      CpuFeatures::Scope use_sse2(SSE2);
+      CpuFeatures::Scope use_cmov(CMOV);
 
-    FloatingPointHelper::LoadSSE2Operands(masm, &check_for_symbols);
-    __ comisd(xmm0, xmm1);
+      FloatingPointHelper::LoadSSE2Operands(masm, &non_number_comparison);
+      __ comisd(xmm0, xmm1);
 
-    // Jump to builtin for NaN.
-    __ j(parity_even, &unordered, not_taken);
-    __ mov(eax, 0);  // equal
-    __ mov(ecx, Immediate(Smi::FromInt(1)));
-    __ cmov(above, eax, Operand(ecx));
-    __ mov(ecx, Immediate(Smi::FromInt(-1)));
-    __ cmov(below, eax, Operand(ecx));
-    __ ret(2 * kPointerSize);
-  } else {
-    FloatingPointHelper::CheckFloatOperands(masm, &check_for_symbols, ebx);
-    FloatingPointHelper::LoadFloatOperands(masm, ecx);
-    __ FCmp();
+      // Don't base result on EFLAGS when a NaN is involved.
+      __ j(parity_even, &unordered, not_taken);
+      // Return a result of -1, 0, or 1, based on EFLAGS.
+      __ mov(eax, 0);  // equal
+      __ mov(ecx, Immediate(Smi::FromInt(1)));
+      __ cmov(above, eax, Operand(ecx));
+      __ mov(ecx, Immediate(Smi::FromInt(-1)));
+      __ cmov(below, eax, Operand(ecx));
+      __ ret(2 * kPointerSize);
+    } else {
+      FloatingPointHelper::CheckFloatOperands(
+          masm, &non_number_comparison, ebx);
+      FloatingPointHelper::LoadFloatOperands(masm, ecx);
+      __ FCmp();
 
-    // Jump to builtin for NaN.
-    __ j(parity_even, &unordered, not_taken);
+      // Don't base result on EFLAGS when a NaN is involved.
+      __ j(parity_even, &unordered, not_taken);
 
-    Label below_lbl, above_lbl;
-    // Return a result of -1, 0, or 1, to indicate result of comparison.
-    __ j(below, &below_lbl, not_taken);
-    __ j(above, &above_lbl, not_taken);
+      Label below_label, above_label;
+      // Return a result of -1, 0, or 1, based on EFLAGS. In all cases remove
+      // two arguments from the stack as they have been pushed in preparation
+      // of a possible runtime call.
+      __ j(below, &below_label, not_taken);
+      __ j(above, &above_label, not_taken);
 
-    __ xor_(eax, Operand(eax));  // equal
-    // Both arguments were pushed in case a runtime call was needed.
-    __ ret(2 * kPointerSize);
+      __ xor_(eax, Operand(eax));
+      __ ret(2 * kPointerSize);
 
-    __ bind(&below_lbl);
-    __ mov(eax, Immediate(Smi::FromInt(-1)));
-    __ ret(2 * kPointerSize);
+      __ bind(&below_label);
+      __ mov(eax, Immediate(Smi::FromInt(-1)));
+      __ ret(2 * kPointerSize);
 
-    __ bind(&above_lbl);
-    __ mov(eax, Immediate(Smi::FromInt(1)));
+      __ bind(&above_label);
+      __ mov(eax, Immediate(Smi::FromInt(1)));
+      __ ret(2 * kPointerSize);
+    }
+
+    // If one of the numbers was NaN, then the result is always false.
+    // The cc is never not-equal.
+    __ bind(&unordered);
+    ASSERT(cc_ != not_equal);
+    if (cc_ == less || cc_ == less_equal) {
+      __ mov(eax, Immediate(Smi::FromInt(1)));
+    } else {
+      __ mov(eax, Immediate(Smi::FromInt(-1)));
+    }
     __ ret(2 * kPointerSize);  // eax, edx were pushed
+
+    // The number comparison code did not provide a valid result.
+    __ bind(&non_number_comparison);
   }
-  // If one of the numbers was NaN, then the result is always false.
-  // The cc is never not-equal.
-  __ bind(&unordered);
-  ASSERT(cc_ != not_equal);
-  if (cc_ == less || cc_ == less_equal) {
-    __ mov(eax, Immediate(Smi::FromInt(1)));
-  } else {
-    __ mov(eax, Immediate(Smi::FromInt(-1)));
-  }
-  __ ret(2 * kPointerSize);  // eax, edx were pushed
 
   // Fast negative check for symbol-to-symbol equality.
-  __ bind(&check_for_symbols);
   Label check_for_strings;
   if (cc_ == equal) {
     BranchIfNonSymbol(masm, &check_for_strings, eax, ecx);
@@ -11543,57 +11767,59 @@
 }
 
 
-// Unfortunately you have to run without snapshots to see most of these
-// names in the profile since most compare stubs end up in the snapshot.
-const char* CompareStub::GetName() {
-  switch (cc_) {
-    case less: return "CompareStub_LT";
-    case greater: return "CompareStub_GT";
-    case less_equal: return "CompareStub_LE";
-    case greater_equal: return "CompareStub_GE";
-    case not_equal: {
-      if (strict_) {
-        if (never_nan_nan_) {
-          return "CompareStub_NE_STRICT_NO_NAN";
-        } else {
-          return "CompareStub_NE_STRICT";
-        }
-      } else {
-        if (never_nan_nan_) {
-          return "CompareStub_NE_NO_NAN";
-        } else {
-          return "CompareStub_NE";
-        }
-      }
-    }
-    case equal: {
-      if (strict_) {
-        if (never_nan_nan_) {
-          return "CompareStub_EQ_STRICT_NO_NAN";
-        } else {
-          return "CompareStub_EQ_STRICT";
-        }
-      } else {
-        if (never_nan_nan_) {
-          return "CompareStub_EQ_NO_NAN";
-        } else {
-          return "CompareStub_EQ";
-        }
-      }
-    }
-    default: return "CompareStub";
-  }
-}
-
-
 int CompareStub::MinorKey() {
   // Encode the three parameters in a unique 16 bit value. To avoid duplicate
   // stubs the never NaN NaN condition is only taken into account if the
   // condition is equals.
-  ASSERT(static_cast<unsigned>(cc_) < (1 << 14));
+  ASSERT(static_cast<unsigned>(cc_) < (1 << 13));
   return ConditionField::encode(static_cast<unsigned>(cc_))
          | StrictField::encode(strict_)
-         | NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false);
+         | NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false)
+         | IncludeNumberCompareField::encode(include_number_compare_);
+}
+
+
+// Unfortunately you have to run without snapshots to see most of these
+// names in the profile since most compare stubs end up in the snapshot.
+const char* CompareStub::GetName() {
+  if (name_ != NULL) return name_;
+  const int kMaxNameLength = 100;
+  name_ = Bootstrapper::AllocateAutoDeletedArray(kMaxNameLength);
+  if (name_ == NULL) return "OOM";
+
+  const char* cc_name;
+  switch (cc_) {
+    case less: cc_name = "LT"; break;
+    case greater: cc_name = "GT"; break;
+    case less_equal: cc_name = "LE"; break;
+    case greater_equal: cc_name = "GE"; break;
+    case equal: cc_name = "EQ"; break;
+    case not_equal: cc_name = "NE"; break;
+    default: cc_name = "UnknownCondition"; break;
+  }
+
+  const char* strict_name = "";
+  if (strict_ && (cc_ == equal || cc_ == not_equal)) {
+    strict_name = "_STRICT";
+  }
+
+  const char* never_nan_nan_name = "";
+  if (never_nan_nan_ && (cc_ == equal || cc_ == not_equal)) {
+    never_nan_nan_name = "_NO_NAN";
+  }
+
+  const char* include_number_compare_name = "";
+  if (!include_number_compare_) {
+    include_number_compare_name = "_NO_NUMBER";
+  }
+
+  OS::SNPrintF(Vector<char>(name_, kMaxNameLength),
+               "CompareStub_%s%s%s%s",
+               cc_name,
+               strict_name,
+               never_nan_nan_name,
+               include_number_compare_name);
+  return name_;
 }
 
 
@@ -12227,6 +12453,9 @@
   Label result_not_equal;
   Label result_greater;
   Label compare_lengths;
+
+  __ IncrementCounter(&Counters::string_compare_native, 1);
+
   // Find minimum length.
   Label left_shorter;
   __ mov(scratch1, FieldOperand(left, String::kLengthOffset));
@@ -12324,7 +12553,6 @@
   __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &runtime);
 
   // Compare flat ascii strings.
-  __ IncrementCounter(&Counters::string_compare_native, 1);
   GenerateCompareFlatAsciiStrings(masm, edx, eax, ecx, ebx, edi);
 
   // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
diff --git a/src/ia32/codegen-ia32.h b/src/ia32/codegen-ia32.h
index 509bbd6..ca4a44b 100644
--- a/src/ia32/codegen-ia32.h
+++ b/src/ia32/codegen-ia32.h
@@ -373,6 +373,7 @@
   // Take the Result that is an untagged int32, and convert it to a tagged
   // Smi or HeapNumber.  Remove the untagged_int32 flag from the result.
   void ConvertInt32ResultToNumber(Result* value);
+  void ConvertInt32ResultToSmi(Result* value);
 
   // Track loop nesting level.
   int loop_nesting() const { return loop_nesting_; }
@@ -528,6 +529,10 @@
                   Condition cc,
                   bool strict,
                   ControlDestination* destination);
+  void GenerateInlineNumberComparison(Result* left_side,
+                                      Result* right_side,
+                                      Condition cc,
+                                      ControlDestination* dest);
 
   // To prevent long attacker-controlled byte sequences, integer constants
   // from the JavaScript source are loaded in two parts if they are larger
@@ -652,7 +657,7 @@
   void CodeForDoWhileConditionPosition(DoWhileStatement* stmt);
   void CodeForSourcePosition(int pos);
 
-  void SetTypeForStackSlot(Slot* slot, NumberInfo info);
+  void SetTypeForStackSlot(Slot* slot, TypeInfo info);
 
 #ifdef DEBUG
   // True if the registers are valid for entry to a block.  There should
@@ -736,7 +741,7 @@
   GenericBinaryOpStub(Token::Value op,
                       OverwriteMode mode,
                       GenericBinaryFlags flags,
-                      NumberInfo operands_type)
+                      TypeInfo operands_type)
       : op_(op),
         mode_(mode),
         flags_(flags),
@@ -759,7 +764,7 @@
         args_in_registers_(ArgsInRegistersBits::decode(key)),
         args_reversed_(ArgsReversedBits::decode(key)),
         use_sse3_(SSE3Bits::decode(key)),
-        static_operands_type_(NumberInfo::ExpandedRepresentation(
+        static_operands_type_(TypeInfo::ExpandedRepresentation(
             StaticTypeInfoBits::decode(key))),
         runtime_operands_type_(runtime_operands_type),
         name_(NULL) {
@@ -786,7 +791,7 @@
   bool use_sse3_;
 
   // Number type information of operands, determined by code generator.
-  NumberInfo static_operands_type_;
+  TypeInfo static_operands_type_;
 
   // Operand type information determined at runtime.
   BinaryOpIC::TypeInfo runtime_operands_type_;
@@ -798,7 +803,7 @@
 #ifdef DEBUG
   void Print() {
     PrintF("GenericBinaryOpStub %d (op %s), "
-           "(mode %d, flags %d, registers %d, reversed %d, number_info %s)\n",
+           "(mode %d, flags %d, registers %d, reversed %d, type_info %s)\n",
            MinorKey(),
            Token::String(op_),
            static_cast<int>(mode_),
diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc
index 3cc56e1..e59dc51 100644
--- a/src/ia32/full-codegen-ia32.cc
+++ b/src/ia32/full-codegen-ia32.cc
@@ -1130,7 +1130,7 @@
   GenericBinaryOpStub stub(op,
                            NO_OVERWRITE,
                            NO_GENERIC_BINARY_FLAGS,
-                           NumberInfo::Unknown());
+                           TypeInfo::Unknown());
   __ CallStub(&stub);
   Apply(context, eax);
 }
@@ -1745,7 +1745,7 @@
   GenericBinaryOpStub stub(expr->binary_op(),
                            NO_OVERWRITE,
                            NO_GENERIC_BINARY_FLAGS,
-                           NumberInfo::Unknown());
+                           TypeInfo::Unknown());
   stub.GenerateCall(masm(), eax, Smi::FromInt(1));
   __ bind(&done);
 
diff --git a/src/ia32/register-allocator-ia32.cc b/src/ia32/register-allocator-ia32.cc
index 0129314..73fefb3 100644
--- a/src/ia32/register-allocator-ia32.cc
+++ b/src/ia32/register-allocator-ia32.cc
@@ -75,7 +75,7 @@
                                                  Immediate(handle()));
     }
     // This result becomes a copy of the fresh one.
-    fresh.set_number_info(number_info());
+    fresh.set_type_info(type_info());
     *this = fresh;
   }
   ASSERT(is_register());
@@ -122,7 +122,7 @@
         }
       }
     }
-    fresh.set_number_info(number_info());
+    fresh.set_type_info(type_info());
     fresh.set_untagged_int32(is_untagged_int32());
     *this = fresh;
   } else if (is_register() && reg().is(target)) {
diff --git a/src/ia32/virtual-frame-ia32.cc b/src/ia32/virtual-frame-ia32.cc
index a8b0e8d..bc27e1d 100644
--- a/src/ia32/virtual-frame-ia32.cc
+++ b/src/ia32/virtual-frame-ia32.cc
@@ -162,7 +162,7 @@
     if (element.is_constant() || element.is_copy()) {
       if (element.is_synced()) {
         // Just spill.
-        elements_[i] = FrameElement::MemoryElement(NumberInfo::Unknown());
+        elements_[i] = FrameElement::MemoryElement(TypeInfo::Unknown());
       } else {
         // Allocate to a register.
         FrameElement backing_element;  // Invalid if not a copy.
@@ -174,7 +174,7 @@
         elements_[i] =
             FrameElement::RegisterElement(fresh.reg(),
                                           FrameElement::NOT_SYNCED,
-                                          NumberInfo::Unknown());
+                                          TypeInfo::Unknown());
         Use(fresh.reg(), i);
 
         // Emit a move.
@@ -207,7 +207,7 @@
       // The copy flag is not relied on before the end of this loop,
       // including when registers are spilled.
       elements_[i].clear_copied();
-      elements_[i].set_number_info(NumberInfo::Unknown());
+      elements_[i].set_type_info(TypeInfo::Unknown());
     }
   }
 }
@@ -597,12 +597,12 @@
     elements_[new_backing_index] =
         FrameElement::RegisterElement(backing_reg,
                                       FrameElement::SYNCED,
-                                      original.number_info());
+                                      original.type_info());
   } else {
     elements_[new_backing_index] =
         FrameElement::RegisterElement(backing_reg,
                                       FrameElement::NOT_SYNCED,
-                                      original.number_info());
+                                      original.type_info());
   }
   // Update the other copies.
   for (int i = new_backing_index + 1; i < element_count(); i++) {
@@ -634,7 +634,7 @@
       FrameElement new_element =
           FrameElement::RegisterElement(fresh.reg(),
                                         FrameElement::NOT_SYNCED,
-                                        original.number_info());
+                                        original.type_info());
       Use(fresh.reg(), element_count());
       elements_.Add(new_element);
       __ mov(fresh.reg(), Operand(ebp, fp_relative(index)));
@@ -796,7 +796,7 @@
       FrameElement new_element =
           FrameElement::RegisterElement(fresh_reg,
                                         FrameElement::NOT_SYNCED,
-                                        original.number_info());
+                                        original.type_info());
       new_element.set_untagged_int32(true);
       Use(fresh_reg, element_count());
       fresh.Unuse();  // BreakTarget does not handle a live Result well.
@@ -808,7 +808,7 @@
         __ mov(fresh_reg, Operand(ebp, fp_relative(index)));
       }
       // Now convert the value to int32, or bail out.
-      if (original.number_info().IsSmi()) {
+      if (original.type_info().IsSmi()) {
         __ SmiUntag(fresh_reg);
         // Pushing the element is completely done.
       } else {
@@ -819,7 +819,7 @@
         __ jmp(&done);
 
         __ bind(&not_smi);
-        if (!original.number_info().IsNumber()) {
+        if (!original.type_info().IsNumber()) {
           __ cmp(FieldOperand(fresh_reg, HeapObject::kMapOffset),
                  Factory::heap_number_map());
           cgen()->unsafe_bailout_->Branch(not_equal);
@@ -1151,11 +1151,11 @@
   ASSERT(element.is_untagged_int32() == cgen()->in_safe_int32_mode());
 
   // Get number type information of the result.
-  NumberInfo info;
+  TypeInfo info;
   if (!element.is_copy()) {
-    info = element.number_info();
+    info = element.type_info();
   } else {
-    info = elements_[element.index()].number_info();
+    info = elements_[element.index()].type_info();
   }
 
   bool pop_needed = (stack_pointer_ == index);
@@ -1165,7 +1165,7 @@
       Result temp = cgen()->allocator()->Allocate();
       ASSERT(temp.is_valid());
       __ pop(temp.reg());
-      temp.set_number_info(info);
+      temp.set_type_info(info);
       temp.set_untagged_int32(element.is_untagged_int32());
       return temp;
     }
@@ -1198,7 +1198,7 @@
     FrameElement new_element =
         FrameElement::RegisterElement(temp.reg(),
                                       FrameElement::SYNCED,
-                                      element.number_info());
+                                      element.type_info());
     // Preserve the copy flag on the element.
     if (element.is_copied()) new_element.set_copied();
     elements_[index] = new_element;
@@ -1233,7 +1233,7 @@
 }
 
 
-void VirtualFrame::EmitPush(Register reg, NumberInfo info) {
+void VirtualFrame::EmitPush(Register reg, TypeInfo info) {
   ASSERT(stack_pointer_ == element_count() - 1);
   elements_.Add(FrameElement::MemoryElement(info));
   stack_pointer_++;
@@ -1241,7 +1241,7 @@
 }
 
 
-void VirtualFrame::EmitPush(Operand operand, NumberInfo info) {
+void VirtualFrame::EmitPush(Operand operand, TypeInfo info) {
   ASSERT(stack_pointer_ == element_count() - 1);
   elements_.Add(FrameElement::MemoryElement(info));
   stack_pointer_++;
@@ -1249,7 +1249,7 @@
 }
 
 
-void VirtualFrame::EmitPush(Immediate immediate, NumberInfo info) {
+void VirtualFrame::EmitPush(Immediate immediate, TypeInfo info) {
   ASSERT(stack_pointer_ == element_count() - 1);
   elements_.Add(FrameElement::MemoryElement(info));
   stack_pointer_++;
diff --git a/src/ia32/virtual-frame-ia32.h b/src/ia32/virtual-frame-ia32.h
index e622cdf..9b6892a 100644
--- a/src/ia32/virtual-frame-ia32.h
+++ b/src/ia32/virtual-frame-ia32.h
@@ -28,7 +28,7 @@
 #ifndef V8_IA32_VIRTUAL_FRAME_IA32_H_
 #define V8_IA32_VIRTUAL_FRAME_IA32_H_
 
-#include "number-info.h"
+#include "type-info.h"
 #include "register-allocator.h"
 #include "scopes.h"
 
@@ -84,7 +84,7 @@
 
   // Create a duplicate of an existing valid frame element.
   FrameElement CopyElementAt(int index,
-    NumberInfo info = NumberInfo::Uninitialized());
+    TypeInfo info = TypeInfo::Uninitialized());
 
   // The number of elements on the virtual frame.
   int element_count() { return elements_.length(); }
@@ -138,7 +138,7 @@
   void ForgetElements(int count);
 
   // Spill all values from the frame to memory.
-  void SpillAll();
+  inline void SpillAll();
 
   // Spill all occurrences of a specific register from the frame.
   void Spill(Register reg) {
@@ -199,7 +199,7 @@
   // Prepare for returning from the frame by spilling locals.  This
   // avoids generating unnecessary merge code when jumping to the
   // shared return site.  Emits code for spills.
-  void PrepareForReturn();
+  inline void PrepareForReturn();
 
   // Number of local variables after when we use a loop for allocating.
   static const int kLocalVarBound = 10;
@@ -398,14 +398,14 @@
   // Push an element on top of the expression stack and emit a
   // corresponding push instruction.
   void EmitPush(Register reg,
-                NumberInfo info = NumberInfo::Unknown());
+                TypeInfo info = TypeInfo::Unknown());
   void EmitPush(Operand operand,
-                NumberInfo info = NumberInfo::Unknown());
+                TypeInfo info = TypeInfo::Unknown());
   void EmitPush(Immediate immediate,
-                NumberInfo info = NumberInfo::Unknown());
+                TypeInfo info = TypeInfo::Unknown());
 
   // Push an element on the virtual frame.
-  inline void Push(Register reg, NumberInfo info = NumberInfo::Unknown());
+  inline void Push(Register reg, TypeInfo info = TypeInfo::Unknown());
   inline void Push(Handle<Object> value);
   inline void Push(Smi* value);
 
@@ -417,7 +417,7 @@
     // This assert will trigger if you try to push the same value twice.
     ASSERT(result->is_valid());
     if (result->is_register()) {
-      Push(result->reg(), result->number_info());
+      Push(result->reg(), result->type_info());
     } else {
       ASSERT(result->is_constant());
       Push(result->handle());
@@ -447,8 +447,8 @@
   }
 
   // Update the type information of a variable frame element directly.
-  inline void SetTypeForLocalAt(int index, NumberInfo info);
-  inline void SetTypeForParamAt(int index, NumberInfo info);
+  inline void SetTypeForLocalAt(int index, TypeInfo info);
+  inline void SetTypeForParamAt(int index, TypeInfo info);
 
  private:
   static const int kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset;
diff --git a/src/jsregexp.cc b/src/jsregexp.cc
index 5a0a482..dfd9ef6 100644
--- a/src/jsregexp.cc
+++ b/src/jsregexp.cc
@@ -4987,7 +4987,9 @@
       case AFTER_WORD_CHARACTER: {
         ASSERT_NOT_NULL(on_success());
         budget = on_success()->ComputeFirstCharacterSet(budget);
-        set_first_character_set(on_success()->first_character_set());
+        if (budget >= 0) {
+          set_first_character_set(on_success()->first_character_set());
+        }
         break;
       }
     }
@@ -5013,6 +5015,10 @@
 int BackReferenceNode::ComputeFirstCharacterSet(int budget) {
   // We don't know anything about the first character of a backreference
   // at this point.
+  // The potential first characters are the first characters of the capture,
+  // and the first characters of the on_success node, depending on whether the
+  // capture can be empty and whether it is known to be participating or known
+  // not to be.
   return kComputeFirstCharacterSetFail;
 }
 
@@ -5032,8 +5038,11 @@
     } else {
       ASSERT(text.type == TextElement::CHAR_CLASS);
       RegExpCharacterClass* char_class = text.data.u_char_class;
+      ZoneList<CharacterRange>* ranges = char_class->ranges();
+      // TODO(lrn): Canonicalize ranges when they are created
+      // instead of waiting until now.
+      CharacterRange::Canonicalize(ranges);
       if (char_class->is_negated()) {
-        ZoneList<CharacterRange>* ranges = char_class->ranges();
         int length = ranges->length();
         int new_length = length + 1;
         if (length > 0) {
@@ -5047,7 +5056,7 @@
         CharacterRange::Negate(ranges, negated_ranges);
         set_first_character_set(negated_ranges);
       } else {
-        set_first_character_set(char_class->ranges());
+        set_first_character_set(ranges);
       }
     }
   }
diff --git a/src/jump-target-heavy-inl.h b/src/jump-target-heavy-inl.h
new file mode 100644
index 0000000..0a2a569
--- /dev/null
+++ b/src/jump-target-heavy-inl.h
@@ -0,0 +1,51 @@
+// 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_JUMP_TARGET_HEAVY_INL_H_
+#define V8_JUMP_TARGET_HEAVY_INL_H_
+
+#include "virtual-frame-inl.h"
+
+namespace v8 {
+namespace internal {
+
+void JumpTarget::InitializeEntryElement(int index, FrameElement* target) {
+  FrameElement* element = &entry_frame_->elements_[index];
+  element->clear_copied();
+  if (target->is_register()) {
+    entry_frame_->set_register_location(target->reg(), index);
+  } else if (target->is_copy()) {
+    entry_frame_->elements_[target->index()].set_copied();
+  }
+  if (direction_ == BIDIRECTIONAL && !target->is_copy()) {
+    element->set_type_info(TypeInfo::Unknown());
+  }
+}
+
+} }  // namespace v8::internal
+
+#endif  // V8_JUMP_TARGET_HEAVY_INL_H_
diff --git a/src/jump-target-heavy.cc b/src/jump-target-heavy.cc
new file mode 100644
index 0000000..85620a2
--- /dev/null
+++ b/src/jump-target-heavy.cc
@@ -0,0 +1,363 @@
+// 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.
+
+#include "v8.h"
+
+#include "codegen-inl.h"
+#include "jump-target-inl.h"
+#include "register-allocator-inl.h"
+
+namespace v8 {
+namespace internal {
+
+
+void JumpTarget::Jump(Result* arg) {
+  ASSERT(cgen()->has_valid_frame());
+
+  cgen()->frame()->Push(arg);
+  DoJump();
+}
+
+
+void JumpTarget::Branch(Condition cc, Result* arg, Hint hint) {
+  ASSERT(cgen()->has_valid_frame());
+
+  // We want to check that non-frame registers at the call site stay in
+  // the same registers on the fall-through branch.
+#ifdef DEBUG
+  Result::Type arg_type = arg->type();
+  Register arg_reg = arg->is_register() ? arg->reg() : no_reg;
+#endif
+
+  cgen()->frame()->Push(arg);
+  DoBranch(cc, hint);
+  *arg = cgen()->frame()->Pop();
+
+  ASSERT(arg->type() == arg_type);
+  ASSERT(!arg->is_register() || arg->reg().is(arg_reg));
+}
+
+
+void JumpTarget::Branch(Condition cc, Result* arg0, Result* arg1, Hint hint) {
+  ASSERT(cgen()->has_valid_frame());
+
+  // We want to check that non-frame registers at the call site stay in
+  // the same registers on the fall-through branch.
+#ifdef DEBUG
+  Result::Type arg0_type = arg0->type();
+  Register arg0_reg = arg0->is_register() ? arg0->reg() : no_reg;
+  Result::Type arg1_type = arg1->type();
+  Register arg1_reg = arg1->is_register() ? arg1->reg() : no_reg;
+#endif
+
+  cgen()->frame()->Push(arg0);
+  cgen()->frame()->Push(arg1);
+  DoBranch(cc, hint);
+  *arg1 = cgen()->frame()->Pop();
+  *arg0 = cgen()->frame()->Pop();
+
+  ASSERT(arg0->type() == arg0_type);
+  ASSERT(!arg0->is_register() || arg0->reg().is(arg0_reg));
+  ASSERT(arg1->type() == arg1_type);
+  ASSERT(!arg1->is_register() || arg1->reg().is(arg1_reg));
+}
+
+
+void BreakTarget::Branch(Condition cc, Result* arg, Hint hint) {
+  ASSERT(cgen()->has_valid_frame());
+
+  int count = cgen()->frame()->height() - expected_height_;
+  if (count > 0) {
+    // We negate and branch here rather than using DoBranch's negate
+    // and branch.  This gives us a hook to remove statement state
+    // from the frame.
+    JumpTarget fall_through;
+    // Branch to fall through will not negate, because it is a
+    // forward-only target.
+    fall_through.Branch(NegateCondition(cc), NegateHint(hint));
+    Jump(arg);  // May emit merge code here.
+    fall_through.Bind();
+  } else {
+#ifdef DEBUG
+    Result::Type arg_type = arg->type();
+    Register arg_reg = arg->is_register() ? arg->reg() : no_reg;
+#endif
+    cgen()->frame()->Push(arg);
+    DoBranch(cc, hint);
+    *arg = cgen()->frame()->Pop();
+    ASSERT(arg->type() == arg_type);
+    ASSERT(!arg->is_register() || arg->reg().is(arg_reg));
+  }
+}
+
+
+void JumpTarget::Bind(Result* arg) {
+  if (cgen()->has_valid_frame()) {
+    cgen()->frame()->Push(arg);
+  }
+  DoBind();
+  *arg = cgen()->frame()->Pop();
+}
+
+
+void JumpTarget::Bind(Result* arg0, Result* arg1) {
+  if (cgen()->has_valid_frame()) {
+    cgen()->frame()->Push(arg0);
+    cgen()->frame()->Push(arg1);
+  }
+  DoBind();
+  *arg1 = cgen()->frame()->Pop();
+  *arg0 = cgen()->frame()->Pop();
+}
+
+
+void JumpTarget::ComputeEntryFrame() {
+  // Given: a collection of frames reaching by forward CFG edges and
+  // the directionality of the block.  Compute: an entry frame for the
+  // block.
+
+  Counters::compute_entry_frame.Increment();
+#ifdef DEBUG
+  if (compiling_deferred_code_) {
+    ASSERT(reaching_frames_.length() > 1);
+    VirtualFrame* frame = reaching_frames_[0];
+    bool all_identical = true;
+    for (int i = 1; i < reaching_frames_.length(); i++) {
+      if (!frame->Equals(reaching_frames_[i])) {
+        all_identical = false;
+        break;
+      }
+    }
+    ASSERT(!all_identical || all_identical);
+  }
+#endif
+
+  // Choose an initial frame.
+  VirtualFrame* initial_frame = reaching_frames_[0];
+
+  // A list of pointers to frame elements in the entry frame.  NULL
+  // indicates that the element has not yet been determined.
+  int length = initial_frame->element_count();
+  ZoneList<FrameElement*> elements(length);
+
+  // Initially populate the list of elements based on the initial
+  // frame.
+  for (int i = 0; i < length; i++) {
+    FrameElement element = initial_frame->elements_[i];
+    // We do not allow copies or constants in bidirectional frames.
+    if (direction_ == BIDIRECTIONAL) {
+      if (element.is_constant() || element.is_copy()) {
+        elements.Add(NULL);
+        continue;
+      }
+    }
+    elements.Add(&initial_frame->elements_[i]);
+  }
+
+  // Compute elements based on the other reaching frames.
+  if (reaching_frames_.length() > 1) {
+    for (int i = 0; i < length; i++) {
+      FrameElement* element = elements[i];
+      for (int j = 1; j < reaching_frames_.length(); j++) {
+        // Element computation is monotonic: new information will not
+        // change our decision about undetermined or invalid elements.
+        if (element == NULL || !element->is_valid()) break;
+
+        FrameElement* other = &reaching_frames_[j]->elements_[i];
+        element = element->Combine(other);
+        if (element != NULL && !element->is_copy()) {
+          ASSERT(other != NULL);
+          // 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.
+          element->set_type_info(TypeInfo::Combine(element->type_info(),
+                                                   other->type_info()));
+        }
+      }
+      elements[i] = element;
+    }
+  }
+
+  // Build the new frame.  A freshly allocated frame has memory elements
+  // for the parameters and some platform-dependent elements (e.g.,
+  // return address).  Replace those first.
+  entry_frame_ = new VirtualFrame();
+  int index = 0;
+  for (; index < entry_frame_->element_count(); index++) {
+    FrameElement* target = elements[index];
+    // If the element is determined, set it now.  Count registers.  Mark
+    // elements as copied exactly when they have a copy.  Undetermined
+    // elements are initially recorded as if in memory.
+    if (target != NULL) {
+      entry_frame_->elements_[index] = *target;
+      InitializeEntryElement(index, target);
+    }
+  }
+  // Then fill in the rest of the frame with new elements.
+  for (; index < length; index++) {
+    FrameElement* target = elements[index];
+    if (target == NULL) {
+      entry_frame_->elements_.Add(
+          FrameElement::MemoryElement(TypeInfo::Uninitialized()));
+    } else {
+      entry_frame_->elements_.Add(*target);
+      InitializeEntryElement(index, target);
+    }
+  }
+
+  // Allocate any still-undetermined frame elements to registers or
+  // memory, from the top down.
+  for (int i = length - 1; i >= 0; i--) {
+    if (elements[i] == NULL) {
+      // Loop over all the reaching frames to check whether the element
+      // is synced on all frames and to count the registers it occupies.
+      bool is_synced = true;
+      RegisterFile candidate_registers;
+      int best_count = kMinInt;
+      int best_reg_num = RegisterAllocator::kInvalidRegister;
+      TypeInfo info = TypeInfo::Uninitialized();
+
+      for (int j = 0; j < reaching_frames_.length(); j++) {
+        FrameElement element = reaching_frames_[j]->elements_[i];
+        if (direction_ == BIDIRECTIONAL) {
+          info = TypeInfo::Unknown();
+        } else if (!element.is_copy()) {
+          info = TypeInfo::Combine(info, element.type_info());
+        } else {
+          // New elements will not be copies, so get number information from
+          // backing element in the reaching frame.
+          info = TypeInfo::Combine(info,
+            reaching_frames_[j]->elements_[element.index()].type_info());
+        }
+        is_synced = is_synced && element.is_synced();
+        if (element.is_register() && !entry_frame_->is_used(element.reg())) {
+          // Count the register occurrence and remember it if better
+          // than the previous best.
+          int num = RegisterAllocator::ToNumber(element.reg());
+          candidate_registers.Use(num);
+          if (candidate_registers.count(num) > best_count) {
+            best_count = candidate_registers.count(num);
+            best_reg_num = num;
+          }
+        }
+      }
+
+      // We must have a number type information now (not for copied elements).
+      ASSERT(entry_frame_->elements_[i].is_copy()
+             || !info.IsUninitialized());
+
+      // If the value is synced on all frames, put it in memory.  This
+      // costs nothing at the merge code but will incur a
+      // memory-to-register move when the value is needed later.
+      if (is_synced) {
+        // Already recorded as a memory element.
+        // Set combined number info.
+        entry_frame_->elements_[i].set_type_info(info);
+        continue;
+      }
+
+      // Try to put it in a register.  If there was no best choice
+      // consider any free register.
+      if (best_reg_num == RegisterAllocator::kInvalidRegister) {
+        for (int j = 0; j < RegisterAllocator::kNumRegisters; j++) {
+          if (!entry_frame_->is_used(j)) {
+            best_reg_num = j;
+            break;
+          }
+        }
+      }
+
+      if (best_reg_num != RegisterAllocator::kInvalidRegister) {
+        // If there was a register choice, use it.  Preserve the copied
+        // flag on the element.
+        bool is_copied = entry_frame_->elements_[i].is_copied();
+        Register reg = RegisterAllocator::ToRegister(best_reg_num);
+        entry_frame_->elements_[i] =
+            FrameElement::RegisterElement(reg, FrameElement::NOT_SYNCED,
+                                          TypeInfo::Uninitialized());
+        if (is_copied) entry_frame_->elements_[i].set_copied();
+        entry_frame_->set_register_location(reg, i);
+      }
+      // Set combined number info.
+      entry_frame_->elements_[i].set_type_info(info);
+    }
+  }
+
+  // If we have incoming backward edges assert we forget all number information.
+#ifdef DEBUG
+  if (direction_ == BIDIRECTIONAL) {
+    for (int i = 0; i < length; ++i) {
+      if (!entry_frame_->elements_[i].is_copy()) {
+        ASSERT(entry_frame_->elements_[i].type_info().IsUnknown());
+      }
+    }
+  }
+#endif
+
+  // The stack pointer is at the highest synced element or the base of
+  // the expression stack.
+  int stack_pointer = length - 1;
+  while (stack_pointer >= entry_frame_->expression_base_index() &&
+         !entry_frame_->elements_[stack_pointer].is_synced()) {
+    stack_pointer--;
+  }
+  entry_frame_->stack_pointer_ = stack_pointer;
+}
+
+
+DeferredCode::DeferredCode()
+    : masm_(CodeGeneratorScope::Current()->masm()),
+      statement_position_(masm_->current_statement_position()),
+      position_(masm_->current_position()) {
+  ASSERT(statement_position_ != RelocInfo::kNoPosition);
+  ASSERT(position_ != RelocInfo::kNoPosition);
+
+  CodeGeneratorScope::Current()->AddDeferred(this);
+#ifdef DEBUG
+  comment_ = "";
+#endif
+
+  // Copy the register locations from the code generator's frame.
+  // These are the registers that will be spilled on entry to the
+  // deferred code and restored on exit.
+  VirtualFrame* frame = CodeGeneratorScope::Current()->frame();
+  int sp_offset = frame->fp_relative(frame->stack_pointer_);
+  for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
+    int loc = frame->register_location(i);
+    if (loc == VirtualFrame::kIllegalIndex) {
+      registers_[i] = kIgnore;
+    } else if (frame->elements_[loc].is_synced()) {
+      // Needs to be restored on exit but not saved on entry.
+      registers_[i] = frame->fp_relative(loc) | kSyncedFlag;
+    } else {
+      int offset = frame->fp_relative(loc);
+      registers_[i] = (offset < sp_offset) ? kPush : offset;
+    }
+  }
+}
+
+} }  // namespace v8::internal
diff --git a/src/jump-target-inl.h b/src/jump-target-inl.h
index 6db0081..4c9ee5b 100644
--- a/src/jump-target-inl.h
+++ b/src/jump-target-inl.h
@@ -30,6 +30,12 @@
 
 #include "virtual-frame-inl.h"
 
+#if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X64
+#include "jump-target-heavy-inl.h"
+#else
+#include "jump-target-light-inl.h"
+#endif
+
 namespace v8 {
 namespace internal {
 
@@ -37,19 +43,6 @@
   return CodeGeneratorScope::Current();
 }
 
-void JumpTarget::InitializeEntryElement(int index, FrameElement* target) {
-  FrameElement* element = &entry_frame_->elements_[index];
-  element->clear_copied();
-  if (target->is_register()) {
-    entry_frame_->set_register_location(target->reg(), index);
-  } else if (target->is_copy()) {
-    entry_frame_->elements_[target->index()].set_copied();
-  }
-  if (direction_ == BIDIRECTIONAL && !target->is_copy()) {
-    element->set_number_info(NumberInfo::Unknown());
-  }
-}
-
 } }  // namespace v8::internal
 
 #endif  // V8_JUMP_TARGET_INL_H_
diff --git a/src/jump-target-light-inl.h b/src/jump-target-light-inl.h
new file mode 100644
index 0000000..8d6c3ac
--- /dev/null
+++ b/src/jump-target-light-inl.h
@@ -0,0 +1,42 @@
+// 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_JUMP_TARGET_LIGHT_INL_H_
+#define V8_JUMP_TARGET_LIGHT_INL_H_
+
+#include "virtual-frame-inl.h"
+
+namespace v8 {
+namespace internal {
+
+void JumpTarget::InitializeEntryElement(int index, FrameElement* target) {
+  UNIMPLEMENTED();
+}
+
+} }  // namespace v8::internal
+
+#endif  // V8_JUMP_TARGET_LIGHT_INL_H_
diff --git a/src/jump-target-light.cc b/src/jump-target-light.cc
new file mode 100644
index 0000000..098d97d
--- /dev/null
+++ b/src/jump-target-light.cc
@@ -0,0 +1,99 @@
+// 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.
+
+#include "v8.h"
+
+#include "codegen-inl.h"
+#include "jump-target-inl.h"
+
+namespace v8 {
+namespace internal {
+
+
+void JumpTarget::Jump(Result* arg) {
+  UNIMPLEMENTED();
+}
+
+
+void JumpTarget::Branch(Condition cc, Result* arg, Hint hint) {
+  UNIMPLEMENTED();
+}
+
+
+void JumpTarget::Branch(Condition cc, Result* arg0, Result* arg1, Hint hint) {
+  UNIMPLEMENTED();
+}
+
+
+void BreakTarget::Branch(Condition cc, Result* arg, Hint hint) {
+  UNIMPLEMENTED();
+}
+
+
+void JumpTarget::Bind(Result* arg) {
+  UNIMPLEMENTED();
+}
+
+
+void JumpTarget::Bind(Result* arg0, Result* arg1) {
+  UNIMPLEMENTED();
+}
+
+
+void JumpTarget::ComputeEntryFrame() {
+  UNIMPLEMENTED();
+}
+
+
+DeferredCode::DeferredCode()
+    : masm_(CodeGeneratorScope::Current()->masm()),
+      statement_position_(masm_->current_statement_position()),
+      position_(masm_->current_position()) {
+  ASSERT(statement_position_ != RelocInfo::kNoPosition);
+  ASSERT(position_ != RelocInfo::kNoPosition);
+
+  CodeGeneratorScope::Current()->AddDeferred(this);
+#ifdef DEBUG
+  comment_ = "";
+#endif
+
+  // Copy the register locations from the code generator's frame.
+  // These are the registers that will be spilled on entry to the
+  // deferred code and restored on exit.
+  VirtualFrame* frame = CodeGeneratorScope::Current()->frame();
+  for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
+    int loc = frame->register_location(i);
+    if (loc == VirtualFrame::kIllegalIndex) {
+      registers_[i] = kIgnore;
+    } else {
+      // Needs to be restored on exit but not saved on entry.
+      registers_[i] = frame->fp_relative(loc) | kSyncedFlag;
+    }
+  }
+}
+
+} }  // namespace v8::internal
diff --git a/src/jump-target.cc b/src/jump-target.cc
index 7b1ced7..8b29995 100644
--- a/src/jump-target.cc
+++ b/src/jump-target.cc
@@ -48,289 +48,21 @@
 }
 
 
-void JumpTarget::ComputeEntryFrame() {
-  // Given: a collection of frames reaching by forward CFG edges and
-  // the directionality of the block.  Compute: an entry frame for the
-  // block.
-
-  Counters::compute_entry_frame.Increment();
-#ifdef DEBUG
-  if (compiling_deferred_code_) {
-    ASSERT(reaching_frames_.length() > 1);
-    VirtualFrame* frame = reaching_frames_[0];
-    bool all_identical = true;
-    for (int i = 1; i < reaching_frames_.length(); i++) {
-      if (!frame->Equals(reaching_frames_[i])) {
-        all_identical = false;
-        break;
-      }
-    }
-    ASSERT(!all_identical || all_identical);
-  }
-#endif
-
-  // Choose an initial frame.
-  VirtualFrame* initial_frame = reaching_frames_[0];
-
-  // A list of pointers to frame elements in the entry frame.  NULL
-  // indicates that the element has not yet been determined.
-  int length = initial_frame->element_count();
-  ZoneList<FrameElement*> elements(length);
-
-  // Initially populate the list of elements based on the initial
-  // frame.
-  for (int i = 0; i < length; i++) {
-    FrameElement element = initial_frame->elements_[i];
-    // We do not allow copies or constants in bidirectional frames.
-    if (direction_ == BIDIRECTIONAL) {
-      if (element.is_constant() || element.is_copy()) {
-        elements.Add(NULL);
-        continue;
-      }
-    }
-    elements.Add(&initial_frame->elements_[i]);
-  }
-
-  // Compute elements based on the other reaching frames.
-  if (reaching_frames_.length() > 1) {
-    for (int i = 0; i < length; i++) {
-      FrameElement* element = elements[i];
-      for (int j = 1; j < reaching_frames_.length(); j++) {
-        // Element computation is monotonic: new information will not
-        // change our decision about undetermined or invalid elements.
-        if (element == NULL || !element->is_valid()) break;
-
-        FrameElement* other = &reaching_frames_[j]->elements_[i];
-        element = element->Combine(other);
-        if (element != NULL && !element->is_copy()) {
-          ASSERT(other != NULL);
-          // 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.
-          element->set_number_info(NumberInfo::Combine(element->number_info(),
-                                                       other->number_info()));
-        }
-      }
-      elements[i] = element;
-    }
-  }
-
-  // Build the new frame.  A freshly allocated frame has memory elements
-  // for the parameters and some platform-dependent elements (e.g.,
-  // return address).  Replace those first.
-  entry_frame_ = new VirtualFrame();
-  int index = 0;
-  for (; index < entry_frame_->element_count(); index++) {
-    FrameElement* target = elements[index];
-    // If the element is determined, set it now.  Count registers.  Mark
-    // elements as copied exactly when they have a copy.  Undetermined
-    // elements are initially recorded as if in memory.
-    if (target != NULL) {
-      entry_frame_->elements_[index] = *target;
-      InitializeEntryElement(index, target);
-    }
-  }
-  // Then fill in the rest of the frame with new elements.
-  for (; index < length; index++) {
-    FrameElement* target = elements[index];
-    if (target == NULL) {
-      entry_frame_->elements_.Add(
-          FrameElement::MemoryElement(NumberInfo::Uninitialized()));
-    } else {
-      entry_frame_->elements_.Add(*target);
-      InitializeEntryElement(index, target);
-    }
-  }
-
-  // Allocate any still-undetermined frame elements to registers or
-  // memory, from the top down.
-  for (int i = length - 1; i >= 0; i--) {
-    if (elements[i] == NULL) {
-      // Loop over all the reaching frames to check whether the element
-      // is synced on all frames and to count the registers it occupies.
-      bool is_synced = true;
-      RegisterFile candidate_registers;
-      int best_count = kMinInt;
-      int best_reg_num = RegisterAllocator::kInvalidRegister;
-      NumberInfo info = NumberInfo::Uninitialized();
-
-      for (int j = 0; j < reaching_frames_.length(); j++) {
-        FrameElement element = reaching_frames_[j]->elements_[i];
-        if (direction_ == BIDIRECTIONAL) {
-          info = NumberInfo::Unknown();
-        } else if (!element.is_copy()) {
-          info = NumberInfo::Combine(info, element.number_info());
-        } else {
-          // New elements will not be copies, so get number information from
-          // backing element in the reaching frame.
-          info = NumberInfo::Combine(info,
-            reaching_frames_[j]->elements_[element.index()].number_info());
-        }
-        is_synced = is_synced && element.is_synced();
-        if (element.is_register() && !entry_frame_->is_used(element.reg())) {
-          // Count the register occurrence and remember it if better
-          // than the previous best.
-          int num = RegisterAllocator::ToNumber(element.reg());
-          candidate_registers.Use(num);
-          if (candidate_registers.count(num) > best_count) {
-            best_count = candidate_registers.count(num);
-            best_reg_num = num;
-          }
-        }
-      }
-
-      // We must have a number type information now (not for copied elements).
-      ASSERT(entry_frame_->elements_[i].is_copy()
-             || !info.IsUninitialized());
-
-      // If the value is synced on all frames, put it in memory.  This
-      // costs nothing at the merge code but will incur a
-      // memory-to-register move when the value is needed later.
-      if (is_synced) {
-        // Already recorded as a memory element.
-        // Set combined number info.
-        entry_frame_->elements_[i].set_number_info(info);
-        continue;
-      }
-
-      // Try to put it in a register.  If there was no best choice
-      // consider any free register.
-      if (best_reg_num == RegisterAllocator::kInvalidRegister) {
-        for (int j = 0; j < RegisterAllocator::kNumRegisters; j++) {
-          if (!entry_frame_->is_used(j)) {
-            best_reg_num = j;
-            break;
-          }
-        }
-      }
-
-      if (best_reg_num != RegisterAllocator::kInvalidRegister) {
-        // If there was a register choice, use it.  Preserve the copied
-        // flag on the element.
-        bool is_copied = entry_frame_->elements_[i].is_copied();
-        Register reg = RegisterAllocator::ToRegister(best_reg_num);
-        entry_frame_->elements_[i] =
-            FrameElement::RegisterElement(reg, FrameElement::NOT_SYNCED,
-                                          NumberInfo::Uninitialized());
-        if (is_copied) entry_frame_->elements_[i].set_copied();
-        entry_frame_->set_register_location(reg, i);
-      }
-      // Set combined number info.
-      entry_frame_->elements_[i].set_number_info(info);
-    }
-  }
-
-  // If we have incoming backward edges assert we forget all number information.
-#ifdef DEBUG
-  if (direction_ == BIDIRECTIONAL) {
-    for (int i = 0; i < length; ++i) {
-      if (!entry_frame_->elements_[i].is_copy()) {
-        ASSERT(entry_frame_->elements_[i].number_info().IsUnknown());
-      }
-    }
-  }
-#endif
-
-  // The stack pointer is at the highest synced element or the base of
-  // the expression stack.
-  int stack_pointer = length - 1;
-  while (stack_pointer >= entry_frame_->expression_base_index() &&
-         !entry_frame_->elements_[stack_pointer].is_synced()) {
-    stack_pointer--;
-  }
-  entry_frame_->stack_pointer_ = stack_pointer;
-}
-
-
 void JumpTarget::Jump() {
   DoJump();
 }
 
 
-void JumpTarget::Jump(Result* arg) {
-  ASSERT(cgen()->has_valid_frame());
-
-  cgen()->frame()->Push(arg);
-  DoJump();
-}
-
-
 void JumpTarget::Branch(Condition cc, Hint hint) {
   DoBranch(cc, hint);
 }
 
 
-#ifdef DEBUG
-#define DECLARE_ARGCHECK_VARS(name)                                \
-  Result::Type name##_type = name->type();                         \
-  Register name##_reg = name->is_register() ? name->reg() : no_reg
-
-#define ASSERT_ARGCHECK(name)                                \
-  ASSERT(name->type() == name##_type);                       \
-  ASSERT(!name->is_register() || name->reg().is(name##_reg))
-
-#else
-#define DECLARE_ARGCHECK_VARS(name) do {} while (false)
-
-#define ASSERT_ARGCHECK(name) do {} while (false)
-#endif
-
-void JumpTarget::Branch(Condition cc, Result* arg, Hint hint) {
-  ASSERT(cgen()->has_valid_frame());
-
-  // We want to check that non-frame registers at the call site stay in
-  // the same registers on the fall-through branch.
-  DECLARE_ARGCHECK_VARS(arg);
-
-  cgen()->frame()->Push(arg);
-  DoBranch(cc, hint);
-  *arg = cgen()->frame()->Pop();
-
-  ASSERT_ARGCHECK(arg);
-}
-
-
-void BreakTarget::Branch(Condition cc, Result* arg, Hint hint) {
-  ASSERT(cgen()->has_valid_frame());
-
-  int count = cgen()->frame()->height() - expected_height_;
-  if (count > 0) {
-    // We negate and branch here rather than using DoBranch's negate
-    // and branch.  This gives us a hook to remove statement state
-    // from the frame.
-    JumpTarget fall_through;
-    // Branch to fall through will not negate, because it is a
-    // forward-only target.
-    fall_through.Branch(NegateCondition(cc), NegateHint(hint));
-    Jump(arg);  // May emit merge code here.
-    fall_through.Bind();
-  } else {
-    DECLARE_ARGCHECK_VARS(arg);
-    cgen()->frame()->Push(arg);
-    DoBranch(cc, hint);
-    *arg = cgen()->frame()->Pop();
-    ASSERT_ARGCHECK(arg);
-  }
-}
-
-#undef DECLARE_ARGCHECK_VARS
-#undef ASSERT_ARGCHECK
-
-
 void JumpTarget::Bind() {
   DoBind();
 }
 
 
-void JumpTarget::Bind(Result* arg) {
-  if (cgen()->has_valid_frame()) {
-    cgen()->frame()->Push(arg);
-  }
-  DoBind();
-  *arg = cgen()->frame()->Pop();
-}
-
-
 void JumpTarget::AddReachingFrame(VirtualFrame* frame) {
   ASSERT(reaching_frames_.length() == merge_labels_.length());
   ASSERT(entry_frame_ == NULL);
diff --git a/src/jump-target.h b/src/jump-target.h
index db7c115..db523b5 100644
--- a/src/jump-target.h
+++ b/src/jump-target.h
@@ -117,12 +117,17 @@
   // the target and the fall-through.
   virtual void Branch(Condition cc, Hint hint = no_hint);
   virtual void Branch(Condition cc, Result* arg, Hint hint = no_hint);
+  virtual void Branch(Condition cc,
+                      Result* arg0,
+                      Result* arg1,
+                      Hint hint = no_hint);
 
   // Bind a jump target.  If there is no current frame at the binding
   // site, there must be at least one frame reaching via a forward
   // jump.
   virtual void Bind();
   virtual void Bind(Result* arg);
+  virtual void Bind(Result* arg0, Result* arg1);
 
   // Emit a call to a jump target.  There must be a current frame at
   // the call.  The frame at the target is the same as the current
diff --git a/src/number-info.h b/src/number-info.h
deleted file mode 100644
index bfc0d9f..0000000
--- a/src/number-info.h
+++ /dev/null
@@ -1,190 +0,0 @@
-// 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_NUMBER_INFO_H_
-#define V8_NUMBER_INFO_H_
-
-namespace v8 {
-namespace internal {
-
-//        Unknown
-//           |
-//         Number
-//         /    |
-//  HeapNumber Integer32
-//        |      |
-//        |     Smi
-//        |     /
-//      Uninitialized.
-
-class NumberInfo {
- public:
-  NumberInfo() { }
-
-  static inline NumberInfo Unknown();
-  // We know it's a number of some sort.
-  static inline NumberInfo Number();
-  // We know it's signed or unsigned 32 bit integer.
-  static inline NumberInfo Integer32();
-  // We know it's a Smi.
-  static inline NumberInfo Smi();
-  // We know it's a heap number.
-  static inline NumberInfo HeapNumber();
-  // We haven't started collecting info yet.
-  static inline NumberInfo Uninitialized();
-
-  // Return compact representation.  Very sensitive to enum values below!
-  int ThreeBitRepresentation() {
-    ASSERT(type_ != kUninitializedType);
-    int answer = type_ > 6 ? type_ -2 : type_;
-    ASSERT(answer >= 0);
-    ASSERT(answer <= 7);
-    return answer;
-  }
-
-  // Decode compact representation.  Very sensitive to enum values below!
-  static NumberInfo ExpandedRepresentation(int three_bit_representation) {
-    Type t = static_cast<Type>(three_bit_representation >= 6 ?
-                               three_bit_representation + 2 :
-                               three_bit_representation);
-    ASSERT(t == kUnknownType ||
-           t == kNumberType ||
-           t == kInteger32Type ||
-           t == kSmiType ||
-           t == kHeapNumberType);
-    return NumberInfo(t);
-  }
-
-  int ToInt() {
-    return type_;
-  }
-
-  static NumberInfo FromInt(int bit_representation) {
-    Type t = static_cast<Type>(bit_representation);
-    ASSERT(t == kUnknownType ||
-           t == kNumberType ||
-           t == kInteger32Type ||
-           t == kSmiType ||
-           t == kHeapNumberType);
-    return NumberInfo(t);
-  }
-
-  // Return the weakest (least precise) common type.
-  static NumberInfo Combine(NumberInfo a, NumberInfo b) {
-    return NumberInfo(static_cast<Type>(a.type_ & b.type_));
-  }
-
-  inline bool IsUnknown() {
-    return type_ == kUnknownType;
-  }
-
-  inline bool IsNumber() {
-    ASSERT(type_ != kUninitializedType);
-    return ((type_ & kNumberType) == kNumberType);
-  }
-
-  inline bool IsSmi() {
-    ASSERT(type_ != kUninitializedType);
-    return ((type_ & kSmiType) == kSmiType);
-  }
-
-  inline bool IsInteger32() {
-    ASSERT(type_ != kUninitializedType);
-    return ((type_ & kInteger32Type) == kInteger32Type);
-  }
-
-  inline bool IsHeapNumber() {
-    ASSERT(type_ != kUninitializedType);
-    return ((type_ & kHeapNumberType) == kHeapNumberType);
-  }
-
-  inline bool IsUninitialized() {
-    return type_ == kUninitializedType;
-  }
-
-  const char* ToString() {
-    switch (type_) {
-      case kUnknownType: return "UnknownType";
-      case kNumberType: return "NumberType";
-      case kSmiType: return "SmiType";
-      case kHeapNumberType: return "HeapNumberType";
-      case kInteger32Type: return "Integer32Type";
-      case kUninitializedType:
-        UNREACHABLE();
-        return "UninitializedType";
-    }
-    UNREACHABLE();
-    return "Unreachable code";
-  }
-
- private:
-  enum Type {
-    kUnknownType = 0,
-    kNumberType = 1,
-    kInteger32Type = 3,
-    kSmiType = 7,
-    kHeapNumberType = 9,
-    kUninitializedType = 15
-  };
-  explicit inline NumberInfo(Type t) : type_(t) { }
-
-  Type type_;
-};
-
-
-NumberInfo NumberInfo::Unknown() {
-  return NumberInfo(kUnknownType);
-}
-
-
-NumberInfo NumberInfo::Number() {
-  return NumberInfo(kNumberType);
-}
-
-
-NumberInfo NumberInfo::Integer32() {
-  return NumberInfo(kInteger32Type);
-}
-
-
-NumberInfo NumberInfo::Smi() {
-  return NumberInfo(kSmiType);
-}
-
-
-NumberInfo NumberInfo::HeapNumber() {
-  return NumberInfo(kHeapNumberType);
-}
-
-
-NumberInfo NumberInfo::Uninitialized() {
-  return NumberInfo(kUninitializedType);
-}
-
-} }  // namespace v8::internal
-
-#endif  // V8_NUMBER_INFO_H_
diff --git a/src/regexp.js b/src/regexp.js
index e2492f7..dc1b042 100644
--- a/src/regexp.js
+++ b/src/regexp.js
@@ -344,6 +344,7 @@
 // on the captures array of the last successful match and the subject string
 // of the last successful match.
 function RegExpGetLastMatch() {
+  if (lastMatchInfoOverride) { return lastMatchInfoOverride[0]; }
   var regExpSubject = LAST_SUBJECT(lastMatchInfo);
   return SubString(regExpSubject,
                    lastMatchInfo[CAPTURE0],
@@ -352,6 +353,11 @@
 
 
 function RegExpGetLastParen() {
+  if (lastMatchInfoOverride) {
+    var override = lastMatchInfoOverride;
+    if (override.length <= 3) return ''; 
+    return override[override.length - 3];
+  }
   var length = NUMBER_OF_CAPTURES(lastMatchInfo);
   if (length <= 2) return '';  // There were no captures.
   // We match the SpiderMonkey behavior: return the substring defined by the
@@ -368,17 +374,32 @@
 
 
 function RegExpGetLeftContext() {
-  return SubString(LAST_SUBJECT(lastMatchInfo),
-                   0,
-                   lastMatchInfo[CAPTURE0]);
+  var start_index;
+  var subject;
+  if (!lastMatchInfoOverride) {
+    start_index = lastMatchInfo[CAPTURE0];
+    subject = LAST_SUBJECT(lastMatchInfo);
+  } else {
+    var override = lastMatchInfoOverride;
+    start_index = override[override.length - 2];
+    subject = override[override.length - 1];
+  }
+  return SubString(subject, 0, start_index);
 }
 
 
 function RegExpGetRightContext() {
-  var subject = LAST_SUBJECT(lastMatchInfo);
-  return SubString(subject,
-                   lastMatchInfo[CAPTURE1],
-                   subject.length);
+  var start_index;
+  var subject;
+  if (!lastMatchInfoOverride) {
+    start_index = lastMatchInfo[CAPTURE1];
+    subject = LAST_SUBJECT(lastMatchInfo);
+  } else {
+    var override = lastMatchInfoOverride;
+    subject = override[override.length - 1];
+    start_index = override[override.length - 2] + subject.length;
+  }
+  return SubString(subject, start_index, subject.length);
 }
 
 
@@ -387,6 +408,10 @@
 // called with indices from 1 to 9.
 function RegExpMakeCaptureGetter(n) {
   return function() {
+    if (lastMatchInfoOverride) {
+      if (n < lastMatchInfoOverride.length - 2) return lastMatchInfoOverride[n];
+      return '';
+    }
     var index = n * 2;
     if (index >= NUMBER_OF_CAPTURES(lastMatchInfo)) return '';
     var matchStart = lastMatchInfo[CAPTURE(index)];
@@ -411,6 +436,12 @@
     0,                 // REGEXP_FIRST_CAPTURE + 1
 ];
 
+// Override last match info with an array of actual substrings.
+// Used internally by replace regexp with function.
+// The array has the format of an "apply" argument for a replacement 
+// function. 
+var lastMatchInfoOverride = null;
+
 // -------------------------------------------------------------------
 
 function SetupRegExp() {
diff --git a/src/register-allocator-inl.h b/src/register-allocator-inl.h
index 8453104..e0ea9e1 100644
--- a/src/register-allocator-inl.h
+++ b/src/register-allocator-inl.h
@@ -104,42 +104,36 @@
 }
 
 
-NumberInfo Result::number_info() const {
+TypeInfo Result::type_info() const {
   ASSERT(is_valid());
-  if (!is_constant()) {
-    return NumberInfo::FromInt(NumberInfoField::decode(value_));
-  }
-  Handle<Object> value = handle();
-  if (value->IsSmi()) return NumberInfo::Smi();
-  if (value->IsHeapNumber()) return NumberInfo::HeapNumber();
-  return NumberInfo::Unknown();
+  return TypeInfo::FromInt(TypeInfoField::decode(value_));
 }
 
 
-void Result::set_number_info(NumberInfo info) {
+void Result::set_type_info(TypeInfo info) {
   ASSERT(is_valid());
-  value_ &= ~NumberInfoField::mask();
-  value_ |= NumberInfoField::encode(info.ToInt());
+  value_ &= ~TypeInfoField::mask();
+  value_ |= TypeInfoField::encode(info.ToInt());
 }
 
 
 bool Result::is_number() const {
-  return number_info().IsNumber();
+  return type_info().IsNumber();
 }
 
 
 bool Result::is_smi() const {
-  return number_info().IsSmi();
+  return type_info().IsSmi();
 }
 
 
 bool Result::is_integer32() const {
-  return number_info().IsInteger32();
+  return type_info().IsInteger32();
 }
 
 
-bool Result::is_heap_number() const {
-  return number_info().IsHeapNumber();
+bool Result::is_double() const {
+  return type_info().IsDouble();
 }
 
 } }  // namespace v8::internal
diff --git a/src/register-allocator.cc b/src/register-allocator.cc
index 64e4428..b9989a5 100644
--- a/src/register-allocator.cc
+++ b/src/register-allocator.cc
@@ -38,11 +38,11 @@
 // Result implementation.
 
 
-Result::Result(Register reg, NumberInfo info) {
+Result::Result(Register reg, TypeInfo info) {
   ASSERT(reg.is_valid() && !RegisterAllocator::IsReserved(reg));
   CodeGeneratorScope::Current()->allocator()->Use(reg);
   value_ = TypeField::encode(REGISTER)
-      | NumberInfoField::encode(info.ToInt())
+      | TypeInfoField::encode(info.ToInt())
       | DataField::encode(reg.code_);
 }
 
diff --git a/src/register-allocator.h b/src/register-allocator.h
index 8bc8ede..0fbc83b 100644
--- a/src/register-allocator.h
+++ b/src/register-allocator.h
@@ -29,7 +29,7 @@
 #define V8_REGISTER_ALLOCATOR_H_
 
 #include "macro-assembler.h"
-#include "number-info.h"
+#include "type-info-inl.h"
 
 #if V8_TARGET_ARCH_IA32
 #include "ia32/register-allocator-ia32.h"
@@ -65,12 +65,13 @@
   Result() { invalidate(); }
 
   // Construct a register Result.
-  explicit Result(Register reg, NumberInfo info = NumberInfo::Unknown());
+  explicit Result(Register reg, TypeInfo info = TypeInfo::Unknown());
 
   // Construct a Result whose value is a compile-time constant.
   explicit Result(Handle<Object> value) {
+    TypeInfo info = TypeInfo::TypeFromValue(value);
     value_ = TypeField::encode(CONSTANT)
-        | NumberInfoField::encode(NumberInfo::Uninitialized().ToInt())
+        | TypeInfoField::encode(info.ToInt())
         | IsUntaggedInt32Field::encode(false)
         | DataField::encode(ConstantList()->length());
     ConstantList()->Add(value);
@@ -102,12 +103,12 @@
 
   void invalidate() { value_ = TypeField::encode(INVALID); }
 
-  inline NumberInfo number_info() const;
-  inline void set_number_info(NumberInfo info);
+  inline TypeInfo type_info() const;
+  inline void set_type_info(TypeInfo info);
   inline bool is_number() const;
   inline bool is_smi() const;
   inline bool is_integer32() const;
-  inline bool is_heap_number() const;
+  inline bool is_double() const;
 
   bool is_valid() const { return type() != INVALID; }
   bool is_register() const { return type() == REGISTER; }
@@ -152,10 +153,11 @@
  private:
   uint32_t value_;
 
+  // Declare BitFields with template parameters <type, start, size>.
   class TypeField: public BitField<Type, 0, 2> {};
-  class NumberInfoField : public BitField<int, 2, 4> {};
-  class IsUntaggedInt32Field : public BitField<bool, 6, 1> {};
-  class DataField: public BitField<uint32_t, 7, 32 - 7> {};
+  class TypeInfoField : public BitField<int, 2, 6> {};
+  class IsUntaggedInt32Field : public BitField<bool, 8, 1> {};
+  class DataField: public BitField<uint32_t, 9, 32 - 9> {};
 
   inline void CopyTo(Result* destination) const;
 
diff --git a/src/runtime.cc b/src/runtime.cc
index b349815..c77d518 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -1567,9 +1567,91 @@
   return CharFromCode(args[0]);
 }
 
+
+class FixedArrayBuilder {
+ public:
+  explicit FixedArrayBuilder(int initial_capacity)
+      : array_(Factory::NewFixedArrayWithHoles(initial_capacity)),
+        length_(0) {
+    // Require a non-zero initial size. Ensures that doubling the size to
+    // extend the array will work.
+    ASSERT(initial_capacity > 0);
+  }
+
+  explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
+      : array_(backing_store),
+        length_(0) {
+    // Require a non-zero initial size. Ensures that doubling the size to
+    // extend the array will work.
+    ASSERT(backing_store->length() > 0);
+  }
+
+  bool HasCapacity(int elements) {
+    int length = array_->length();
+    int required_length = length_ + elements;
+    return (length >= required_length);
+  }
+
+  void EnsureCapacity(int elements) {
+    int length = array_->length();
+    int required_length = length_ + elements;
+    if (length < required_length) {
+      int new_length = length;
+      do {
+        new_length *= 2;
+      } while (new_length < required_length);
+      Handle<FixedArray> extended_array =
+          Factory::NewFixedArrayWithHoles(new_length);
+      array_->CopyTo(0, *extended_array, 0, length_);
+      array_ = extended_array;
+    }
+  }
+
+  void Add(Object* value) {
+    ASSERT(length_ < capacity());
+    array_->set(length_, value);
+    length_++;
+  }
+
+  void Add(Smi* value) {
+    ASSERT(length_ < capacity());
+    array_->set(length_, value);
+    length_++;
+  }
+
+  Handle<FixedArray> array() {
+    return array_;
+  }
+
+  int length() {
+    return length_;
+  }
+
+  int capacity() {
+    return array_->length();
+  }
+
+  Handle<JSArray> ToJSArray() {
+    Handle<JSArray> result_array = Factory::NewJSArrayWithElements(array_);
+    result_array->set_length(Smi::FromInt(length_));
+    return result_array;
+  }
+
+  Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
+    target_array->set_elements(*array_);
+    target_array->set_length(Smi::FromInt(length_));
+    return target_array;
+  }
+
+ private:
+  Handle<FixedArray> array_;
+  int length_;
+};
+
+
 // Forward declarations.
-static const int kStringBuilderConcatHelperLengthBits = 11;
-static const int kStringBuilderConcatHelperPositionBits = 19;
+const int kStringBuilderConcatHelperLengthBits = 11;
+const int kStringBuilderConcatHelperPositionBits = 19;
 
 template <typename schar>
 static inline void StringBuilderConcatHelper(String*,
@@ -1577,15 +1659,19 @@
                                              FixedArray*,
                                              int);
 
-typedef BitField<int, 0, 11> StringBuilderSubstringLength;
-typedef BitField<int, 11, 19> StringBuilderSubstringPosition;
+typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
+    StringBuilderSubstringLength;
+typedef BitField<int,
+                 kStringBuilderConcatHelperLengthBits,
+                 kStringBuilderConcatHelperPositionBits>
+    StringBuilderSubstringPosition;
+
 
 class ReplacementStringBuilder {
  public:
   ReplacementStringBuilder(Handle<String> subject, int estimated_part_count)
-      : subject_(subject),
-        parts_(Factory::NewFixedArray(estimated_part_count)),
-        part_count_(0),
+      : array_builder_(estimated_part_count),
+        subject_(subject),
         character_count_(0),
         is_ascii_(subject->IsAsciiRepresentation()) {
     // Require a non-zero initial size. Ensures that doubling the size to
@@ -1593,38 +1679,35 @@
     ASSERT(estimated_part_count > 0);
   }
 
-  void EnsureCapacity(int elements) {
-    int length = parts_->length();
-    int required_length = part_count_ + elements;
-    if (length < required_length) {
-      int new_length = length;
-      do {
-        new_length *= 2;
-      } while (new_length < required_length);
-      Handle<FixedArray> extended_array =
-          Factory::NewFixedArray(new_length);
-      parts_->CopyTo(0, *extended_array, 0, part_count_);
-      parts_ = extended_array;
-    }
-  }
-
-  void AddSubjectSlice(int from, int to) {
+  static inline void AddSubjectSlice(FixedArrayBuilder* builder,
+                                     int from,
+                                     int to) {
     ASSERT(from >= 0);
     int length = to - from;
     ASSERT(length > 0);
-    // Can we encode the slice in 11 bits for length and 19 bits for
-    // start position - as used by StringBuilderConcatHelper?
     if (StringBuilderSubstringLength::is_valid(length) &&
         StringBuilderSubstringPosition::is_valid(from)) {
       int encoded_slice = StringBuilderSubstringLength::encode(length) |
           StringBuilderSubstringPosition::encode(from);
-      AddElement(Smi::FromInt(encoded_slice));
+      builder->Add(Smi::FromInt(encoded_slice));
     } else {
       // Otherwise encode as two smis.
-      AddElement(Smi::FromInt(-length));
-      AddElement(Smi::FromInt(from));
+      builder->Add(Smi::FromInt(-length));
+      builder->Add(Smi::FromInt(from));
     }
-    IncrementCharacterCount(length);
+  }
+
+
+  void EnsureCapacity(int elements) {
+    array_builder_.EnsureCapacity(elements);
+  }
+
+
+  void AddSubjectSlice(int from, int to) {
+    AddSubjectSlice(&array_builder_, from, to);
+    // Can we encode the slice in 11 bits for length and 19 bits for
+    // start position - as used by StringBuilderConcatHelper?
+    IncrementCharacterCount(to - from);
   }
 
 
@@ -1640,7 +1723,7 @@
 
 
   Handle<String> ToString() {
-    if (part_count_ == 0) {
+    if (array_builder_.length() == 0) {
       return Factory::empty_string();
     }
 
@@ -1652,8 +1735,8 @@
       char* char_buffer = seq->GetChars();
       StringBuilderConcatHelper(*subject_,
                                 char_buffer,
-                                *parts_,
-                                part_count_);
+                                *array_builder_.array(),
+                                array_builder_.length());
     } else {
       // Non-ASCII.
       joined_string = NewRawTwoByteString(character_count_);
@@ -1662,8 +1745,8 @@
       uc16* char_buffer = seq->GetChars();
       StringBuilderConcatHelper(*subject_,
                                 char_buffer,
-                                *parts_,
-                                part_count_);
+                                *array_builder_.array(),
+                                array_builder_.length());
     }
     return joined_string;
   }
@@ -1676,8 +1759,14 @@
     character_count_ += by;
   }
 
- private:
+  Handle<JSArray> GetParts() {
+    Handle<JSArray> result =
+        Factory::NewJSArrayWithElements(array_builder_.array());
+    result->set_length(Smi::FromInt(array_builder_.length()));
+    return result;
+  }
 
+ private:
   Handle<String> NewRawAsciiString(int size) {
     CALL_HEAP_FUNCTION(Heap::AllocateRawAsciiString(size), String);
   }
@@ -1690,14 +1779,12 @@
 
   void AddElement(Object* element) {
     ASSERT(element->IsSmi() || element->IsString());
-    ASSERT(parts_->length() > part_count_);
-    parts_->set(part_count_, element);
-    part_count_++;
+    ASSERT(array_builder_.capacity() > array_builder_.length());
+    array_builder_.Add(element);
   }
 
+  FixedArrayBuilder array_builder_;
   Handle<String> subject_;
-  Handle<FixedArray> parts_;
-  int part_count_;
   int character_count_;
   bool is_ascii_;
 };
@@ -2105,7 +2192,6 @@
 }
 
 
-
 // Cap on the maximal shift in the Boyer-Moore implementation. By setting a
 // limit, we can fix the size of tables.
 static const int kBMMaxShift = 0xff;
@@ -2869,6 +2955,468 @@
 }
 
 
+// Two smis before and after the match, for very long strings.
+const int kMaxBuilderEntriesPerRegExpMatch = 5;
+
+
+static void SetLastMatchInfoNoCaptures(Handle<String> subject,
+                                       Handle<JSArray> last_match_info,
+                                       int match_start,
+                                       int match_end) {
+  // Fill last_match_info with a single capture.
+  last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
+  AssertNoAllocation no_gc;
+  FixedArray* elements = FixedArray::cast(last_match_info->elements());
+  RegExpImpl::SetLastCaptureCount(elements, 2);
+  RegExpImpl::SetLastInput(elements, *subject);
+  RegExpImpl::SetLastSubject(elements, *subject);
+  RegExpImpl::SetCapture(elements, 0, match_start);
+  RegExpImpl::SetCapture(elements, 1, match_end);
+}
+
+
+template <typename schar>
+static bool SearchCharMultiple(Vector<schar> subject,
+                               String* pattern,
+                               schar pattern_char,
+                               FixedArrayBuilder* builder,
+                               int* match_pos) {
+  // Position of last match.
+  int pos = *match_pos;
+  int subject_length = subject.length();
+  while (pos < subject_length) {
+    int match_end = pos + 1;
+    if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
+      *match_pos = pos;
+      return false;
+    }
+    int new_pos = SingleCharIndexOf(subject, pattern_char, match_end);
+    if (new_pos >= 0) {
+      // Match has been found.
+      if (new_pos > match_end) {
+        ReplacementStringBuilder::AddSubjectSlice(builder, match_end, new_pos);
+      }
+      pos = new_pos;
+      builder->Add(pattern);
+    } else {
+      break;
+    }
+  }
+  if (pos + 1 < subject_length) {
+    ReplacementStringBuilder::AddSubjectSlice(builder, pos + 1, subject_length);
+  }
+  *match_pos = pos;
+  return true;
+}
+
+
+static bool SearchCharMultiple(Handle<String> subject,
+                               Handle<String> pattern,
+                               Handle<JSArray> last_match_info,
+                               FixedArrayBuilder* builder) {
+  ASSERT(subject->IsFlat());
+  ASSERT_EQ(1, pattern->length());
+  uc16 pattern_char = pattern->Get(0);
+  // Treating position before first as initial "previous match position".
+  int match_pos = -1;
+
+  for (;;) {  // Break when search complete.
+    builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
+    AssertNoAllocation no_gc;
+    if (subject->IsAsciiRepresentation()) {
+      if (pattern_char > String::kMaxAsciiCharCode) {
+        break;
+      }
+      Vector<const char> subject_vector = subject->ToAsciiVector();
+      char pattern_ascii_char = static_cast<char>(pattern_char);
+      bool complete = SearchCharMultiple<const char>(subject_vector,
+                                                     *pattern,
+                                                     pattern_ascii_char,
+                                                     builder,
+                                                     &match_pos);
+      if (complete) break;
+    } else {
+      Vector<const uc16> subject_vector = subject->ToUC16Vector();
+      bool complete = SearchCharMultiple<const uc16>(subject_vector,
+                                                     *pattern,
+                                                     pattern_char,
+                                                     builder,
+                                                     &match_pos);
+      if (complete) break;
+    }
+  }
+
+  if (match_pos >= 0) {
+    SetLastMatchInfoNoCaptures(subject,
+                               last_match_info,
+                               match_pos,
+                               match_pos + 1);
+    return true;
+  }
+  return false;  // No matches at all.
+}
+
+
+template <typename schar, typename pchar>
+static bool SearchStringMultiple(Vector<schar> subject,
+                                 String* pattern,
+                                 Vector<pchar> pattern_string,
+                                 FixedArrayBuilder* builder,
+                                 int* match_pos) {
+  int pos = *match_pos;
+  int subject_length = subject.length();
+  int pattern_length = pattern_string.length();
+  int max_search_start = subject_length - pattern_length;
+  bool is_ascii = (sizeof(schar) == 1);
+  StringSearchStrategy strategy =
+      InitializeStringSearch(pattern_string, is_ascii);
+  switch (strategy) {
+    case SEARCH_FAIL: return false;
+    case SEARCH_SHORT:
+      while (pos <= max_search_start) {
+        if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
+          *match_pos = pos;
+          return false;
+        }
+        // Position of end of previous match.
+        int match_end = pos + pattern_length;
+        int new_pos = SimpleIndexOf(subject, pattern_string, match_end);
+        if (new_pos >= 0) {
+          // A match.
+          if (new_pos > match_end) {
+            ReplacementStringBuilder::AddSubjectSlice(builder,
+                                                      match_end,
+                                                      new_pos);
+          }
+          pos = new_pos;
+          builder->Add(pattern);
+        } else {
+          break;
+        }
+      }
+      break;
+    case SEARCH_LONG:
+      while (pos  <= max_search_start) {
+        if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
+         *match_pos = pos;
+         return false;
+        }
+        int new_pos = ComplexIndexOf(subject,
+                                     pattern_string,
+                                     pos + pattern_length);
+        if (new_pos >= 0) {
+         // A match has been found.
+          if (new_pos > pos) {
+           ReplacementStringBuilder::AddSubjectSlice(builder, pos, new_pos);
+          }
+          pos = new_pos;
+          builder->Add(pattern);
+        } else {
+         break;
+        }
+      }
+      break;
+  }
+  if (pos < max_search_start) {
+    ReplacementStringBuilder::AddSubjectSlice(builder,
+                                              pos + pattern_length,
+                                              subject_length);
+  }
+  *match_pos = pos;
+  return true;
+}
+
+
+static bool SearchStringMultiple(Handle<String> subject,
+                                 Handle<String> pattern,
+                                 Handle<JSArray> last_match_info,
+                                 FixedArrayBuilder* builder) {
+  ASSERT(subject->IsFlat());
+  ASSERT(pattern->IsFlat());
+  ASSERT(pattern->length() > 1);
+
+  // Treating as if a previous match was before first character.
+  int match_pos = -pattern->length();
+
+  for (;;) {  // Break when search complete.
+    builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
+    AssertNoAllocation no_gc;
+    if (subject->IsAsciiRepresentation()) {
+      Vector<const char> subject_vector = subject->ToAsciiVector();
+      if (pattern->IsAsciiRepresentation()) {
+        if (SearchStringMultiple(subject_vector,
+                                 *pattern,
+                                 pattern->ToAsciiVector(),
+                                 builder,
+                                 &match_pos)) break;
+      } else {
+        if (SearchStringMultiple(subject_vector,
+                                 *pattern,
+                                 pattern->ToUC16Vector(),
+                                 builder,
+                                 &match_pos)) break;
+      }
+    } else {
+      Vector<const uc16> subject_vector = subject->ToUC16Vector();
+      if (pattern->IsAsciiRepresentation()) {
+        if (SearchStringMultiple(subject_vector,
+                                 *pattern,
+                                 pattern->ToAsciiVector(),
+                                 builder,
+                                 &match_pos)) break;
+      } else {
+        if (SearchStringMultiple(subject_vector,
+                                 *pattern,
+                                 pattern->ToUC16Vector(),
+                                 builder,
+                                 &match_pos)) break;
+      }
+    }
+  }
+
+  if (match_pos >= 0) {
+    SetLastMatchInfoNoCaptures(subject,
+                               last_match_info,
+                               match_pos,
+                               match_pos + pattern->length());
+    return true;
+  }
+  return false;  // No matches at all.
+}
+
+
+static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
+    Handle<String> subject,
+    Handle<JSRegExp> regexp,
+    Handle<JSArray> last_match_array,
+    FixedArrayBuilder* builder) {
+  ASSERT(subject->IsFlat());
+  int match_start = -1;
+  int match_end = 0;
+  int pos = 0;
+  int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
+  if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
+
+  OffsetsVector registers(required_registers);
+  Vector<int> register_vector(registers.vector(), registers.length());
+  int subject_length = subject->length();
+
+  for (;;) {  // Break on failure, return on exception.
+    RegExpImpl::IrregexpResult result =
+        RegExpImpl::IrregexpExecOnce(regexp,
+                                     subject,
+                                     pos,
+                                     register_vector);
+    if (result == RegExpImpl::RE_SUCCESS) {
+      match_start = register_vector[0];
+      builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
+      if (match_end < match_start) {
+        ReplacementStringBuilder::AddSubjectSlice(builder,
+                                                  match_end,
+                                                  match_start);
+      }
+      match_end = register_vector[1];
+      HandleScope loop_scope;
+      builder->Add(*Factory::NewSubString(subject, match_start, match_end));
+      if (match_start != match_end) {
+        pos = match_end;
+      } else {
+        pos = match_end + 1;
+        if (pos > subject_length) break;
+      }
+    } else if (result == RegExpImpl::RE_FAILURE) {
+      break;
+    } else {
+      ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
+      return result;
+    }
+  }
+
+  if (match_start >= 0) {
+    if (match_end < subject_length) {
+      ReplacementStringBuilder::AddSubjectSlice(builder,
+                                                match_end,
+                                                subject_length);
+    }
+    SetLastMatchInfoNoCaptures(subject,
+                               last_match_array,
+                               match_start,
+                               match_end);
+    return RegExpImpl::RE_SUCCESS;
+  } else {
+    return RegExpImpl::RE_FAILURE;  // No matches at all.
+  }
+}
+
+
+static RegExpImpl::IrregexpResult SearchRegExpMultiple(
+    Handle<String> subject,
+    Handle<JSRegExp> regexp,
+    Handle<JSArray> last_match_array,
+    FixedArrayBuilder* builder) {
+
+  ASSERT(subject->IsFlat());
+  int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
+  if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
+
+  OffsetsVector registers(required_registers);
+  Vector<int> register_vector(registers.vector(), registers.length());
+
+  RegExpImpl::IrregexpResult result =
+      RegExpImpl::IrregexpExecOnce(regexp,
+                                   subject,
+                                   0,
+                                   register_vector);
+
+  int capture_count = regexp->CaptureCount();
+  int subject_length = subject->length();
+
+  // Position to search from.
+  int pos = 0;
+  // End of previous match. Differs from pos if match was empty.
+  int match_end = 0;
+  if (result == RegExpImpl::RE_SUCCESS) {
+    // Need to keep a copy of the previous match for creating last_match_info
+    // at the end, so we have two vectors that we swap between.
+    OffsetsVector registers2(required_registers);
+    Vector<int> prev_register_vector(registers2.vector(), registers2.length());
+
+    do {
+      int match_start = register_vector[0];
+      builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
+      if (match_end < match_start) {
+        ReplacementStringBuilder::AddSubjectSlice(builder,
+                                                  match_end,
+                                                  match_start);
+      }
+      match_end = register_vector[1];
+
+      {
+        // Avoid accumulating new handles inside loop.
+        HandleScope temp_scope;
+        // Arguments array to replace function is match, captures, index and
+        // subject, i.e., 3 + capture count in total.
+        Handle<FixedArray> elements = Factory::NewFixedArray(3 + capture_count);
+        elements->set(0, *Factory::NewSubString(subject,
+                                                match_start,
+                                                match_end));
+        for (int i = 1; i <= capture_count; i++) {
+          Handle<String> substring =
+              Factory::NewSubString(subject,
+                                    register_vector[i * 2],
+                                    register_vector[i * 2 + 1]);
+          elements->set(i, *substring);
+        }
+        elements->set(capture_count + 1, Smi::FromInt(match_start));
+        elements->set(capture_count + 2, *subject);
+        builder->Add(*Factory::NewJSArrayWithElements(elements));
+      }
+      // Swap register vectors, so the last successful match is in
+      // prev_register_vector.
+      Vector<int> tmp = prev_register_vector;
+      prev_register_vector = register_vector;
+      register_vector = tmp;
+
+      if (match_end > match_start) {
+        pos = match_end;
+      } else {
+        pos = match_end + 1;
+        if (pos > subject_length) {
+          break;
+        }
+      }
+
+      result = RegExpImpl::IrregexpExecOnce(regexp,
+                                            subject,
+                                            pos,
+                                            register_vector);
+    } while (result == RegExpImpl::RE_SUCCESS);
+
+    if (result != RegExpImpl::RE_EXCEPTION) {
+      // Finished matching, with at least one match.
+      if (match_end < subject_length) {
+        ReplacementStringBuilder::AddSubjectSlice(builder,
+                                                  match_end,
+                                                  subject_length);
+      }
+
+      int last_match_capture_count = (capture_count + 1) * 2;
+      int last_match_array_size =
+          last_match_capture_count + RegExpImpl::kLastMatchOverhead;
+      last_match_array->EnsureSize(last_match_array_size);
+      AssertNoAllocation no_gc;
+      FixedArray* elements = FixedArray::cast(last_match_array->elements());
+      RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
+      RegExpImpl::SetLastSubject(elements, *subject);
+      RegExpImpl::SetLastInput(elements, *subject);
+      for (int i = 0; i < last_match_capture_count; i++) {
+        RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
+      }
+      return RegExpImpl::RE_SUCCESS;
+    }
+  }
+  // No matches at all, return failure or exception result directly.
+  return result;
+}
+
+
+static Object* Runtime_RegExpExecMultiple(Arguments args) {
+  ASSERT(args.length() == 4);
+  HandleScope handles;
+
+  CONVERT_ARG_CHECKED(String, subject, 1);
+  if (!subject->IsFlat()) { FlattenString(subject); }
+  CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
+  CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
+  CONVERT_ARG_CHECKED(JSArray, result_array, 3);
+
+  ASSERT(last_match_info->HasFastElements());
+  ASSERT(regexp->GetFlags().is_global());
+  Handle<FixedArray> result_elements;
+  if (result_array->HasFastElements()) {
+    result_elements =
+        Handle<FixedArray>(FixedArray::cast(result_array->elements()));
+  } else {
+    result_elements = Factory::NewFixedArrayWithHoles(16);
+  }
+  FixedArrayBuilder builder(result_elements);
+
+  if (regexp->TypeTag() == JSRegExp::ATOM) {
+    Handle<String> pattern(
+        String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
+    int pattern_length = pattern->length();
+    if (pattern_length == 1) {
+      if (SearchCharMultiple(subject, pattern, last_match_info, &builder)) {
+        return *builder.ToJSArray(result_array);
+      }
+      return Heap::null_value();
+    }
+
+    if (!pattern->IsFlat()) FlattenString(pattern);
+    if (SearchStringMultiple(subject, pattern, last_match_info, &builder)) {
+      return *builder.ToJSArray(result_array);
+    }
+    return Heap::null_value();
+  }
+
+  ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
+
+  RegExpImpl::IrregexpResult result;
+  if (regexp->CaptureCount() == 0) {
+    result = SearchRegExpNoCaptureMultiple(subject,
+                                           regexp,
+                                           last_match_info,
+                                           &builder);
+  } else {
+    result = SearchRegExpMultiple(subject, regexp, last_match_info, &builder);
+  }
+  if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
+  if (result == RegExpImpl::RE_FAILURE) return Heap::null_value();
+  ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
+  return Failure::Exception();
+}
+
+
 static Object* Runtime_NumberToRadixString(Arguments args) {
   NoHandleAllocation ha;
   ASSERT(args.length() == 2);
diff --git a/src/runtime.h b/src/runtime.h
index 4175902..42af3df 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -153,6 +153,7 @@
   /* Regular expressions */ \
   F(RegExpCompile, 3, 1) \
   F(RegExpExec, 4, 1) \
+  F(RegExpExecMultiple, 4, 1) \
   \
   /* Strings */ \
   F(StringCharCodeAt, 2, 1) \
diff --git a/src/spaces.cc b/src/spaces.cc
index 08399ee..5f191ed 100644
--- a/src/spaces.cc
+++ b/src/spaces.cc
@@ -2749,6 +2749,9 @@
 
 bool LargeObjectSpace::Contains(HeapObject* object) {
   Address address = object->address();
+  if (Heap::new_space()->Contains(address)) {
+    return false;
+  }
   Page* page = Page::FromAddress(address);
 
   SLOW_ASSERT(!page->IsLargeObjectPage()
diff --git a/src/string.js b/src/string.js
index e663ec3..f4489ef 100644
--- a/src/string.js
+++ b/src/string.js
@@ -405,97 +405,91 @@
   builder.addSpecialSlice(start, end);
 };
 
+// TODO(lrn): This array will survive indefinitely if replace is never
+// called again. However, it will be empty, since the contents are cleared 
+// in the finally block.
+var reusableReplaceArray = $Array(16);
 
 // Helper function for replacing regular expressions with the result of a
-// function application in String.prototype.replace.  The function application
-// must be interleaved with the regexp matching (contrary to ECMA-262
-// 15.5.4.11) to mimic SpiderMonkey and KJS behavior when the function uses
-// the static properties of the RegExp constructor.  Example:
-//     'abcd'.replace(/(.)/g, function() { return RegExp.$1; }
-// should be 'abcd' and not 'dddd' (or anything else).
+// function application in String.prototype.replace.
 function StringReplaceRegExpWithFunction(subject, regexp, replace) {
-  var matchInfo = DoRegExpExec(regexp, subject, 0);
-  if (IS_NULL(matchInfo)) return subject;
-
-  var result = new ReplaceResultBuilder(subject);
-  // There's at least one match.  If the regexp is global, we have to loop
-  // over all matches.  The loop is not in C++ code here like the one in
-  // RegExp.prototype.exec, because of the interleaved function application.
-  // Unfortunately, that means this code is nearly duplicated, here and in
-  // jsregexp.cc.
   if (regexp.global) {
-    var previous = 0;
-    var startOfMatch;
-    if (NUMBER_OF_CAPTURES(matchInfo) == 2) {
-      // Both branches contain essentially the same loop except for the call
-      // to the replace function. The branch is put outside of the loop for
-      // speed
-      do {
-        startOfMatch = matchInfo[CAPTURE0];
-        result.addSpecialSlice(previous, startOfMatch);
-        previous = matchInfo[CAPTURE1];
-        var match = SubString(subject, startOfMatch, previous);
-        // Don't call directly to avoid exposing the built-in global object.
-        result.add(replace.call(null, match, startOfMatch, subject));
-        // Can't use matchInfo any more from here, since the function could
-        // overwrite it.
-        // Continue with the next match.
-        // Increment previous if we matched an empty string, as per ECMA-262
-        // 15.5.4.10.
-        if (previous == startOfMatch) {
-          // Add the skipped character to the output, if any.
-          if (previous < subject.length) {
-            result.addSpecialSlice(previous, previous + 1);
-          }
-          previous++;
-          // Per ECMA-262 15.10.6.2, if the previous index is greater than the
-          // string length, there is no match
-          if (previous > subject.length) {
-            return result.generate();
-          }
-        }
-        matchInfo = DoRegExpExec(regexp, subject, previous);
-      } while (!IS_NULL(matchInfo));
+    var resultArray = reusableReplaceArray;
+    if (resultArray) {
+      reusableReplaceArray = null;
     } else {
-      do {
-        startOfMatch = matchInfo[CAPTURE0];
-        result.addSpecialSlice(previous, startOfMatch);
-        previous = matchInfo[CAPTURE1];
-        result.add(ApplyReplacementFunction(replace, matchInfo, subject));
-        // Can't use matchInfo any more from here, since the function could
-        // overwrite it.
-        // Continue with the next match.
-        // Increment previous if we matched an empty string, as per ECMA-262
-        // 15.5.4.10.
-        if (previous == startOfMatch) {
-          // Add the skipped character to the output, if any.
-          if (previous < subject.length) {
-            result.addSpecialSlice(previous, previous + 1);
-          }
-          previous++;
-          // Per ECMA-262 15.10.6.2, if the previous index is greater than the
-          // string length, there is no match
-          if (previous > subject.length) {
-            return result.generate();
-          }
-        }
-        matchInfo = DoRegExpExec(regexp, subject, previous);
-      } while (!IS_NULL(matchInfo));
+      // Inside a nested replace (replace called from the replacement function
+      // of another replace) or we have failed to set the reusable array
+      // back due to an exception in a replacement function. Create a new
+      // array to use in the future, or until the original is written back.
+      resultArray = $Array(16);
     }
-
-    // Tack on the final right substring after the last match.
-    result.addSpecialSlice(previous, subject.length);
-
+    try {
+      // Must handle exceptions thrown by the replace functions correctly,
+      // including unregistering global regexps.
+      var res = %RegExpExecMultiple(regexp, 
+                                    subject, 
+                                    lastMatchInfo, 
+                                    resultArray);
+      regexp.lastIndex = 0;
+      if (IS_NULL(res)) {
+        // No matches at all. 
+        return subject;  
+      }  
+      var len = res.length; 
+      var i = 0;
+      if (NUMBER_OF_CAPTURES(lastMatchInfo) == 2) {
+        var match_start = 0;
+        while (i < len) {
+          var elem = res[i];
+          if (%_IsSmi(elem)) {
+            if (elem > 0) {
+              match_start = (elem >> 11) + (elem & 0x7ff);
+            } else {
+              match_start = res[++i] - elem;
+            }
+          } else {
+            var func_result = replace.call(null, elem, match_start, subject);
+            if (!IS_STRING(func_result)) func_result = TO_STRING(func_result);
+            res[i] = func_result;
+            match_start += elem.length; 
+          }
+          i++;
+        }      
+      } else {      
+        while (i < len) {
+          var elem = res[i];
+          if (!%_IsSmi(elem)) {
+            // elem must be an Array.
+            // Use the apply argument as backing for global RegExp properties.
+            lastMatchInfoOverride = elem;
+            var func_result = replace.apply(null, elem);
+            if (!IS_STRING(func_result)) func_result = TO_STRING(func_result);
+            res[i] = func_result;
+          }
+          i++;
+        }
+      }
+      var result = new ReplaceResultBuilder(subject, res);
+      return result.generate();
+    } finally {
+      lastMatchInfoOverride = null;
+      resultArray.length = 0;
+      reusableReplaceArray = resultArray;
+    }
   } else { // Not a global regexp, no need to loop.
+    var matchInfo = DoRegExpExec(regexp, subject, 0);
+    if (IS_NULL(matchInfo)) return subject;
+    
+    var result = new ReplaceResultBuilder(subject);
     result.addSpecialSlice(0, matchInfo[CAPTURE0]);
     var endOfMatch = matchInfo[CAPTURE1];
     result.add(ApplyReplacementFunction(replace, matchInfo, subject));
     // Can't use matchInfo any more from here, since the function could
     // overwrite it.
     result.addSpecialSlice(endOfMatch, subject.length);
+    return result.generate();
   }
-
-  return result.generate();
 }
 
 
@@ -522,17 +516,15 @@
 
 
 // ECMA-262 section 15.5.4.12
-function StringSearch(re) {
+function StringSearch(re) { 
   var regexp = new $RegExp(re);
   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);
-  regexp.lastIndex = last_idx;     // restore lastIndex
-  if (result == null)
-    return -1;
-  else
-    return result.index;
+  var match = DoRegExpExec(regexp, s, 0);
+  if (match) {
+    lastMatchInfo = match;
+    return match[CAPTURE0];
+  }
+  return -1;
 }
 
 
@@ -896,8 +888,11 @@
 
 // ReplaceResultBuilder support.
 function ReplaceResultBuilder(str) {
-  this.__proto__ = void 0;
-  this.elements = new $Array();
+  if (%_ArgumentsLength() > 1) {
+    this.elements = %_Arguments(1);
+  } else {
+    this.elements = new $Array();
+  }
   this.special_string = str;
 }
 
diff --git a/src/type-info-inl.h b/src/type-info-inl.h
new file mode 100644
index 0000000..90d3f55
--- /dev/null
+++ b/src/type-info-inl.h
@@ -0,0 +1,55 @@
+// 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_TYPE_INFO_INL_H_
+#define V8_TYPE_INFO_INL_H_
+
+#include "type-info.h"
+#include "objects-inl.h"
+
+namespace v8 {
+namespace internal {
+
+
+TypeInfo TypeInfo::TypeFromValue(Handle<Object> value) {
+  TypeInfo info;
+  if (value->IsSmi()) {
+    info = TypeInfo::Smi();
+  } else if (value->IsHeapNumber()) {
+    info = TypeInfo::IsInt32Double(HeapNumber::cast(*value)->value())
+        ? TypeInfo::Integer32()
+        : TypeInfo::Double();
+  } else {
+    info = TypeInfo::Unknown();
+  }
+  return info;
+}
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_TYPE_INFO_INL_H_
diff --git a/src/type-info.h b/src/type-info.h
new file mode 100644
index 0000000..15bc128
--- /dev/null
+++ b/src/type-info.h
@@ -0,0 +1,239 @@
+// 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_TYPE_INFO_H_
+#define V8_TYPE_INFO_H_
+
+#include "globals.h"
+
+namespace v8 {
+namespace internal {
+
+//        Unknown
+//           |
+//      PrimitiveType
+//           |   \--------|
+//         Number      String
+//         /    |         |
+//    Double  Integer32   |
+//        |      |       /
+//        |     Smi     /
+//        |     /      /
+//        Uninitialized.
+
+class TypeInfo {
+ public:
+  TypeInfo() { }
+
+  static inline TypeInfo Unknown();
+  // We know it's a primitive type.
+  static inline TypeInfo Primitive();
+  // We know it's a number of some sort.
+  static inline TypeInfo Number();
+  // We know it's signed or unsigned 32 bit integer.
+  static inline TypeInfo Integer32();
+  // We know it's a Smi.
+  static inline TypeInfo Smi();
+  // We know it's a heap number.
+  static inline TypeInfo Double();
+  // We know it's a string.
+  static inline TypeInfo String();
+  // We haven't started collecting info yet.
+  static inline TypeInfo Uninitialized();
+
+  // Return compact representation.  Very sensitive to enum values below!
+  // Compacting drops information about primtive types and strings types.
+  // We use the compact representation when we only care about number types.
+  int ThreeBitRepresentation() {
+    ASSERT(type_ != kUninitializedType);
+    int answer = type_ & 0xf;
+    answer = answer > 6 ? answer - 2 : answer;
+    ASSERT(answer >= 0);
+    ASSERT(answer <= 7);
+    return answer;
+  }
+
+  // Decode compact representation.  Very sensitive to enum values below!
+  static TypeInfo ExpandedRepresentation(int three_bit_representation) {
+    Type t = static_cast<Type>(three_bit_representation >= 6 ?
+                               three_bit_representation + 2 :
+                               three_bit_representation);
+    t = (t == kUnknownType) ? t : static_cast<Type>(t | kPrimitiveType);
+    ASSERT(t == kUnknownType ||
+           t == kNumberType ||
+           t == kInteger32Type ||
+           t == kSmiType ||
+           t == kDoubleType);
+    return TypeInfo(t);
+  }
+
+  int ToInt() {
+    return type_;
+  }
+
+  static TypeInfo FromInt(int bit_representation) {
+    Type t = static_cast<Type>(bit_representation);
+    ASSERT(t == kUnknownType ||
+           t == kPrimitiveType ||
+           t == kNumberType ||
+           t == kInteger32Type ||
+           t == kSmiType ||
+           t == kDoubleType ||
+           t == kStringType);
+    return TypeInfo(t);
+  }
+
+  // Return the weakest (least precise) common type.
+  static TypeInfo Combine(TypeInfo a, TypeInfo b) {
+    return TypeInfo(static_cast<Type>(a.type_ & b.type_));
+  }
+
+
+  // Integer32 is an integer that can be represented as either a signed
+  // 32-bit integer or as an unsigned 32-bit integer. It has to be
+  // in the range [-2^31, 2^32 - 1]. We also have to check for negative 0
+  // as it is not an Integer32.
+  static inline bool IsInt32Double(double value) {
+    const DoubleRepresentation minus_zero(-0.0);
+    DoubleRepresentation rep(value);
+    if (rep.bits == minus_zero.bits) return false;
+    if (value >= kMinInt && value <= kMaxUInt32) {
+      if (value <= kMaxInt && value == static_cast<int32_t>(value)) {
+        return true;
+      }
+      if (value == static_cast<uint32_t>(value)) return true;
+    }
+    return false;
+  }
+
+  static inline TypeInfo TypeFromValue(Handle<Object> value);
+
+  inline bool IsUnknown() {
+    return type_ == kUnknownType;
+  }
+
+  inline bool IsNumber() {
+    ASSERT(type_ != kUninitializedType);
+    return ((type_ & kNumberType) == kNumberType);
+  }
+
+  inline bool IsSmi() {
+    ASSERT(type_ != kUninitializedType);
+    return ((type_ & kSmiType) == kSmiType);
+  }
+
+  inline bool IsInteger32() {
+    ASSERT(type_ != kUninitializedType);
+    return ((type_ & kInteger32Type) == kInteger32Type);
+  }
+
+  inline bool IsDouble() {
+    ASSERT(type_ != kUninitializedType);
+    return ((type_ & kDoubleType) == kDoubleType);
+  }
+
+  inline bool IsUninitialized() {
+    return type_ == kUninitializedType;
+  }
+
+  const char* ToString() {
+    switch (type_) {
+      case kUnknownType: return "UnknownType";
+      case kPrimitiveType: return "PrimitiveType";
+      case kNumberType: return "NumberType";
+      case kInteger32Type: return "Integer32Type";
+      case kSmiType: return "SmiType";
+      case kDoubleType: return "DoubleType";
+      case kStringType: return "StringType";
+      case kUninitializedType:
+        UNREACHABLE();
+        return "UninitializedType";
+    }
+    UNREACHABLE();
+    return "Unreachable code";
+  }
+
+ private:
+  // We use 6 bits to represent the types.
+  enum Type {
+    kUnknownType = 0,          // 000000
+    kPrimitiveType = 0x10,     // 010000
+    kNumberType = 0x11,        // 010001
+    kInteger32Type = 0x13,     // 010011
+    kSmiType = 0x17,           // 010111
+    kDoubleType = 0x19,        // 011001
+    kStringType = 0x30,        // 110000
+    kUninitializedType = 0x3f  // 111111
+  };
+  explicit inline TypeInfo(Type t) : type_(t) { }
+
+  Type type_;
+};
+
+
+TypeInfo TypeInfo::Unknown() {
+  return TypeInfo(kUnknownType);
+}
+
+
+TypeInfo TypeInfo::Primitive() {
+  return TypeInfo(kPrimitiveType);
+}
+
+
+TypeInfo TypeInfo::Number() {
+  return TypeInfo(kNumberType);
+}
+
+
+TypeInfo TypeInfo::Integer32() {
+  return TypeInfo(kInteger32Type);
+}
+
+
+TypeInfo TypeInfo::Smi() {
+  return TypeInfo(kSmiType);
+}
+
+
+TypeInfo TypeInfo::Double() {
+  return TypeInfo(kDoubleType);
+}
+
+
+TypeInfo TypeInfo::String() {
+  return TypeInfo(kStringType);
+}
+
+
+TypeInfo TypeInfo::Uninitialized() {
+  return TypeInfo(kUninitializedType);
+}
+
+} }  // namespace v8::internal
+
+#endif  // V8_TYPE_INFO_H_
diff --git a/src/v8.cc b/src/v8.cc
index 395401d..5af2003 100644
--- a/src/v8.cc
+++ b/src/v8.cc
@@ -155,6 +155,14 @@
 }
 
 
+static uint32_t random_seed() {
+  if (FLAG_random_seed == 0) {
+    return random();
+  }
+  return FLAG_random_seed;
+}
+
+
 uint32_t V8::Random() {
   // Random number generator using George Marsaglia's MWC algorithm.
   static uint32_t hi = 0;
@@ -164,8 +172,8 @@
   // should ever become zero again, or if random() returns zero, we
   // avoid getting stuck with zero bits in hi or lo by re-initializing
   // them on demand.
-  if (hi == 0) hi = random();
-  if (lo == 0) lo = random();
+  if (hi == 0) hi = random_seed();
+  if (lo == 0) lo = random_seed();
 
   // Mix the bits.
   hi = 36969 * (hi & 0xFFFF) + (hi >> 16);
diff --git a/src/v8natives.js b/src/v8natives.js
index 6a32d7b..4a8dfab 100644
--- a/src/v8natives.js
+++ b/src/v8natives.js
@@ -221,7 +221,7 @@
 
 // ECMA-262 - 15.2.4.6
 function ObjectIsPrototypeOf(V) {
-  if (!IS_OBJECT(V) && !IS_FUNCTION(V)) return false;
+  if (!IS_OBJECT(V) && !IS_FUNCTION(V) && !IS_UNDETECTABLE(V)) return false;
   return %IsInPrototypeChain(this, V);
 }
 
@@ -236,7 +236,7 @@
 
 // Extensions for providing property getters and setters.
 function ObjectDefineGetter(name, fun) {
-  if (this == null) {
+  if (this == null && !IS_UNDETECTABLE(this)) {
     throw new $TypeError('Object.prototype.__defineGetter__: this is Null');
   }
   if (!IS_FUNCTION(fun)) {
@@ -247,7 +247,7 @@
 
 
 function ObjectLookupGetter(name) {
-  if (this == null) {
+  if (this == null && !IS_UNDETECTABLE(this)) {
     throw new $TypeError('Object.prototype.__lookupGetter__: this is Null');
   }
   return %LookupAccessor(ToObject(this), ToString(name), GETTER);
@@ -255,7 +255,7 @@
 
 
 function ObjectDefineSetter(name, fun) {
-  if (this == null) {
+  if (this == null && !IS_UNDETECTABLE(this)) {
     throw new $TypeError('Object.prototype.__defineSetter__: this is Null');
   }
   if (!IS_FUNCTION(fun)) {
@@ -267,7 +267,7 @@
 
 
 function ObjectLookupSetter(name) {
-  if (this == null) {
+  if (this == null && !IS_UNDETECTABLE(this)) {
     throw new $TypeError('Object.prototype.__lookupSetter__: this is Null');
   }
   return %LookupAccessor(ToObject(this), ToString(name), SETTER);
@@ -275,7 +275,8 @@
 
 
 function ObjectKeys(obj) {
-  if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj))
+  if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj) &&
+      !IS_UNDETECTABLE(obj))
     throw MakeTypeError("obj_ctor_property_non_object", ["keys"]);
   return %LocalKeys(obj);
 }
@@ -594,7 +595,8 @@
 
 // ES5 section 15.2.3.2.
 function ObjectGetPrototypeOf(obj) {
-  if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj))
+  if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj) &&
+      !IS_UNDETECTABLE(obj))
     throw MakeTypeError("obj_ctor_property_non_object", ["getPrototypeOf"]);
   return obj.__proto__;
 }
@@ -602,7 +604,8 @@
 
 // ES5 section 15.2.3.3 
 function ObjectGetOwnPropertyDescriptor(obj, p) {
-  if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj))
+  if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj) &&
+      !IS_UNDETECTABLE(obj))
     throw MakeTypeError("obj_ctor_property_non_object", ["getOwnPropertyDescriptor"]);
   var desc = GetOwnProperty(obj, p);
   return FromPropertyDescriptor(desc);
@@ -611,7 +614,8 @@
 
 // ES5 section 15.2.3.4.
 function ObjectGetOwnPropertyNames(obj) {
-  if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj))
+  if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj) &&
+      !IS_UNDETECTABLE(obj))
     throw MakeTypeError("obj_ctor_property_non_object", ["getOwnPropertyNames"]);
 
   // Find all the indexed properties.
@@ -664,7 +668,8 @@
 
 // ES5 section 15.2.3.6.
 function ObjectDefineProperty(obj, p, attributes) {
-  if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj))
+  if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj) &&
+      !IS_UNDETECTABLE(obj))
     throw MakeTypeError("obj_ctor_property_non_object", ["defineProperty"]);
   var name = ToString(p);
   var desc = ToPropertyDescriptor(attributes);
@@ -675,7 +680,8 @@
 
 // ES5 section 15.2.3.7.
 function ObjectDefineProperties(obj, properties) {
- if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj))
+ if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj) &&
+     !IS_UNDETECTABLE(obj))
     throw MakeTypeError("obj_ctor_property_non_object", ["defineProperties"]);
   var props = ToObject(properties);
   var key_values = [];
diff --git a/src/version.cc b/src/version.cc
index a40b3b8..7217c7b 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      8
-#define PATCH_LEVEL       3
+#define BUILD_NUMBER      9
+#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/virtual-frame-heavy-inl.h b/src/virtual-frame-heavy-inl.h
new file mode 100644
index 0000000..a4a0a9b
--- /dev/null
+++ b/src/virtual-frame-heavy-inl.h
@@ -0,0 +1,136 @@
+// 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_VIRTUAL_FRAME_HEAVY_INL_H_
+#define V8_VIRTUAL_FRAME_HEAVY_INL_H_
+
+#include "type-info.h"
+#include "register-allocator.h"
+#include "scopes.h"
+
+namespace v8 {
+namespace internal {
+
+// On entry to a function, the virtual frame already contains the receiver,
+// the parameters, and a return address.  All frame elements are in memory.
+VirtualFrame::VirtualFrame()
+    : elements_(parameter_count() + local_count() + kPreallocatedElements),
+      stack_pointer_(parameter_count() + 1) {  // 0-based index of TOS.
+  for (int i = 0; i <= stack_pointer_; i++) {
+    elements_.Add(FrameElement::MemoryElement(TypeInfo::Unknown()));
+  }
+  for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
+    register_locations_[i] = kIllegalIndex;
+  }
+}
+
+
+// When cloned, a frame is a deep copy of the original.
+VirtualFrame::VirtualFrame(VirtualFrame* original)
+    : elements_(original->element_count()),
+      stack_pointer_(original->stack_pointer_) {
+  elements_.AddAll(original->elements_);
+  // Copy register locations from original.
+  memcpy(&register_locations_,
+         original->register_locations_,
+         sizeof(register_locations_));
+}
+
+
+void VirtualFrame::PushFrameSlotAt(int index) {
+  elements_.Add(CopyElementAt(index));
+}
+
+
+void VirtualFrame::Push(Register reg, TypeInfo info) {
+  if (is_used(reg)) {
+    int index = register_location(reg);
+    FrameElement element = CopyElementAt(index, info);
+    elements_.Add(element);
+  } else {
+    Use(reg, element_count());
+    FrameElement element =
+        FrameElement::RegisterElement(reg, FrameElement::NOT_SYNCED, info);
+    elements_.Add(element);
+  }
+}
+
+
+void VirtualFrame::Push(Handle<Object> value) {
+  FrameElement element =
+      FrameElement::ConstantElement(value, FrameElement::NOT_SYNCED);
+  elements_.Add(element);
+}
+
+
+bool VirtualFrame::Equals(VirtualFrame* other) {
+#ifdef DEBUG
+  for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
+    if (register_location(i) != other->register_location(i)) {
+      return false;
+    }
+  }
+  if (element_count() != other->element_count()) return false;
+#endif
+  if (stack_pointer_ != other->stack_pointer_) return false;
+  for (int i = 0; i < element_count(); i++) {
+    if (!elements_[i].Equals(other->elements_[i])) return false;
+  }
+
+  return true;
+}
+
+
+void VirtualFrame::SetTypeForLocalAt(int index, TypeInfo info) {
+  elements_[local0_index() + index].set_type_info(info);
+}
+
+
+// Make the type of all elements be MEMORY.
+void VirtualFrame::SpillAll() {
+  for (int i = 0; i < element_count(); i++) {
+    SpillElementAt(i);
+  }
+}
+
+
+void VirtualFrame::PrepareForReturn() {
+  // Spill all locals. This is necessary to make sure all locals have
+  // the right value when breaking at the return site in the debugger.
+  for (int i = 0; i < expression_base_index(); i++) {
+    SpillElementAt(i);
+  }
+}
+
+
+void VirtualFrame::SetTypeForParamAt(int index, TypeInfo info) {
+  elements_[param0_index() + index].set_type_info(info);
+}
+
+} }  // namespace v8::internal
+
+#endif  // V8_VIRTUAL_FRAME_HEAVY_INL_H_
diff --git a/src/virtual-frame-heavy.cc b/src/virtual-frame-heavy.cc
new file mode 100644
index 0000000..854ed75
--- /dev/null
+++ b/src/virtual-frame-heavy.cc
@@ -0,0 +1,298 @@
+// 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.
+
+#include "v8.h"
+
+#include "codegen-inl.h"
+#include "register-allocator-inl.h"
+#include "virtual-frame-inl.h"
+
+namespace v8 {
+namespace internal {
+
+void VirtualFrame::SetElementAt(int index, Result* value) {
+  int frame_index = element_count() - index - 1;
+  ASSERT(frame_index >= 0);
+  ASSERT(frame_index < element_count());
+  ASSERT(value->is_valid());
+  FrameElement original = elements_[frame_index];
+
+  // Early exit if the element is the same as the one being set.
+  bool same_register = original.is_register()
+      && value->is_register()
+      && original.reg().is(value->reg());
+  bool same_constant = original.is_constant()
+      && value->is_constant()
+      && original.handle().is_identical_to(value->handle());
+  if (same_register || same_constant) {
+    value->Unuse();
+    return;
+  }
+
+  InvalidateFrameSlotAt(frame_index);
+
+  if (value->is_register()) {
+    if (is_used(value->reg())) {
+      // The register already appears on the frame.  Either the existing
+      // register element, or the new element at frame_index, must be made
+      // a copy.
+      int i = register_location(value->reg());
+
+      if (i < frame_index) {
+        // The register FrameElement is lower in the frame than the new copy.
+        elements_[frame_index] = CopyElementAt(i);
+      } else {
+        // There was an early bailout for the case of setting a
+        // register element to itself.
+        ASSERT(i != frame_index);
+        elements_[frame_index] = elements_[i];
+        elements_[i] = CopyElementAt(frame_index);
+        if (elements_[frame_index].is_synced()) {
+          elements_[i].set_sync();
+        }
+        elements_[frame_index].clear_sync();
+        set_register_location(value->reg(), frame_index);
+        for (int j = i + 1; j < element_count(); j++) {
+          if (elements_[j].is_copy() && elements_[j].index() == i) {
+            elements_[j].set_index(frame_index);
+          }
+        }
+      }
+    } else {
+      // The register value->reg() was not already used on the frame.
+      Use(value->reg(), frame_index);
+      elements_[frame_index] =
+          FrameElement::RegisterElement(value->reg(),
+                                        FrameElement::NOT_SYNCED,
+                                        value->type_info());
+    }
+  } else {
+    ASSERT(value->is_constant());
+    elements_[frame_index] =
+        FrameElement::ConstantElement(value->handle(),
+                                      FrameElement::NOT_SYNCED);
+  }
+  value->Unuse();
+}
+
+
+// Create a duplicate of an existing valid frame element.
+// We can pass an optional number type information that will override the
+// existing information about the backing element. The new information must
+// not conflict with the existing type information and must be equally or
+// more precise. The default parameter value kUninitialized means that there
+// is no additional information.
+FrameElement VirtualFrame::CopyElementAt(int index, TypeInfo info) {
+  ASSERT(index >= 0);
+  ASSERT(index < element_count());
+
+  FrameElement target = elements_[index];
+  FrameElement result;
+
+  switch (target.type()) {
+    case FrameElement::CONSTANT:
+      // We do not copy constants and instead return a fresh unsynced
+      // constant.
+      result = FrameElement::ConstantElement(target.handle(),
+                                             FrameElement::NOT_SYNCED);
+      break;
+
+    case FrameElement::COPY:
+      // We do not allow copies of copies, so we follow one link to
+      // the actual backing store of a copy before making a copy.
+      index = target.index();
+      ASSERT(elements_[index].is_memory() || elements_[index].is_register());
+      // Fall through.
+
+    case FrameElement::MEMORY:  // Fall through.
+    case FrameElement::REGISTER: {
+      // All copies are backed by memory or register locations.
+      result.set_type(FrameElement::COPY);
+      result.clear_copied();
+      result.clear_sync();
+      result.set_index(index);
+      elements_[index].set_copied();
+      // Update backing element's number information.
+      TypeInfo existing = elements_[index].type_info();
+      ASSERT(!existing.IsUninitialized());
+      // Assert that the new type information (a) does not conflict with the
+      // existing one and (b) is equally or more precise.
+      ASSERT((info.ToInt() & existing.ToInt()) == existing.ToInt());
+      ASSERT((info.ToInt() | existing.ToInt()) == info.ToInt());
+
+      elements_[index].set_type_info(!info.IsUninitialized()
+                                       ? info
+                                       : existing);
+      break;
+    }
+    case FrameElement::INVALID:
+      // We should not try to copy invalid elements.
+      UNREACHABLE();
+      break;
+  }
+  return result;
+}
+
+
+// Modify the state of the virtual frame to match the actual frame by adding
+// extra in-memory elements to the top of the virtual frame.  The extra
+// elements will be externally materialized on the actual frame (eg, by
+// pushing an exception handler).  No code is emitted.
+void VirtualFrame::Adjust(int count) {
+  ASSERT(count >= 0);
+  ASSERT(stack_pointer_ == element_count() - 1);
+
+  for (int i = 0; i < count; i++) {
+    elements_.Add(FrameElement::MemoryElement(TypeInfo::Unknown()));
+  }
+  stack_pointer_ += count;
+}
+
+
+void VirtualFrame::ForgetElements(int count) {
+  ASSERT(count >= 0);
+  ASSERT(element_count() >= count);
+
+  for (int i = 0; i < count; i++) {
+    FrameElement last = elements_.RemoveLast();
+    if (last.is_register()) {
+      // A hack to properly count register references for the code
+      // generator's current frame and also for other frames.  The
+      // same code appears in PrepareMergeTo.
+      if (cgen()->frame() == this) {
+        Unuse(last.reg());
+      } else {
+        set_register_location(last.reg(), kIllegalIndex);
+      }
+    }
+  }
+}
+
+
+// Make the type of the element at a given index be MEMORY.
+void VirtualFrame::SpillElementAt(int index) {
+  if (!elements_[index].is_valid()) return;
+
+  SyncElementAt(index);
+  // Number type information is preserved.
+  // Copies get their number information from their backing element.
+  TypeInfo info;
+  if (!elements_[index].is_copy()) {
+    info = elements_[index].type_info();
+  } else {
+    info = elements_[elements_[index].index()].type_info();
+  }
+  // The element is now in memory.  Its copied flag is preserved.
+  FrameElement new_element = FrameElement::MemoryElement(info);
+  if (elements_[index].is_copied()) {
+    new_element.set_copied();
+  }
+  if (elements_[index].is_untagged_int32()) {
+    new_element.set_untagged_int32(true);
+  }
+  if (elements_[index].is_register()) {
+    Unuse(elements_[index].reg());
+  }
+  elements_[index] = new_element;
+}
+
+
+// Clear the dirty bit for the element at a given index.
+void VirtualFrame::SyncElementAt(int index) {
+  if (index <= stack_pointer_) {
+    if (!elements_[index].is_synced()) SyncElementBelowStackPointer(index);
+  } else if (index == stack_pointer_ + 1) {
+    SyncElementByPushing(index);
+  } else {
+    SyncRange(stack_pointer_ + 1, index);
+  }
+}
+
+
+void VirtualFrame::PrepareMergeTo(VirtualFrame* expected) {
+  // Perform state changes on this frame that will make merge to the
+  // expected frame simpler or else increase the likelihood that his
+  // frame will match another.
+  for (int i = 0; i < element_count(); i++) {
+    FrameElement source = elements_[i];
+    FrameElement target = expected->elements_[i];
+
+    if (!target.is_valid() ||
+        (target.is_memory() && !source.is_memory() && source.is_synced())) {
+      // No code needs to be generated to invalidate valid elements.
+      // No code needs to be generated to move values to memory if
+      // they are already synced.  We perform those moves here, before
+      // merging.
+      if (source.is_register()) {
+        // If the frame is the code generator's current frame, we have
+        // to decrement both the frame-internal and global register
+        // counts.
+        if (cgen()->frame() == this) {
+          Unuse(source.reg());
+        } else {
+          set_register_location(source.reg(), kIllegalIndex);
+        }
+      }
+      elements_[i] = target;
+    } else if (target.is_register() && !target.is_synced() &&
+               !source.is_memory()) {
+      // If an element's target is a register that doesn't need to be
+      // synced, and the element is not in memory, then the sync state
+      // of the element is irrelevant.  We clear the sync bit.
+      ASSERT(source.is_valid());
+      elements_[i].clear_sync();
+    }
+  }
+}
+
+
+void VirtualFrame::PrepareForCall(int spilled_args, int dropped_args) {
+  ASSERT(height() >= dropped_args);
+  ASSERT(height() >= spilled_args);
+  ASSERT(dropped_args <= spilled_args);
+
+  SyncRange(0, element_count() - 1);
+  // Spill registers.
+  for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
+    if (is_used(i)) {
+      SpillElementAt(register_location(i));
+    }
+  }
+
+  // Spill the arguments.
+  for (int i = element_count() - spilled_args; i < element_count(); i++) {
+    if (!elements_[i].is_memory()) {
+      SpillElementAt(i);
+    }
+  }
+
+  // Forget the frame elements that will be popped by the call.
+  Forget(dropped_args);
+}
+
+
+} }  // namespace v8::internal
diff --git a/src/virtual-frame-inl.h b/src/virtual-frame-inl.h
index 4050d71..e4c6e6e 100644
--- a/src/virtual-frame-inl.h
+++ b/src/virtual-frame-inl.h
@@ -30,62 +30,16 @@
 
 #include "virtual-frame.h"
 
+#if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X64
+#include "virtual-frame-heavy-inl.h"
+#else
+#include "virtual-frame-light-inl.h"
+#endif
+
+
 namespace v8 {
 namespace internal {
 
-
-// On entry to a function, the virtual frame already contains the receiver,
-// the parameters, and a return address.  All frame elements are in memory.
-VirtualFrame::VirtualFrame()
-    : elements_(parameter_count() + local_count() + kPreallocatedElements),
-      stack_pointer_(parameter_count() + 1) {  // 0-based index of TOS.
-  for (int i = 0; i <= stack_pointer_; i++) {
-    elements_.Add(FrameElement::MemoryElement(NumberInfo::Unknown()));
-  }
-  for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
-    register_locations_[i] = kIllegalIndex;
-  }
-}
-
-
-// When cloned, a frame is a deep copy of the original.
-VirtualFrame::VirtualFrame(VirtualFrame* original)
-    : elements_(original->element_count()),
-      stack_pointer_(original->stack_pointer_) {
-  elements_.AddAll(original->elements_);
-  // Copy register locations from original.
-  memcpy(&register_locations_,
-         original->register_locations_,
-         sizeof(register_locations_));
-}
-
-
-void VirtualFrame::PushFrameSlotAt(int index) {
-  elements_.Add(CopyElementAt(index));
-}
-
-
-void VirtualFrame::Push(Register reg, NumberInfo info) {
-  if (is_used(reg)) {
-    int index = register_location(reg);
-    FrameElement element = CopyElementAt(index, info);
-    elements_.Add(element);
-  } else {
-    Use(reg, element_count());
-    FrameElement element =
-        FrameElement::RegisterElement(reg, FrameElement::NOT_SYNCED, info);
-    elements_.Add(element);
-  }
-}
-
-
-void VirtualFrame::Push(Handle<Object> value) {
-  FrameElement element =
-      FrameElement::ConstantElement(value, FrameElement::NOT_SYNCED);
-  elements_.Add(element);
-}
-
-
 void VirtualFrame::Push(Smi* value) {
   Push(Handle<Object> (value));
 }
@@ -101,35 +55,6 @@
   SetElementAt(0, &tos);
 }
 
-
-bool VirtualFrame::Equals(VirtualFrame* other) {
-#ifdef DEBUG
-  for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
-    if (register_location(i) != other->register_location(i)) {
-      return false;
-    }
-  }
-  if (element_count() != other->element_count()) return false;
-#endif
-  if (stack_pointer_ != other->stack_pointer_) return false;
-  for (int i = 0; i < element_count(); i++) {
-    if (!elements_[i].Equals(other->elements_[i])) return false;
-  }
-
-  return true;
-}
-
-
-void VirtualFrame::SetTypeForLocalAt(int index, NumberInfo info) {
-  elements_[local0_index() + index].set_number_info(info);
-}
-
-
-void VirtualFrame::SetTypeForParamAt(int index, NumberInfo info) {
-  elements_[param0_index() + index].set_number_info(info);
-}
-
-
 } }  // namespace v8::internal
 
 #endif  // V8_VIRTUAL_FRAME_INL_H_
diff --git a/src/virtual-frame-light-inl.h b/src/virtual-frame-light-inl.h
new file mode 100644
index 0000000..5c823ae
--- /dev/null
+++ b/src/virtual-frame-light-inl.h
@@ -0,0 +1,95 @@
+// 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_VIRTUAL_FRAME_LIGHT_INL_H_
+#define V8_VIRTUAL_FRAME_LIGHT_INL_H_
+
+#include "type-info.h"
+#include "register-allocator.h"
+#include "scopes.h"
+
+namespace v8 {
+namespace internal {
+
+// On entry to a function, the virtual frame already contains the receiver,
+// the parameters, and a return address.  All frame elements are in memory.
+VirtualFrame::VirtualFrame()
+    : element_count_(parameter_count() + 2),
+      stack_pointer_(parameter_count() + 1) {
+  for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
+    register_locations_[i] = kIllegalIndex;
+  }
+}
+
+
+// When cloned, a frame is a deep copy of the original.
+VirtualFrame::VirtualFrame(VirtualFrame* original)
+    : element_count_(original->element_count()),
+      stack_pointer_(original->stack_pointer_) {
+  memcpy(&register_locations_,
+         original->register_locations_,
+         sizeof(register_locations_));
+}
+
+
+void VirtualFrame::Push(Handle<Object> value) {
+  UNIMPLEMENTED();
+}
+
+
+bool VirtualFrame::Equals(VirtualFrame* other) {
+#ifdef DEBUG
+  for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
+    if (register_location(i) != other->register_location(i)) {
+      return false;
+    }
+  }
+  if (element_count() != other->element_count()) return false;
+#endif
+  if (stack_pointer_ != other->stack_pointer_) return false;
+
+  return true;
+}
+
+
+void VirtualFrame::SetTypeForLocalAt(int index, TypeInfo info) {
+  UNIMPLEMENTED();
+}
+
+
+// Everything is always spilled anyway.
+void VirtualFrame::SpillAll() {
+}
+
+
+void VirtualFrame::PrepareForReturn() {
+}
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_VIRTUAL_FRAME_LIGHT_INL_H_
diff --git a/src/virtual-frame-light.cc b/src/virtual-frame-light.cc
new file mode 100644
index 0000000..4662cf0
--- /dev/null
+++ b/src/virtual-frame-light.cc
@@ -0,0 +1,52 @@
+// 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.
+
+#include "v8.h"
+
+#include "codegen-inl.h"
+#include "register-allocator-inl.h"
+#include "virtual-frame-inl.h"
+
+namespace v8 {
+namespace internal {
+
+void VirtualFrame::Adjust(int count) {
+  ASSERT(count >= 0);
+  ASSERT(stack_pointer_ == element_count() - 1);
+
+  element_count_ += count;
+  stack_pointer_ += count;
+}
+
+
+// Make the type of the element at a given index be MEMORY.
+void VirtualFrame::SpillElementAt(int index) {
+  UNIMPLEMENTED();
+}
+
+
+} }  // namespace v8::internal
diff --git a/src/virtual-frame.cc b/src/virtual-frame.cc
index 070424c..d618bc2 100644
--- a/src/virtual-frame.cc
+++ b/src/virtual-frame.cc
@@ -37,99 +37,6 @@
 // -------------------------------------------------------------------------
 // VirtualFrame implementation.
 
-// Create a duplicate of an existing valid frame element.
-// We can pass an optional number type information that will override the
-// existing information about the backing element. The new information must
-// not conflict with the existing type information and must be equally or
-// more precise. The default parameter value kUninitialized means that there
-// is no additional information.
-FrameElement VirtualFrame::CopyElementAt(int index, NumberInfo info) {
-  ASSERT(index >= 0);
-  ASSERT(index < element_count());
-
-  FrameElement target = elements_[index];
-  FrameElement result;
-
-  switch (target.type()) {
-    case FrameElement::CONSTANT:
-      // We do not copy constants and instead return a fresh unsynced
-      // constant.
-      result = FrameElement::ConstantElement(target.handle(),
-                                             FrameElement::NOT_SYNCED);
-      break;
-
-    case FrameElement::COPY:
-      // We do not allow copies of copies, so we follow one link to
-      // the actual backing store of a copy before making a copy.
-      index = target.index();
-      ASSERT(elements_[index].is_memory() || elements_[index].is_register());
-      // Fall through.
-
-    case FrameElement::MEMORY:  // Fall through.
-    case FrameElement::REGISTER: {
-      // All copies are backed by memory or register locations.
-      result.set_type(FrameElement::COPY);
-      result.clear_copied();
-      result.clear_sync();
-      result.set_index(index);
-      elements_[index].set_copied();
-      // Update backing element's number information.
-      NumberInfo existing = elements_[index].number_info();
-      ASSERT(!existing.IsUninitialized());
-      // Assert that the new type information (a) does not conflict with the
-      // existing one and (b) is equally or more precise.
-      ASSERT((info.ToInt() & existing.ToInt()) == existing.ToInt());
-      ASSERT((info.ToInt() | existing.ToInt()) == info.ToInt());
-
-      elements_[index].set_number_info(!info.IsUninitialized()
-                                       ? info
-                                       : existing);
-      break;
-    }
-    case FrameElement::INVALID:
-      // We should not try to copy invalid elements.
-      UNREACHABLE();
-      break;
-  }
-  return result;
-}
-
-
-// Modify the state of the virtual frame to match the actual frame by adding
-// extra in-memory elements to the top of the virtual frame.  The extra
-// elements will be externally materialized on the actual frame (eg, by
-// pushing an exception handler).  No code is emitted.
-void VirtualFrame::Adjust(int count) {
-  ASSERT(count >= 0);
-  ASSERT(stack_pointer_ == element_count() - 1);
-
-  for (int i = 0; i < count; i++) {
-    elements_.Add(FrameElement::MemoryElement(NumberInfo::Unknown()));
-  }
-  stack_pointer_ += count;
-}
-
-
-void VirtualFrame::ForgetElements(int count) {
-  ASSERT(count >= 0);
-  ASSERT(element_count() >= count);
-
-  for (int i = 0; i < count; i++) {
-    FrameElement last = elements_.RemoveLast();
-    if (last.is_register()) {
-      // A hack to properly count register references for the code
-      // generator's current frame and also for other frames.  The
-      // same code appears in PrepareMergeTo.
-      if (cgen()->frame() == this) {
-        Unuse(last.reg());
-      } else {
-        set_register_location(last.reg(), kIllegalIndex);
-      }
-    }
-  }
-}
-
-
 // If there are any registers referenced only by the frame, spill one.
 Register VirtualFrame::SpillAnyRegister() {
   // Find the leftmost (ordered by register number) register whose only
@@ -145,191 +52,6 @@
 }
 
 
-// Make the type of the element at a given index be MEMORY.
-void VirtualFrame::SpillElementAt(int index) {
-  if (!elements_[index].is_valid()) return;
-
-  SyncElementAt(index);
-  // Number type information is preserved.
-  // Copies get their number information from their backing element.
-  NumberInfo info;
-  if (!elements_[index].is_copy()) {
-    info = elements_[index].number_info();
-  } else {
-    info = elements_[elements_[index].index()].number_info();
-  }
-  // The element is now in memory.  Its copied flag is preserved.
-  FrameElement new_element = FrameElement::MemoryElement(info);
-  if (elements_[index].is_copied()) {
-    new_element.set_copied();
-  }
-  if (elements_[index].is_untagged_int32()) {
-    new_element.set_untagged_int32(true);
-  }
-  if (elements_[index].is_register()) {
-    Unuse(elements_[index].reg());
-  }
-  elements_[index] = new_element;
-}
-
-
-// Clear the dirty bit for the element at a given index.
-void VirtualFrame::SyncElementAt(int index) {
-  if (index <= stack_pointer_) {
-    if (!elements_[index].is_synced()) SyncElementBelowStackPointer(index);
-  } else if (index == stack_pointer_ + 1) {
-    SyncElementByPushing(index);
-  } else {
-    SyncRange(stack_pointer_ + 1, index);
-  }
-}
-
-
-// Make the type of all elements be MEMORY.
-void VirtualFrame::SpillAll() {
-  for (int i = 0; i < element_count(); i++) {
-    SpillElementAt(i);
-  }
-}
-
-
-void VirtualFrame::PrepareMergeTo(VirtualFrame* expected) {
-  // Perform state changes on this frame that will make merge to the
-  // expected frame simpler or else increase the likelihood that his
-  // frame will match another.
-  for (int i = 0; i < element_count(); i++) {
-    FrameElement source = elements_[i];
-    FrameElement target = expected->elements_[i];
-
-    if (!target.is_valid() ||
-        (target.is_memory() && !source.is_memory() && source.is_synced())) {
-      // No code needs to be generated to invalidate valid elements.
-      // No code needs to be generated to move values to memory if
-      // they are already synced.  We perform those moves here, before
-      // merging.
-      if (source.is_register()) {
-        // If the frame is the code generator's current frame, we have
-        // to decrement both the frame-internal and global register
-        // counts.
-        if (cgen()->frame() == this) {
-          Unuse(source.reg());
-        } else {
-          set_register_location(source.reg(), kIllegalIndex);
-        }
-      }
-      elements_[i] = target;
-    } else if (target.is_register() && !target.is_synced() &&
-               !source.is_memory()) {
-      // If an element's target is a register that doesn't need to be
-      // synced, and the element is not in memory, then the sync state
-      // of the element is irrelevant.  We clear the sync bit.
-      ASSERT(source.is_valid());
-      elements_[i].clear_sync();
-    }
-  }
-}
-
-
-void VirtualFrame::PrepareForCall(int spilled_args, int dropped_args) {
-  ASSERT(height() >= dropped_args);
-  ASSERT(height() >= spilled_args);
-  ASSERT(dropped_args <= spilled_args);
-
-  SyncRange(0, element_count() - 1);
-  // Spill registers.
-  for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
-    if (is_used(i)) {
-      SpillElementAt(register_location(i));
-    }
-  }
-
-  // Spill the arguments.
-  for (int i = element_count() - spilled_args; i < element_count(); i++) {
-    if (!elements_[i].is_memory()) {
-      SpillElementAt(i);
-    }
-  }
-
-  // Forget the frame elements that will be popped by the call.
-  Forget(dropped_args);
-}
-
-
-void VirtualFrame::PrepareForReturn() {
-  // Spill all locals. This is necessary to make sure all locals have
-  // the right value when breaking at the return site in the debugger.
-  for (int i = 0; i < expression_base_index(); i++) {
-    SpillElementAt(i);
-  }
-}
-
-
-void VirtualFrame::SetElementAt(int index, Result* value) {
-  int frame_index = element_count() - index - 1;
-  ASSERT(frame_index >= 0);
-  ASSERT(frame_index < element_count());
-  ASSERT(value->is_valid());
-  FrameElement original = elements_[frame_index];
-
-  // Early exit if the element is the same as the one being set.
-  bool same_register = original.is_register()
-      && value->is_register()
-      && original.reg().is(value->reg());
-  bool same_constant = original.is_constant()
-      && value->is_constant()
-      && original.handle().is_identical_to(value->handle());
-  if (same_register || same_constant) {
-    value->Unuse();
-    return;
-  }
-
-  InvalidateFrameSlotAt(frame_index);
-
-  if (value->is_register()) {
-    if (is_used(value->reg())) {
-      // The register already appears on the frame.  Either the existing
-      // register element, or the new element at frame_index, must be made
-      // a copy.
-      int i = register_location(value->reg());
-
-      if (i < frame_index) {
-        // The register FrameElement is lower in the frame than the new copy.
-        elements_[frame_index] = CopyElementAt(i);
-      } else {
-        // There was an early bailout for the case of setting a
-        // register element to itself.
-        ASSERT(i != frame_index);
-        elements_[frame_index] = elements_[i];
-        elements_[i] = CopyElementAt(frame_index);
-        if (elements_[frame_index].is_synced()) {
-          elements_[i].set_sync();
-        }
-        elements_[frame_index].clear_sync();
-        set_register_location(value->reg(), frame_index);
-        for (int j = i + 1; j < element_count(); j++) {
-          if (elements_[j].is_copy() && elements_[j].index() == i) {
-            elements_[j].set_index(frame_index);
-          }
-        }
-      }
-    } else {
-      // The register value->reg() was not already used on the frame.
-      Use(value->reg(), frame_index);
-      elements_[frame_index] =
-          FrameElement::RegisterElement(value->reg(),
-                                        FrameElement::NOT_SYNCED,
-                                        value->number_info());
-    }
-  } else {
-    ASSERT(value->is_constant());
-    elements_[frame_index] =
-        FrameElement::ConstantElement(value->handle(),
-                                      FrameElement::NOT_SYNCED);
-  }
-  value->Unuse();
-}
-
-
 // Specialization of List::ResizeAdd to non-inlined version for FrameElements.
 // The function ResizeAdd becomes a real function, whose implementation is the
 // inlined ResizeAddInternal.
diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc
index 2d875e1..108384c 100644
--- a/src/x64/codegen-x64.cc
+++ b/src/x64/codegen-x64.cc
@@ -4368,7 +4368,7 @@
 
   if (value.is_number()) {
     Comment cmnt(masm_, "ONLY_NUMBER");
-    // Fast case if NumberInfo indicates only numbers.
+    // Fast case if TypeInfo indicates only numbers.
     if (FLAG_debug_code) {
       __ AbortIfNotNumber(value.reg(), "ToBoolean operand is not a number.");
     }
@@ -5291,8 +5291,8 @@
   }
 
   // Get number type of left and right sub-expressions.
-  NumberInfo operands_type =
-      NumberInfo::Combine(left.number_info(), right.number_info());
+  TypeInfo operands_type =
+      TypeInfo::Combine(left.type_info(), right.type_info());
 
   Result answer;
   if (left_is_non_smi_constant || right_is_non_smi_constant) {
@@ -5324,13 +5324,13 @@
     }
   }
 
-  // Set NumberInfo of result according to the operation performed.
+  // Set TypeInfo of result according to the operation performed.
   // We rely on the fact that smis have a 32 bit payload on x64.
   ASSERT(kSmiValueSize == 32);
-  NumberInfo result_type = NumberInfo::Unknown();
+  TypeInfo result_type = TypeInfo::Unknown();
   switch (op) {
     case Token::COMMA:
-      result_type = right.number_info();
+      result_type = right.type_info();
       break;
     case Token::OR:
     case Token::AND:
@@ -5341,37 +5341,37 @@
     case Token::BIT_XOR:
     case Token::BIT_AND:
       // Result is always a smi.
-      result_type = NumberInfo::Smi();
+      result_type = TypeInfo::Smi();
       break;
     case Token::SAR:
     case Token::SHL:
       // Result is always a smi.
-      result_type = NumberInfo::Smi();
+      result_type = TypeInfo::Smi();
       break;
     case Token::SHR:
       // Result of x >>> y is always a smi if y >= 1, otherwise a number.
       result_type = (right.is_constant() && right.handle()->IsSmi()
                      && Smi::cast(*right.handle())->value() >= 1)
-          ? NumberInfo::Smi()
-          : NumberInfo::Number();
+          ? TypeInfo::Smi()
+          : TypeInfo::Number();
       break;
     case Token::ADD:
       // Result could be a string or a number. Check types of inputs.
       result_type = operands_type.IsNumber()
-          ? NumberInfo::Number()
-          : NumberInfo::Unknown();
+          ? TypeInfo::Number()
+          : TypeInfo::Unknown();
       break;
     case Token::SUB:
     case Token::MUL:
     case Token::DIV:
     case Token::MOD:
       // Result is always a number.
-      result_type = NumberInfo::Number();
+      result_type = TypeInfo::Number();
       break;
     default:
       UNREACHABLE();
   }
-  answer.set_number_info(result_type);
+  answer.set_type_info(result_type);
   frame_->Push(&answer);
 }
 
@@ -9105,51 +9105,55 @@
   // Encode the three parameters in a unique 16 bit value. To avoid duplicate
   // stubs the never NaN NaN condition is only taken into account if the
   // condition is equals.
-  ASSERT(static_cast<unsigned>(cc_) < (1 << 14));
+  ASSERT(static_cast<unsigned>(cc_) < (1 << 13));
   return ConditionField::encode(static_cast<unsigned>(cc_))
          | StrictField::encode(strict_)
-         | NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false);
+         | NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false)
+         | IncludeNumberCompareField::encode(include_number_compare_);
 }
 
 
+// Unfortunately you have to run without snapshots to see most of these
+// names in the profile since most compare stubs end up in the snapshot.
 const char* CompareStub::GetName() {
+  if (name_ != NULL) return name_;
+  const int kMaxNameLength = 100;
+  name_ = Bootstrapper::AllocateAutoDeletedArray(kMaxNameLength);
+  if (name_ == NULL) return "OOM";
+
+  const char* cc_name;
   switch (cc_) {
-    case less: return "CompareStub_LT";
-    case greater: return "CompareStub_GT";
-    case less_equal: return "CompareStub_LE";
-    case greater_equal: return "CompareStub_GE";
-    case not_equal: {
-      if (strict_) {
-        if (never_nan_nan_) {
-          return "CompareStub_NE_STRICT_NO_NAN";
-        } else {
-          return "CompareStub_NE_STRICT";
-        }
-      } else {
-        if (never_nan_nan_) {
-          return "CompareStub_NE_NO_NAN";
-        } else {
-          return "CompareStub_NE";
-        }
-      }
-    }
-    case equal: {
-      if (strict_) {
-        if (never_nan_nan_) {
-          return "CompareStub_EQ_STRICT_NO_NAN";
-        } else {
-          return "CompareStub_EQ_STRICT";
-        }
-      } else {
-        if (never_nan_nan_) {
-          return "CompareStub_EQ_NO_NAN";
-        } else {
-          return "CompareStub_EQ";
-        }
-      }
-    }
-    default: return "CompareStub";
+    case less: cc_name = "LT"; break;
+    case greater: cc_name = "GT"; break;
+    case less_equal: cc_name = "LE"; break;
+    case greater_equal: cc_name = "GE"; break;
+    case equal: cc_name = "EQ"; break;
+    case not_equal: cc_name = "NE"; break;
+    default: cc_name = "UnknownCondition"; break;
   }
+
+  const char* strict_name = "";
+  if (strict_ && (cc_ == equal || cc_ == not_equal)) {
+    strict_name = "_STRICT";
+  }
+
+  const char* never_nan_nan_name = "";
+  if (never_nan_nan_ && (cc_ == equal || cc_ == not_equal)) {
+    never_nan_nan_name = "_NO_NAN";
+  }
+
+  const char* include_number_compare_name = "";
+  if (!include_number_compare_) {
+    include_number_compare_name = "_NO_NUMBER";
+  }
+
+  OS::SNPrintF(Vector<char>(name_, kMaxNameLength),
+               "CompareStub_%s%s%s%s",
+               cc_name,
+               strict_name,
+               never_nan_nan_name,
+               include_number_compare_name);
+  return name_;
 }
 
 
diff --git a/src/x64/codegen-x64.h b/src/x64/codegen-x64.h
index a43856f..3f33918 100644
--- a/src/x64/codegen-x64.h
+++ b/src/x64/codegen-x64.h
@@ -667,7 +667,7 @@
   GenericBinaryOpStub(Token::Value op,
                       OverwriteMode mode,
                       GenericBinaryFlags flags,
-                      NumberInfo operands_type = NumberInfo::Unknown())
+                      TypeInfo operands_type = TypeInfo::Unknown())
       : op_(op),
         mode_(mode),
         flags_(flags),
@@ -687,7 +687,7 @@
         args_in_registers_(ArgsInRegistersBits::decode(key)),
         args_reversed_(ArgsReversedBits::decode(key)),
         use_sse3_(SSE3Bits::decode(key)),
-        static_operands_type_(NumberInfo::ExpandedRepresentation(
+        static_operands_type_(TypeInfo::ExpandedRepresentation(
             StaticTypeInfoBits::decode(key))),
         runtime_operands_type_(type_info),
         name_(NULL) {
@@ -714,7 +714,7 @@
   bool use_sse3_;
 
   // Number type information of operands, determined by code generator.
-  NumberInfo static_operands_type_;
+  TypeInfo static_operands_type_;
 
   // Operand type information determined at runtime.
   BinaryOpIC::TypeInfo runtime_operands_type_;
diff --git a/src/x64/register-allocator-x64.cc b/src/x64/register-allocator-x64.cc
index 9dc97b8..cf29593 100644
--- a/src/x64/register-allocator-x64.cc
+++ b/src/x64/register-allocator-x64.cc
@@ -44,7 +44,7 @@
     ASSERT(fresh.is_valid());
     CodeGeneratorScope::Current()->masm()->Move(fresh.reg(), handle());
     // This result becomes a copy of the fresh one.
-    fresh.set_number_info(number_info());
+    fresh.set_type_info(type_info());
     *this = fresh;
   }
   ASSERT(is_register());
@@ -62,7 +62,7 @@
       ASSERT(is_constant());
       CodeGeneratorScope::Current()->masm()->Move(fresh.reg(), handle());
     }
-    fresh.set_number_info(number_info());
+    fresh.set_type_info(type_info());
     *this = fresh;
   } else if (is_register() && reg().is(target)) {
     ASSERT(CodeGeneratorScope::Current()->has_valid_frame());
diff --git a/src/x64/virtual-frame-x64.cc b/src/x64/virtual-frame-x64.cc
index 79be20b..fa04b63 100644
--- a/src/x64/virtual-frame-x64.cc
+++ b/src/x64/virtual-frame-x64.cc
@@ -177,7 +177,7 @@
 }
 
 
-void VirtualFrame::EmitPush(Register reg, NumberInfo info) {
+void VirtualFrame::EmitPush(Register reg, TypeInfo info) {
   ASSERT(stack_pointer_ == element_count() - 1);
   elements_.Add(FrameElement::MemoryElement(info));
   stack_pointer_++;
@@ -185,7 +185,7 @@
 }
 
 
-void VirtualFrame::EmitPush(const Operand& operand, NumberInfo info) {
+void VirtualFrame::EmitPush(const Operand& operand, TypeInfo info) {
   ASSERT(stack_pointer_ == element_count() - 1);
   elements_.Add(FrameElement::MemoryElement(info));
   stack_pointer_++;
@@ -193,7 +193,7 @@
 }
 
 
-void VirtualFrame::EmitPush(Immediate immediate, NumberInfo info) {
+void VirtualFrame::EmitPush(Immediate immediate, TypeInfo info) {
   ASSERT(stack_pointer_ == element_count() - 1);
   elements_.Add(FrameElement::MemoryElement(info));
   stack_pointer_++;
@@ -203,7 +203,7 @@
 
 void VirtualFrame::EmitPush(Smi* smi_value) {
   ASSERT(stack_pointer_ == element_count() - 1);
-  elements_.Add(FrameElement::MemoryElement(NumberInfo::Smi()));
+  elements_.Add(FrameElement::MemoryElement(TypeInfo::Smi()));
   stack_pointer_++;
   __ Push(smi_value);
 }
@@ -211,19 +211,14 @@
 
 void VirtualFrame::EmitPush(Handle<Object> value) {
   ASSERT(stack_pointer_ == element_count() - 1);
-  NumberInfo info = NumberInfo::Unknown();
-  if (value->IsSmi()) {
-    info = NumberInfo::Smi();
-  } else if (value->IsHeapNumber()) {
-    info = NumberInfo::HeapNumber();
-  }
+  TypeInfo info = TypeInfo::TypeFromValue(value);
   elements_.Add(FrameElement::MemoryElement(info));
   stack_pointer_++;
   __ Push(value);
 }
 
 
-void VirtualFrame::EmitPush(Heap::RootListIndex index, NumberInfo info) {
+void VirtualFrame::EmitPush(Heap::RootListIndex index, TypeInfo info) {
   ASSERT(stack_pointer_ == element_count() - 1);
   elements_.Add(FrameElement::MemoryElement(info));
   stack_pointer_++;
@@ -297,12 +292,12 @@
     elements_[new_backing_index] =
         FrameElement::RegisterElement(backing_reg,
                                       FrameElement::SYNCED,
-                                      original.number_info());
+                                      original.type_info());
   } else {
     elements_[new_backing_index] =
         FrameElement::RegisterElement(backing_reg,
                                       FrameElement::NOT_SYNCED,
-                                      original.number_info());
+                                      original.type_info());
   }
   // Update the other copies.
   for (int i = new_backing_index + 1; i < element_count(); i++) {
@@ -334,7 +329,7 @@
       FrameElement new_element =
           FrameElement::RegisterElement(fresh.reg(),
                                         FrameElement::NOT_SYNCED,
-                                        original.number_info());
+                                        original.type_info());
       Use(fresh.reg(), element_count());
       elements_.Add(new_element);
       __ movq(fresh.reg(), Operand(rbp, fp_relative(index)));
@@ -480,7 +475,7 @@
     if (element.is_constant() || element.is_copy()) {
       if (element.is_synced()) {
         // Just spill.
-        elements_[i] = FrameElement::MemoryElement(NumberInfo::Unknown());
+        elements_[i] = FrameElement::MemoryElement(TypeInfo::Unknown());
       } else {
         // Allocate to a register.
         FrameElement backing_element;  // Invalid if not a copy.
@@ -492,7 +487,7 @@
         elements_[i] =
             FrameElement::RegisterElement(fresh.reg(),
                                           FrameElement::NOT_SYNCED,
-                                          NumberInfo::Unknown());
+                                          TypeInfo::Unknown());
         Use(fresh.reg(), i);
 
         // Emit a move.
@@ -521,7 +516,7 @@
       // The copy flag is not relied on before the end of this loop,
       // including when registers are spilled.
       elements_[i].clear_copied();
-      elements_[i].set_number_info(NumberInfo::Unknown());
+      elements_[i].set_type_info(TypeInfo::Unknown());
     }
   }
 }
@@ -728,11 +723,11 @@
   ASSERT(element.is_valid());
 
   // Get number type information of the result.
-  NumberInfo info;
+  TypeInfo info;
   if (!element.is_copy()) {
-    info = element.number_info();
+    info = element.type_info();
   } else {
-    info = elements_[element.index()].number_info();
+    info = elements_[element.index()].type_info();
   }
 
   bool pop_needed = (stack_pointer_ == index);
@@ -742,7 +737,7 @@
       Result temp = cgen()->allocator()->Allocate();
       ASSERT(temp.is_valid());
       __ pop(temp.reg());
-      temp.set_number_info(info);
+      temp.set_type_info(info);
       return temp;
     }
 
@@ -772,7 +767,7 @@
     FrameElement new_element =
         FrameElement::RegisterElement(temp.reg(),
                                       FrameElement::SYNCED,
-                                      element.number_info());
+                                      element.type_info());
     // Preserve the copy flag on the element.
     if (element.is_copied()) new_element.set_copied();
     elements_[index] = new_element;
diff --git a/src/x64/virtual-frame-x64.h b/src/x64/virtual-frame-x64.h
index 3e9f6dd..15653ed 100644
--- a/src/x64/virtual-frame-x64.h
+++ b/src/x64/virtual-frame-x64.h
@@ -28,7 +28,7 @@
 #ifndef V8_X64_VIRTUAL_FRAME_X64_H_
 #define V8_X64_VIRTUAL_FRAME_X64_H_
 
-#include "number-info.h"
+#include "type-info.h"
 #include "register-allocator.h"
 #include "scopes.h"
 
@@ -83,7 +83,7 @@
 
   // Create a duplicate of an existing valid frame element.
   FrameElement CopyElementAt(int index,
-    NumberInfo info = NumberInfo::Uninitialized());
+    TypeInfo info = TypeInfo::Uninitialized());
 
   // The number of elements on the virtual frame.
   int element_count() { return elements_.length(); }
@@ -139,7 +139,7 @@
   void ForgetElements(int count);
 
   // Spill all values from the frame to memory.
-  void SpillAll();
+  inline void SpillAll();
 
   // Spill all occurrences of a specific register from the frame.
   void Spill(Register reg) {
@@ -200,7 +200,7 @@
   // Prepare for returning from the frame by spilling locals.  This
   // avoids generating unnecessary merge code when jumping to the
   // shared return site.  Emits code for spills.
-  void PrepareForReturn();
+  inline void PrepareForReturn();
 
   // Number of local variables after when we use a loop for allocating.
   static const int kLocalVarBound = 7;
@@ -383,19 +383,19 @@
   // Push an element on top of the expression stack and emit a
   // corresponding push instruction.
   void EmitPush(Register reg,
-                NumberInfo info = NumberInfo::Unknown());
+                TypeInfo info = TypeInfo::Unknown());
   void EmitPush(const Operand& operand,
-                NumberInfo info = NumberInfo::Unknown());
+                TypeInfo info = TypeInfo::Unknown());
   void EmitPush(Heap::RootListIndex index,
-                NumberInfo info = NumberInfo::Unknown());
+                TypeInfo info = TypeInfo::Unknown());
   void EmitPush(Immediate immediate,
-                NumberInfo info = NumberInfo::Unknown());
+                TypeInfo info = TypeInfo::Unknown());
   void EmitPush(Smi* value);
   // Uses kScratchRegister, emits appropriate relocation info.
   void EmitPush(Handle<Object> value);
 
   // Push an element on the virtual frame.
-  inline void Push(Register reg, NumberInfo info = NumberInfo::Unknown());
+  inline void Push(Register reg, TypeInfo info = TypeInfo::Unknown());
   inline void Push(Handle<Object> value);
   inline void Push(Smi* value);
 
@@ -403,7 +403,7 @@
   // frame).
   void Push(Result* result) {
     if (result->is_register()) {
-      Push(result->reg(), result->number_info());
+      Push(result->reg(), result->type_info());
     } else {
       ASSERT(result->is_constant());
       Push(result->handle());
@@ -416,8 +416,8 @@
   // the frame.  Nip(k) is equivalent to x = Pop(), Drop(k), Push(x).
   inline void Nip(int num_dropped);
 
-  inline void SetTypeForLocalAt(int index, NumberInfo info);
-  inline void SetTypeForParamAt(int index, NumberInfo info);
+  inline void SetTypeForLocalAt(int index, TypeInfo info);
+  inline void SetTypeForParamAt(int index, TypeInfo info);
 
  private:
   static const int kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset;