Version 1.2.14.

Added separate paged heap space for global property cells and avoid updating the write barrier when storing into them.

Improved peep-hole optimization on ARM platforms by not emitting unnecessary debug information.

Re-enabled ICs for loads and calls that skip a global object during lookup through the prototype chain.

Allowed access through global proxies to use ICs.

Fixed issue 401.


git-svn-id: http://v8.googlecode.com/svn/trunk@2438 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/ChangeLog b/ChangeLog
index f0954bc..83ebc02 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2009-07-13: Version 1.2.14
+
+        Added separate paged heap space for global property cells and
+        avoid updating the write barrier when storing into them.
+
+        Improved peep-hole optimization on ARM platforms by not emitting
+        unnecessary debug information.
+
+        Re-enabled ICs for loads and calls that skip a global object
+        during lookup through the prototype chain.
+
+        Allowed access through global proxies to use ICs.
+
+        Fixed issue 401.
+
+
 2009-07-09: Version 1.2.13
 
         Fixed issue 397, issue 398, and issue 399.
diff --git a/src/api.h b/src/api.h
index 85b13ec..f1057a8 100644
--- a/src/api.h
+++ b/src/api.h
@@ -244,9 +244,10 @@
 
 // Implementations of ToLocal
 
-#define MAKE_TO_LOCAL(Name, From, To) \
+#define MAKE_TO_LOCAL(Name, From, To)                                       \
   Local<v8::To> Utils::Name(v8::internal::Handle<v8::internal::From> obj) { \
-    return Local<To>(reinterpret_cast<To*>(obj.location())); \
+    ASSERT(!obj->IsTheHole());                                              \
+    return Local<To>(reinterpret_cast<To*>(obj.location()));                \
   }
 
 MAKE_TO_LOCAL(ToLocal, Context, Context)
diff --git a/src/apinatives.js b/src/apinatives.js
index 2981eec..6451e62 100644
--- a/src/apinatives.js
+++ b/src/apinatives.js
@@ -51,6 +51,7 @@
       var Constructor = %GetTemplateField(data, kApiConstructorOffset);
       var result = Constructor ? new (Instantiate(Constructor))() : {};
       ConfigureTemplateInstance(result, data);
+      result = %ToFastProperties(result);
       return result;
     default:
       throw 'Unknown API tag <' + tag + '>';
diff --git a/src/arm/assembler-arm.cc b/src/arm/assembler-arm.cc
index a393ac0..3ed99f9 100644
--- a/src/arm/assembler-arm.cc
+++ b/src/arm/assembler-arm.cc
@@ -697,6 +697,7 @@
 
 
 void Assembler::blx(int branch_offset) {  // v5 and above
+  WriteRecordedPositions();
   ASSERT((branch_offset & 1) == 0);
   int h = ((branch_offset & 2) >> 1)*B24;
   int imm24 = branch_offset >> 2;
@@ -706,12 +707,14 @@
 
 
 void Assembler::blx(Register target, Condition cond) {  // v5 and above
+  WriteRecordedPositions();
   ASSERT(!target.is(pc));
   emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | 3*B4 | target.code());
 }
 
 
 void Assembler::bx(Register target, Condition cond) {  // v5 and above, plus v4t
+  WriteRecordedPositions();
   ASSERT(!target.is(pc));  // use of pc is actually allowed, but discouraged
   emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | B4 | target.code());
 }
@@ -810,6 +813,9 @@
 
 
 void Assembler::mov(Register dst, const Operand& src, SBit s, Condition cond) {
+  if (dst.is(pc)) {
+    WriteRecordedPositions();
+  }
   addrmod1(cond | 13*B21 | s, r0, dst, src);
 }
 
@@ -937,6 +943,9 @@
 
 // Load/Store instructions
 void Assembler::ldr(Register dst, const MemOperand& src, Condition cond) {
+  if (dst.is(pc)) {
+    WriteRecordedPositions();
+  }
   addrmod2(cond | B26 | L, dst, src);
 
   // Eliminate pattern: push(r), pop(r)
@@ -1274,7 +1283,6 @@
   if (pos == RelocInfo::kNoPosition) return;
   ASSERT(pos >= 0);
   current_position_ = pos;
-  WriteRecordedPositions();
 }
 
 
@@ -1282,7 +1290,6 @@
   if (pos == RelocInfo::kNoPosition) return;
   ASSERT(pos >= 0);
   current_statement_position_ = pos;
-  WriteRecordedPositions();
 }
 
 
diff --git a/src/arm/ic-arm.cc b/src/arm/ic-arm.cc
index 07c767e..2ca74a9 100644
--- a/src/arm/ic-arm.cc
+++ b/src/arm/ic-arm.cc
@@ -192,11 +192,14 @@
   //  -- [sp]  : receiver
   // -----------------------------------
 
-  // NOTE: Right now, this code always misses on ARM which is
-  // sub-optimal. We should port the fast case code from IA-32.
+  Label miss;
 
-  Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Miss));
-  __ Jump(ic, RelocInfo::CODE_TARGET);
+  // Load receiver.
+  __ ldr(r0, MemOperand(sp, 0));
+
+  StubCompiler::GenerateLoadFunctionPrototype(masm, r0, r1, r3, &miss);
+  __ bind(&miss);
+  StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
 }
 
 
diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc
index e3e5502..6d9ace8 100644
--- a/src/arm/stub-cache-arm.cc
+++ b/src/arm/stub-cache-arm.cc
@@ -171,110 +171,6 @@
 }
 
 
-void StubCompiler::GenerateLoadField(MacroAssembler* masm,
-                                     JSObject* object,
-                                     JSObject* holder,
-                                     Register receiver,
-                                     Register scratch1,
-                                     Register scratch2,
-                                     int index,
-                                     Label* miss_label) {
-  // Check that the receiver isn't a smi.
-  __ tst(receiver, Operand(kSmiTagMask));
-  __ b(eq, miss_label);
-
-  // Check that the maps haven't changed.
-  Register reg =
-      masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
-  GenerateFastPropertyLoad(masm, r0, reg, holder, index);
-  __ Ret();
-}
-
-
-void StubCompiler::GenerateLoadConstant(MacroAssembler* masm,
-                                        JSObject* object,
-                                        JSObject* holder,
-                                        Register receiver,
-                                        Register scratch1,
-                                        Register scratch2,
-                                        Object* value,
-                                        Label* miss_label) {
-  // Check that the receiver isn't a smi.
-  __ tst(receiver, Operand(kSmiTagMask));
-  __ b(eq, miss_label);
-
-  // Check that the maps haven't changed.
-  Register reg =
-      masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
-
-  // Return the constant value.
-  __ mov(r0, Operand(Handle<Object>(value)));
-  __ Ret();
-}
-
-
-void StubCompiler::GenerateLoadCallback(MacroAssembler* masm,
-                                        JSObject* object,
-                                        JSObject* holder,
-                                        Register receiver,
-                                        Register name,
-                                        Register scratch1,
-                                        Register scratch2,
-                                        AccessorInfo* callback,
-                                        Label* miss_label) {
-  // Check that the receiver isn't a smi.
-  __ tst(receiver, Operand(kSmiTagMask));
-  __ b(eq, miss_label);
-
-  // Check that the maps haven't changed.
-  Register reg =
-      masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
-
-  // Push the arguments on the JS stack of the caller.
-  __ push(receiver);  // receiver
-  __ mov(ip, Operand(Handle<AccessorInfo>(callback)));  // callback data
-  __ push(ip);
-  __ push(name);  // name
-  __ push(reg);  // holder
-
-  // Do tail-call to the runtime system.
-  ExternalReference load_callback_property =
-      ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
-  __ TailCallRuntime(load_callback_property, 4);
-}
-
-
-void StubCompiler::GenerateLoadInterceptor(MacroAssembler* masm,
-                                           JSObject* object,
-                                           JSObject* holder,
-                                           Smi* lookup_hint,
-                                           Register receiver,
-                                           Register name,
-                                           Register scratch1,
-                                           Register scratch2,
-                                           Label* miss_label) {
-  // Check that the receiver isn't a smi.
-  __ tst(receiver, Operand(kSmiTagMask));
-  __ b(eq, miss_label);
-
-  // Check that the maps haven't changed.
-  Register reg =
-      masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
-
-  // Push the arguments on the JS stack of the caller.
-  __ push(receiver);  // receiver
-  __ push(reg);  // holder
-  __ push(name);  // name
-  __ mov(scratch1, Operand(lookup_hint));
-  __ push(scratch1);
-
-  // Do tail-call to the runtime system.
-  ExternalReference load_ic_property =
-      ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
-  __ TailCallRuntime(load_ic_property, 4);
-}
-
-
 void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
                                            Register receiver,
                                            Register scratch,
@@ -351,6 +247,17 @@
 }
 
 
+void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
+                                                 Register receiver,
+                                                 Register scratch1,
+                                                 Register scratch2,
+                                                 Label* miss_label) {
+  __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
+  __ mov(r0, scratch1);
+  __ Ret();
+}
+
+
 // Generate StoreField code, value is passed in r0 register.
 // After executing generated code, the receiver_reg and name_reg
 // may be clobbered.
@@ -462,6 +369,147 @@
 #define __ ACCESS_MASM(masm())
 
 
+Register StubCompiler::CheckPrototypes(JSObject* object,
+                                       Register object_reg,
+                                       JSObject* holder,
+                                       Register holder_reg,
+                                       Register scratch,
+                                       String* name,
+                                       Label* miss) {
+  // Check that the maps haven't changed.
+  Register result =
+      masm()->CheckMaps(object, object_reg, holder, holder_reg, scratch, miss);
+
+  // If we've skipped any global objects, it's not enough to verify
+  // that their maps haven't changed.
+  while (object != holder) {
+    if (object->IsGlobalObject()) {
+      GlobalObject* global = GlobalObject::cast(object);
+      Object* probe = global->EnsurePropertyCell(name);
+      if (probe->IsFailure()) {
+        set_failure(Failure::cast(probe));
+        return result;
+      }
+      JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe);
+      ASSERT(cell->value()->IsTheHole());
+      __ mov(scratch, Operand(Handle<Object>(cell)));
+      __ ldr(scratch,
+             FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
+      __ cmp(scratch, Operand(Factory::the_hole_value()));
+      __ b(ne, miss);
+    }
+    object = JSObject::cast(object->GetPrototype());
+  }
+
+  // Return the register containin the holder.
+  return result;
+}
+
+
+void StubCompiler::GenerateLoadField(JSObject* object,
+                                     JSObject* holder,
+                                     Register receiver,
+                                     Register scratch1,
+                                     Register scratch2,
+                                     int index,
+                                     String* name,
+                                     Label* miss) {
+  // Check that the receiver isn't a smi.
+  __ tst(receiver, Operand(kSmiTagMask));
+  __ b(eq, miss);
+
+  // Check that the maps haven't changed.
+  Register reg =
+      CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
+  GenerateFastPropertyLoad(masm(), r0, reg, holder, index);
+  __ Ret();
+}
+
+
+void StubCompiler::GenerateLoadConstant(JSObject* object,
+                                        JSObject* holder,
+                                        Register receiver,
+                                        Register scratch1,
+                                        Register scratch2,
+                                        Object* value,
+                                        String* name,
+                                        Label* miss) {
+  // Check that the receiver isn't a smi.
+  __ tst(receiver, Operand(kSmiTagMask));
+  __ b(eq, miss);
+
+  // Check that the maps haven't changed.
+  Register reg =
+      CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
+
+  // Return the constant value.
+  __ mov(r0, Operand(Handle<Object>(value)));
+  __ Ret();
+}
+
+
+void StubCompiler::GenerateLoadCallback(JSObject* object,
+                                        JSObject* holder,
+                                        Register receiver,
+                                        Register name_reg,
+                                        Register scratch1,
+                                        Register scratch2,
+                                        AccessorInfo* callback,
+                                        String* name,
+                                        Label* miss) {
+  // Check that the receiver isn't a smi.
+  __ tst(receiver, Operand(kSmiTagMask));
+  __ b(eq, miss);
+
+  // Check that the maps haven't changed.
+  Register reg =
+      CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
+
+  // Push the arguments on the JS stack of the caller.
+  __ push(receiver);  // receiver
+  __ mov(ip, Operand(Handle<AccessorInfo>(callback)));  // callback data
+  __ push(ip);
+  __ push(name_reg);  // name
+  __ push(reg);  // holder
+
+  // Do tail-call to the runtime system.
+  ExternalReference load_callback_property =
+      ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
+  __ TailCallRuntime(load_callback_property, 4);
+}
+
+
+void StubCompiler::GenerateLoadInterceptor(JSObject* object,
+                                           JSObject* holder,
+                                           Smi* lookup_hint,
+                                           Register receiver,
+                                           Register name_reg,
+                                           Register scratch1,
+                                           Register scratch2,
+                                           String* name,
+                                           Label* miss) {
+  // Check that the receiver isn't a smi.
+  __ tst(receiver, Operand(kSmiTagMask));
+  __ b(eq, miss);
+
+  // Check that the maps haven't changed.
+  Register reg =
+      CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
+
+  // Push the arguments on the JS stack of the caller.
+  __ push(receiver);  // receiver
+  __ push(reg);  // holder
+  __ push(name_reg);  // name
+  __ mov(scratch1, Operand(lookup_hint));
+  __ push(scratch1);
+
+  // Do tail-call to the runtime system.
+  ExternalReference load_ic_property =
+      ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
+  __ TailCallRuntime(load_ic_property, 4);
+}
+
+
 Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
   // ----------- S t a t e -------------
   //  -- r1: function
@@ -513,7 +561,7 @@
 
   // Do the right check and compute the holder register.
   Register reg =
-      masm()->CheckMaps(JSObject::cast(object), r0, holder, r3, r2, &miss);
+      CheckPrototypes(JSObject::cast(object), r0, holder, r3, r2, name, &miss);
   GenerateFastPropertyLoad(masm(), r1, reg, holder, index);
 
   // Check that the function really is a function.
@@ -546,6 +594,7 @@
 Object* CallStubCompiler::CompileCallConstant(Object* object,
                                               JSObject* holder,
                                               JSFunction* function,
+                                              String* name,
                                               CheckType check) {
   // ----------- S t a t e -------------
   //  -- lr: return address
@@ -569,7 +618,7 @@
   switch (check) {
     case RECEIVER_MAP_CHECK:
       // Check that the maps haven't changed.
-      __ CheckMaps(JSObject::cast(object), r1, holder, r3, r2, &miss);
+      CheckPrototypes(JSObject::cast(object), r1, holder, r3, r2, name, &miss);
 
       // Patch the receiver on the stack with the global proxy if
       // necessary.
@@ -587,8 +636,8 @@
       GenerateLoadGlobalFunctionPrototype(masm(),
                                           Context::STRING_FUNCTION_INDEX,
                                           r2);
-      __ CheckMaps(JSObject::cast(object->GetPrototype()),
-                   r2, holder, r3, r1, &miss);
+      CheckPrototypes(JSObject::cast(object->GetPrototype()), r2, holder, r3,
+                      r1, name, &miss);
       break;
 
     case NUMBER_CHECK: {
@@ -603,8 +652,8 @@
       GenerateLoadGlobalFunctionPrototype(masm(),
                                           Context::NUMBER_FUNCTION_INDEX,
                                           r2);
-      __ CheckMaps(JSObject::cast(object->GetPrototype()),
-                   r2, holder, r3, r1, &miss);
+      CheckPrototypes(JSObject::cast(object->GetPrototype()), r2, holder, r3,
+                      r1, name, &miss);
       break;
     }
 
@@ -620,13 +669,13 @@
       GenerateLoadGlobalFunctionPrototype(masm(),
                                           Context::BOOLEAN_FUNCTION_INDEX,
                                           r2);
-      __ CheckMaps(JSObject::cast(object->GetPrototype()),
-                   r2, holder, r3, r1, &miss);
+      CheckPrototypes(JSObject::cast(object->GetPrototype()), r2, holder, r3,
+                      r1, name, &miss);
       break;
     }
 
     case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
-      __ CheckMaps(JSObject::cast(object), r1, holder, r3, r2, &miss);
+      CheckPrototypes(JSObject::cast(object), r1, holder, r3, r2, name, &miss);
       // Make sure object->elements()->map() != Heap::hash_table_map()
       // Get the elements array of the object.
       __ ldr(r3, FieldMemOperand(r1, JSObject::kElementsOffset));
@@ -685,7 +734,8 @@
 }
 
 
-Object* CallStubCompiler::CompileCallGlobal(GlobalObject* object,
+Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
+                                            GlobalObject* holder,
                                             JSGlobalPropertyCell* cell,
                                             JSFunction* function,
                                             String* name) {
@@ -699,11 +749,19 @@
   // Get the number of arguments.
   const int argc = arguments().immediate();
 
-  // Check that the map of the global has not changed.
-  __ ldr(r2, MemOperand(sp, argc * kPointerSize));
-  __ ldr(r3, FieldMemOperand(r2, HeapObject::kMapOffset));
-  __ cmp(r3, Operand(Handle<Map>(object->map())));
-  __ b(ne, &miss);
+  // Get the receiver from the stack.
+  __ ldr(r0, MemOperand(sp, argc * kPointerSize));
+
+  // If the object is the holder then we know that it's a global
+  // object which can only happen for contextual calls. In this case,
+  // the receiver cannot be a smi.
+  if (object != holder) {
+    __ tst(r0, Operand(kSmiTagMask));
+    __ b(eq, &miss);
+  }
+
+  // Check that the maps haven't changed.
+  CheckPrototypes(object, r0, holder, r3, r2, name, &miss);
 
   // Get the value from the cell.
   __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
@@ -715,8 +773,10 @@
 
   // Patch the receiver on the stack with the global proxy if
   // necessary.
-  __ ldr(r3, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
-  __ str(r3, MemOperand(sp, argc * kPointerSize));
+  if (object->IsGlobalObject()) {
+    __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
+    __ str(r3, MemOperand(sp, argc * kPointerSize));
+  }
 
   // Setup the context (function already in r1).
   __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
@@ -902,8 +962,6 @@
   // Store the value in the cell.
   __ mov(r2, Operand(Handle<JSGlobalPropertyCell>(cell)));
   __ str(r0, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
-  __ mov(r1, Operand(JSGlobalPropertyCell::kValueOffset));
-  __ RecordWrite(r2, r1, r3);
 
   __ Ret();
 
@@ -932,7 +990,7 @@
 
   __ ldr(r0, MemOperand(sp, 0));
 
-  GenerateLoadField(masm(), object, holder, r0, r3, r1, index, &miss);
+  GenerateLoadField(object, holder, r0, r3, r1, index, name, &miss);
   __ bind(&miss);
   GenerateLoadMiss(masm(), Code::LOAD_IC);
 
@@ -953,7 +1011,7 @@
   Label miss;
 
   __ ldr(r0, MemOperand(sp, 0));
-  GenerateLoadCallback(masm(), object, holder, r0, r2, r3, r1, callback, &miss);
+  GenerateLoadCallback(object, holder, r0, r2, r3, r1, callback, name, &miss);
   __ bind(&miss);
   GenerateLoadMiss(masm(), Code::LOAD_IC);
 
@@ -975,7 +1033,7 @@
 
   __ ldr(r0, MemOperand(sp, 0));
 
-  GenerateLoadConstant(masm(), object, holder, r0, r3, r1, value, &miss);
+  GenerateLoadConstant(object, holder, r0, r3, r1, value, name, &miss);
   __ bind(&miss);
   GenerateLoadMiss(masm(), Code::LOAD_IC);
 
@@ -996,14 +1054,14 @@
 
   __ ldr(r0, MemOperand(sp, 0));
 
-  GenerateLoadInterceptor(masm(),
-                          object,
+  GenerateLoadInterceptor(object,
                           holder,
                           holder->InterceptorPropertyLookupHint(name),
                           r0,
                           r2,
                           r3,
                           r1,
+                          name,
                           &miss);
   __ bind(&miss);
   GenerateLoadMiss(masm(), Code::LOAD_IC);
@@ -1013,7 +1071,8 @@
 }
 
 
-Object* LoadStubCompiler::CompileLoadGlobal(GlobalObject* object,
+Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
+                                            GlobalObject* holder,
                                             JSGlobalPropertyCell* cell,
                                             String* name,
                                             bool is_dont_delete) {
@@ -1026,11 +1085,19 @@
 
   __ IncrementCounter(&Counters::named_load_global_inline, 1, r1, r3);
 
-  // Check that the map of the global has not changed.
+  // Get the receiver from the stack.
   __ ldr(r1, MemOperand(sp, 0 * kPointerSize));
-  __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
-  __ cmp(r3, Operand(Handle<Map>(object->map())));
-  __ b(ne, &miss);
+
+  // If the object is the holder then we know that it's a global
+  // object which can only happen for contextual calls. In this case,
+  // the receiver cannot be a smi.
+  if (object != holder) {
+    __ tst(r1, Operand(kSmiTagMask));
+    __ b(eq, &miss);
+  }
+
+  // Check that the map of the global has not changed.
+  CheckPrototypes(object, r1, holder, r3, r0, name, &miss);
 
   // Get the value from the cell.
   __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
@@ -1073,7 +1140,7 @@
   __ cmp(r2, Operand(Handle<String>(name)));
   __ b(ne, &miss);
 
-  GenerateLoadField(masm(), receiver, holder, r0, r3, r1, index, &miss);
+  GenerateLoadField(receiver, holder, r0, r3, r1, index, name, &miss);
   __ bind(&miss);
   GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
 
@@ -1098,8 +1165,7 @@
   __ cmp(r2, Operand(Handle<String>(name)));
   __ b(ne, &miss);
 
-  GenerateLoadCallback(masm(), receiver, holder, r0, r2, r3,
-                       r1, callback, &miss);
+  GenerateLoadCallback(receiver, holder, r0, r2, r3, r1, callback, name, &miss);
   __ bind(&miss);
   GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
 
@@ -1125,7 +1191,7 @@
   __ cmp(r2, Operand(Handle<String>(name)));
   __ b(ne, &miss);
 
-  GenerateLoadConstant(masm(), receiver, holder, r0, r3, r1, value, &miss);
+  GenerateLoadConstant(receiver, holder, r0, r3, r1, value, name, &miss);
   __ bind(&miss);
   GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
 
@@ -1151,14 +1217,14 @@
   __ cmp(r2, Operand(Handle<String>(name)));
   __ b(ne, &miss);
 
-  GenerateLoadInterceptor(masm(),
-                          receiver,
+  GenerateLoadInterceptor(receiver,
                           holder,
                           Smi::FromInt(JSObject::kLookupInHolder),
                           r0,
                           r2,
                           r3,
                           r1,
+                          name,
                           &miss);
   __ bind(&miss);
   GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index c64b92a..ad5396e 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -1373,43 +1373,35 @@
   if (from->HasFastProperties()) {
     Handle<DescriptorArray> descs =
         Handle<DescriptorArray>(from->map()->instance_descriptors());
-    int offset = 0;
-    while (true) {
-      // Iterating through the descriptors is not gc safe so we have to
-      // store the value in a handle and create a new stream for each entry.
-      DescriptorReader stream(*descs, offset);
-      if (stream.eos()) break;
-      // We have to read out the next offset before we do anything that may
-      // cause a gc, since the DescriptorReader is not gc safe.
-      offset = stream.next_position();
-      PropertyDetails details = stream.GetDetails();
+    for (int i = 0; i < descs->number_of_descriptors(); i++) {
+      PropertyDetails details = PropertyDetails(descs->GetDetails(i));
       switch (details.type()) {
         case FIELD: {
           HandleScope inner;
-          Handle<String> key = Handle<String>(stream.GetKey());
-          int index = stream.GetFieldIndex();
+          Handle<String> key = Handle<String>(descs->GetKey(i));
+          int index = descs->GetFieldIndex(i);
           Handle<Object> value = Handle<Object>(from->FastPropertyAt(index));
           SetProperty(to, key, value, details.attributes());
           break;
         }
         case CONSTANT_FUNCTION: {
           HandleScope inner;
-          Handle<String> key = Handle<String>(stream.GetKey());
+          Handle<String> key = Handle<String>(descs->GetKey(i));
           Handle<JSFunction> fun =
-              Handle<JSFunction>(stream.GetConstantFunction());
+              Handle<JSFunction>(descs->GetConstantFunction(i));
           SetProperty(to, key, fun, details.attributes());
           break;
         }
         case CALLBACKS: {
           LookupResult result;
-          to->LocalLookup(stream.GetKey(), &result);
+          to->LocalLookup(descs->GetKey(i), &result);
           // If the property is already there we skip it
           if (result.IsValid()) continue;
           HandleScope inner;
           Handle<DescriptorArray> inst_descs =
               Handle<DescriptorArray>(to->map()->instance_descriptors());
-          Handle<String> key = Handle<String>(stream.GetKey());
-          Handle<Object> entry = Handle<Object>(stream.GetCallbacksObject());
+          Handle<String> key = Handle<String>(descs->GetKey(i));
+          Handle<Object> entry = Handle<Object>(descs->GetCallbacksObject(i));
           inst_descs = Factory::CopyAppendProxyDescriptor(inst_descs,
                                                           key,
                                                           entry,
diff --git a/src/d8-posix.cc b/src/d8-posix.cc
index 3a091f9..fe130ce 100644
--- a/src/d8-posix.cc
+++ b/src/d8-posix.cc
@@ -370,7 +370,11 @@
 // whether it exited normally.  In the common case this doesn't matter because
 // we don't get here before the child has closed stdout and most programs don't
 // do that before they exit.
-#if defined(WNOWAIT) && !defined(ANDROID)
+//
+// We're disabling usage of waitid in Mac OS X because it doens't work for us:
+// a parent process hangs on waiting while a child process is already a zombie.
+// See http://code.google.com/p/v8/issues/detail?id=401.
+#if defined(WNOWAIT) && !defined(ANDROID) && !defined(__APPLE__)
 #define HAS_WAITID 1
 #endif
 
diff --git a/src/debug.cc b/src/debug.cc
index e37bfb7..52be930 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -1260,6 +1260,7 @@
 
 // Handle stepping into a function.
 void Debug::HandleStepIn(Handle<JSFunction> function,
+                         Handle<Object> holder,
                          Address fp,
                          bool is_constructor) {
   // If the frame pointer is not supplied by the caller find it.
@@ -1285,21 +1286,12 @@
           Builtins::builtin(Builtins::FunctionCall)) {
         // Handle function.apply and function.call separately to flood the
         // function to be called and not the code for Builtins::FunctionApply or
-        // Builtins::FunctionCall. At the point of the call IC to call either
-        // Builtins::FunctionApply or Builtins::FunctionCall the expression
-        // stack has the following content:
-        //   symbol "apply" or "call"
-        //   function apply or call was called on
-        //   receiver for apply or call (first parameter to apply or call)
-        //   ... further arguments to apply or call.
-        JavaScriptFrameIterator it;
-        ASSERT(it.frame()->fp() == fp);
-        ASSERT(it.frame()->GetExpression(1)->IsJSFunction());
-        if (it.frame()->GetExpression(1)->IsJSFunction()) {
-          Handle<JSFunction>
-              actual_function(JSFunction::cast(it.frame()->GetExpression(1)));
-          Handle<SharedFunctionInfo> actual_shared(actual_function->shared());
-          Debug::FloodWithOneShot(actual_shared);
+        // Builtins::FunctionCall. The receiver of call/apply is the target
+        // function.
+        if (!holder.is_null() && holder->IsJSFunction()) {
+          Handle<SharedFunctionInfo> shared_info(
+              JSFunction::cast(*holder)->shared());
+          Debug::FloodWithOneShot(shared_info);
         }
       } else {
         Debug::FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
diff --git a/src/debug.h b/src/debug.h
index a1abced..970dbbe 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -270,6 +270,7 @@
 
   static bool StepInActive() { return thread_local_.step_into_fp_ != 0; }
   static void HandleStepIn(Handle<JSFunction> function,
+                           Handle<Object> holder,
                            Address fp,
                            bool is_constructor);
   static Address step_in_fp() { return thread_local_.step_into_fp_; }
@@ -363,6 +364,10 @@
   static const int kIa32CallInstructionLength = 5;
   static const int kIa32JSReturnSequenceLength = 6;
 
+  // The x64 JS return sequence is padded with int3 to make it large
+  // enough to hold a call instruction when the debugger patches it.
+  static const int kX64JSReturnSequenceLength = 13;
+
   // Code generator routines.
   static void GenerateLoadICDebugBreak(MacroAssembler* masm);
   static void GenerateStoreICDebugBreak(MacroAssembler* masm);
diff --git a/src/factory.cc b/src/factory.cc
index 572180d..1045a4c 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -570,13 +570,9 @@
   int descriptor_count = 0;
 
   // Copy the descriptors from the array.
-  {
-    DescriptorWriter w(*result);
-    for (DescriptorReader r(*array); !r.eos(); r.advance()) {
-      if (!r.IsNullDescriptor()) {
-        w.WriteFrom(&r);
-      }
-      descriptor_count++;
+  for (int i = 0; i < array->number_of_descriptors(); i++) {
+    if (array->GetType(i) != NULL_DESCRIPTOR) {
+      result->CopyFrom(descriptor_count++, *array, i);
     }
   }
 
@@ -596,9 +592,6 @@
     if (result->LinearSearch(*key, descriptor_count) ==
         DescriptorArray::kNotFound) {
       CallbacksDescriptor desc(*key, *entry, entry->property_attributes());
-      // We do not use a DescriptorWriter because SymbolFromString can
-      // allocate. A DescriptorWriter holds a raw pointer and is
-      // therefore not GC safe.
       result->Set(descriptor_count, &desc);
       descriptor_count++;
     } else {
@@ -609,13 +602,11 @@
   // If duplicates were detected, allocate a result of the right size
   // and transfer the elements.
   if (duplicates > 0) {
+    int number_of_descriptors = result->number_of_descriptors() - duplicates;
     Handle<DescriptorArray> new_result =
-        NewDescriptorArray(result->number_of_descriptors() - duplicates);
-    DescriptorWriter w(*new_result);
-    DescriptorReader r(*result);
-    while (!w.eos()) {
-      w.WriteFrom(&r);
-      r.advance();
+        NewDescriptorArray(number_of_descriptors);
+    for (int i = 0; i < number_of_descriptors; i++) {
+      new_result->CopyFrom(i, *result, i);
     }
     result = new_result;
   }
diff --git a/src/globals.h b/src/globals.h
index 8088331..44bd527 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -257,14 +257,16 @@
 // NOTE: SpaceIterator depends on AllocationSpace enumeration values being
 // consecutive.
 enum AllocationSpace {
-  NEW_SPACE,          // Semispaces collected with copying collector.
-  OLD_POINTER_SPACE,  // Must be first of the paged spaces - see PagedSpaces.
-  OLD_DATA_SPACE,     // May not have pointers to new space.
-  CODE_SPACE,         // Also one of the old spaces.  Marked executable.
-  MAP_SPACE,          // Only map objects.
-  LO_SPACE,           // Large objects.
+  NEW_SPACE,            // Semispaces collected with copying collector.
+  OLD_POINTER_SPACE,    // May contain pointers to new space.
+  OLD_DATA_SPACE,       // Must not have pointers to new space.
+  CODE_SPACE,           // No pointers to new space, marked executable.
+  MAP_SPACE,            // Only and all map objects.
+  CELL_SPACE,           // Only and all cell objects.
+  LO_SPACE,             // Promoted large objects.
+
   FIRST_SPACE = NEW_SPACE,
-  LAST_SPACE = LO_SPACE  // <= 5 (see kSpaceBits and kLOSpacePointer)
+  LAST_SPACE = LO_SPACE
 };
 const int kSpaceTagSize = 3;
 const int kSpaceTagMask = (1 << kSpaceTagSize) - 1;
diff --git a/src/handles.cc b/src/handles.cc
index afed6e9..510ea95 100644
--- a/src/handles.cc
+++ b/src/handles.cc
@@ -289,10 +289,11 @@
     // hidden symbols hash code is zero (and no other string has hash
     // code zero) it will always occupy the first entry if present.
     DescriptorArray* descriptors = obj->map()->instance_descriptors();
-    DescriptorReader r(descriptors, 0);  // Explicitly position reader at zero.
-    if (!r.eos() && (r.GetKey() == *key) && r.IsProperty()) {
-      ASSERT(r.type() == FIELD);
-      return Handle<Object>(obj->FastPropertyAt(r.GetFieldIndex()));
+    if ((descriptors->number_of_descriptors() > 0) &&
+        (descriptors->GetKey(0) == *key) &&
+        descriptors->IsProperty(0)) {
+      ASSERT(descriptors->GetType(0) == FIELD);
+      return Handle<Object>(obj->FastPropertyAt(descriptors->GetFieldIndex(0)));
     }
   }
 
@@ -588,12 +589,13 @@
     int num_enum = object->NumberOfEnumProperties();
     Handle<FixedArray> storage = Factory::NewFixedArray(num_enum);
     Handle<FixedArray> sort_array = Factory::NewFixedArray(num_enum);
-    for (DescriptorReader r(object->map()->instance_descriptors());
-         !r.eos();
-         r.advance()) {
-      if (r.IsProperty() && !r.IsDontEnum()) {
-        (*storage)->set(index, r.GetKey());
-        (*sort_array)->set(index, Smi::FromInt(r.GetDetails().index()));
+    Handle<DescriptorArray> descs =
+        Handle<DescriptorArray>(object->map()->instance_descriptors());
+    for (int i = 0; i < descs->number_of_descriptors(); i++) {
+      if (descs->IsProperty(i) && !descs->IsDontEnum(i)) {
+        (*storage)->set(index, descs->GetKey(i));
+        PropertyDetails details(descs->GetDetails(i));
+        (*sort_array)->set(index, Smi::FromInt(details.index()));
         index++;
       }
     }
diff --git a/src/heap-inl.h b/src/heap-inl.h
index 3b6efed..36c6f4b 100644
--- a/src/heap-inl.h
+++ b/src/heap-inl.h
@@ -82,6 +82,8 @@
     result = code_space_->AllocateRaw(size_in_bytes);
   } else if (LO_SPACE == space) {
     result = lo_space_->AllocateRaw(size_in_bytes);
+  } else if (CELL_SPACE == space) {
+    result = cell_space_->AllocateRaw(size_in_bytes);
   } else {
     ASSERT(MAP_SPACE == space);
     result = map_space_->AllocateRaw(size_in_bytes);
@@ -107,12 +109,23 @@
 }
 
 
-Object* Heap::AllocateRawMap(int size_in_bytes) {
+Object* Heap::AllocateRawMap() {
 #ifdef DEBUG
   Counters::objs_since_last_full.Increment();
   Counters::objs_since_last_young.Increment();
 #endif
-  Object* result = map_space_->AllocateRaw(size_in_bytes);
+  Object* result = map_space_->AllocateRaw(Map::kSize);
+  if (result->IsFailure()) old_gen_exhausted_ = true;
+  return result;
+}
+
+
+Object* Heap::AllocateRawCell() {
+#ifdef DEBUG
+  Counters::objs_since_last_full.Increment();
+  Counters::objs_since_last_young.Increment();
+#endif
+  Object* result = cell_space_->AllocateRaw(JSGlobalPropertyCell::kSize);
   if (result->IsFailure()) old_gen_exhausted_ = true;
   return result;
 }
diff --git a/src/heap.cc b/src/heap.cc
index 3706159..0af3d90 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -53,6 +53,7 @@
 OldSpace* Heap::old_data_space_ = NULL;
 OldSpace* Heap::code_space_ = NULL;
 MapSpace* Heap::map_space_ = NULL;
+CellSpace* Heap::cell_space_ = NULL;
 LargeObjectSpace* Heap::lo_space_ = NULL;
 
 static const int kMinimumPromotionLimit = 2*MB;
@@ -110,7 +111,8 @@
       old_pointer_space_->Capacity() +
       old_data_space_->Capacity() +
       code_space_->Capacity() +
-      map_space_->Capacity();
+      map_space_->Capacity() +
+      cell_space_->Capacity();
 }
 
 
@@ -121,7 +123,8 @@
       old_pointer_space_->Available() +
       old_data_space_->Available() +
       code_space_->Available() +
-      map_space_->Available();
+      map_space_->Available() +
+      cell_space_->Available();
 }
 
 
@@ -130,6 +133,7 @@
          old_data_space_ != NULL &&
          code_space_ != NULL &&
          map_space_ != NULL &&
+         cell_space_ != NULL &&
          lo_space_ != NULL;
 }
 
@@ -359,6 +363,8 @@
       return code_space_->Available() >= requested_size;
     case MAP_SPACE:
       return map_space_->Available() >= requested_size;
+    case CELL_SPACE:
+      return cell_space_->Available() >= requested_size;
     case LO_SPACE:
       return lo_space_->Available() >= requested_size;
   }
@@ -595,6 +601,7 @@
 }
 #endif
 
+
 void Heap::Scavenge() {
 #ifdef DEBUG
   if (FLAG_enable_slow_asserts) VerifyNonPointerSpacePointers();
@@ -653,7 +660,7 @@
   // Copy objects reachable from weak pointers.
   GlobalHandles::IterateWeakRoots(&scavenge_visitor);
 
-#if V8_HOST_ARCH_64_BIT
+#ifdef V8_HOST_ARCH_64_BIT
   // TODO(X64): Make this go away again. We currently disable RSets for
   // 64-bit-mode.
   HeapObjectIterator old_pointer_iterator(old_pointer_space_);
@@ -673,13 +680,25 @@
       heap_object->Iterate(&scavenge_visitor);
     }
   }
-#else  // V8_HOST_ARCH_64_BIT
+#else  // !defined(V8_HOST_ARCH_64_BIT)
   // Copy objects reachable from the old generation.  By definition,
   // there are no intergenerational pointers in code or data spaces.
   IterateRSet(old_pointer_space_, &ScavengePointer);
   IterateRSet(map_space_, &ScavengePointer);
   lo_space_->IterateRSet(&ScavengePointer);
-#endif   // V8_HOST_ARCH_64_BIT
+#endif
+
+  // Copy objects reachable from cells by scavenging cell values directly.
+  HeapObjectIterator cell_iterator(cell_space_);
+  while (cell_iterator.has_next()) {
+    HeapObject* cell = cell_iterator.next();
+    if (cell->IsJSGlobalPropertyCell()) {
+      Address value_address =
+          reinterpret_cast<Address>(cell) +
+          (JSGlobalPropertyCell::kValueOffset - kHeapObjectTag);
+      scavenge_visitor.VisitPointer(reinterpret_cast<Object**>(value_address));
+    }
+  }
 
   do {
     ASSERT(new_space_front <= new_space_.top());
@@ -819,8 +838,8 @@
 
 
 void Heap::RebuildRSets() {
-  // By definition, we do not care about remembered set bits in code or data
-  // spaces.
+  // By definition, we do not care about remembered set bits in code,
+  // data, or cell spaces.
   map_space_->ClearRSet();
   RebuildRSets(map_space_);
 
@@ -995,7 +1014,7 @@
 
 Object* Heap::AllocatePartialMap(InstanceType instance_type,
                                  int instance_size) {
-  Object* result = AllocateRawMap(Map::kSize);
+  Object* result = AllocateRawMap();
   if (result->IsFailure()) return result;
 
   // Map::cast cannot be used due to uninitialized map field.
@@ -1009,7 +1028,7 @@
 
 
 Object* Heap::AllocateMap(InstanceType instance_type, int instance_size) {
-  Object* result = AllocateRawMap(Map::kSize);
+  Object* result = AllocateRawMap();
   if (result->IsFailure()) return result;
 
   Map* map = reinterpret_cast<Map*>(result);
@@ -1055,7 +1074,6 @@
 bool Heap::CreateInitialMaps() {
   Object* obj = AllocatePartialMap(MAP_TYPE, Map::kSize);
   if (obj->IsFailure()) return false;
-
   // Map::cast cannot be used due to uninitialized map field.
   Map* new_meta_map = reinterpret_cast<Map*>(obj);
   set_meta_map(new_meta_map);
@@ -1069,11 +1087,6 @@
   if (obj->IsFailure()) return false;
   set_oddball_map(Map::cast(obj));
 
-  obj = AllocatePartialMap(JS_GLOBAL_PROPERTY_CELL_TYPE,
-                           JSGlobalPropertyCell::kSize);
-  if (obj->IsFailure()) return false;
-  set_global_property_cell_map(Map::cast(obj));
-
   // Allocate the empty array
   obj = AllocateEmptyFixedArray();
   if (obj->IsFailure()) return false;
@@ -1083,11 +1096,10 @@
   if (obj->IsFailure()) return false;
   set_null_value(obj);
 
-  // Allocate the empty descriptor array.  AllocateMap can now be used.
+  // Allocate the empty descriptor array.
   obj = AllocateEmptyFixedArray();
   if (obj->IsFailure()) return false;
-  // There is a check against empty_descriptor_array() in cast().
-  set_empty_descriptor_array(reinterpret_cast<DescriptorArray*>(obj));
+  set_empty_descriptor_array(DescriptorArray::cast(obj));
 
   // Fix the instance_descriptors for the existing maps.
   meta_map()->set_instance_descriptors(empty_descriptor_array());
@@ -1099,22 +1111,16 @@
   oddball_map()->set_instance_descriptors(empty_descriptor_array());
   oddball_map()->set_code_cache(empty_fixed_array());
 
-  global_property_cell_map()->set_instance_descriptors(
-      empty_descriptor_array());
-  global_property_cell_map()->set_code_cache(empty_fixed_array());
-
   // Fix prototype object for existing maps.
   meta_map()->set_prototype(null_value());
   meta_map()->set_constructor(null_value());
 
   fixed_array_map()->set_prototype(null_value());
   fixed_array_map()->set_constructor(null_value());
+
   oddball_map()->set_prototype(null_value());
   oddball_map()->set_constructor(null_value());
 
-  global_property_cell_map()->set_prototype(null_value());
-  global_property_cell_map()->set_constructor(null_value());
-
   obj = AllocateMap(HEAP_NUMBER_TYPE, HeapNumber::kSize);
   if (obj->IsFailure()) return false;
   set_heap_number_map(Map::cast(obj));
@@ -1168,13 +1174,18 @@
   if (obj->IsFailure()) return false;
   set_code_map(Map::cast(obj));
 
+  obj = AllocateMap(JS_GLOBAL_PROPERTY_CELL_TYPE,
+                    JSGlobalPropertyCell::kSize);
+  if (obj->IsFailure()) return false;
+  set_global_property_cell_map(Map::cast(obj));
+
   obj = AllocateMap(FILLER_TYPE, kPointerSize);
   if (obj->IsFailure()) return false;
-  set_one_word_filler_map(Map::cast(obj));
+  set_one_pointer_filler_map(Map::cast(obj));
 
   obj = AllocateMap(FILLER_TYPE, 2 * kPointerSize);
   if (obj->IsFailure()) return false;
-  set_two_word_filler_map(Map::cast(obj));
+  set_two_pointer_filler_map(Map::cast(obj));
 
   for (unsigned i = 0; i < ARRAY_SIZE(struct_table); i++) {
     const StructTable& entry = struct_table[i];
@@ -1242,9 +1253,7 @@
 
 
 Object* Heap::AllocateJSGlobalPropertyCell(Object* value) {
-  Object* result = AllocateRaw(JSGlobalPropertyCell::kSize,
-                               OLD_POINTER_SPACE,
-                               OLD_POINTER_SPACE);
+  Object* result = AllocateRawCell();
   if (result->IsFailure()) return result;
   HeapObject::cast(result)->set_map(global_property_cell_map());
   JSGlobalPropertyCell::cast(result)->set_value(value);
@@ -1821,7 +1830,7 @@
   if (size == 0) return;
   HeapObject* filler = HeapObject::FromAddress(addr);
   if (size == kPointerSize) {
-    filler->set_map(Heap::one_word_filler_map());
+    filler->set_map(Heap::one_pointer_filler_map());
   } else {
     filler->set_map(Heap::byte_array_map());
     ByteArray::cast(filler)->set_length(ByteArray::LengthFor(size));
@@ -2697,6 +2706,8 @@
   code_space_->ReportStatistics();
   PrintF("Map space : ");
   map_space_->ReportStatistics();
+  PrintF("Cell space : ");
+  cell_space_->ReportStatistics();
   PrintF("Large object space : ");
   lo_space_->ReportStatistics();
   PrintF(">>>>>> ========================================= >>>>>>\n");
@@ -2717,6 +2728,7 @@
      old_data_space_->Contains(addr) ||
      code_space_->Contains(addr) ||
      map_space_->Contains(addr) ||
+     cell_space_->Contains(addr) ||
      lo_space_->SlowContains(addr));
 }
 
@@ -2741,6 +2753,8 @@
       return code_space_->Contains(addr);
     case MAP_SPACE:
       return map_space_->Contains(addr);
+    case CELL_SPACE:
+      return cell_space_->Contains(addr);
     case LO_SPACE:
       return lo_space_->SlowContains(addr);
   }
@@ -2754,12 +2768,20 @@
   ASSERT(HasBeenSetup());
 
   VerifyPointersVisitor visitor;
-  Heap::IterateRoots(&visitor);
+  IterateRoots(&visitor);
 
-  AllSpaces spaces;
-  while (Space* space = spaces.next()) {
-    space->Verify();
-  }
+  new_space_.Verify();
+
+  VerifyPointersAndRSetVisitor rset_visitor;
+  old_pointer_space_->Verify(&rset_visitor);
+  map_space_->Verify(&rset_visitor);
+
+  VerifyPointersVisitor no_rset_visitor;
+  old_data_space_->Verify(&no_rset_visitor);
+  code_space_->Verify(&no_rset_visitor);
+  cell_space_->Verify(&no_rset_visitor);
+
+  lo_space_->Verify();
 }
 #endif  // DEBUG
 
@@ -2964,6 +2986,7 @@
       + old_data_space_->Size()
       + code_space_->Size()
       + map_space_->Size()
+      + cell_space_->Size()
       + lo_space_->Size();
 }
 
@@ -3041,6 +3064,13 @@
   // enough to hold at least a page will cause it to allocate.
   if (!map_space_->Setup(NULL, 0)) return false;
 
+  // Initialize global property cell space.
+  cell_space_ = new CellSpace(old_generation_size_, CELL_SPACE);
+  if (cell_space_ == NULL) return false;
+  // Setting up a paged space without giving it a virtual memory range big
+  // enough to hold at least a page will cause it to allocate.
+  if (!cell_space_->Setup(NULL, 0)) return false;
+
   // The large object code space may contain code or data.  We set the memory
   // to be non-executable here for safety, but this means we need to enable it
   // explicitly when allocating large code objects.
@@ -3093,6 +3123,12 @@
     map_space_ = NULL;
   }
 
+  if (cell_space_ != NULL) {
+    cell_space_->TearDown();
+    delete cell_space_;
+    cell_space_ = NULL;
+  }
+
   if (lo_space_ != NULL) {
     lo_space_->TearDown();
     delete lo_space_;
@@ -3104,11 +3140,9 @@
 
 
 void Heap::Shrink() {
-  // Try to shrink map, old, and code spaces.
-  map_space_->Shrink();
-  old_pointer_space_->Shrink();
-  old_data_space_->Shrink();
-  code_space_->Shrink();
+  // Try to shrink all paged spaces.
+  PagedSpaces spaces;
+  while (PagedSpace* space = spaces.next()) space->Shrink();
 }
 
 
@@ -3116,24 +3150,16 @@
 
 void Heap::Protect() {
   if (HasBeenSetup()) {
-    new_space_.Protect();
-    map_space_->Protect();
-    old_pointer_space_->Protect();
-    old_data_space_->Protect();
-    code_space_->Protect();
-    lo_space_->Protect();
+    AllSpaces spaces;
+    while (Space* space = spaces.next()) space->Protect();
   }
 }
 
 
 void Heap::Unprotect() {
   if (HasBeenSetup()) {
-    new_space_.Unprotect();
-    map_space_->Unprotect();
-    old_pointer_space_->Unprotect();
-    old_data_space_->Unprotect();
-    code_space_->Unprotect();
-    lo_space_->Unprotect();
+    AllSpaces spaces;
+    while (Space* space = spaces.next()) space->Unprotect();
   }
 }
 
@@ -3171,6 +3197,8 @@
       return Heap::code_space();
     case MAP_SPACE:
       return Heap::map_space();
+    case CELL_SPACE:
+      return Heap::cell_space();
     case LO_SPACE:
       return Heap::lo_space();
     default:
@@ -3189,6 +3217,8 @@
       return Heap::code_space();
     case MAP_SPACE:
       return Heap::map_space();
+    case CELL_SPACE:
+      return Heap::cell_space();
     default:
       return NULL;
   }
@@ -3262,6 +3292,9 @@
     case MAP_SPACE:
       iterator_ = new HeapObjectIterator(Heap::map_space());
       break;
+    case CELL_SPACE:
+      iterator_ = new HeapObjectIterator(Heap::cell_space());
+      break;
     case LO_SPACE:
       iterator_ = new LargeObjectIterator(Heap::lo_space());
       break;
diff --git a/src/heap.h b/src/heap.h
index c88b5e6..f395988 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -105,8 +105,8 @@
   V(Map, boilerplate_function_map, BoilerplateFunctionMap)                     \
   V(Map, shared_function_info_map, SharedFunctionInfoMap)                      \
   V(Map, proxy_map, ProxyMap)                                                  \
-  V(Map, one_word_filler_map, OneWordFillerMap)                                \
-  V(Map, two_word_filler_map, TwoWordFillerMap)                                \
+  V(Map, one_pointer_filler_map, OnePointerFillerMap)                          \
+  V(Map, two_pointer_filler_map, TwoPointerFillerMap)                          \
   V(Object, nan_value, NanValue)                                               \
   V(Object, undefined_value, UndefinedValue)                                   \
   V(Object, minus_zero_value, MinusZeroValue)                                  \
@@ -263,6 +263,7 @@
   static OldSpace* old_data_space() { return old_data_space_; }
   static OldSpace* code_space() { return code_space_; }
   static MapSpace* map_space() { return map_space_; }
+  static CellSpace* cell_space() { return cell_space_; }
   static LargeObjectSpace* lo_space() { return lo_space_; }
 
   static bool always_allocate() { return always_allocate_scope_depth_ != 0; }
@@ -852,6 +853,7 @@
   static OldSpace* old_data_space_;
   static OldSpace* code_space_;
   static MapSpace* map_space_;
+  static CellSpace* cell_space_;
   static LargeObjectSpace* lo_space_;
   static HeapState gc_state_;
 
@@ -975,7 +977,10 @@
   // to Heap::AllocateRaw(size_in_bytes, MAP_SPACE), except that (a) it doesn't
   // have to test the allocation space argument and (b) can reduce code size
   // (since both AllocateRaw and AllocateRawMap are inlined).
-  static inline Object* AllocateRawMap(int size_in_bytes);
+  static inline Object* AllocateRawMap();
+
+  // Allocate an uninitialized object in the global property cell space.
+  static inline Object* AllocateRawCell();
 
   // Initializes a JSObject based on its map.
   static void InitializeJSObjectFromMap(JSObject* obj,
diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc
index 3b2eaa0..6d1dc2d 100644
--- a/src/ia32/codegen-ia32.cc
+++ b/src/ia32/codegen-ia32.cc
@@ -7591,6 +7591,16 @@
     __ dec(Operand::StaticVariable(scope_depth));
   }
 
+  // Make sure we're not trying to return 'the hole' from the runtime
+  // call as this may lead to crashes in the IC code later.
+  if (FLAG_debug_code) {
+    Label okay;
+    __ cmp(eax, Factory::the_hole_value());
+    __ j(not_equal, &okay);
+    __ int3();
+    __ bind(&okay);
+  }
+
   // Check for failure result.
   Label failure_returned;
   ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0);
diff --git a/src/ia32/ic-ia32.cc b/src/ia32/ic-ia32.cc
index 97de4da..90e0fd1 100644
--- a/src/ia32/ic-ia32.cc
+++ b/src/ia32/ic-ia32.cc
@@ -75,6 +75,12 @@
   __ cmp(r0, JS_GLOBAL_PROXY_TYPE);
   __ j(equal, miss_label, not_taken);
 
+  // Possible work-around for http://crbug.com/16276.
+  __ cmp(r0, JS_GLOBAL_OBJECT_TYPE);
+  __ j(equal, miss_label, not_taken);
+  __ cmp(r0, JS_BUILTINS_OBJECT_TYPE);
+  __ j(equal, miss_label, not_taken);
+
   // Check that the properties array is a dictionary.
   __ mov(r0, FieldOperand(r1, JSObject::kPropertiesOffset));
   __ cmp(FieldOperand(r0, HeapObject::kMapOffset),
diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc
index 2ee826e..0a887d5 100644
--- a/src/ia32/stub-cache-ia32.cc
+++ b/src/ia32/stub-cache-ia32.cc
@@ -273,114 +273,6 @@
 }
 
 
-void StubCompiler::GenerateLoadField(MacroAssembler* masm,
-                                     JSObject* object,
-                                     JSObject* holder,
-                                     Register receiver,
-                                     Register scratch1,
-                                     Register scratch2,
-                                     int index,
-                                     Label* miss_label) {
-  // Check that the receiver isn't a smi.
-  __ test(receiver, Immediate(kSmiTagMask));
-  __ j(zero, miss_label, not_taken);
-
-  // Check that the maps haven't changed.
-  Register reg =
-      masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
-
-  // Get the value from the properties.
-  GenerateFastPropertyLoad(masm, eax, reg, holder, index);
-  __ ret(0);
-}
-
-
-void StubCompiler::GenerateLoadCallback(MacroAssembler* masm,
-                                        JSObject* object,
-                                        JSObject* holder,
-                                        Register receiver,
-                                        Register name,
-                                        Register scratch1,
-                                        Register scratch2,
-                                        AccessorInfo* callback,
-                                        Label* miss_label) {
-  // Check that the receiver isn't a smi.
-  __ test(receiver, Immediate(kSmiTagMask));
-  __ j(zero, miss_label, not_taken);
-
-  // Check that the maps haven't changed.
-  Register reg =
-      masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
-
-  // Push the arguments on the JS stack of the caller.
-  __ pop(scratch2);  // remove return address
-  __ push(receiver);  // receiver
-  __ push(Immediate(Handle<AccessorInfo>(callback)));  // callback data
-  __ push(name);  // name
-  __ push(reg);  // holder
-  __ push(scratch2);  // restore return address
-
-  // Do tail-call to the runtime system.
-  ExternalReference load_callback_property =
-      ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
-  __ TailCallRuntime(load_callback_property, 4);
-}
-
-
-void StubCompiler::GenerateLoadConstant(MacroAssembler* masm,
-                                        JSObject* object,
-                                        JSObject* holder,
-                                        Register receiver,
-                                        Register scratch1,
-                                        Register scratch2,
-                                        Object* value,
-                                        Label* miss_label) {
-  // Check that the receiver isn't a smi.
-  __ test(receiver, Immediate(kSmiTagMask));
-  __ j(zero, miss_label, not_taken);
-
-  // Check that the maps haven't changed.
-  Register reg =
-      masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
-
-  // Return the constant value.
-  __ mov(eax, Handle<Object>(value));
-  __ ret(0);
-}
-
-
-void StubCompiler::GenerateLoadInterceptor(MacroAssembler* masm,
-                                           JSObject* object,
-                                           JSObject* holder,
-                                           Smi* lookup_hint,
-                                           Register receiver,
-                                           Register name,
-                                           Register scratch1,
-                                           Register scratch2,
-                                           Label* miss_label) {
-  // Check that the receiver isn't a smi.
-  __ test(receiver, Immediate(kSmiTagMask));
-  __ j(zero, miss_label, not_taken);
-
-  // Check that the maps haven't changed.
-  Register reg =
-      masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
-
-  // Push the arguments on the JS stack of the caller.
-  __ pop(scratch2);  // remove return address
-  __ push(receiver);  // receiver
-  __ push(reg);  // holder
-  __ push(name);  // name
-  // TODO(367): Maybe don't push lookup_hint for LOOKUP_IN_HOLDER and/or
-  // LOOKUP_IN_PROTOTYPE, but use a special version of lookup method?
-  __ push(Immediate(lookup_hint));
-  __ push(scratch2);  // restore return address
-
-  // Do tail-call to the runtime system.
-  ExternalReference load_ic_property =
-      ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
-  __ TailCallRuntime(load_ic_property, 4);
-}
 
 
 void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
@@ -474,10 +366,159 @@
 
 
 #undef __
-
 #define __ ACCESS_MASM(masm())
 
 
+Register StubCompiler::CheckPrototypes(JSObject* object,
+                                       Register object_reg,
+                                       JSObject* holder,
+                                       Register holder_reg,
+                                       Register scratch,
+                                       String* name,
+                                       Label* miss) {
+  // Check that the maps haven't changed.
+  Register result =
+      masm()->CheckMaps(object, object_reg, holder, holder_reg, scratch, miss);
+
+  // If we've skipped any global objects, it's not enough to verify
+  // that their maps haven't changed.
+  while (object != holder) {
+    if (object->IsGlobalObject()) {
+      GlobalObject* global = GlobalObject::cast(object);
+      Object* probe = global->EnsurePropertyCell(name);
+      if (probe->IsFailure()) {
+        set_failure(Failure::cast(probe));
+        return result;
+      }
+      JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe);
+      ASSERT(cell->value()->IsTheHole());
+      __ mov(scratch, Immediate(Handle<Object>(cell)));
+      __ cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset),
+             Immediate(Factory::the_hole_value()));
+      __ j(not_equal, miss, not_taken);
+    }
+    object = JSObject::cast(object->GetPrototype());
+  }
+
+  // Return the register containin the holder.
+  return result;
+}
+
+
+void StubCompiler::GenerateLoadField(JSObject* object,
+                                     JSObject* holder,
+                                     Register receiver,
+                                     Register scratch1,
+                                     Register scratch2,
+                                     int index,
+                                     String* name,
+                                     Label* miss) {
+  // Check that the receiver isn't a smi.
+  __ test(receiver, Immediate(kSmiTagMask));
+  __ j(zero, miss, not_taken);
+
+  // Check the prototype chain.
+  Register reg =
+      CheckPrototypes(object, receiver, holder,
+                      scratch1, scratch2, name, miss);
+
+  // Get the value from the properties.
+  GenerateFastPropertyLoad(masm(), eax, reg, holder, index);
+  __ ret(0);
+}
+
+
+void StubCompiler::GenerateLoadCallback(JSObject* object,
+                                        JSObject* holder,
+                                        Register receiver,
+                                        Register name_reg,
+                                        Register scratch1,
+                                        Register scratch2,
+                                        AccessorInfo* callback,
+                                        String* name,
+                                        Label* miss) {
+  // Check that the receiver isn't a smi.
+  __ test(receiver, Immediate(kSmiTagMask));
+  __ j(zero, miss, not_taken);
+
+  // Check that the maps haven't changed.
+  Register reg =
+      CheckPrototypes(object, receiver, holder,
+                      scratch1, scratch2, name, miss);
+
+  // Push the arguments on the JS stack of the caller.
+  __ pop(scratch2);  // remove return address
+  __ push(receiver);  // receiver
+  __ push(Immediate(Handle<AccessorInfo>(callback)));  // callback data
+  __ push(name_reg);  // name
+  __ push(reg);  // holder
+  __ push(scratch2);  // restore return address
+
+  // Do tail-call to the runtime system.
+  ExternalReference load_callback_property =
+      ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
+  __ TailCallRuntime(load_callback_property, 4);
+}
+
+
+void StubCompiler::GenerateLoadConstant(JSObject* object,
+                                        JSObject* holder,
+                                        Register receiver,
+                                        Register scratch1,
+                                        Register scratch2,
+                                        Object* value,
+                                        String* name,
+                                        Label* miss) {
+  // Check that the receiver isn't a smi.
+  __ test(receiver, Immediate(kSmiTagMask));
+  __ j(zero, miss, not_taken);
+
+  // Check that the maps haven't changed.
+  Register reg =
+      CheckPrototypes(object, receiver, holder,
+                      scratch1, scratch2, name, miss);
+
+  // Return the constant value.
+  __ mov(eax, Handle<Object>(value));
+  __ ret(0);
+}
+
+
+void StubCompiler::GenerateLoadInterceptor(JSObject* object,
+                                           JSObject* holder,
+                                           Smi* lookup_hint,
+                                           Register receiver,
+                                           Register name_reg,
+                                           Register scratch1,
+                                           Register scratch2,
+                                           String* name,
+                                           Label* miss) {
+  // Check that the receiver isn't a smi.
+  __ test(receiver, Immediate(kSmiTagMask));
+  __ j(zero, miss, not_taken);
+
+  // Check that the maps haven't changed.
+  Register reg =
+      CheckPrototypes(object, receiver, holder,
+                      scratch1, scratch2, name, miss);
+
+  // Push the arguments on the JS stack of the caller.
+  __ pop(scratch2);  // remove return address
+  __ push(receiver);  // receiver
+  __ push(reg);  // holder
+  __ push(name_reg);  // name
+  // TODO(367): Maybe don't push lookup_hint for LOOKUP_IN_HOLDER and/or
+  // LOOKUP_IN_PROTOTYPE, but use a special version of lookup method?
+  __ push(Immediate(lookup_hint));
+  __ push(scratch2);  // restore return address
+
+  // Do tail-call to the runtime system.
+  ExternalReference load_ic_property =
+      ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
+  __ TailCallRuntime(load_ic_property, 4);
+}
+
+
 // TODO(1241006): Avoid having lazy compile stubs specialized by the
 // number of arguments. It is not needed anymore.
 Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
@@ -520,7 +561,8 @@
 
   // Do the right check and compute the holder register.
   Register reg =
-      masm()->CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
+      CheckPrototypes(JSObject::cast(object), edx, holder,
+                      ebx, ecx, name, &miss);
 
   GenerateFastPropertyLoad(masm(), edi, reg, holder, index);
 
@@ -553,6 +595,7 @@
 Object* CallStubCompiler::CompileCallConstant(Object* object,
                                               JSObject* holder,
                                               JSFunction* function,
+                                              String* name,
                                               CheckType check) {
   // ----------- S t a t e -------------
   // -----------------------------------
@@ -575,7 +618,8 @@
   switch (check) {
     case RECEIVER_MAP_CHECK:
       // Check that the maps haven't changed.
-      __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
+      CheckPrototypes(JSObject::cast(object), edx, holder,
+                      ebx, ecx, name, &miss);
 
       // Patch the receiver on the stack with the global proxy if
       // necessary.
@@ -595,8 +639,8 @@
       GenerateLoadGlobalFunctionPrototype(masm(),
                                           Context::STRING_FUNCTION_INDEX,
                                           ecx);
-      __ CheckMaps(JSObject::cast(object->GetPrototype()),
-                   ecx, holder, ebx, edx, &miss);
+      CheckPrototypes(JSObject::cast(object->GetPrototype()), ecx, holder,
+                      ebx, edx, name, &miss);
       break;
 
     case NUMBER_CHECK: {
@@ -611,8 +655,8 @@
       GenerateLoadGlobalFunctionPrototype(masm(),
                                           Context::NUMBER_FUNCTION_INDEX,
                                           ecx);
-      __ CheckMaps(JSObject::cast(object->GetPrototype()),
-                   ecx, holder, ebx, edx, &miss);
+      CheckPrototypes(JSObject::cast(object->GetPrototype()), ecx, holder,
+                      ebx, edx, name, &miss);
       break;
     }
 
@@ -628,13 +672,14 @@
       GenerateLoadGlobalFunctionPrototype(masm(),
                                           Context::BOOLEAN_FUNCTION_INDEX,
                                           ecx);
-      __ CheckMaps(JSObject::cast(object->GetPrototype()),
-                   ecx, holder, ebx, edx, &miss);
+      CheckPrototypes(JSObject::cast(object->GetPrototype()), ecx, holder,
+                      ebx, edx, name, &miss);
       break;
     }
 
     case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
-      __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
+      CheckPrototypes(JSObject::cast(object), edx, holder,
+                      ebx, ecx, name, &miss);
       // Make sure object->elements()->map() != Heap::dictionary_array_map()
       // Get the elements array of the object.
       __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
@@ -692,7 +737,8 @@
 
   // Check that maps have not changed and compute the holder register.
   Register reg =
-      masm()->CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
+      CheckPrototypes(JSObject::cast(object), edx, holder,
+                      ebx, ecx, name, &miss);
 
   // Enter an internal frame.
   __ EnterInternalFrame();
@@ -745,7 +791,8 @@
 }
 
 
-Object* CallStubCompiler::CompileCallGlobal(GlobalObject* object,
+Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
+                                            GlobalObject* holder,
                                             JSGlobalPropertyCell* cell,
                                             JSFunction* function,
                                             String* name) {
@@ -758,11 +805,19 @@
   // Get the number of arguments.
   const int argc = arguments().immediate();
 
-  // Check that the map of the global has not changed.
+  // Get the receiver from the stack.
   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
-  __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
-         Immediate(Handle<Map>(object->map())));
-  __ j(not_equal, &miss, not_taken);
+
+  // If the object is the holder then we know that it's a global
+  // object which can only happen for contextual calls. In this case,
+  // the receiver cannot be a smi.
+  if (object != holder) {
+    __ test(edx, Immediate(kSmiTagMask));
+    __ j(zero, &miss, not_taken);
+  }
+
+  // Check that the maps haven't changed.
+  CheckPrototypes(object, edx, holder, ebx, ecx, name, &miss);
 
   // Get the value from the cell.
   __ mov(edi, Immediate(Handle<JSGlobalPropertyCell>(cell)));
@@ -773,8 +828,10 @@
   __ j(not_equal, &miss, not_taken);
 
   // Patch the receiver on the stack with the global proxy.
-  __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
-  __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
+  if (object->IsGlobalObject()) {
+    __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
+    __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
+  }
 
   // Setup the context (function already in edi).
   __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
@@ -964,11 +1021,6 @@
   __ mov(ecx, Immediate(Handle<JSGlobalPropertyCell>(cell)));
   __ mov(FieldOperand(ecx, JSGlobalPropertyCell::kValueOffset), eax);
 
-  // RecordWrite clobbers the value register. Pass the value being stored in
-  // edx.
-  __ mov(edx, eax);
-  __ RecordWrite(ecx, JSGlobalPropertyCell::kValueOffset, edx, ebx);
-
   // Return the value (register eax).
   __ ret(0);
 
@@ -1027,6 +1079,7 @@
 }
 
 
+
 Object* LoadStubCompiler::CompileLoadField(JSObject* object,
                                            JSObject* holder,
                                            int index,
@@ -1039,7 +1092,7 @@
   Label miss;
 
   __ mov(eax, (Operand(esp, kPointerSize)));
-  GenerateLoadField(masm(), object, holder, eax, ebx, edx, index, &miss);
+  GenerateLoadField(object, holder, eax, ebx, edx, index, name, &miss);
   __ bind(&miss);
   GenerateLoadMiss(masm(), Code::LOAD_IC);
 
@@ -1060,8 +1113,8 @@
   Label miss;
 
   __ mov(eax, (Operand(esp, kPointerSize)));
-  GenerateLoadCallback(masm(), object, holder, eax, ecx, ebx,
-                       edx, callback, &miss);
+  GenerateLoadCallback(object, holder, eax, ecx, ebx, edx,
+                       callback, name, &miss);
   __ bind(&miss);
   GenerateLoadMiss(masm(), Code::LOAD_IC);
 
@@ -1082,7 +1135,7 @@
   Label miss;
 
   __ mov(eax, (Operand(esp, kPointerSize)));
-  GenerateLoadConstant(masm(), object, holder, eax, ebx, edx, value, &miss);
+  GenerateLoadConstant(object, holder, eax, ebx, edx, value, name, &miss);
   __ bind(&miss);
   GenerateLoadMiss(masm(), Code::LOAD_IC);
 
@@ -1104,14 +1157,14 @@
   __ mov(eax, (Operand(esp, kPointerSize)));
   // TODO(368): Compile in the whole chain: all the interceptors in
   // prototypes and ultimate answer.
-  GenerateLoadInterceptor(masm(),
-                          receiver,
+  GenerateLoadInterceptor(receiver,
                           holder,
                           holder->InterceptorPropertyLookupHint(name),
                           eax,
                           ecx,
                           edx,
                           ebx,
+                          name,
                           &miss);
 
   __ bind(&miss);
@@ -1122,7 +1175,8 @@
 }
 
 
-Object* LoadStubCompiler::CompileLoadGlobal(GlobalObject* object,
+Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
+                                            GlobalObject* holder,
                                             JSGlobalPropertyCell* cell,
                                             String* name,
                                             bool is_dont_delete) {
@@ -1135,11 +1189,19 @@
 
   __ IncrementCounter(&Counters::named_load_global_inline, 1);
 
-  // Check that the map of the global has not changed.
+  // Get the receiver from the stack.
   __ mov(eax, (Operand(esp, kPointerSize)));
-  __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
-         Immediate(Handle<Map>(object->map())));
-  __ j(not_equal, &miss, not_taken);
+
+  // If the object is the holder then we know that it's a global
+  // object which can only happen for contextual loads. In this case,
+  // the receiver cannot be a smi.
+  if (object != holder) {
+    __ test(eax, Immediate(kSmiTagMask));
+    __ j(zero, &miss, not_taken);
+  }
+
+  // Check that the maps haven't changed.
+  CheckPrototypes(object, eax, holder, ebx, edx, name, &miss);
 
   // Get the value from the cell.
   __ mov(eax, Immediate(Handle<JSGlobalPropertyCell>(cell)));
@@ -1185,7 +1247,8 @@
   __ cmp(Operand(eax), Immediate(Handle<String>(name)));
   __ j(not_equal, &miss, not_taken);
 
-  GenerateLoadField(masm(), receiver, holder, ecx, ebx, edx, index, &miss);
+  GenerateLoadField(receiver, holder, ecx, ebx, edx, index, name, &miss);
+
   __ bind(&miss);
   __ DecrementCounter(&Counters::keyed_load_field, 1);
   GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
@@ -1214,8 +1277,8 @@
   __ cmp(Operand(eax), Immediate(Handle<String>(name)));
   __ j(not_equal, &miss, not_taken);
 
-  GenerateLoadCallback(masm(), receiver, holder, ecx, eax, ebx, edx,
-                       callback, &miss);
+  GenerateLoadCallback(receiver, holder, ecx, eax, ebx, edx,
+                       callback, name, &miss);
   __ bind(&miss);
   __ DecrementCounter(&Counters::keyed_load_callback, 1);
   GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
@@ -1244,7 +1307,8 @@
   __ cmp(Operand(eax), Immediate(Handle<String>(name)));
   __ j(not_equal, &miss, not_taken);
 
-  GenerateLoadConstant(masm(), receiver, holder, ecx, ebx, edx, value, &miss);
+  GenerateLoadConstant(receiver, holder, ecx, ebx, edx,
+                       value, name, &miss);
   __ bind(&miss);
   __ DecrementCounter(&Counters::keyed_load_constant_function, 1);
   GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
@@ -1272,14 +1336,14 @@
   __ cmp(Operand(eax), Immediate(Handle<String>(name)));
   __ j(not_equal, &miss, not_taken);
 
-  GenerateLoadInterceptor(masm(),
-                          receiver,
+  GenerateLoadInterceptor(receiver,
                           holder,
                           Smi::FromInt(JSObject::kLookupInHolder),
                           ecx,
                           eax,
                           edx,
                           ebx,
+                          name,
                           &miss);
   __ bind(&miss);
   __ DecrementCounter(&Counters::keyed_load_interceptor, 1);
diff --git a/src/ic.cc b/src/ic.cc
index dfdf722..7e82295 100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -327,13 +327,11 @@
     return TypeError("non_object_property_call", object, name);
   }
 
-  Object* result = Heap::the_hole_value();
-
   // Check if the name is trivially convertible to an index and get
   // the element if so.
   uint32_t index;
   if (name->AsArrayIndex(&index)) {
-    result = object->GetElement(index);
+    Object* result = object->GetElement(index);
     if (result->IsJSFunction()) return result;
 
     // Try to find a suitable function delegate for the object at hand.
@@ -363,7 +361,7 @@
 
   // Get the property.
   PropertyAttributes attr;
-  result = object->GetProperty(*object, &lookup, *name, &attr);
+  Object* result = object->GetProperty(*object, &lookup, *name, &attr);
   if (result->IsFailure()) return result;
   if (lookup.type() == INTERCEPTOR) {
     // If the object does not have the requested property, check which
@@ -397,7 +395,7 @@
       // cause GC.
       HandleScope scope;
       Handle<JSFunction> function(JSFunction::cast(result));
-      Debug::HandleStepIn(function, fp(), false);
+      Debug::HandleStepIn(function, object, fp(), false);
       return *function;
     }
 #endif
@@ -452,24 +450,26 @@
       }
       case NORMAL: {
         if (!object->IsJSObject()) return;
-        if (object->IsGlobalObject()) {
-          // The stub generated for the global object picks the value directly
-          // from the property cell. So the property must be directly on the
-          // global object.
-          Handle<GlobalObject> global = Handle<GlobalObject>::cast(object);
-          if (lookup->holder() != *global) return;
+        Handle<JSObject> receiver = Handle<JSObject>::cast(object);
+
+        if (lookup->holder()->IsGlobalObject()) {
+          GlobalObject* global = GlobalObject::cast(lookup->holder());
           JSGlobalPropertyCell* cell =
               JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
           if (!cell->value()->IsJSFunction()) return;
           JSFunction* function = JSFunction::cast(cell->value());
-          code = StubCache::ComputeCallGlobal(argc, in_loop, *name, *global,
-                                              cell, function);
+          code = StubCache::ComputeCallGlobal(argc,
+                                              in_loop,
+                                              *name,
+                                              *receiver,
+                                              global,
+                                              cell,
+                                              function);
         } else {
           // There is only one shared stub for calling normalized
           // properties. It does not traverse the prototype chain, so the
           // property must be found in the receiver for the stub to be
           // applicable.
-          Handle<JSObject> receiver = Handle<JSObject>::cast(object);
           if (lookup->holder() != *receiver) return;
           code = StubCache::ComputeCallNormal(argc, in_loop, *name, *receiver);
         }
@@ -657,16 +657,15 @@
         break;
       }
       case NORMAL: {
-        if (object->IsGlobalObject()) {
-          // The stub generated for the global object picks the value directly
-          // from the property cell. So the property must be directly on the
-          // global object.
-          Handle<GlobalObject> global = Handle<GlobalObject>::cast(object);
-          if (lookup->holder() != *global) return;
+        if (lookup->holder()->IsGlobalObject()) {
+          GlobalObject* global = GlobalObject::cast(lookup->holder());
           JSGlobalPropertyCell* cell =
               JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
-          code = StubCache::ComputeLoadGlobal(*name, *global,
-                                              cell, lookup->IsDontDelete());
+          code = StubCache::ComputeLoadGlobal(*name,
+                                              *receiver,
+                                              global,
+                                              cell,
+                                              lookup->IsDontDelete());
         } else {
           // There is only one shared stub for loading normalized
           // properties. It does not traverse the prototype chain, so the
diff --git a/src/mark-compact.cc b/src/mark-compact.cc
index 8ab0264..6e823b3 100644
--- a/src/mark-compact.cc
+++ b/src/mark-compact.cc
@@ -56,6 +56,7 @@
 int MarkCompactCollector::live_old_pointer_objects_ = 0;
 int MarkCompactCollector::live_code_objects_ = 0;
 int MarkCompactCollector::live_map_objects_ = 0;
+int MarkCompactCollector::live_cell_objects_ = 0;
 int MarkCompactCollector::live_lo_objects_ = 0;
 #endif
 
@@ -155,6 +156,7 @@
   live_old_data_objects_ = 0;
   live_code_objects_ = 0;
   live_map_objects_ = 0;
+  live_cell_objects_ = 0;
   live_lo_objects_ = 0;
 #endif
 }
@@ -710,6 +712,10 @@
   ScanOverflowedObjects(&map_it);
   if (marking_stack.is_full()) return;
 
+  HeapObjectIterator cell_it(Heap::cell_space(), &OverflowObjectSize);
+  ScanOverflowedObjects(&cell_it);
+  if (marking_stack.is_full()) return;
+
   LargeObjectIterator lo_it(Heap::lo_space(), &OverflowObjectSize);
   ScanOverflowedObjects(&lo_it);
   if (marking_stack.is_full()) return;
@@ -809,6 +815,9 @@
   } else if (Heap::map_space()->Contains(obj)) {
     ASSERT(obj->IsMap());
     live_map_objects_++;
+  } else if (Heap::cell_space()->Contains(obj)) {
+    ASSERT(obj->IsJSGlobalPropertyCell());
+    live_cell_objects_++;
   } else if (Heap::old_pointer_space()->Contains(obj)) {
     live_old_pointer_objects_++;
   } else if (Heap::old_data_space()->Contains(obj)) {
@@ -968,27 +977,32 @@
 
 
 // Allocation functions for the paged spaces call the space's MCAllocateRaw.
-inline Object* MCAllocateFromOldPointerSpace(HeapObject* object,
+inline Object* MCAllocateFromOldPointerSpace(HeapObject* ignore,
                                              int object_size) {
   return Heap::old_pointer_space()->MCAllocateRaw(object_size);
 }
 
 
-inline Object* MCAllocateFromOldDataSpace(HeapObject* object, int object_size) {
+inline Object* MCAllocateFromOldDataSpace(HeapObject* ignore, int object_size) {
   return Heap::old_data_space()->MCAllocateRaw(object_size);
 }
 
 
-inline Object* MCAllocateFromCodeSpace(HeapObject* object, int object_size) {
+inline Object* MCAllocateFromCodeSpace(HeapObject* ignore, int object_size) {
   return Heap::code_space()->MCAllocateRaw(object_size);
 }
 
 
-inline Object* MCAllocateFromMapSpace(HeapObject* object, int object_size) {
+inline Object* MCAllocateFromMapSpace(HeapObject* ignore, int object_size) {
   return Heap::map_space()->MCAllocateRaw(object_size);
 }
 
 
+inline Object* MCAllocateFromCellSpace(HeapObject* ignore, int object_size) {
+  return Heap::cell_space()->MCAllocateRaw(object_size);
+}
+
+
 // The forwarding address is encoded at the same offset as the current
 // to-space object, but in from space.
 inline void EncodeForwardingAddressInNewSpace(HeapObject* old_object,
@@ -1147,7 +1161,7 @@
         ByteArray::cast(object)->set_length(ByteArray::LengthFor(size));
       } else {
         ASSERT(size == kPointerSize);
-        object->set_map(Heap::raw_unchecked_one_word_filler_map());
+        object->set_map(Heap::raw_unchecked_one_pointer_filler_map());
       }
       ASSERT(object->Size() == size);
     }
@@ -1197,8 +1211,8 @@
       // loop.
     }
 
-    // If the last region was not live we need to from free_start to the
-    // allocation top in the page.
+    // If the last region was not live we need to deallocate from
+    // free_start to the allocation top in the page.
     if (!is_previous_alive) {
       int free_size = p->AllocationTop() - free_start;
       if (free_size > 0) {
@@ -1242,6 +1256,21 @@
 }
 
 
+void MarkCompactCollector::DeallocateCellBlock(Address start,
+                                               int size_in_bytes) {
+  // Free-list elements in cell space are assumed to have a fixed size.
+  // We break the free block into chunks and add them to the free list
+  // individually.
+  int size = Heap::cell_space()->object_size_in_bytes();
+  ASSERT(size_in_bytes % size == 0);
+  Heap::ClearRSetRange(start, size_in_bytes);
+  Address end = start + size_in_bytes;
+  for (Address a = start; a < end; a += size) {
+    Heap::cell_space()->Free(a);
+  }
+}
+
+
 void MarkCompactCollector::EncodeForwardingAddresses() {
   ASSERT(state_ == ENCODE_FORWARDING_ADDRESSES);
   // Objects in the active semispace of the young generation may be
@@ -1262,6 +1291,11 @@
                                         LogNonLiveCodeObject>(
       Heap::code_space());
 
+  EncodeForwardingAddressesInPagedSpace<MCAllocateFromCellSpace,
+                                        IgnoreNonLiveObject>(
+      Heap::cell_space());
+
+
   // Compute new space next to last after the old and code spaces have been
   // compacted.  Objects in new space can be promoted to old or code space.
   EncodeForwardingAddressesInNewSpace();
@@ -1280,6 +1314,7 @@
   Heap::old_data_space()->MCWriteRelocationInfoToPage();
   Heap::code_space()->MCWriteRelocationInfoToPage();
   Heap::map_space()->MCWriteRelocationInfoToPage();
+  Heap::cell_space()->MCWriteRelocationInfoToPage();
 }
 
 
@@ -1294,6 +1329,7 @@
   SweepSpace(Heap::old_pointer_space(), &DeallocateOldPointerBlock);
   SweepSpace(Heap::old_data_space(), &DeallocateOldDataBlock);
   SweepSpace(Heap::code_space(), &DeallocateCodeBlock);
+  SweepSpace(Heap::cell_space(), &DeallocateCellBlock);
   SweepSpace(Heap::new_space());
   SweepSpace(Heap::map_space(), &DeallocateMapBlock);
 }
@@ -1372,15 +1408,16 @@
     ASSERT(!Heap::InFromSpace(obj));
 
     if (Heap::new_space()->Contains(obj)) {
-      Address f_addr = Heap::new_space()->FromSpaceLow() +
-                       Heap::new_space()->ToSpaceOffsetForAddress(old_addr);
-      new_addr = Memory::Address_at(f_addr);
+      Address forwarding_pointer_addr =
+          Heap::new_space()->FromSpaceLow() +
+          Heap::new_space()->ToSpaceOffsetForAddress(old_addr);
+      new_addr = Memory::Address_at(forwarding_pointer_addr);
 
 #ifdef DEBUG
       ASSERT(Heap::old_pointer_space()->Contains(new_addr) ||
              Heap::old_data_space()->Contains(new_addr) ||
-             Heap::code_space()->Contains(new_addr) ||
-             Heap::new_space()->FromSpaceContains(new_addr));
+             Heap::new_space()->FromSpaceContains(new_addr) ||
+             Heap::lo_space()->Contains(HeapObject::FromAddress(new_addr)));
 
       if (Heap::new_space()->FromSpaceContains(new_addr)) {
         ASSERT(Heap::new_space()->FromSpaceOffsetForAddress(new_addr) <=
@@ -1393,32 +1430,19 @@
       return;
 
     } else {
-      ASSERT(Heap::old_pointer_space()->Contains(obj) ||
-             Heap::old_data_space()->Contains(obj) ||
-             Heap::code_space()->Contains(obj) ||
-             Heap::map_space()->Contains(obj));
-
-      new_addr = MarkCompactCollector::GetForwardingAddressInOldSpace(obj);
-      ASSERT(Heap::old_pointer_space()->Contains(new_addr) ||
-             Heap::old_data_space()->Contains(new_addr) ||
-             Heap::code_space()->Contains(new_addr) ||
-             Heap::map_space()->Contains(new_addr));
-
 #ifdef DEBUG
-      if (Heap::old_pointer_space()->Contains(obj)) {
-        ASSERT(Heap::old_pointer_space()->MCSpaceOffsetForAddress(new_addr) <=
-               Heap::old_pointer_space()->MCSpaceOffsetForAddress(old_addr));
-      } else if (Heap::old_data_space()->Contains(obj)) {
-        ASSERT(Heap::old_data_space()->MCSpaceOffsetForAddress(new_addr) <=
-               Heap::old_data_space()->MCSpaceOffsetForAddress(old_addr));
-      } else if (Heap::code_space()->Contains(obj)) {
-        ASSERT(Heap::code_space()->MCSpaceOffsetForAddress(new_addr) <=
-               Heap::code_space()->MCSpaceOffsetForAddress(old_addr));
-      } else {
-        ASSERT(Heap::map_space()->MCSpaceOffsetForAddress(new_addr) <=
-               Heap::map_space()->MCSpaceOffsetForAddress(old_addr));
+      PagedSpaces spaces;
+      PagedSpace* original_space = spaces.next();
+      while (original_space != NULL) {
+        if (original_space->Contains(obj)) break;
+        original_space = spaces.next();
       }
+      ASSERT(original_space != NULL);
 #endif
+      new_addr = MarkCompactCollector::GetForwardingAddressInOldSpace(obj);
+      ASSERT(original_space->Contains(new_addr));
+      ASSERT(original_space->MCSpaceOffsetForAddress(new_addr) <=
+             original_space->MCSpaceOffsetForAddress(old_addr));
     }
 
     *p = HeapObject::FromAddress(new_addr);
@@ -1450,6 +1474,8 @@
                                           &UpdatePointersInOldObject);
   int live_codes = IterateLiveObjects(Heap::code_space(),
                                       &UpdatePointersInOldObject);
+  int live_cells = IterateLiveObjects(Heap::cell_space(),
+                                      &UpdatePointersInOldObject);
   int live_news = IterateLiveObjects(Heap::new_space(),
                                      &UpdatePointersInNewObject);
 
@@ -1461,15 +1487,14 @@
   USE(live_pointer_olds);
   USE(live_data_olds);
   USE(live_codes);
+  USE(live_cells);
   USE(live_news);
-
-#ifdef DEBUG
   ASSERT(live_maps == live_map_objects_);
   ASSERT(live_data_olds == live_old_data_objects_);
   ASSERT(live_pointer_olds == live_old_pointer_objects_);
   ASSERT(live_codes == live_code_objects_);
+  ASSERT(live_cells == live_cell_objects_);
   ASSERT(live_news == live_young_objects_);
-#endif
 }
 
 
@@ -1590,30 +1615,31 @@
   int live_data_olds = IterateLiveObjects(Heap::old_data_space(),
                                           &RelocateOldDataObject);
   int live_codes = IterateLiveObjects(Heap::code_space(), &RelocateCodeObject);
+  int live_cells = IterateLiveObjects(Heap::cell_space(), &RelocateCellObject);
   int live_news = IterateLiveObjects(Heap::new_space(), &RelocateNewObject);
 
   USE(live_maps);
   USE(live_data_olds);
   USE(live_pointer_olds);
   USE(live_codes);
+  USE(live_cells);
   USE(live_news);
-#ifdef DEBUG
   ASSERT(live_maps == live_map_objects_);
   ASSERT(live_data_olds == live_old_data_objects_);
   ASSERT(live_pointer_olds == live_old_pointer_objects_);
   ASSERT(live_codes == live_code_objects_);
+  ASSERT(live_cells == live_cell_objects_);
   ASSERT(live_news == live_young_objects_);
-#endif
 
   // Notify code object in LO to convert IC target to address
   // This must happen after lo_space_->Compact
   LargeObjectIterator it(Heap::lo_space());
   while (it.has_next()) { ConvertCodeICTargetToAddress(it.next()); }
 
-  // Flips from and to spaces
+  // Flip from and to spaces
   Heap::new_space()->Flip();
 
-  // Sets age_mark to bottom in to space
+  // Set age_mark to bottom in to space
   Address mark = Heap::new_space()->bottom();
   Heap::new_space()->set_age_mark(mark);
 
@@ -1637,7 +1663,7 @@
 
 
 int MarkCompactCollector::RelocateMapObject(HeapObject* obj) {
-  // decode map pointer (forwarded address)
+  // Recover map pointer.
   MapWord encoding = obj->map_word();
   Address map_addr = encoding.DecodeMapAddress(Heap::map_space());
   ASSERT(Heap::map_space()->Contains(HeapObject::FromAddress(map_addr)));
@@ -1645,10 +1671,10 @@
   // Get forwarding address before resetting map pointer
   Address new_addr = GetForwardingAddressInOldSpace(obj);
 
-  // recover map pointer
+  // Reset map pointer.  The meta map object may not be copied yet so
+  // Map::cast does not yet work.
   obj->set_map(reinterpret_cast<Map*>(HeapObject::FromAddress(map_addr)));
 
-  // The meta map object may not be copied yet.
   Address old_addr = obj->address();
 
   if (new_addr != old_addr) {
@@ -1665,23 +1691,23 @@
 }
 
 
-static inline int RelocateOldObject(HeapObject* obj,
-                                    OldSpace* space,
-                                    Address new_addr,
-                                    Address map_addr) {
-  // recover map pointer
-  obj->set_map(reinterpret_cast<Map*>(HeapObject::FromAddress(map_addr)));
+static inline int RestoreMap(HeapObject* obj,
+                             PagedSpace* space,
+                             Address new_addr,
+                             Address map_addr) {
+  // This must be a non-map object, and the function relies on the
+  // assumption that the Map space is compacted before the other paged
+  // spaces (see RelocateObjects).
 
-  // This is a non-map object, it relies on the assumption that the Map space
-  // is compacted before the Old space (see RelocateObjects).
+  // Reset map pointer.
+  obj->set_map(Map::cast(HeapObject::FromAddress(map_addr)));
+
   int obj_size = obj->Size();
   ASSERT_OBJECT_SIZE(obj_size);
 
   ASSERT(space->MCSpaceOffsetForAddress(new_addr) <=
          space->MCSpaceOffsetForAddress(obj->address()));
 
-  space->MCAdjustRelocationEnd(new_addr, obj_size);
-
 #ifdef DEBUG
   if (FLAG_gc_verbose) {
     PrintF("relocate %p -> %p\n", obj->address(), new_addr);
@@ -1693,21 +1719,22 @@
 
 
 int MarkCompactCollector::RelocateOldNonCodeObject(HeapObject* obj,
-                                                   OldSpace* space) {
-  // decode map pointer (forwarded address)
+                                                   PagedSpace* space) {
+  // Recover map pointer.
   MapWord encoding = obj->map_word();
   Address map_addr = encoding.DecodeMapAddress(Heap::map_space());
   ASSERT(Heap::map_space()->Contains(map_addr));
 
-  // Get forwarding address before resetting map pointer
+  // Get forwarding address before resetting map pointer.
   Address new_addr = GetForwardingAddressInOldSpace(obj);
 
-  int obj_size = RelocateOldObject(obj, space, new_addr, map_addr);
+  // Reset the map pointer.
+  int obj_size = RestoreMap(obj, space, new_addr, map_addr);
 
   Address old_addr = obj->address();
 
   if (new_addr != old_addr) {
-    memmove(new_addr, old_addr, obj_size);  // copy contents
+    memmove(new_addr, old_addr, obj_size);  // Copy contents
   }
 
   ASSERT(!HeapObject::FromAddress(new_addr)->IsCode());
@@ -1726,8 +1753,13 @@
 }
 
 
+int MarkCompactCollector::RelocateCellObject(HeapObject* obj) {
+  return RelocateOldNonCodeObject(obj, Heap::cell_space());
+}
+
+
 int MarkCompactCollector::RelocateCodeObject(HeapObject* obj) {
-  // decode map pointer (forwarded address)
+  // Recover map pointer.
   MapWord encoding = obj->map_word();
   Address map_addr = encoding.DecodeMapAddress(Heap::map_space());
   ASSERT(Heap::map_space()->Contains(HeapObject::FromAddress(map_addr)));
@@ -1735,23 +1767,23 @@
   // Get forwarding address before resetting map pointer
   Address new_addr = GetForwardingAddressInOldSpace(obj);
 
-  int obj_size = RelocateOldObject(obj, Heap::code_space(), new_addr, map_addr);
+  // Reset the map pointer.
+  int obj_size = RestoreMap(obj, Heap::code_space(), new_addr, map_addr);
 
-  // convert inline cache target to address using old address
+  // Convert inline cache target to address using old address.
   if (obj->IsCode()) {
-    // convert target to address first related to old_address
     Code::cast(obj)->ConvertICTargetsFromObjectToAddress();
   }
 
   Address old_addr = obj->address();
 
   if (new_addr != old_addr) {
-    memmove(new_addr, old_addr, obj_size);  // copy contents
+    memmove(new_addr, old_addr, obj_size);  // Copy contents.
   }
 
   HeapObject* copied_to = HeapObject::FromAddress(new_addr);
   if (copied_to->IsCode()) {
-    // may also update inline cache target.
+    // May also update inline cache target.
     Code::cast(copied_to)->Relocate(new_addr - old_addr);
     // Notify the logger that compiled code has moved.
     LOG(CodeMoveEvent(old_addr, new_addr));
@@ -1771,15 +1803,15 @@
   Address new_addr =
     Memory::Address_at(Heap::new_space()->FromSpaceLow() + offset);
 
+#ifdef DEBUG
   if (Heap::new_space()->FromSpaceContains(new_addr)) {
     ASSERT(Heap::new_space()->FromSpaceOffsetForAddress(new_addr) <=
            Heap::new_space()->ToSpaceOffsetForAddress(old_addr));
   } else {
-    OldSpace* target_space = Heap::TargetSpace(obj);
-    ASSERT(target_space == Heap::old_pointer_space() ||
-           target_space == Heap::old_data_space());
-    target_space->MCAdjustRelocationEnd(new_addr, obj_size);
+    ASSERT(Heap::TargetSpace(obj) == Heap::old_pointer_space() ||
+           Heap::TargetSpace(obj) == Heap::old_data_space());
   }
+#endif
 
   // New and old addresses cannot overlap.
   memcpy(reinterpret_cast<void*>(new_addr),
diff --git a/src/mark-compact.h b/src/mark-compact.h
index d7ad630..bd9e4a0 100644
--- a/src/mark-compact.h
+++ b/src/mark-compact.h
@@ -293,6 +293,7 @@
   static void DeallocateOldDataBlock(Address start, int size_in_bytes);
   static void DeallocateCodeBlock(Address start, int size_in_bytes);
   static void DeallocateMapBlock(Address start, int size_in_bytes);
+  static void DeallocateCellBlock(Address start, int size_in_bytes);
 
   // If we are not compacting the heap, we simply sweep the spaces except
   // for the large object space, clearing mark bits and adding unmarked
@@ -352,8 +353,12 @@
   static int RelocateOldPointerObject(HeapObject* obj);
   static int RelocateOldDataObject(HeapObject* obj);
 
+  // Relocate a property cell object.
+  static int RelocateCellObject(HeapObject* obj);
+
   // Helper function.
-  static inline int RelocateOldNonCodeObject(HeapObject* obj, OldSpace* space);
+  static inline int RelocateOldNonCodeObject(HeapObject* obj,
+                                             PagedSpace* space);
 
   // Relocates an object in the code space.
   static int RelocateCodeObject(HeapObject* obj);
@@ -393,6 +398,9 @@
   // Number of live objects in Heap::map_space_.
   static int live_map_objects_;
 
+  // Number of live objects in Heap::cell_space_.
+  static int live_cell_objects_;
+
   // Number of live objects in Heap::lo_space_.
   static int live_lo_objects_;
 
diff --git a/src/objects-debug.cc b/src/objects-debug.cc
index 4974268..d54f741 100644
--- a/src/objects-debug.cc
+++ b/src/objects-debug.cc
@@ -271,29 +271,38 @@
 
 void JSObject::PrintProperties() {
   if (HasFastProperties()) {
-    for (DescriptorReader r(map()->instance_descriptors());
-         !r.eos();
-         r.advance()) {
+    DescriptorArray* descs = map()->instance_descriptors();
+    for (int i = 0; i < descs->number_of_descriptors(); i++) {
       PrintF("   ");
-      r.GetKey()->StringPrint();
+      descs->GetKey(i)->StringPrint();
       PrintF(": ");
-      if (r.type() == FIELD) {
-        FastPropertyAt(r.GetFieldIndex())->ShortPrint();
-        PrintF(" (field at offset %d)\n", r.GetFieldIndex());
-      } else if (r.type() ==  CONSTANT_FUNCTION) {
-        r.GetConstantFunction()->ShortPrint();
-        PrintF(" (constant function)\n");
-      } else if (r.type() == CALLBACKS) {
-        r.GetCallbacksObject()->ShortPrint();
-        PrintF(" (callback)\n");
-      } else if (r.type() == MAP_TRANSITION) {
-        PrintF(" (map transition)\n");
-      } else if (r.type() == CONSTANT_TRANSITION) {
-        PrintF(" (constant transition)\n");
-      } else if (r.type() == NULL_DESCRIPTOR) {
-        PrintF(" (null descriptor)\n");
-      } else {
-        UNREACHABLE();
+      switch (descs->GetType(i)) {
+        case FIELD: {
+          int index = descs->GetFieldIndex(i);
+          FastPropertyAt(index)->ShortPrint();
+          PrintF(" (field at offset %d)\n", index);
+          break;
+        }
+        case CONSTANT_FUNCTION:
+          descs->GetConstantFunction(i)->ShortPrint();
+          PrintF(" (constant function)\n");
+          break;
+        case CALLBACKS:
+          descs->GetCallbacksObject(i)->ShortPrint();
+          PrintF(" (callback)\n");
+          break;
+        case MAP_TRANSITION:
+          PrintF(" (map transition)\n");
+          break;
+        case CONSTANT_TRANSITION:
+          PrintF(" (constant transition)\n");
+          break;
+        case NULL_DESCRIPTOR:
+          PrintF(" (null descriptor)\n");
+          break;
+        default:
+          UNREACHABLE();
+          break;
       }
     }
   } else {
@@ -1062,11 +1071,10 @@
 
 void DescriptorArray::PrintDescriptors() {
   PrintF("Descriptor array  %d\n", number_of_descriptors());
-  int number = 0;
-  for (DescriptorReader r(this); !r.eos(); r.advance()) {
+  for (int i = 0; i < number_of_descriptors(); i++) {
+    PrintF(" %d: ", i);
     Descriptor desc;
-    r.Get(&desc);
-    PrintF(" %d: ", number++);
+    Get(i, &desc);
     desc.Print();
   }
   PrintF("\n");
@@ -1076,14 +1084,14 @@
 bool DescriptorArray::IsSortedNoDuplicates() {
   String* current_key = NULL;
   uint32_t current = 0;
-  for (DescriptorReader r(this); !r.eos(); r.advance()) {
-    String* key = r.GetKey();
+  for (int i = 0; i < number_of_descriptors(); i++) {
+    String* key = GetKey(i);
     if (key == current_key) {
       PrintDescriptors();
       return false;
     }
     current_key = key;
-    uint32_t hash = r.GetKey()->Hash();
+    uint32_t hash = GetKey(i)->Hash();
     if (hash < current) {
       PrintDescriptors();
       return false;
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 3b152d6..37c9b8b 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -768,6 +768,8 @@
 
 
 Failure* Failure::RetryAfterGC(int requested_bytes) {
+  // Assert that the space encoding fits in the three bytes allotted for it.
+  ASSERT((LAST_SPACE & ~kSpaceTagMask) == 0);
   int requested = requested_bytes >> kObjectAlignmentBits;
   int value = (requested << kSpaceTagSize) | NEW_SPACE;
   ASSERT(value >> kSpaceTagSize == requested);
@@ -1060,7 +1062,17 @@
 ACCESSORS(Oddball, to_number, Object, kToNumberOffset)
 
 
-ACCESSORS(JSGlobalPropertyCell, value, Object, kValueOffset)
+Object* JSGlobalPropertyCell::value() {
+  return READ_FIELD(this, kValueOffset);
+}
+
+
+void JSGlobalPropertyCell::set_value(Object* val, WriteBarrierMode ignored) {
+  // The write barrier is not used for global property cells.
+  ASSERT(!val->IsJSGlobalPropertyCell());
+  WRITE_FIELD(this, kValueOffset, val);
+}
+
 
 int JSObject::GetHeaderSize() {
   switch (map()->instance_type()) {
@@ -1339,6 +1351,56 @@
 }
 
 
+PropertyType DescriptorArray::GetType(int descriptor_number) {
+  ASSERT(descriptor_number < number_of_descriptors());
+  return PropertyDetails(GetDetails(descriptor_number)).type();
+}
+
+
+int DescriptorArray::GetFieldIndex(int descriptor_number) {
+  return Descriptor::IndexFromValue(GetValue(descriptor_number));
+}
+
+
+JSFunction* DescriptorArray::GetConstantFunction(int descriptor_number) {
+  return JSFunction::cast(GetValue(descriptor_number));
+}
+
+
+Object* DescriptorArray::GetCallbacksObject(int descriptor_number) {
+  ASSERT(GetType(descriptor_number) == CALLBACKS);
+  return GetValue(descriptor_number);
+}
+
+
+AccessorDescriptor* DescriptorArray::GetCallbacks(int descriptor_number) {
+  ASSERT(GetType(descriptor_number) == CALLBACKS);
+  Proxy* p = Proxy::cast(GetCallbacksObject(descriptor_number));
+  return reinterpret_cast<AccessorDescriptor*>(p->proxy());
+}
+
+
+bool DescriptorArray::IsProperty(int descriptor_number) {
+  return GetType(descriptor_number) < FIRST_PHANTOM_PROPERTY_TYPE;
+}
+
+
+bool DescriptorArray::IsTransition(int descriptor_number) {
+  PropertyType t = GetType(descriptor_number);
+  return t == MAP_TRANSITION || t == CONSTANT_TRANSITION;
+}
+
+
+bool DescriptorArray::IsNullDescriptor(int descriptor_number) {
+  return GetType(descriptor_number) == NULL_DESCRIPTOR;
+}
+
+
+bool DescriptorArray::IsDontEnum(int descriptor_number) {
+  return PropertyDetails(GetDetails(descriptor_number)).IsDontEnum();
+}
+
+
 void DescriptorArray::Get(int descriptor_number, Descriptor* desc) {
   desc->Init(GetKey(descriptor_number),
              GetValue(descriptor_number),
@@ -1362,6 +1424,13 @@
 }
 
 
+void DescriptorArray::CopyFrom(int index, DescriptorArray* src, int src_index) {
+  Descriptor desc;
+  src->Get(src_index, &desc);
+  Set(index, &desc);
+}
+
+
 void DescriptorArray::Swap(int first, int second) {
   fast_swap(this, ToKeyIndex(first), ToKeyIndex(second));
   FixedArray* content_array = GetContentArray();
@@ -2642,7 +2711,7 @@
                                       Object* key,
                                       Object* value,
                                       PropertyDetails details) {
-  ASSERT(!key->IsString() || details.index() > 0);
+  ASSERT(!key->IsString() || details.IsDeleted() || details.index() > 0);
   int index = HashTable<Shape, Key>::EntryToIndex(entry);
   WriteBarrierMode mode = FixedArray::GetWriteBarrierMode();
   FixedArray::set(index, key, mode);
diff --git a/src/objects.cc b/src/objects.cc
index 93e7495..a9004c9 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -436,8 +436,7 @@
       store_value = Heap::AllocateJSGlobalPropertyCell(value);
       if (store_value->IsFailure()) return store_value;
     }
-    Object* dict =
-        property_dictionary()->Add(name, store_value, details);
+    Object* dict = property_dictionary()->Add(name, store_value, details);
     if (dict->IsFailure()) return dict;
     set_properties(StringDictionary::cast(dict));
     return value;
@@ -1633,6 +1632,7 @@
   return *value_handle;
 }
 
+
 void JSObject::LookupCallbackSetterInPrototypes(String* name,
                                                 LookupResult* result) {
   for (Object* pt = GetPrototype();
@@ -1660,7 +1660,7 @@
     if (JSObject::cast(pt)->HasFastElements()) continue;
     NumberDictionary* dictionary = JSObject::cast(pt)->element_dictionary();
     int entry = dictionary->FindEntry(index);
-    if (entry != StringDictionary::kNotFound) {
+    if (entry != NumberDictionary::kNotFound) {
       Object* element = dictionary->ValueAt(entry);
       PropertyDetails details = dictionary->DetailsAt(entry);
       if (details.type() == CALLBACKS) {
@@ -1712,30 +1712,24 @@
   } else {
     int entry = property_dictionary()->FindEntry(name);
     if (entry != StringDictionary::kNotFound) {
-      // Make sure to disallow caching for uninitialized constants
-      // found in the dictionary-mode objects.
       Object* value = property_dictionary()->ValueAt(entry);
       if (IsGlobalObject()) {
         PropertyDetails d = property_dictionary()->DetailsAt(entry);
         if (d.IsDeleted()) {
-          // We've skipped a global object during lookup, so we cannot
-          // use inline caching because the map of the global object
-          // doesn't change if the property should be re-added.
-          result->DisallowCaching();
           result->NotFound();
           return;
         }
         value = JSGlobalPropertyCell::cast(value)->value();
         ASSERT(result->IsLoaded());
       }
-      if (value->IsTheHole()) {
-        result->DisallowCaching();
-      }
+      // Make sure to disallow caching for uninitialized constants
+      // found in the dictionary-mode objects.
+      if (value->IsTheHole()) result->DisallowCaching();
       result->DictionaryResult(this, entry);
       return;
     }
     // Slow case object skipped during lookup. Do not use inline caching.
-    result->DisallowCaching();
+    if (!IsGlobalObject()) result->DisallowCaching();
   }
   result->NotFound();
 }
@@ -2121,20 +2115,19 @@
   if (obj->IsFailure()) return obj;
   StringDictionary* dictionary = StringDictionary::cast(obj);
 
-  for (DescriptorReader r(map()->instance_descriptors());
-       !r.eos();
-       r.advance()) {
-    PropertyDetails details = r.GetDetails();
+  DescriptorArray* descs = map()->instance_descriptors();
+  for (int i = 0; i < descs->number_of_descriptors(); i++) {
+    PropertyDetails details = descs->GetDetails(i);
     switch (details.type()) {
       case CONSTANT_FUNCTION: {
         PropertyDetails d =
             PropertyDetails(details.attributes(), NORMAL, details.index());
-        Object* value = r.GetConstantFunction();
+        Object* value = descs->GetConstantFunction(i);
         if (IsGlobalObject()) {
           value = Heap::AllocateJSGlobalPropertyCell(value);
           if (value->IsFailure()) return value;
         }
-        Object* result = dictionary->Add(r.GetKey(), value, d);
+        Object* result = dictionary->Add(descs->GetKey(i), value, d);
         if (result->IsFailure()) return result;
         dictionary = StringDictionary::cast(result);
         break;
@@ -2142,12 +2135,12 @@
       case FIELD: {
         PropertyDetails d =
             PropertyDetails(details.attributes(), NORMAL, details.index());
-        Object* value = FastPropertyAt(r.GetFieldIndex());
+        Object* value = FastPropertyAt(descs->GetFieldIndex(i));
         if (IsGlobalObject()) {
           value = Heap::AllocateJSGlobalPropertyCell(value);
           if (value->IsFailure()) return value;
         }
-        Object* result = dictionary->Add(r.GetKey(), value, d);
+        Object* result = dictionary->Add(descs->GetKey(i), value, d);
         if (result->IsFailure()) return result;
         dictionary = StringDictionary::cast(result);
         break;
@@ -2155,12 +2148,12 @@
       case CALLBACKS: {
         PropertyDetails d =
             PropertyDetails(details.attributes(), CALLBACKS, details.index());
-        Object* value = r.GetCallbacksObject();
+        Object* value = descs->GetCallbacksObject(i);
         if (IsGlobalObject()) {
           value = Heap::AllocateJSGlobalPropertyCell(value);
           if (value->IsFailure()) return value;
         }
-        Object* result = dictionary->Add(r.GetKey(), value, d);
+        Object* result = dictionary->Add(descs->GetKey(i), value, d);
         if (result->IsFailure()) return result;
         dictionary = StringDictionary::cast(result);
         break;
@@ -2574,35 +2567,44 @@
 
 int Map::NumberOfDescribedProperties() {
   int result = 0;
-  for (DescriptorReader r(instance_descriptors()); !r.eos(); r.advance()) {
-    if (r.IsProperty()) result++;
+  DescriptorArray* descs = instance_descriptors();
+  for (int i = 0; i < descs->number_of_descriptors(); i++) {
+    if (descs->IsProperty(i)) result++;
   }
   return result;
 }
 
 
 int Map::PropertyIndexFor(String* name) {
-  for (DescriptorReader r(instance_descriptors()); !r.eos(); r.advance()) {
-    if (r.Equals(name) && !r.IsNullDescriptor()) return r.GetFieldIndex();
+  DescriptorArray* descs = instance_descriptors();
+  for (int i = 0; i < descs->number_of_descriptors(); i++) {
+    if (name->Equals(descs->GetKey(i)) && !descs->IsNullDescriptor(i)) {
+      return descs->GetFieldIndex(i);
+    }
   }
   return -1;
 }
 
 
 int Map::NextFreePropertyIndex() {
-  int index = -1;
-  for (DescriptorReader r(instance_descriptors()); !r.eos(); r.advance()) {
-    if (r.type() == FIELD) {
-      if (r.GetFieldIndex() > index) index = r.GetFieldIndex();
+  int max_index = -1;
+  DescriptorArray* descs = instance_descriptors();
+  for (int i = 0; i < descs->number_of_descriptors(); i++) {
+    if (descs->GetType(i) == FIELD) {
+      int current_index = descs->GetFieldIndex(i);
+      if (current_index > max_index) max_index = current_index;
     }
   }
-  return index+1;
+  return max_index + 1;
 }
 
 
 AccessorDescriptor* Map::FindAccessor(String* name) {
-  for (DescriptorReader r(instance_descriptors()); !r.eos(); r.advance()) {
-    if (r.Equals(name) && r.type() == CALLBACKS) return r.GetCallbacks();
+  DescriptorArray* descs = instance_descriptors();
+  for (int i = 0; i < descs->number_of_descriptors(); i++) {
+    if (name->Equals(descs->GetKey(i)) && descs->GetType(i) == CALLBACKS) {
+      return descs->GetCallbacks(i);
+    }
   }
   return NULL;
 }
@@ -2850,16 +2852,15 @@
 
 Object* JSObject::SlowReverseLookup(Object* value) {
   if (HasFastProperties()) {
-    for (DescriptorReader r(map()->instance_descriptors());
-         !r.eos();
-         r.advance()) {
-      if (r.type() == FIELD) {
-        if (FastPropertyAt(r.GetFieldIndex()) == value) {
-          return r.GetKey();
+    DescriptorArray* descs = map()->instance_descriptors();
+    for (int i = 0; i < descs->number_of_descriptors(); i++) {
+      if (descs->GetType(i) == FIELD) {
+        if (FastPropertyAt(descs->GetFieldIndex(i)) == value) {
+          return descs->GetKey(i);
         }
-      } else if (r.type() == CONSTANT_FUNCTION) {
-        if (r.GetConstantFunction() == value) {
-          return r.GetKey();
+      } else if (descs->GetType(i) == CONSTANT_FUNCTION) {
+        if (descs->GetConstantFunction(i) == value) {
+          return descs->GetKey(i);
         }
       }
     }
@@ -3173,13 +3174,13 @@
   int transitions = 0;
   int null_descriptors = 0;
   if (remove_transitions) {
-    for (DescriptorReader r(this); !r.eos(); r.advance()) {
-      if (r.IsTransition()) transitions++;
-      if (r.IsNullDescriptor()) null_descriptors++;
+    for (int i = 0; i < number_of_descriptors(); i++) {
+      if (IsTransition(i)) transitions++;
+      if (IsNullDescriptor(i)) null_descriptors++;
     }
   } else {
-    for (DescriptorReader r(this); !r.eos(); r.advance()) {
-      if (r.IsNullDescriptor()) null_descriptors++;
+    for (int i = 0; i < number_of_descriptors(); i++) {
+      if (IsNullDescriptor(i)) null_descriptors++;
     }
   }
   int new_size = number_of_descriptors() - transitions - null_descriptors;
@@ -3227,32 +3228,31 @@
 
   // Copy the descriptors, filtering out transitions and null descriptors,
   // and inserting or replacing a descriptor.
-  DescriptorWriter w(new_descriptors);
-  DescriptorReader r(this);
   uint32_t descriptor_hash = descriptor->GetKey()->Hash();
+  int from_index = 0;
+  int to_index = 0;
 
-  for (; !r.eos(); r.advance()) {
-    if (r.GetKey()->Hash() > descriptor_hash ||
-        r.GetKey() == descriptor->GetKey()) break;
-    if (r.IsNullDescriptor()) continue;
-    if (remove_transitions && r.IsTransition()) continue;
-    w.WriteFrom(&r);
+  for (; from_index < number_of_descriptors(); from_index++) {
+    String* key = GetKey(from_index);
+    if (key->Hash() > descriptor_hash || key == descriptor->GetKey()) {
+      break;
+    }
+    if (IsNullDescriptor(from_index)) continue;
+    if (remove_transitions && IsTransition(from_index)) continue;
+    new_descriptors->CopyFrom(to_index++, this, from_index);
   }
-  w.Write(descriptor);
-  if (replacing) {
-    ASSERT(r.GetKey() == descriptor->GetKey());
-    r.advance();
-  } else {
-    ASSERT(r.eos() ||
-           r.GetKey()->Hash() > descriptor_hash ||
-           r.IsNullDescriptor());
+
+  new_descriptors->Set(to_index++, descriptor);
+  if (replacing) from_index++;
+
+  for (; from_index < number_of_descriptors(); from_index++) {
+    if (IsNullDescriptor(from_index)) continue;
+    if (remove_transitions && IsTransition(from_index)) continue;
+    new_descriptors->CopyFrom(to_index++, this, from_index);
   }
-  for (; !r.eos(); r.advance()) {
-    if (r.IsNullDescriptor()) continue;
-    if (remove_transitions && r.IsTransition()) continue;
-    w.WriteFrom(&r);
-  }
-  ASSERT(w.eos());
+
+  ASSERT(to_index == new_descriptors->number_of_descriptors());
+  SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates());
 
   return new_descriptors;
 }
@@ -3265,8 +3265,8 @@
 
   // Compute the size of the map transition entries to be removed.
   int num_removed = 0;
-  for (DescriptorReader r(this); !r.eos(); r.advance()) {
-    if (!r.IsProperty()) num_removed++;
+  for (int i = 0; i < number_of_descriptors(); i++) {
+    if (!IsProperty(i)) num_removed++;
   }
 
   // Allocate the new descriptor array.
@@ -3275,11 +3275,11 @@
   DescriptorArray* new_descriptors = DescriptorArray::cast(result);
 
   // Copy the content.
-  DescriptorWriter w(new_descriptors);
-  for (DescriptorReader r(this); !r.eos(); r.advance()) {
-    if (r.IsProperty()) w.WriteFrom(&r);
+  int next_descriptor = 0;
+  for (int i = 0; i < number_of_descriptors(); i++) {
+    if (IsProperty(i)) new_descriptors->CopyFrom(next_descriptor++, this, i);
   }
-  ASSERT(w.eos());
+  ASSERT(next_descriptor == new_descriptors->number_of_descriptors());
 
   return new_descriptors;
 }
@@ -4586,10 +4586,10 @@
 
 void Map::CreateBackPointers() {
   DescriptorArray* descriptors = instance_descriptors();
-  for (DescriptorReader r(descriptors); !r.eos(); r.advance()) {
-    if (r.type() == MAP_TRANSITION) {
+  for (int i = 0; i < descriptors->number_of_descriptors(); i++) {
+    if (descriptors->GetType(i) == MAP_TRANSITION) {
       // Get target.
-      Map* target = Map::cast(r.GetValue());
+      Map* target = Map::cast(descriptors->GetValue(i));
 #ifdef DEBUG
       // Verify target.
       Object* source_prototype = prototype();
@@ -4600,7 +4600,7 @@
       ASSERT(target_prototype->IsJSObject() ||
              target_prototype->IsNull());
       ASSERT(source_prototype->IsMap() ||
-          source_prototype == target_prototype);
+             source_prototype == target_prototype);
 #endif
       // Point target back to source.  set_prototype() will not let us set
       // the prototype to a map, as we do here.
@@ -6018,13 +6018,11 @@
 
 int JSObject::NumberOfLocalProperties(PropertyAttributes filter) {
   if (HasFastProperties()) {
+    DescriptorArray* descs = map()->instance_descriptors();
     int result = 0;
-    for (DescriptorReader r(map()->instance_descriptors());
-         !r.eos();
-         r.advance()) {
-      PropertyDetails details = r.GetDetails();
-      if (details.IsProperty() &&
-          (details.attributes() & filter) == 0) {
+    for (int i = 0; i < descs->number_of_descriptors(); i++) {
+      PropertyDetails details = descs->GetDetails(i);
+      if (details.IsProperty() && (details.attributes() & filter) == 0) {
         result++;
       }
     }
@@ -6157,16 +6155,11 @@
 // purpose of this function is to provide reflection information for the object
 // mirrors.
 void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) {
-  ASSERT(storage->length() >=
-         NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE)) -
-             index);
+  ASSERT(storage->length() >= (NumberOfLocalProperties(NONE) - index));
   if (HasFastProperties()) {
-    for (DescriptorReader r(map()->instance_descriptors());
-         !r.eos();
-         r.advance()) {
-      if (r.IsProperty()) {
-        storage->set(index++, r.GetKey());
-      }
+    DescriptorArray* descs = map()->instance_descriptors();
+    for (int i = 0; i < descs->number_of_descriptors(); i++) {
+      if (descs->IsProperty(i)) storage->set(index++, descs->GetKey(i));
     }
     ASSERT(storage->length() >= index);
   } else {
@@ -6841,6 +6834,26 @@
 }
 
 
+Object* GlobalObject::EnsurePropertyCell(String* name) {
+  ASSERT(!HasFastProperties());
+  int entry = property_dictionary()->FindEntry(name);
+  if (entry == StringDictionary::kNotFound) {
+    Object* cell = Heap::AllocateJSGlobalPropertyCell(Heap::the_hole_value());
+    if (cell->IsFailure()) return cell;
+    PropertyDetails details(NONE, NORMAL);
+    details = details.AsDeleted();
+    Object* dictionary = property_dictionary()->Add(name, cell, details);
+    if (dictionary->IsFailure()) return dictionary;
+    set_properties(StringDictionary::cast(dictionary));
+    return cell;
+  } else {
+    Object* value = property_dictionary()->ValueAt(entry);
+    ASSERT(value->IsJSGlobalPropertyCell());
+    return value;
+  }
+}
+
+
 Object* SymbolTable::LookupString(String* string, Object** s) {
   SymbolKey key(string);
   return LookupKey(&key, s);
@@ -7200,7 +7213,7 @@
 
   uint32_t entry = Dictionary<Shape, Key>::FindInsertionEntry(hash);
   // Insert element at empty or deleted entry
-  if (details.index() == 0 && Shape::kIsEnumerable) {
+  if (!details.IsDeleted() && details.index() == 0 && Shape::kIsEnumerable) {
     // Assign an enumeration index to the property and update
     // SetNextEnumerationIndex.
     int index = NextEnumerationIndex();
@@ -7273,7 +7286,9 @@
   for (int i = 0; i < capacity; i++) {
     Object* k = HashTable<Shape, Key>::KeyAt(i);
     if (HashTable<Shape, Key>::IsKey(k)) {
-      PropertyAttributes attr = DetailsAt(i).attributes();
+      PropertyDetails details = DetailsAt(i);
+      if (details.IsDeleted()) continue;
+      PropertyAttributes attr = details.attributes();
       if ((attr & filter) == 0) result++;
     }
   }
@@ -7297,7 +7312,9 @@
   for (int i = 0; i < capacity; i++) {
      Object* k = HashTable<Shape, Key>::KeyAt(i);
      if (HashTable<Shape, Key>::IsKey(k)) {
-       PropertyAttributes attr = DetailsAt(i).attributes();
+       PropertyDetails details = DetailsAt(i);
+       if (details.IsDeleted()) continue;
+       PropertyAttributes attr = details.attributes();
        if ((attr & filter) == 0) storage->set(index++, k);
      }
   }
@@ -7315,13 +7332,12 @@
      Object* k = KeyAt(i);
      if (IsKey(k)) {
        PropertyDetails details = DetailsAt(i);
-       if (!details.IsDontEnum()) {
-         storage->set(index, k);
-         sort_array->set(index,
-                         Smi::FromInt(details.index()),
-                         SKIP_WRITE_BARRIER);
-         index++;
-       }
+       if (details.IsDeleted() || details.IsDontEnum()) continue;
+       storage->set(index, k);
+       sort_array->set(index,
+                       Smi::FromInt(details.index()),
+                       SKIP_WRITE_BARRIER);
+       index++;
      }
   }
   storage->SortPairs(sort_array, sort_array->length());
@@ -7338,6 +7354,8 @@
   for (int i = 0; i < capacity; i++) {
     Object* k = HashTable<Shape, Key>::KeyAt(i);
     if (HashTable<Shape, Key>::IsKey(k)) {
+      PropertyDetails details = DetailsAt(i);
+      if (details.IsDeleted()) continue;
       storage->set(index++, k);
     }
   }
@@ -7410,7 +7428,7 @@
   if (fields->IsFailure()) return fields;
 
   // Fill in the instance descriptor and the fields.
-  DescriptorWriter w(descriptors);
+  int next_descriptor = 0;
   int current_offset = 0;
   for (int i = 0; i < capacity; i++) {
     Object* k = KeyAt(i);
@@ -7427,7 +7445,7 @@
                                      JSFunction::cast(value),
                                      details.attributes(),
                                      details.index());
-        w.Write(&d);
+        descriptors->Set(next_descriptor++, &d);
       } else if (type == NORMAL) {
         if (current_offset < inobject_props) {
           obj->InObjectPropertyAtPut(current_offset,
@@ -7441,13 +7459,13 @@
                           current_offset++,
                           details.attributes(),
                           details.index());
-        w.Write(&d);
+        descriptors->Set(next_descriptor++, &d);
       } else if (type == CALLBACKS) {
         CallbacksDescriptor d(String::cast(key),
                               value,
                               details.attributes(),
                               details.index());
-        w.Write(&d);
+        descriptors->Set(next_descriptor++, &d);
       } else {
         UNREACHABLE();
       }
diff --git a/src/objects.h b/src/objects.h
index 446b4a7..5c76e4a 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -928,12 +928,14 @@
 
 // Failure is used for reporting out of memory situations and
 // propagating exceptions through the runtime system.  Failure objects
-// are transient and cannot occur as part of the objects graph.
+// are transient and cannot occur as part of the object graph.
 //
 // Failures are a single word, encoded as follows:
 // +-------------------------+---+--+--+
 // |rrrrrrrrrrrrrrrrrrrrrrrrr|sss|tt|11|
 // +-------------------------+---+--+--+
+//  3                       7 6 4 32 10
+//  1
 //
 // The low two bits, 0-1, are the failure tag, 11.  The next two bits,
 // 2-3, are a failure type tag 'tt' with possible values:
@@ -944,18 +946,13 @@
 //
 // The next three bits, 4-6, are an allocation space tag 'sss'.  The
 // allocation space tag is 000 for all failure types except
-// RETRY_AFTER_GC.  For RETRY_AFTER_GC, the possible values are
-// (the encoding is found in globals.h):
-//   000 NEW_SPACE
-//   001 OLD_SPACE
-//   010 CODE_SPACE
-//   011 MAP_SPACE
-//   100 LO_SPACE
+// RETRY_AFTER_GC.  For RETRY_AFTER_GC, the possible values are the
+// allocation spaces (the encoding is found in globals.h).
 //
-// The remaining bits is the number of words requested by the
-// allocation request that failed, and is zeroed except for
-// RETRY_AFTER_GC failures.  The 25 bits (on a 32 bit platform) gives
-// a representable range of 2^27 bytes (128MB).
+// The remaining bits is the size of the allocation request in units
+// of the pointer size, and is zeroed except for RETRY_AFTER_GC
+// failures.  The 25 bits (on a 32 bit platform) gives a representable
+// range of 2^27 bytes (128MB).
 
 // Failure type tag info.
 const int kFailureTypeTagSize = 2;
@@ -1085,14 +1082,6 @@
 
   inline Address ToEncodedAddress();
 
- private:
-  // HeapObject calls the private constructor and directly reads the value.
-  friend class HeapObject;
-
-  explicit MapWord(uintptr_t value) : value_(value) {}
-
-  uintptr_t value_;
-
   // Bits used by the marking phase of the garbage collector.
   //
   // The first word of a heap object is normally a map pointer. The last two
@@ -1134,6 +1123,14 @@
   // 0xFFE00000
   static const uint32_t kForwardingOffsetMask =
       ~(kMapPageIndexMask | kMapPageOffsetMask);
+
+ private:
+  // HeapObject calls the private constructor and directly reads the value.
+  friend class HeapObject;
+
+  explicit MapWord(uintptr_t value) : value_(value) {}
+
+  uintptr_t value_;
 };
 
 
@@ -1853,15 +1850,28 @@
   // using the supplied storage for the small "bridge".
   void SetEnumCache(FixedArray* bridge_storage, FixedArray* new_cache);
 
-  // Accessors for fetching instance descriptor at descriptor number..
+  // Accessors for fetching instance descriptor at descriptor number.
   inline String* GetKey(int descriptor_number);
   inline Object* GetValue(int descriptor_number);
   inline Smi* GetDetails(int descriptor_number);
+  inline PropertyType GetType(int descriptor_number);
+  inline int GetFieldIndex(int descriptor_number);
+  inline JSFunction* GetConstantFunction(int descriptor_number);
+  inline Object* GetCallbacksObject(int descriptor_number);
+  inline AccessorDescriptor* GetCallbacks(int descriptor_number);
+  inline bool IsProperty(int descriptor_number);
+  inline bool IsTransition(int descriptor_number);
+  inline bool IsNullDescriptor(int descriptor_number);
+  inline bool IsDontEnum(int descriptor_number);
 
   // Accessor for complete descriptor.
   inline void Get(int descriptor_number, Descriptor* desc);
   inline void Set(int descriptor_number, Descriptor* desc);
 
+  // Transfer complete descriptor from another descriptor array to
+  // this one.
+  inline void CopyFrom(int index, DescriptorArray* src, int src_index);
+
   // Copy the descriptor array, insert a new descriptor and optionally
   // remove map transitions.  If the descriptor is already present, it is
   // replaced.  If a replaced descriptor is a real property (not a transition
@@ -3243,6 +3253,9 @@
   // Retrieve the property cell used to store a property.
   Object* GetPropertyCell(LookupResult* result);
 
+  // Ensure that the global object has a cell for the given property name.
+  Object* EnsurePropertyCell(String* name);
+
   // Casting.
   static inline GlobalObject* cast(Object* obj);
 
diff --git a/src/property.cc b/src/property.cc
index 2915c4a..caa7397 100644
--- a/src/property.cc
+++ b/src/property.cc
@@ -31,20 +31,6 @@
 namespace internal {
 
 
-void DescriptorWriter::Write(Descriptor* desc) {
-  ASSERT(desc->key_->IsSymbol());
-  descriptors_->Set(pos_, desc);
-  advance();
-}
-
-
-void DescriptorWriter::WriteFrom(DescriptorReader* reader) {
-  Descriptor desc;
-  reader->Get(&desc);
-  Write(&desc);
-}
-
-
 #ifdef DEBUG
 void LookupResult::Print() {
   if (!IsValid()) {
diff --git a/src/property.h b/src/property.h
index 69e5640..1869719 100644
--- a/src/property.h
+++ b/src/property.h
@@ -95,8 +95,6 @@
         value_(value),
         details_(attributes, type, index) { }
 
-  friend class DescriptorWriter;
-  friend class DescriptorReader;
   friend class DescriptorArray;
 };
 
@@ -324,92 +322,6 @@
 };
 
 
-// The DescriptorStream is an abstraction for iterating over a map's
-// instance descriptors.
-class DescriptorStream BASE_EMBEDDED {
- public:
-  explicit DescriptorStream(DescriptorArray* descriptors, int pos) {
-    descriptors_ = descriptors;
-    pos_ = pos;
-    limit_ = descriptors_->number_of_descriptors();
-  }
-
-  // Tells whether we have reached the end of the steam.
-  bool eos() { return pos_ >= limit_; }
-
-  int next_position() { return pos_ + 1; }
-  void advance() { pos_ = next_position(); }
-
- protected:
-  DescriptorArray* descriptors_;
-  int pos_;   // Current position.
-  int limit_;  // Limit for position.
-};
-
-
-class DescriptorReader: public DescriptorStream {
- public:
-  explicit DescriptorReader(DescriptorArray* descriptors, int pos = 0)
-      : DescriptorStream(descriptors, pos) {}
-
-  String* GetKey() { return descriptors_->GetKey(pos_); }
-  Object* GetValue() { return descriptors_->GetValue(pos_); }
-  PropertyDetails GetDetails() {
-    return PropertyDetails(descriptors_->GetDetails(pos_));
-  }
-
-  int GetFieldIndex() { return Descriptor::IndexFromValue(GetValue()); }
-
-  bool IsDontEnum() { return GetDetails().IsDontEnum(); }
-
-  PropertyType type() { return GetDetails().type(); }
-
-  // Tells whether the type is a transition.
-  bool IsTransition() {
-    PropertyType t = type();
-    ASSERT(t != INTERCEPTOR);
-    return t == MAP_TRANSITION || t == CONSTANT_TRANSITION;
-  }
-
-  bool IsNullDescriptor() {
-    return type() == NULL_DESCRIPTOR;
-  }
-
-  bool IsProperty() {
-    return type() < FIRST_PHANTOM_PROPERTY_TYPE;
-  }
-
-  JSFunction* GetConstantFunction() { return JSFunction::cast(GetValue()); }
-
-  AccessorDescriptor* GetCallbacks() {
-    ASSERT(type() == CALLBACKS);
-    Proxy* p = Proxy::cast(GetCallbacksObject());
-    return reinterpret_cast<AccessorDescriptor*>(p->proxy());
-  }
-
-  Object* GetCallbacksObject() {
-    ASSERT(type() == CALLBACKS);
-    return GetValue();
-  }
-
-  bool Equals(String* name) { return name->Equals(GetKey()); }
-
-  void Get(Descriptor* desc) {
-    descriptors_->Get(pos_, desc);
-  }
-};
-
-class DescriptorWriter: public DescriptorStream {
- public:
-  explicit DescriptorWriter(DescriptorArray* descriptors)
-      : DescriptorStream(descriptors, 0) {}
-
-  // Append a descriptor to this stream.
-  void Write(Descriptor* desc);
-  // Read a descriptor from the reader and append it to this stream.
-  void WriteFrom(DescriptorReader* reader);
-};
-
 } }  // namespace v8::internal
 
 #endif  // V8_PROPERTY_H_
diff --git a/src/runtime.cc b/src/runtime.cc
index ea2690e..350d391 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -4316,7 +4316,7 @@
 #ifdef ENABLE_DEBUGGER_SUPPORT
   // Handle stepping into constructors if step into is active.
   if (Debug::StepInActive()) {
-    Debug::HandleStepIn(function, 0, true);
+    Debug::HandleStepIn(function, Handle<Object>::null(), 0, true);
   }
 #endif
 
diff --git a/src/serialize.cc b/src/serialize.cc
index f633b06..592cf5a 100644
--- a/src/serialize.cc
+++ b/src/serialize.cc
@@ -42,47 +42,44 @@
 namespace v8 {
 namespace internal {
 
-// Encoding: a RelativeAddress must be able to fit in a pointer:
-// it is encoded as an Address with (from MS to LS bits):
-// 27 bits identifying a word in the space, in one of three formats:
-// - MAP and OLD spaces: 16 bits of page number, 11 bits of word offset in page
-// - NEW space:          27 bits of word offset
-// - LO space:           27 bits of page number
-// 3 bits to encode the AllocationSpace (special values for code in LO space)
-// 2 bits identifying this as a HeapObject
+// 32-bit encoding: a RelativeAddress must be able to fit in a
+// pointer: it is encoded as an Address with (from LS to MS bits):
+// - 2 bits identifying this as a HeapObject.
+// - 4 bits to encode the AllocationSpace (including special values for
+//   code and fixed arrays in LO space)
+// - 27 bits identifying a word in the space, in one of three formats:
+// - paged spaces: 16 bits of page number, 11 bits of word offset in page
+// - NEW space:    27 bits of word offset
+// - LO space:     27 bits of page number
 
 const int kSpaceShift = kHeapObjectTagSize;
-const int kSpaceBits = kSpaceTagSize;
-const int kSpaceMask = kSpaceTagMask;
-
-// These value are used instead of space numbers when serializing/
-// deserializing.  They indicate an object that is in large object space, but
-// should be treated specially.
-// Make the pages executable on platforms that support it:
-const int kLOSpaceExecutable = LAST_SPACE + 1;
-// Reserve space for write barrier bits (for objects that can contain
-// references to new space):
-const int kLOSpacePointer = LAST_SPACE + 2;
-
+const int kSpaceBits = 4;
+const int kSpaceMask = (1 << kSpaceBits) - 1;
 
 const int kOffsetShift = kSpaceShift + kSpaceBits;
 const int kOffsetBits = 11;
 const int kOffsetMask = (1 << kOffsetBits) - 1;
 
-const int kPageBits = 32 - (kOffsetBits + kSpaceBits + kHeapObjectTagSize);
 const int kPageShift = kOffsetShift + kOffsetBits;
+const int kPageBits = 32 - (kOffsetBits + kSpaceBits + kHeapObjectTagSize);
 const int kPageMask = (1 << kPageBits) - 1;
 
 const int kPageAndOffsetShift = kOffsetShift;
 const int kPageAndOffsetBits = kPageBits + kOffsetBits;
 const int kPageAndOffsetMask = (1 << kPageAndOffsetBits) - 1;
 
+// These values are special allocation space tags used for
+// serialization.
+// Mar the pages executable on platforms that support it.
+const int kLargeCode = LAST_SPACE + 1;
+// Allocate extra remembered-set bits.
+const int kLargeFixedArray = LAST_SPACE + 2;
+
 
 static inline AllocationSpace GetSpace(Address addr) {
   const intptr_t encoded = reinterpret_cast<intptr_t>(addr);
   int space_number = (static_cast<int>(encoded >> kSpaceShift) & kSpaceMask);
-  if (space_number == kLOSpaceExecutable) space_number = LO_SPACE;
-  else if (space_number == kLOSpacePointer) space_number = LO_SPACE;
+  if (space_number > LAST_SPACE) space_number = LO_SPACE;
   return static_cast<AllocationSpace>(space_number);
 }
 
@@ -91,7 +88,7 @@
   const intptr_t encoded = reinterpret_cast<intptr_t>(addr);
   const int space_number =
       (static_cast<int>(encoded >> kSpaceShift) & kSpaceMask);
-  return (space_number == kLOSpaceExecutable);
+  return (space_number == kLargeCode);
 }
 
 
@@ -99,7 +96,7 @@
   const intptr_t encoded = reinterpret_cast<intptr_t>(addr);
   const int space_number =
       (static_cast<int>(encoded >> kSpaceShift) & kSpaceMask);
-  return (space_number == kLOSpacePointer);
+  return (space_number == kLargeFixedArray);
 }
 
 
@@ -147,6 +144,9 @@
                   int page_index,
                   int page_offset)
   : space_(space), page_index_(page_index), page_offset_(page_offset)  {
+    // Assert that the space encoding (plus the two pseudo-spaces for
+    // special large objects) fits in the available bits.
+    ASSERT(((LAST_SPACE + 2) & ~kSpaceMask) == 0);
     ASSERT(space <= LAST_SPACE && space >= 0);
   }
 
@@ -154,8 +154,7 @@
   Address Encode() const;
 
   AllocationSpace space() const {
-    if (space_ == kLOSpaceExecutable) return LO_SPACE;
-    if (space_ == kLOSpacePointer) return LO_SPACE;
+    if (space_ > LAST_SPACE) return LO_SPACE;
     return static_cast<AllocationSpace>(space_);
   }
   int page_index() const { return page_index_; }
@@ -165,7 +164,8 @@
     return space_ == CODE_SPACE ||
            space_ == OLD_POINTER_SPACE ||
            space_ == OLD_DATA_SPACE ||
-           space_ == MAP_SPACE;
+           space_ == MAP_SPACE ||
+           space_ == CELL_SPACE;
   }
 
   void next_address(int offset) { page_offset_ += offset; }
@@ -180,11 +180,11 @@
 
   void set_to_large_code_object() {
     ASSERT(space_ == LO_SPACE);
-    space_ = kLOSpaceExecutable;
+    space_ = kLargeCode;
   }
   void set_to_large_fixed_array() {
     ASSERT(space_ == LO_SPACE);
-    space_ = kLOSpacePointer;
+    space_ = kLargeFixedArray;
   }
 
 
@@ -201,6 +201,7 @@
   int result = 0;
   switch (space_) {
     case MAP_SPACE:
+    case CELL_SPACE:
     case OLD_POINTER_SPACE:
     case OLD_DATA_SPACE:
     case CODE_SPACE:
@@ -216,8 +217,8 @@
       result = word_offset << kPageAndOffsetShift;
       break;
     case LO_SPACE:
-    case kLOSpaceExecutable:
-    case kLOSpacePointer:
+    case kLargeCode:
+    case kLargeFixedArray:
       ASSERT_EQ(0, page_offset_);
       ASSERT_EQ(0, page_index_ & ~kPageAndOffsetMask);
       result = page_index_ << kPageAndOffsetShift;
@@ -235,6 +236,7 @@
   ASSERT(page_offset_ >= 0 && page_index_ >= 0);
   switch (space_) {
     case MAP_SPACE:
+    case CELL_SPACE:
     case OLD_POINTER_SPACE:
     case OLD_DATA_SPACE:
     case CODE_SPACE:
@@ -245,8 +247,8 @@
       ASSERT(page_index_ == 0);
       break;
     case LO_SPACE:
-    case kLOSpaceExecutable:
-    case kLOSpacePointer:
+    case kLargeCode:
+    case kLargeFixedArray:
       ASSERT(page_offset_ == 0);
       break;
   }
@@ -291,6 +293,7 @@
 void SimulatedHeapSpace::InitEmptyHeap(AllocationSpace space) {
   switch (space) {
     case MAP_SPACE:
+    case CELL_SPACE:
     case OLD_POINTER_SPACE:
     case OLD_DATA_SPACE:
     case CODE_SPACE:
@@ -307,12 +310,15 @@
 void SimulatedHeapSpace::InitCurrentHeap(AllocationSpace space) {
   switch (space) {
     case MAP_SPACE:
+    case CELL_SPACE:
     case OLD_POINTER_SPACE:
     case OLD_DATA_SPACE:
     case CODE_SPACE: {
       PagedSpace* ps;
       if (space == MAP_SPACE) {
         ps = Heap::map_space();
+      } else if (space == CELL_SPACE) {
+        ps = Heap::cell_space();
       } else if (space == OLD_POINTER_SPACE) {
         ps = Heap::old_pointer_space();
       } else if (space == OLD_DATA_SPACE) {
@@ -1121,6 +1127,8 @@
   writer_->PutInt(Heap::code_space()->Size() + Heap::new_space()->Size());
   writer_->PutC('|');
   writer_->PutInt(Heap::map_space()->Size());
+  writer_->PutC('|');
+  writer_->PutInt(Heap::cell_space()->Size());
   writer_->PutC(']');
   // Write global handles.
   writer_->PutC('G');
@@ -1303,6 +1311,7 @@
 Deserializer::Deserializer(const byte* str, int len)
   : reader_(str, len),
     map_pages_(kInitArraySize),
+    cell_pages_(kInitArraySize),
     old_pointer_pages_(kInitArraySize),
     old_data_pages_(kInitArraySize),
     code_pages_(kInitArraySize),
@@ -1475,6 +1484,8 @@
   InitPagedSpace(Heap::code_space(), reader_.GetInt(), &code_pages_);
   reader_.ExpectC('|');
   InitPagedSpace(Heap::map_space(), reader_.GetInt(), &map_pages_);
+  reader_.ExpectC('|');
+  InitPagedSpace(Heap::cell_space(), reader_.GetInt(), &cell_pages_);
   reader_.ExpectC(']');
   // Create placeholders for global handles later to be fill during
   // IterateRoots.
@@ -1607,6 +1618,9 @@
     case MAP_SPACE:
       return ResolvePaged(PageIndex(encoded), PageOffset(encoded),
                           Heap::map_space(), &map_pages_);
+    case CELL_SPACE:
+      return ResolvePaged(PageIndex(encoded), PageOffset(encoded),
+                          Heap::cell_space(), &cell_pages_);
     case OLD_POINTER_SPACE:
       return ResolvePaged(PageIndex(encoded), PageOffset(encoded),
                           Heap::old_pointer_space(), &old_pointer_pages_);
diff --git a/src/serialize.h b/src/serialize.h
index 7f4eb63..1b24065 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -320,10 +320,11 @@
   bool has_log_;  // The file has log information.
 
   // Resolve caches the following:
-  List<Page*> map_pages_;          // All pages in the map space.
+  List<Page*> map_pages_;  // All pages in the map space.
+  List<Page*> cell_pages_;  // All pages in the cell space.
   List<Page*> old_pointer_pages_;  // All pages in the old pointer space.
-  List<Page*> old_data_pages_;     // All pages in the old data space.
-  List<Page*> code_pages_;
+  List<Page*> old_data_pages_;  // All pages in the old data space.
+  List<Page*> code_pages_;  // All pages in the code space.
   List<Object*> large_objects_;    // All known large objects.
   // A list of global handles at deserialization time.
   List<Object**> global_handles_;
diff --git a/src/spaces.cc b/src/spaces.cc
index 3f3a635..2393281 100644
--- a/src/spaces.cc
+++ b/src/spaces.cc
@@ -37,8 +37,8 @@
 // For contiguous spaces, top should be in the space (or at the end) and limit
 // should be the end of the space.
 #define ASSERT_SEMISPACE_ALLOCATION_INFO(info, space) \
-  ASSERT((space).low() <= (info).top                 \
-         && (info).top <= (space).high()             \
+  ASSERT((space).low() <= (info).top                  \
+         && (info).top <= (space).high()              \
          && (info).limit == (space).high())
 
 
@@ -786,6 +786,77 @@
 #endif
 
 
+#ifdef DEBUG
+// We do not assume that the PageIterator works, because it depends on the
+// invariants we are checking during verification.
+void PagedSpace::Verify(ObjectVisitor* visitor) {
+  // The allocation pointer should be valid, and it should be in a page in the
+  // space.
+  ASSERT(allocation_info_.VerifyPagedAllocation());
+  Page* top_page = Page::FromAllocationTop(allocation_info_.top);
+  ASSERT(MemoryAllocator::IsPageInSpace(top_page, this));
+
+  // Loop over all the pages.
+  bool above_allocation_top = false;
+  Page* current_page = first_page_;
+  while (current_page->is_valid()) {
+    if (above_allocation_top) {
+      // We don't care what's above the allocation top.
+    } else {
+      // Unless this is the last page in the space containing allocated
+      // objects, the allocation top should be at a constant offset from the
+      // object area end.
+      Address top = current_page->AllocationTop();
+      if (current_page == top_page) {
+        ASSERT(top == allocation_info_.top);
+        // The next page will be above the allocation top.
+        above_allocation_top = true;
+      } else {
+        ASSERT(top == current_page->ObjectAreaEnd() - page_extra_);
+      }
+
+      // It should be packed with objects from the bottom to the top.
+      Address current = current_page->ObjectAreaStart();
+      while (current < top) {
+        HeapObject* object = HeapObject::FromAddress(current);
+
+        // The first word should be a map, and we expect all map pointers to
+        // be in map space.
+        Map* map = object->map();
+        ASSERT(map->IsMap());
+        ASSERT(Heap::map_space()->Contains(map));
+
+        // Perform space-specific object verification.
+        VerifyObject(object);
+
+        // The object itself should look OK.
+        object->Verify();
+
+        // All the interior pointers should be contained in the heap and
+        // have their remembered set bits set if required as determined
+        // by the visitor.
+        int size = object->Size();
+        if (object->IsCode()) {
+          Code::cast(object)->ConvertICTargetsFromAddressToObject();
+          object->IterateBody(map->instance_type(), size, visitor);
+          Code::cast(object)->ConvertICTargetsFromObjectToAddress();
+        } else {
+          object->IterateBody(map->instance_type(), size, visitor);
+        }
+
+        current += size;
+      }
+
+      // The allocation pointer should not be in the middle of an object.
+      ASSERT(current == top);
+    }
+
+    current_page = current_page->next_page();
+  }
+}
+#endif
+
+
 // -----------------------------------------------------------------------------
 // NewSpace implementation
 
@@ -1265,13 +1336,13 @@
   // If the block is too small (eg, one or two words), to hold both a size
   // field and a next pointer, we give it a filler map that gives it the
   // correct size.
-  if (size_in_bytes > ByteArray::kHeaderSize) {
+  if (size_in_bytes > ByteArray::kAlignedSize) {
     set_map(Heap::raw_unchecked_byte_array_map());
     ByteArray::cast(this)->set_length(ByteArray::LengthFor(size_in_bytes));
   } else if (size_in_bytes == kPointerSize) {
-    set_map(Heap::raw_unchecked_one_word_filler_map());
+    set_map(Heap::raw_unchecked_one_pointer_filler_map());
   } else if (size_in_bytes == 2 * kPointerSize) {
-    set_map(Heap::raw_unchecked_two_word_filler_map());
+    set_map(Heap::raw_unchecked_two_pointer_filler_map());
   } else {
     UNREACHABLE();
   }
@@ -1280,16 +1351,26 @@
 
 
 Address FreeListNode::next() {
-  ASSERT(map() == Heap::raw_unchecked_byte_array_map());
-  ASSERT(Size() >= kNextOffset + kPointerSize);
-  return Memory::Address_at(address() + kNextOffset);
+  ASSERT(map() == Heap::raw_unchecked_byte_array_map() ||
+         map() == Heap::raw_unchecked_two_pointer_filler_map());
+  if (map() == Heap::raw_unchecked_byte_array_map()) {
+    ASSERT(Size() >= kNextOffset + kPointerSize);
+    return Memory::Address_at(address() + kNextOffset);
+  } else {
+    return Memory::Address_at(address() + kPointerSize);
+  }
 }
 
 
 void FreeListNode::set_next(Address next) {
-  ASSERT(map() == Heap::raw_unchecked_byte_array_map());
-  ASSERT(Size() >= kNextOffset + kPointerSize);
-  Memory::Address_at(address() + kNextOffset) = next;
+  ASSERT(map() == Heap::raw_unchecked_byte_array_map() ||
+         map() == Heap::raw_unchecked_two_pointer_filler_map());
+  if (map() == Heap::raw_unchecked_byte_array_map()) {
+    ASSERT(Size() >= kNextOffset + kPointerSize);
+    Memory::Address_at(address() + kNextOffset) = next;
+  } else {
+    Memory::Address_at(address() + kPointerSize) = next;
+  }
 }
 
 
@@ -1445,42 +1526,42 @@
 #endif
 
 
-MapSpaceFreeList::MapSpaceFreeList(AllocationSpace owner) {
-  owner_ = owner;
+FixedSizeFreeList::FixedSizeFreeList(AllocationSpace owner, int object_size)
+    : owner_(owner), object_size_(object_size) {
   Reset();
 }
 
 
-void MapSpaceFreeList::Reset() {
+void FixedSizeFreeList::Reset() {
   available_ = 0;
   head_ = NULL;
 }
 
 
-void MapSpaceFreeList::Free(Address start) {
+void FixedSizeFreeList::Free(Address start) {
 #ifdef DEBUG
-  for (int i = 0; i < Map::kSize; i += kPointerSize) {
+  for (int i = 0; i < object_size_; i += kPointerSize) {
     Memory::Address_at(start + i) = kZapValue;
   }
 #endif
   ASSERT(!FLAG_always_compact);  // We only use the freelists with mark-sweep.
   FreeListNode* node = FreeListNode::FromAddress(start);
-  node->set_size(Map::kSize);
+  node->set_size(object_size_);
   node->set_next(head_);
   head_ = node->address();
-  available_ += Map::kSize;
+  available_ += object_size_;
 }
 
 
-Object* MapSpaceFreeList::Allocate() {
+Object* FixedSizeFreeList::Allocate() {
   if (head_ == NULL) {
-    return Failure::RetryAfterGC(Map::kSize, owner_);
+    return Failure::RetryAfterGC(object_size_, owner_);
   }
 
   ASSERT(!FLAG_always_compact);  // We only use the freelists with mark-sweep.
   FreeListNode* node = FreeListNode::FromAddress(head_);
   head_ = node->next();
-  available_ -= Map::kSize;
+  available_ -= object_size_;
   return node;
 }
 
@@ -1494,7 +1575,6 @@
     // the space is considered 'available' and we will rediscover live data
     // and waste during the collection.
     MCResetRelocationInfo();
-    mc_end_of_relocation_ = bottom();
     ASSERT(Available() == Capacity());
   } else {
     // During a non-compacting collection, everything below the linear
@@ -1510,24 +1590,6 @@
 }
 
 
-void OldSpace::MCAdjustRelocationEnd(Address address, int size_in_bytes) {
-  ASSERT(Contains(address));
-  Address current_top = mc_end_of_relocation_;
-  Page* current_page = Page::FromAllocationTop(current_top);
-
-  // No more objects relocated to this page?  Move to the next.
-  ASSERT(current_top <= current_page->mc_relocation_top);
-  if (current_top == current_page->mc_relocation_top) {
-    // The space should already be properly expanded.
-    Page* next_page = current_page->next_page();
-    CHECK(next_page->is_valid());
-    mc_end_of_relocation_ = next_page->ObjectAreaStart();
-  }
-  ASSERT(mc_end_of_relocation_ == address);
-  mc_end_of_relocation_ += size_in_bytes;
-}
-
-
 void OldSpace::MCCommitRelocationInfo() {
   // Update fast allocation info.
   allocation_info_.top = mc_forwarding_info_.top;
@@ -1624,76 +1686,6 @@
 
 
 #ifdef DEBUG
-// We do not assume that the PageIterator works, because it depends on the
-// invariants we are checking during verification.
-void OldSpace::Verify() {
-  // The allocation pointer should be valid, and it should be in a page in the
-  // space.
-  ASSERT(allocation_info_.VerifyPagedAllocation());
-  Page* top_page = Page::FromAllocationTop(allocation_info_.top);
-  ASSERT(MemoryAllocator::IsPageInSpace(top_page, this));
-
-  // Loop over all the pages.
-  bool above_allocation_top = false;
-  Page* current_page = first_page_;
-  while (current_page->is_valid()) {
-    if (above_allocation_top) {
-      // We don't care what's above the allocation top.
-    } else {
-      // Unless this is the last page in the space containing allocated
-      // objects, the allocation top should be at the object area end.
-      Address top = current_page->AllocationTop();
-      if (current_page == top_page) {
-        ASSERT(top == allocation_info_.top);
-        // The next page will be above the allocation top.
-        above_allocation_top = true;
-      } else {
-        ASSERT(top == current_page->ObjectAreaEnd());
-      }
-
-      // It should be packed with objects from the bottom to the top.
-      Address current = current_page->ObjectAreaStart();
-      while (current < top) {
-        HeapObject* object = HeapObject::FromAddress(current);
-
-        // The first word should be a map, and we expect all map pointers to
-        // be in map space.
-        Map* map = object->map();
-        ASSERT(map->IsMap());
-        ASSERT(Heap::map_space()->Contains(map));
-
-        // The object should not be a map.
-        ASSERT(!object->IsMap());
-
-        // The object itself should look OK.
-        object->Verify();
-
-        // All the interior pointers should be contained in the heap and have
-        // their remembered set bits set if they point to new space.  Code
-        // objects do not have remembered set bits that we care about.
-        VerifyPointersAndRSetVisitor rset_visitor;
-        VerifyPointersVisitor no_rset_visitor;
-        int size = object->Size();
-        if (object->IsCode()) {
-          Code::cast(object)->ConvertICTargetsFromAddressToObject();
-          object->IterateBody(map->instance_type(), size, &no_rset_visitor);
-          Code::cast(object)->ConvertICTargetsFromObjectToAddress();
-        } else {
-          object->IterateBody(map->instance_type(), size, &rset_visitor);
-        }
-
-        current += size;
-      }
-
-      // The allocation pointer should not be in the middle of an object.
-      ASSERT(current == top);
-    }
-
-    current_page = current_page->next_page();
-  }
-}
-
-
 struct CommentStatistic {
   const char* comment;
   int size;
@@ -1987,25 +1979,13 @@
 #endif
 
 // -----------------------------------------------------------------------------
-// MapSpace implementation
+// FixedSpace implementation
 
-void MapSpace::PrepareForMarkCompact(bool will_compact) {
+void FixedSpace::PrepareForMarkCompact(bool will_compact) {
   if (will_compact) {
     // Reset relocation info.
     MCResetRelocationInfo();
 
-    // Initialize map index entry.
-    int page_count = 0;
-    PageIterator it(this, PageIterator::ALL_PAGES);
-    while (it.has_next()) {
-      ASSERT_MAP_PAGE_INDEX(page_count);
-
-      Page* p = it.next();
-      ASSERT(p->mc_page_index == page_count);
-
-      page_addresses_[page_count++] = p->address();
-    }
-
     // During a compacting collection, everything in the space is considered
     // 'available' (set by the call to MCResetRelocationInfo) and we will
     // rediscover live and wasted bytes during the collection.
@@ -2023,7 +2003,7 @@
 }
 
 
-void MapSpace::MCCommitRelocationInfo() {
+void FixedSpace::MCCommitRelocationInfo() {
   // Update fast allocation info.
   allocation_info_.top = mc_forwarding_info_.top;
   allocation_info_.limit = mc_forwarding_info_.limit;
@@ -2053,7 +2033,8 @@
 // Slow case for normal allocation. Try in order: (1) allocate in the next
 // page in the space, (2) allocate off the space's free list, (3) expand the
 // space, (4) fail.
-HeapObject* MapSpace::SlowAllocateRaw(int size_in_bytes) {
+HeapObject* FixedSpace::SlowAllocateRaw(int size_in_bytes) {
+  ASSERT_EQ(object_size_in_bytes_, size_in_bytes);
   // Linear allocation in this space has failed.  If there is another page
   // in the space, move to that page and allocate there.  This allocation
   // should succeed.
@@ -2062,10 +2043,10 @@
     return AllocateInNextPage(current_page, size_in_bytes);
   }
 
-  // There is no next page in this space.  Try free list allocation.  The
-  // map space free list implicitly assumes that all free blocks are map
-  // sized.
-  if (size_in_bytes == Map::kSize) {
+  // There is no next page in this space.  Try free list allocation.
+  // The fixed space free list implicitly assumes that all free blocks
+  // are of the fixed size.
+  if (size_in_bytes == object_size_in_bytes_) {
     Object* result = free_list_.Allocate();
     if (!result->IsFailure()) {
       accounting_stats_.AllocateBytes(size_in_bytes);
@@ -2094,81 +2075,19 @@
 // Move to the next page (there is assumed to be one) and allocate there.
 // The top of page block is always wasted, because it is too small to hold a
 // map.
-HeapObject* MapSpace::AllocateInNextPage(Page* current_page,
-                                         int size_in_bytes) {
+HeapObject* FixedSpace::AllocateInNextPage(Page* current_page,
+                                           int size_in_bytes) {
   ASSERT(current_page->next_page()->is_valid());
-  ASSERT(current_page->ObjectAreaEnd() - allocation_info_.top == kPageExtra);
-  accounting_stats_.WasteBytes(kPageExtra);
+  ASSERT(current_page->ObjectAreaEnd() - allocation_info_.top == page_extra_);
+  ASSERT_EQ(object_size_in_bytes_, size_in_bytes);
+  accounting_stats_.WasteBytes(page_extra_);
   SetAllocationInfo(&allocation_info_, current_page->next_page());
   return AllocateLinearly(&allocation_info_, size_in_bytes);
 }
 
 
 #ifdef DEBUG
-// We do not assume that the PageIterator works, because it depends on the
-// invariants we are checking during verification.
-void MapSpace::Verify() {
-  // The allocation pointer should be valid, and it should be in a page in the
-  // space.
-  ASSERT(allocation_info_.VerifyPagedAllocation());
-  Page* top_page = Page::FromAllocationTop(allocation_info_.top);
-  ASSERT(MemoryAllocator::IsPageInSpace(top_page, this));
-
-  // Loop over all the pages.
-  bool above_allocation_top = false;
-  Page* current_page = first_page_;
-  while (current_page->is_valid()) {
-    if (above_allocation_top) {
-      // We don't care what's above the allocation top.
-    } else {
-      // Unless this is the last page in the space containing allocated
-      // objects, the allocation top should be at a constant offset from the
-      // object area end.
-      Address top = current_page->AllocationTop();
-      if (current_page == top_page) {
-        ASSERT(top == allocation_info_.top);
-        // The next page will be above the allocation top.
-        above_allocation_top = true;
-      } else {
-        ASSERT(top == current_page->ObjectAreaEnd() - kPageExtra);
-      }
-
-      // It should be packed with objects from the bottom to the top.
-      Address current = current_page->ObjectAreaStart();
-      while (current < top) {
-        HeapObject* object = HeapObject::FromAddress(current);
-
-        // The first word should be a map, and we expect all map pointers to
-        // be in map space.
-        Map* map = object->map();
-        ASSERT(map->IsMap());
-        ASSERT(Heap::map_space()->Contains(map));
-
-        // The object should be a map or a byte array.
-        ASSERT(object->IsMap() || object->IsByteArray());
-
-        // The object itself should look OK.
-        object->Verify();
-
-        // All the interior pointers should be contained in the heap and
-        // have their remembered set bits set if they point to new space.
-        VerifyPointersAndRSetVisitor visitor;
-        int size = object->Size();
-        object->IterateBody(map->instance_type(), size, &visitor);
-
-        current += size;
-      }
-
-      // The allocation pointer should not be in the middle of an object.
-      ASSERT(current == top);
-    }
-
-    current_page = current_page->next_page();
-  }
-}
-
-
-void MapSpace::ReportStatistics() {
+void FixedSpace::ReportStatistics() {
   int pct = Available() * 100 / Capacity();
   PrintF("  capacity: %d, waste: %d, available: %d, %%%d\n",
          Capacity(), Waste(), Available(), pct);
@@ -2215,7 +2134,50 @@
 }
 
 
-void MapSpace::PrintRSet() { DoPrintRSet("map"); }
+void FixedSpace::PrintRSet() { DoPrintRSet(name_); }
+#endif
+
+
+// -----------------------------------------------------------------------------
+// MapSpace implementation
+
+void MapSpace::PrepareForMarkCompact(bool will_compact) {
+  // Call prepare of the super class.
+  FixedSpace::PrepareForMarkCompact(will_compact);
+
+  if (will_compact) {
+    // Initialize map index entry.
+    int page_count = 0;
+    PageIterator it(this, PageIterator::ALL_PAGES);
+    while (it.has_next()) {
+      ASSERT_MAP_PAGE_INDEX(page_count);
+
+      Page* p = it.next();
+      ASSERT(p->mc_page_index == page_count);
+
+      page_addresses_[page_count++] = p->address();
+    }
+  }
+}
+
+
+#ifdef DEBUG
+void MapSpace::VerifyObject(HeapObject* object) {
+  // The object should be a map or a free-list node.
+  ASSERT(object->IsMap() || object->IsByteArray());
+}
+#endif
+
+
+// -----------------------------------------------------------------------------
+// GlobalPropertyCellSpace implementation
+
+#ifdef DEBUG
+void CellSpace::VerifyObject(HeapObject* object) {
+  // The object should be a global object property cell or a free-list node.
+  ASSERT(object->IsJSGlobalPropertyCell() ||
+         object->map() == Heap::two_pointer_filler_map());
+}
 #endif
 
 
diff --git a/src/spaces.h b/src/spaces.h
index 676652b..ccd1d27 100644
--- a/src/spaces.h
+++ b/src/spaces.h
@@ -302,7 +302,6 @@
   virtual int Size() = 0;
 
 #ifdef DEBUG
-  virtual void Verify() = 0;
   virtual void Print() = 0;
 #endif
 
@@ -836,6 +835,13 @@
   // Print meta info and objects in this space.
   virtual void Print();
 
+  // Verify integrity of this space.
+  virtual void Verify(ObjectVisitor* visitor);
+
+  // Overridden by subclasses to verify space-specific object
+  // properties (e.g., only maps or free-list nodes are in map space).
+  virtual void VerifyObject(HeapObject* obj) {}
+
   // Report code object related statistics
   void CollectCodeStatistics();
   static void ReportCodeStatistics();
@@ -862,6 +868,12 @@
   // Relocation information during mark-compact collections.
   AllocationInfo mc_forwarding_info_;
 
+  // Bytes of each page that cannot be allocated.  Possibly non-zero
+  // for pages in spaces with only fixed-size objects.  Always zero
+  // for pages in spaces with variable sized objects (those pages are
+  // padded with free-list nodes).
+  int page_extra_;
+
   // Sets allocation pointer to a page bottom.
   static void SetAllocationInfo(AllocationInfo* alloc_info, Page* p);
 
@@ -1315,8 +1327,7 @@
  private:
   // The size range of blocks, in bytes. (Smaller allocations are allowed, but
   // will always result in waste.)
-  static const int kMinBlockSize =
-      POINTER_SIZE_ALIGN(ByteArray::kHeaderSize) + kPointerSize;
+  static const int kMinBlockSize = 2 * kPointerSize;
   static const int kMaxBlockSize = Page::kMaxHeapObjectSize;
 
   // The identity of the owning space, for building allocation Failure
@@ -1391,9 +1402,9 @@
 
 
 // The free list for the map space.
-class MapSpaceFreeList BASE_EMBEDDED {
+class FixedSizeFreeList BASE_EMBEDDED {
  public:
-  explicit MapSpaceFreeList(AllocationSpace owner);
+  FixedSizeFreeList(AllocationSpace owner, int object_size);
 
   // Clear the free list.
   void Reset();
@@ -1402,12 +1413,12 @@
   int available() { return available_; }
 
   // Place a node on the free list.  The block starting at 'start' (assumed to
-  // have size Map::kSize) is placed on the free list.  Bookkeeping
+  // have size object_size_) is placed on the free list.  Bookkeeping
   // information will be written to the block, ie, its contents will be
   // destroyed.  The start address should be word aligned.
   void Free(Address start);
 
-  // Allocate a map-sized block from the free list.  The block is unitialized.
+  // Allocate a fixed sized block from the free list.  The block is unitialized.
   // A failure is returned if no block is available.
   Object* Allocate();
 
@@ -1422,7 +1433,10 @@
   // objects.
   AllocationSpace owner_;
 
-  DISALLOW_COPY_AND_ASSIGN(MapSpaceFreeList);
+  // The size of the objects in this space.
+  int object_size_;
+
+  DISALLOW_COPY_AND_ASSIGN(FixedSizeFreeList);
 };
 
 
@@ -1437,6 +1451,7 @@
                     AllocationSpace id,
                     Executability executable)
       : PagedSpace(max_capacity, id, executable), free_list_(id) {
+    page_extra_ = 0;
   }
 
   // The bytes available on the free list (ie, not above the linear allocation
@@ -1460,20 +1475,11 @@
   // clears the free list.
   virtual void PrepareForMarkCompact(bool will_compact);
 
-  // Adjust the top of relocation pointer to point to the end of the object
-  // given by 'address' and 'size_in_bytes'.  Move it to the next page if
-  // necessary, ensure that it points to the address, then increment it by the
-  // size.
-  void MCAdjustRelocationEnd(Address address, int size_in_bytes);
-
   // Updates the allocation pointer to the relocation top after a mark-compact
   // collection.
   virtual void MCCommitRelocationInfo();
 
 #ifdef DEBUG
-  // Verify integrity of this space.
-  virtual void Verify();
-
   // Reports statistics for the space
   void ReportStatistics();
   // Dump the remembered sets in the space to stdout.
@@ -1492,39 +1498,41 @@
   // The space's free list.
   OldSpaceFreeList free_list_;
 
-  // During relocation, we keep a pointer to the most recently relocated
-  // object in order to know when to move to the next page.
-  Address mc_end_of_relocation_;
-
  public:
   TRACK_MEMORY("OldSpace")
 };
 
 
 // -----------------------------------------------------------------------------
-// Old space for all map objects
+// Old space for objects of a fixed size
 
-class MapSpace : public PagedSpace {
+class FixedSpace : public PagedSpace {
  public:
-  // Creates a map space object with a maximum capacity.
-  explicit MapSpace(int max_capacity, AllocationSpace id)
-      : PagedSpace(max_capacity, id, NOT_EXECUTABLE), free_list_(id) { }
+  FixedSpace(int max_capacity,
+             AllocationSpace id,
+             int object_size_in_bytes,
+             const char* name)
+      : PagedSpace(max_capacity, id, NOT_EXECUTABLE),
+        object_size_in_bytes_(object_size_in_bytes),
+        name_(name),
+        free_list_(id, object_size_in_bytes) {
+    page_extra_ = Page::kObjectAreaSize % object_size_in_bytes;
+  }
 
   // The top of allocation in a page in this space. Undefined if page is unused.
   virtual Address PageAllocationTop(Page* page) {
     return page == TopPageOf(allocation_info_) ? top()
-        : page->ObjectAreaEnd() - kPageExtra;
+        : page->ObjectAreaEnd() - page_extra_;
   }
 
-  // Give a map-sized block of memory to the space's free list.
+  int object_size_in_bytes() { return object_size_in_bytes_; }
+
+  // Give a fixed sized block of memory to the space's free list.
   void Free(Address start) {
     free_list_.Free(start);
     accounting_stats_.DeallocateBytes(Map::kSize);
   }
 
-  // Given an index, returns the page address.
-  Address PageAddress(int page_index) { return page_addresses_[page_index]; }
-
   // Prepares for a mark-compact GC.
   virtual void PrepareForMarkCompact(bool will_compact);
 
@@ -1533,21 +1541,13 @@
   virtual void MCCommitRelocationInfo();
 
 #ifdef DEBUG
-  // Verify integrity of this space.
-  virtual void Verify();
-
   // Reports statistic info of the space
   void ReportStatistics();
+
   // Dump the remembered sets in the space to stdout.
   void PrintRSet();
 #endif
 
-  // Constants.
-  static const int kMapPageIndexBits = 10;
-  static const int kMaxMapPageIndex = (1 << kMapPageIndexBits) - 1;
-
-  static const int kPageExtra = Page::kObjectAreaSize % Map::kSize;
-
  protected:
   // Virtual function in the superclass.  Slow path of AllocateRaw.
   HeapObject* SlowAllocateRaw(int size_in_bytes);
@@ -1557,9 +1557,41 @@
   HeapObject* AllocateInNextPage(Page* current_page, int size_in_bytes);
 
  private:
-  // The space's free list.
-  MapSpaceFreeList free_list_;
+  // The size of objects in this space.
+  int object_size_in_bytes_;
 
+  // The name of this space.
+  const char* name_;
+
+  // The space's free list.
+  FixedSizeFreeList free_list_;
+};
+
+
+// -----------------------------------------------------------------------------
+// Old space for all map objects
+
+class MapSpace : public FixedSpace {
+ public:
+  // Creates a map space object with a maximum capacity.
+  MapSpace(int max_capacity, AllocationSpace id)
+      : FixedSpace(max_capacity, id, Map::kSize, "map") {}
+
+  // Prepares for a mark-compact GC.
+  virtual void PrepareForMarkCompact(bool will_compact);
+
+  // Given an index, returns the page address.
+  Address PageAddress(int page_index) { return page_addresses_[page_index]; }
+
+  // Constants.
+  static const int kMaxMapPageIndex = (1 << MapWord::kMapPageIndexBits) - 1;
+
+ protected:
+#ifdef DEBUG
+  virtual void VerifyObject(HeapObject* obj);
+#endif
+
+ private:
   // An array of page start address in a map space.
   Address page_addresses_[kMaxMapPageIndex + 1];
 
@@ -1569,6 +1601,25 @@
 
 
 // -----------------------------------------------------------------------------
+// Old space for all global object property cell objects
+
+class CellSpace : public FixedSpace {
+ public:
+  // Creates a property cell space object with a maximum capacity.
+  CellSpace(int max_capacity, AllocationSpace id)
+      : FixedSpace(max_capacity, id, JSGlobalPropertyCell::kSize, "cell") {}
+
+ protected:
+#ifdef DEBUG
+  virtual void VerifyObject(HeapObject* obj);
+#endif
+
+ public:
+  TRACK_MEMORY("MapSpace")
+};
+
+
+// -----------------------------------------------------------------------------
 // Large objects ( > Page::kMaxHeapObjectSize ) are allocated and managed by
 // the large object space. A large object is allocated from OS heap with
 // extra padding bytes (Page::kPageSize + Page::kObjectStartOffset).
diff --git a/src/string-stream.cc b/src/string-stream.cc
index 44ba297..9a137e3 100644
--- a/src/string-stream.cc
+++ b/src/string-stream.cc
@@ -343,10 +343,11 @@
     Add("<Invalid map>\n");
     return;
   }
-  for (DescriptorReader r(map->instance_descriptors()); !r.eos(); r.advance()) {
-    switch (r.type()) {
+  DescriptorArray* descs = map->instance_descriptors();
+  for (int i = 0; i < descs->number_of_descriptors(); i++) {
+    switch (descs->GetType(i)) {
       case FIELD: {
-        Object* key = r.GetKey();
+        Object* key = descs->GetKey(i);
         if (key->IsString() || key->IsNumber()) {
           int len = 3;
           if (key->IsString()) {
@@ -360,7 +361,7 @@
             key->ShortPrint();
           }
           Add(": ");
-          Object* value = js_object->FastPropertyAt(r.GetFieldIndex());
+          Object* value = js_object->FastPropertyAt(descs->GetFieldIndex(i));
           Add("%o\n", value);
         }
       }
diff --git a/src/stub-cache.cc b/src/stub-cache.cc
index 8b3822a..7eb8cd3 100644
--- a/src/stub-cache.cc
+++ b/src/stub-cache.cc
@@ -173,14 +173,19 @@
 
 
 Object* StubCache::ComputeLoadGlobal(String* name,
-                                     GlobalObject* receiver,
+                                     JSObject* receiver,
+                                     GlobalObject* holder,
                                      JSGlobalPropertyCell* cell,
                                      bool is_dont_delete) {
   Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, NORMAL);
   Object* code = receiver->map()->FindInCodeCache(name, flags);
   if (code->IsUndefined()) {
     LoadStubCompiler compiler;
-    code = compiler.CompileLoadGlobal(receiver, cell, name, is_dont_delete);
+    code = compiler.CompileLoadGlobal(receiver,
+                                      holder,
+                                      cell,
+                                      name,
+                                      is_dont_delete);
     if (code->IsFailure()) return code;
     LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
     Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
@@ -445,7 +450,7 @@
     if (!function->is_compiled()) return Failure::InternalError();
     // Compile the stub - only create stubs for fully compiled functions.
     CallStubCompiler compiler(argc, in_loop);
-    code = compiler.CompileCallConstant(object, holder, function, check);
+    code = compiler.CompileCallConstant(object, holder, function, name, check);
     if (code->IsFailure()) return code;
     ASSERT_EQ(flags, Code::cast(code)->flags());
     LOG(CodeCreateEvent(Logger::CALL_IC_TAG, Code::cast(code), name));
@@ -537,7 +542,8 @@
 Object* StubCache::ComputeCallGlobal(int argc,
                                      InLoopFlag in_loop,
                                      String* name,
-                                     GlobalObject* receiver,
+                                     JSObject* receiver,
+                                     GlobalObject* holder,
                                      JSGlobalPropertyCell* cell,
                                      JSFunction* function) {
   Code::Flags flags =
@@ -550,7 +556,7 @@
     // caches.
     if (!function->is_compiled()) return Failure::InternalError();
     CallStubCompiler compiler(argc, in_loop);
-    code = compiler.CompileCallGlobal(receiver, cell, function, name);
+    code = compiler.CompileCallGlobal(receiver, holder, cell, function, name);
     if (code->IsFailure()) return code;
     ASSERT_EQ(flags, Code::cast(code)->flags());
     LOG(CodeCreateEvent(Logger::CALL_IC_TAG, Code::cast(code), name));
@@ -951,6 +957,10 @@
 
 
 Object* StubCompiler::GetCodeWithFlags(Code::Flags flags, const char* name) {
+  // Check for allocation failures during stub compilation.
+  if (failure_->IsFailure()) return failure_;
+
+  // Create code object in the heap.
   CodeDesc desc;
   masm_.GetCode(&desc);
   Object* result = Heap::CreateCode(desc, NULL, flags, masm_.CodeObject());
diff --git a/src/stub-cache.h b/src/stub-cache.h
index 9abf370..8bee370 100644
--- a/src/stub-cache.h
+++ b/src/stub-cache.h
@@ -79,7 +79,8 @@
 
 
   static Object* ComputeLoadGlobal(String* name,
-                                   GlobalObject* receiver,
+                                   JSObject* receiver,
+                                   GlobalObject* holder,
                                    JSGlobalPropertyCell* cell,
                                    bool is_dont_delete);
 
@@ -164,7 +165,8 @@
   static Object* ComputeCallGlobal(int argc,
                                    InLoopFlag in_loop,
                                    String* name,
-                                   GlobalObject* receiver,
+                                   JSObject* receiver,
+                                   GlobalObject* holder,
                                    JSGlobalPropertyCell* cell,
                                    JSFunction* function);
 
@@ -322,7 +324,7 @@
     JSARRAY_HAS_FAST_ELEMENTS_CHECK
   };
 
-  StubCompiler() : scope_(), masm_(NULL, 256) { }
+  StubCompiler() : scope_(), masm_(NULL, 256), failure_(NULL) { }
 
   Object* CompileCallInitialize(Code::Flags flags);
   Object* CompileCallPreMonomorphic(Code::Flags flags);
@@ -342,40 +344,7 @@
   static void GenerateFastPropertyLoad(MacroAssembler* masm,
                                        Register dst, Register src,
                                        JSObject* holder, int index);
-  static void GenerateLoadField(MacroAssembler* masm,
-                                JSObject* object,
-                                JSObject* holder,
-                                Register receiver,
-                                Register scratch1,
-                                Register scratch2,
-                                int index,
-                                Label* miss_label);
-  static void GenerateLoadCallback(MacroAssembler* masm,
-                                   JSObject* object,
-                                   JSObject* holder,
-                                   Register receiver,
-                                   Register name,
-                                   Register scratch1,
-                                   Register scratch2,
-                                   AccessorInfo* callback,
-                                   Label* miss_label);
-  static void GenerateLoadConstant(MacroAssembler* masm,
-                                   JSObject* object,
-                                   JSObject* holder,
-                                   Register receiver,
-                                   Register scratch1,
-                                   Register scratch2,
-                                   Object* value,
-                                   Label* miss_label);
-  static void GenerateLoadInterceptor(MacroAssembler* masm,
-                                      JSObject* object,
-                                      JSObject* holder,
-                                      Smi* lookup_hint,
-                                      Register receiver,
-                                      Register name,
-                                      Register scratch1,
-                                      Register scratch2,
-                                      Label* miss_label);
+
   static void GenerateLoadArrayLength(MacroAssembler* masm,
                                       Register receiver,
                                       Register scratch,
@@ -410,10 +379,60 @@
   Object* GetCodeWithFlags(Code::Flags flags, String* name);
 
   MacroAssembler* masm() { return &masm_; }
+  void set_failure(Failure* failure) { failure_ = failure; }
+
+  // Check the integrity of the prototype chain to make sure that the
+  // current IC is still valid.
+  Register CheckPrototypes(JSObject* object,
+                           Register object_reg,
+                           JSObject* holder,
+                           Register holder_reg,
+                           Register scratch,
+                           String* name,
+                           Label* miss);
+
+  void GenerateLoadField(JSObject* object,
+                         JSObject* holder,
+                         Register receiver,
+                         Register scratch1,
+                         Register scratch2,
+                         int index,
+                         String* name,
+                         Label* miss);
+
+  void GenerateLoadCallback(JSObject* object,
+                            JSObject* holder,
+                            Register receiver,
+                            Register name_reg,
+                            Register scratch1,
+                            Register scratch2,
+                            AccessorInfo* callback,
+                            String* name,
+                            Label* miss);
+
+  void GenerateLoadConstant(JSObject* object,
+                            JSObject* holder,
+                            Register receiver,
+                            Register scratch1,
+                            Register scratch2,
+                            Object* value,
+                            String* name,
+                            Label* miss);
+
+  void GenerateLoadInterceptor(JSObject* object,
+                               JSObject* holder,
+                               Smi* lookup_hint,
+                               Register receiver,
+                               Register name_reg,
+                               Register scratch1,
+                               Register scratch2,
+                               String* name,
+                               Label* miss);
 
  private:
   HandleScope scope_;
   MacroAssembler masm_;
+  Failure* failure_;
 };
 
 
@@ -435,8 +454,9 @@
                                  JSObject* holder,
                                  String* name);
 
-  Object* CompileLoadGlobal(GlobalObject* object,
-                            JSGlobalPropertyCell* holder,
+  Object* CompileLoadGlobal(JSObject* object,
+                            GlobalObject* holder,
+                            JSGlobalPropertyCell* cell,
                             String* name,
                             bool is_dont_delete);
 
@@ -515,11 +535,13 @@
   Object* CompileCallConstant(Object* object,
                               JSObject* holder,
                               JSFunction* function,
+                              String* name,
                               CheckType check);
   Object* CompileCallInterceptor(Object* object,
                                  JSObject* holder,
                                  String* name);
-  Object* CompileCallGlobal(GlobalObject* object,
+  Object* CompileCallGlobal(JSObject* object,
+                            GlobalObject* holder,
                             JSGlobalPropertyCell* cell,
                             JSFunction* function,
                             String* name);
diff --git a/src/unicode.cc b/src/unicode.cc
index 4a9e070..ef13593 100644
--- a/src/unicode.cc
+++ b/src/unicode.cc
@@ -194,18 +194,13 @@
 uchar Utf8::CalculateValue(const byte* str,
                            unsigned length,
                            unsigned* cursor) {
-  static const uchar kMaxOneByteChar = 0x7F;
-  static const uchar kMaxTwoByteChar = 0x7FF;
-  static const uchar kMaxThreeByteChar = 0xFFFF;
-  static const uchar kMaxFourByteChar = 0x1FFFFF;
-
   // We only get called for non-ascii characters.
   if (length == 1) {
     *cursor += 1;
     return kBadChar;
   }
-  int first = str[0];
-  int second = str[1] ^ 0x80;
+  byte first = str[0];
+  byte second = str[1] ^ 0x80;
   if (second & 0xC0) {
     *cursor += 1;
     return kBadChar;
@@ -227,7 +222,7 @@
     *cursor += 1;
     return kBadChar;
   }
-  int third = str[2] ^ 0x80;
+  byte third = str[2] ^ 0x80;
   if (third & 0xC0) {
     *cursor += 1;
     return kBadChar;
@@ -245,7 +240,7 @@
     *cursor += 1;
     return kBadChar;
   }
-  int fourth = str[3] ^ 0x80;
+  byte fourth = str[3] ^ 0x80;
   if (fourth & 0xC0) {
     *cursor += 1;
     return kBadChar;
diff --git a/src/version.cc b/src/version.cc
index 87d99d8..f1833a5 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     1
 #define MINOR_VERSION     2
-#define BUILD_NUMBER      13
-#define PATCH_LEVEL       2 
+#define BUILD_NUMBER      14
+#define PATCH_LEVEL       0
 #define CANDIDATE_VERSION false
 
 // Define SONAME to have the SCons build the put a specific SONAME into the
diff --git a/src/x64/assembler-x64.cc b/src/x64/assembler-x64.cc
index 167334f..c4ee454 100644
--- a/src/x64/assembler-x64.cc
+++ b/src/x64/assembler-x64.cc
@@ -73,45 +73,8 @@
 XMMRegister xmm15 = { 15 };
 
 
-Operand::Operand(Register base, int32_t disp): rex_(0) {
-  len_ = 1;
-  if (base.is(rsp) || base.is(r12)) {
-    // SIB byte is needed to encode (rsp + offset) or (r12 + offset).
-    set_sib(times_1, rsp, base);
-  }
-
-  if (disp == 0 && !base.is(rbp) && !base.is(r13)) {
-    set_modrm(0, base);
-  } else if (is_int8(disp)) {
-    set_modrm(1, base);
-    set_disp8(disp);
-  } else {
-    set_modrm(2, base);
-    set_disp32(disp);
-  }
-}
-
-
-Operand::Operand(Register base,
-                 Register index,
-                 ScaleFactor scale,
-                 int32_t disp): rex_(0) {
-  ASSERT(!index.is(rsp));
-  len_ = 1;
-  set_sib(scale, index, base);
-  if (disp == 0 && !base.is(rbp) && !base.is(r13)) {
-    // This call to set_modrm doesn't overwrite the REX.B (or REX.X) bits
-    // possibly set by set_sib.
-    set_modrm(0, rsp);
-  } else if (is_int8(disp)) {
-    set_modrm(1, rsp);
-    set_disp8(disp);
-  } else {
-    set_modrm(2, rsp);
-    set_disp32(disp);
-  }
-}
-
+// -----------------------------------------------------------------------------
+// Implementation of CpuFeatures
 
 // The required user mode extensions in X64 are (from AMD64 ABI Table A.1):
 //   fpu, tsc, cx8, cmov, mmx, sse, sse2, fxsr, syscall
@@ -193,6 +156,71 @@
   ASSERT(IsSupported(CMOV));
 }
 
+
+// -----------------------------------------------------------------------------
+// Implementation of RelocInfo
+
+// Patch the code at the current PC with a call to the target address.
+// Additional guard int3 instructions can be added if required.
+void RelocInfo::PatchCodeWithCall(Address target, int guard_bytes) {
+  // Call instruction takes up 13 bytes and int3 takes up one byte.
+  Address patch_site = pc_;
+  Memory::uint16_at(patch_site) = 0xBA49u;  // movq r10, imm64
+  // Write "0x00, call r10" starting at last byte of address.  We overwrite
+  // the 0x00 later, and this lets us write a uint32.
+  Memory::uint32_at(patch_site + 9) = 0xD2FF4900u;  // 0x00, call r10
+  Memory::Address_at(patch_site + 2) = target;
+
+  // Add the requested number of int3 instructions after the call.
+  for (int i = 0; i < guard_bytes; i++) {
+    *(patch_site + 13 + i) = 0xCC;  // int3
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Implementation of Operand
+
+Operand::Operand(Register base, int32_t disp): rex_(0) {
+  len_ = 1;
+  if (base.is(rsp) || base.is(r12)) {
+    // SIB byte is needed to encode (rsp + offset) or (r12 + offset).
+    set_sib(times_1, rsp, base);
+  }
+
+  if (disp == 0 && !base.is(rbp) && !base.is(r13)) {
+    set_modrm(0, base);
+  } else if (is_int8(disp)) {
+    set_modrm(1, base);
+    set_disp8(disp);
+  } else {
+    set_modrm(2, base);
+    set_disp32(disp);
+  }
+}
+
+
+Operand::Operand(Register base,
+                 Register index,
+                 ScaleFactor scale,
+                 int32_t disp): rex_(0) {
+  ASSERT(!index.is(rsp));
+  len_ = 1;
+  set_sib(scale, index, base);
+  if (disp == 0 && !base.is(rbp) && !base.is(r13)) {
+    // This call to set_modrm doesn't overwrite the REX.B (or REX.X) bits
+    // possibly set by set_sib.
+    set_modrm(0, rsp);
+  } else if (is_int8(disp)) {
+    set_modrm(1, rsp);
+    set_disp8(disp);
+  } else {
+    set_modrm(2, rsp);
+    set_disp32(disp);
+  }
+}
+
+
 // -----------------------------------------------------------------------------
 // Implementation of Assembler
 
@@ -579,6 +607,23 @@
 }
 
 
+void Assembler::shift_32(Register dst, Immediate shift_amount, int subcode) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  ASSERT(is_uint6(shift_amount.value_));  // illegal shift count
+  if (shift_amount.value_ == 1) {
+    emit_optional_rex_32(dst);
+    emit(0xD1);
+    emit_modrm(subcode, dst);
+  } else {
+    emit_optional_rex_32(dst);
+    emit(0xC1);
+    emit_modrm(subcode, dst);
+    emit(shift_amount.value_);
+  }
+}
+
+
 void Assembler::bt(const Operand& dst, Register src) {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
diff --git a/src/x64/assembler-x64.h b/src/x64/assembler-x64.h
index 7e30934..e895332 100644
--- a/src/x64/assembler-x64.h
+++ b/src/x64/assembler-x64.h
@@ -690,11 +690,22 @@
     shift(dst, shift_amount, 0x7);
   }
 
+  // Shifts dst right, duplicating sign bit, by shift_amount bits.
+  // Shifting by 1 is handled efficiently.
+  void sarl(Register dst, Immediate shift_amount) {
+    shift_32(dst, shift_amount, 0x7);
+  }
+
   // Shifts dst right, duplicating sign bit, by cl % 64 bits.
   void sar(Register dst) {
     shift(dst, 0x7);
   }
 
+  // Shifts dst right, duplicating sign bit, by cl % 64 bits.
+  void sarl(Register dst) {
+    shift_32(dst, 0x7);
+  }
+
   void shl(Register dst, Immediate shift_amount) {
     shift(dst, shift_amount, 0x4);
   }
@@ -1123,6 +1134,7 @@
                                  Immediate src);
   // Emit machine code for a shift operation.
   void shift(Register dst, Immediate shift_amount, int subcode);
+  void shift_32(Register dst, Immediate shift_amount, int subcode);
   // Shift dst by cl % 64 bits.
   void shift(Register dst, int subcode);
   void shift_32(Register dst, int subcode);
diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc
index b1f2b8f..e3e32e6 100644
--- a/src/x64/codegen-x64.cc
+++ b/src/x64/codegen-x64.cc
@@ -355,14 +355,19 @@
   // receiver.
   frame_->Exit();
   masm_->ret((scope_->num_parameters() + 1) * kPointerSize);
+  // Add padding that will be overwritten by a debugger breakpoint.
+  // frame_->Exit() generates "movq rsp, rbp; pop rbp" length 5.
+  // "ret k" has length 2.
+  const int kPadding = Debug::kX64JSReturnSequenceLength - 5 - 2;
+  for (int i = 0; i < kPadding; ++i) {
+    masm_->int3();
+  }
   DeleteFrame();
 
-  // TODO(x64): introduce kX64JSReturnSequenceLength and enable assert.
-
   // Check that the size of the code used for returning matches what is
   // expected by the debugger.
-  // ASSERT_EQ(Debug::kIa32JSReturnSequenceLength,
-  //          masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
+  ASSERT_EQ(Debug::kX64JSReturnSequenceLength,
+            masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
 }
 
 
@@ -1292,7 +1297,7 @@
   node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY);
 
   __ movq(rax, frame_->ElementAt(0));  // load the current count
-  __ cmpq(rax, frame_->ElementAt(1));  // compare to the array length
+  __ cmpl(rax, frame_->ElementAt(1));  // compare to the array length
   node->break_target()->Branch(above_equal);
 
   // Get the i'th entry of the array.
@@ -2724,12 +2729,6 @@
 
 
 void DeferredPrefixCountOperation::Generate() {
-  // Undo the optimistic smi operation.
-  if (is_increment_) {
-    __ subq(dst_, Immediate(Smi::FromInt(1)));
-  } else {
-    __ addq(dst_, Immediate(Smi::FromInt(1)));
-  }
   __ push(dst_);
   __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
   __ push(rax);
@@ -2765,12 +2764,6 @@
 
 
 void DeferredPostfixCountOperation::Generate() {
-  // Undo the optimistic smi operation.
-  if (is_increment_) {
-    __ subq(dst_, Immediate(Smi::FromInt(1)));
-  } else {
-    __ addq(dst_, Immediate(Smi::FromInt(1)));
-  }
   __ push(dst_);
   __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
 
@@ -2827,19 +2820,6 @@
     // Ensure the new value is writable.
     frame_->Spill(new_value.reg());
 
-    // In order to combine the overflow and the smi tag check, we need
-    // to be able to allocate a byte register.  We attempt to do so
-    // without spilling.  If we fail, we will generate separate overflow
-    // and smi tag checks.
-    //
-    // We allocate and clear the temporary register before
-    // performing the count operation since clearing the register using
-    // xor will clear the overflow flag.
-    Result tmp = allocator_->AllocateWithoutSpilling();
-
-    // Clear scratch register to prepare it for setcc after the operation below.
-    __ xor_(kScratchRegister, kScratchRegister);
-
     DeferredCode* deferred = NULL;
     if (is_postfix) {
       deferred = new DeferredPostfixCountOperation(new_value.reg(),
@@ -2850,25 +2830,26 @@
                                                   is_increment);
     }
 
+    Result tmp = allocator_->AllocateWithoutSpilling();
+    ASSERT(kSmiTagMask == 1 && kSmiTag == 0);
+    __ movl(tmp.reg(), Immediate(kSmiTagMask));
+    // Smi test.
+    __ movq(kScratchRegister, new_value.reg());
     if (is_increment) {
-      __ addq(new_value.reg(), Immediate(Smi::FromInt(1)));
+      __ addl(kScratchRegister, Immediate(Smi::FromInt(1)));
     } else {
-      __ subq(new_value.reg(), Immediate(Smi::FromInt(1)));
+      __ subl(kScratchRegister, Immediate(Smi::FromInt(1)));
     }
-
-    // If the count operation didn't overflow and the result is a valid
-    // smi, we're done. Otherwise, we jump to the deferred slow-case
-    // code.
-
-    // We combine the overflow and the smi tag check.
-    __ setcc(overflow, kScratchRegister);
-    __ or_(kScratchRegister, new_value.reg());
-    __ testl(kScratchRegister, Immediate(kSmiTagMask));
+    // deferred->Branch(overflow);
+    __ cmovl(overflow, kScratchRegister, tmp.reg());
+    __ testl(kScratchRegister, tmp.reg());
     tmp.Unuse();
     deferred->Branch(not_zero);
+    __ movq(new_value.reg(), kScratchRegister);
 
     deferred->BindExit();
 
+
     // Postfix: store the old value in the allocated slot under the
     // reference.
     if (is_postfix) frame_->SetElementAt(target.size(), &old_value);
@@ -5081,12 +5062,12 @@
     // Perform the operation.
     switch (op) {
       case Token::SAR:
-        __ sar(answer.reg());
+        __ sarl(answer.reg());
         // No checks of result necessary
         break;
       case Token::SHR: {
         Label result_ok;
-        __ shr(answer.reg());
+        __ shrl(answer.reg());
         // Check that the *unsigned* result fits in a smi.  Neither of
         // the two high-order bits can be set:
         //  * 0x80000000: high bit would be lost when smi tagging.
@@ -5109,7 +5090,7 @@
         Label result_ok;
         __ shl(answer.reg());
         // Check that the *signed* result fits in a smi.
-        __ cmpq(answer.reg(), Immediate(0xc0000000));
+        __ cmpl(answer.reg(), Immediate(0xc0000000));
         __ j(positive, &result_ok);
         ASSERT(kSmiTag == 0);
         __ shl(rcx, Immediate(kSmiTagSize));
@@ -6675,12 +6656,12 @@
       // Move the second operand into register ecx.
       __ movq(rcx, rbx);
       // Remove tags from operands (but keep sign).
-      __ sar(rax, Immediate(kSmiTagSize));
-      __ sar(rcx, Immediate(kSmiTagSize));
+      __ sarl(rax, Immediate(kSmiTagSize));
+      __ sarl(rcx, Immediate(kSmiTagSize));
       // Perform the operation.
       switch (op_) {
         case Token::SAR:
-          __ sar(rax);
+          __ sarl(rax);
           // No checks of result necessary
           break;
         case Token::SHR:
@@ -6691,19 +6672,17 @@
           // - 0x40000000: this number would convert to negative when
           // Smi tagging these two cases can only happen with shifts
           // by 0 or 1 when handed a valid smi.
-          __ testq(rax, Immediate(0xc0000000));
+          __ testl(rax, Immediate(0xc0000000));
           __ j(not_zero, slow);
           break;
         case Token::SHL:
           __ shll(rax);
-          // TODO(Smi): Significant change if Smi changes.
           // Check that the *signed* result fits in a smi.
           // It does, if the 30th and 31st bits are equal, since then
           // shifting the SmiTag in at the bottom doesn't change the sign.
           ASSERT(kSmiTagSize == 1);
           __ cmpl(rax, Immediate(0xc0000000));
           __ j(sign, slow);
-          __ movsxlq(rax, rax);  // Extend new sign of eax into rax.
           break;
         default:
           UNREACHABLE();
@@ -6815,7 +6794,6 @@
         __ testl(rax, Immediate(1));
         __ j(not_zero, &operand_conversion_failure);
       } else {
-        // TODO(X64): Verify that SSE3 is always supported, drop this code.
         // Check if right operand is int32.
         __ fist_s(Operand(rsp, 0 * kPointerSize));
         __ fild_s(Operand(rsp, 0 * kPointerSize));
@@ -6842,9 +6820,9 @@
         case Token::BIT_OR:  __ or_(rax, rcx); break;
         case Token::BIT_AND: __ and_(rax, rcx); break;
         case Token::BIT_XOR: __ xor_(rax, rcx); break;
-        case Token::SAR: __ sar(rax); break;
-        case Token::SHL: __ shl(rax); break;
-        case Token::SHR: __ shr(rax); break;
+        case Token::SAR: __ sarl(rax); break;
+        case Token::SHL: __ shll(rax); break;
+        case Token::SHR: __ shrl(rax); break;
         default: UNREACHABLE();
       }
       if (op_ == Token::SHR) {
diff --git a/src/x64/debug-x64.cc b/src/x64/debug-x64.cc
index 3b10132..e94e781 100644
--- a/src/x64/debug-x64.cc
+++ b/src/x64/debug-x64.cc
@@ -38,8 +38,10 @@
 #ifdef ENABLE_DEBUGGER_SUPPORT
 
 bool Debug::IsDebugBreakAtReturn(v8::internal::RelocInfo* rinfo) {
-  UNIMPLEMENTED();
-  return false;
+  ASSERT(RelocInfo::IsJSReturn(rinfo->rmode()));
+  // 11th byte of patch is 0x49, 11th byte of JS return is 0xCC (int3).
+  ASSERT(*(rinfo->pc() + 10) == 0x49 || *(rinfo->pc() + 10) == 0xCC);
+  return (*(rinfo->pc() + 10) == 0x49);
 }
 
 void Debug::GenerateCallICDebugBreak(MacroAssembler* masm) {
diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc
index 1a24694..c577615 100644
--- a/src/x64/stub-cache-x64.cc
+++ b/src/x64/stub-cache-x64.cc
@@ -42,7 +42,8 @@
 Object* CallStubCompiler::CompileCallConstant(Object* a,
                                               JSObject* b,
                                               JSFunction* c,
-                                              StubCompiler::CheckType d) {
+                                              String* d,
+                                              StubCompiler::CheckType e) {
   UNIMPLEMENTED();
   return NULL;
 }
@@ -65,7 +66,8 @@
 
 
 
-Object* CallStubCompiler::CompileCallGlobal(GlobalObject* object,
+Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
+                                            GlobalObject* holder,
                                             JSGlobalPropertyCell* cell,
                                             JSFunction* function,
                                             String* name) {
@@ -109,7 +111,8 @@
 }
 
 
-Object* LoadStubCompiler::CompileLoadGlobal(GlobalObject* object,
+Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
+                                            GlobalObject* holder,
                                             JSGlobalPropertyCell* cell,
                                             String* name,
                                             bool is_dont_delete) {
diff --git a/test/cctest/cctest.status b/test/cctest/cctest.status
index 68aabb5..bb82fc8 100644
--- a/test/cctest/cctest.status
+++ b/test/cctest/cctest.status
@@ -60,3 +60,65 @@
 # the JavaScript stacks are separate.
 test-api/ExceptionOrder: FAIL
 test-api/TryCatchInTryFinally: FAIL
+
+
+[ $arch == x64 ]
+test-regexp/Graph: CRASH || FAIL
+test-decls/Present: CRASH || FAIL
+test-decls/Unknown: CRASH || FAIL
+test-decls/Appearing: CRASH || FAIL
+test-decls/Absent: CRASH || FAIL
+test-debug/DebugStub: CRASH || FAIL
+test-decls/AbsentInPrototype: CRASH || FAIL
+test-decls/Reappearing: CRASH || FAIL
+test-debug/DebugInfo: CRASH || FAIL
+test-decls/ExistsInPrototype: CRASH || FAIL
+test-debug/BreakPointICStore: CRASH || FAIL
+test-debug/BreakPointICLoad: CRASH || FAIL
+test-debug/BreakPointICCall: CRASH || FAIL
+test-debug/BreakPointReturn: CRASH || FAIL
+test-debug/GCDuringBreakPointProcessing: CRASH || FAIL
+test-debug/BreakPointSurviveGC: CRASH || FAIL
+test-debug/BreakPointThroughJavaScript: CRASH || FAIL
+test-debug/ScriptBreakPointByNameThroughJavaScript: CRASH || FAIL
+test-debug/ScriptBreakPointByIdThroughJavaScript: CRASH || FAIL
+test-debug/EnableDisableScriptBreakPoint: CRASH || FAIL
+test-debug/ConditionalScriptBreakPoint: CRASH || FAIL
+test-debug/ScriptBreakPointIgnoreCount: CRASH || FAIL
+test-debug/ScriptBreakPointReload: CRASH || FAIL
+test-debug/ScriptBreakPointMultiple: CRASH || FAIL
+test-debug/RemoveBreakPointInBreak: CRASH || FAIL
+test-debug/DebugEvaluate: CRASH || FAIL
+test-debug/ScriptBreakPointLine: CRASH || FAIL
+test-debug/ScriptBreakPointLineOffset: CRASH || FAIL
+test-debug/DebugStepLinear: CRASH || FAIL
+test-debug/DebugStepKeyedLoadLoop: CRASH || FAIL
+test-debug/DebugStepKeyedStoreLoop: CRASH || FAIL
+test-debug/DebugStepLinearMixedICs: CRASH || FAIL
+test-debug/DebugStepFor: CRASH || FAIL
+test-debug/DebugStepIf: CRASH || FAIL
+test-debug/DebugStepSwitch: CRASH || FAIL
+test-debug/StepInOutSimple: CRASH || FAIL
+test-debug/StepInOutBranch: CRASH || FAIL
+test-debug/StepInOutTree: CRASH || FAIL
+test-debug/DebugStepNatives: CRASH || FAIL
+test-debug/DebugStepFunctionApply: CRASH || FAIL
+test-debug/DebugStepFunctionCall: CRASH || FAIL
+test-debug/StepWithException: CRASH || FAIL
+test-debug/DebugBreak: CRASH || FAIL
+test-debug/DisableBreak: CRASH || FAIL
+test-debug/MessageQueues: CRASH || FAIL
+test-debug/CallFunctionInDebugger: CRASH || FAIL
+test-debug/RecursiveBreakpoints: CRASH || FAIL
+test-debug/DebuggerUnload: CRASH || FAIL
+test-debug/DebuggerClearMessageHandler: CRASH || FAIL
+test-debug/DebuggerClearMessageHandlerWhileActive: CRASH || FAIL
+test-debug/DebuggerHostDispatch: CRASH || FAIL
+test-debug/DebugBreakInMessageHandler: CRASH || FAIL
+test-api/HugeConsStringOutOfMemory: CRASH || FAIL
+test-api/OutOfMemory: CRASH || FAIL
+test-api/OutOfMemoryNested: CRASH || FAIL
+test-api/Threading: CRASH || FAIL
+test-api/TryCatchSourceInfo: CRASH || FAIL
+test-api/RegExpInterruption: CRASH || FAIL
+test-api/RegExpStringModification: CRASH || FAIL
diff --git a/test/message/message.status b/test/message/message.status
index fc2896b..d40151e 100644
--- a/test/message/message.status
+++ b/test/message/message.status
@@ -29,3 +29,16 @@
 
 # All tests in the bug directory are expected to fail.
 bugs: FAIL
+
+[ $arch == x64 ]
+
+simple-throw.js: FAIL
+try-catch-finally-throw-in-catch-and-finally.js: FAIL
+try-catch-finally-throw-in-catch.js: FAIL
+try-catch-finally-throw-in-finally.js: FAIL
+try-finally-throw-in-finally.js: FAIL
+try-finally-throw-in-try-and-finally.js: FAIL
+try-finally-throw-in-try.js: FAIL
+overwritten-builtins.js: FAIL
+regress-73.js: FAIL
+regress-75.js: FAIL
diff --git a/test/mjsunit/apply.js b/test/mjsunit/apply.js
index 1d9dde9..a4b0fd7 100644
--- a/test/mjsunit/apply.js
+++ b/test/mjsunit/apply.js
@@ -38,12 +38,12 @@
 assertTrue(this === f0.apply(this), "2a");
 assertTrue(this === f0.apply(this, new Array(1)), "2b");
 assertTrue(this === f0.apply(this, new Array(2)), "2c");
-assertTrue(this === f0.apply(this, new Array(4242)), "2c");
+assertTrue(this === f0.apply(this, new Array(4242)), "2d");
 
 assertTrue(this === f0.apply(null), "3a");
 assertTrue(this === f0.apply(null, new Array(1)), "3b");
 assertTrue(this === f0.apply(null, new Array(2)), "3c");
-assertTrue(this === f0.apply(this, new Array(4242)), "2c");
+assertTrue(this === f0.apply(this, new Array(4242)), "3d");
 
 assertTrue(this === f0.apply(void 0), "4a");
 assertTrue(this === f0.apply(void 0, new Array(1)), "4b");
@@ -51,26 +51,26 @@
 
 assertTrue(void 0 === f1.apply(), "1-1");
 
-assertTrue(void 0 === f1.apply(this), "2a");
-assertTrue(void 0 === f1.apply(this, new Array(1)), "2b");
-assertTrue(void 0 === f1.apply(this, new Array(2)), "2c");
-assertTrue(void 0 === f1.apply(this, new Array(4242)), "2c");
-assertTrue(42 === f1.apply(this, new Array(42, 43)), "2c");
-assertEquals("foo", f1.apply(this, new Array("foo", "bar", "baz", "boo")), "2c");
+assertTrue(void 0 === f1.apply(this), "5a");
+assertTrue(void 0 === f1.apply(this, new Array(1)), "5b");
+assertTrue(void 0 === f1.apply(this, new Array(2)), "5c");
+assertTrue(void 0 === f1.apply(this, new Array(4242)), "5d");
+assertTrue(42 === f1.apply(this, new Array(42, 43)), "5e");
+assertEquals("foo", f1.apply(this, new Array("foo", "bar", "baz", "bo")), "5f");
 
-assertTrue(void 0 === f1.apply(null), "3a");
-assertTrue(void 0 === f1.apply(null, new Array(1)), "3b");
-assertTrue(void 0 === f1.apply(null, new Array(2)), "3c");
-assertTrue(void 0 === f1.apply(null, new Array(4242)), "2c");
-assertTrue(42 === f1.apply(null, new Array(42, 43)), "2c");
-assertEquals("foo", f1.apply(null, new Array("foo", "bar", "baz", "boo")), "2c");
+assertTrue(void 0 === f1.apply(null), "6a");
+assertTrue(void 0 === f1.apply(null, new Array(1)), "6b");
+assertTrue(void 0 === f1.apply(null, new Array(2)), "6c");
+assertTrue(void 0 === f1.apply(null, new Array(4242)), "6d");
+assertTrue(42 === f1.apply(null, new Array(42, 43)), "6e");
+assertEquals("foo", f1.apply(null, new Array("foo", "bar", "baz", "bo")), "6f");
 
-assertTrue(void 0 === f1.apply(void 0), "4a");
-assertTrue(void 0 === f1.apply(void 0, new Array(1)), "4b");
-assertTrue(void 0 === f1.apply(void 0, new Array(2)), "4c");
-assertTrue(void 0 === f1.apply(void 0, new Array(4242)), "4c");
-assertTrue(42 === f1.apply(void 0, new Array(42, 43)), "2c");
-assertEquals("foo", f1.apply(void 0, new Array("foo", "bar", "baz", "boo")), "2c");
+assertTrue(void 0 === f1.apply(void 0), "7a");
+assertTrue(void 0 === f1.apply(void 0, new Array(1)), "7b");
+assertTrue(void 0 === f1.apply(void 0, new Array(2)), "7c");
+assertTrue(void 0 === f1.apply(void 0, new Array(4242)), "7d");
+assertTrue(42 === f1.apply(void 0, new Array(42, 43)), "7e");
+assertEquals("foo", f1.apply(void 0, new Array("foo", "bar", "ba", "b")), "7f");
 
 var arr = new Array(42, "foo", "fish", "horse");
 function j(a, b, c, d, e, f, g, h, i, j, k, l) {
@@ -81,7 +81,7 @@
 var expect = "42foofishhorse";
 for (var i = 0; i < 8; i++)
   expect += "undefined";
-assertEquals(expect, j.apply(undefined, arr));
+assertEquals(expect, j.apply(undefined, arr), "apply to undefined");
 
 assertThrows("f0.apply(this, 1);");
 assertThrows("f0.apply(this, 1, 2);");
@@ -95,7 +95,7 @@
   return doo;
 }
   
-assertEquals("42foofishhorse", f.apply(this, arr));
+assertEquals("42foofishhorse", f.apply(this, arr), "apply to this");
 
 function s() {
   var doo = this;
@@ -105,7 +105,7 @@
   return doo;
 }
 
-assertEquals("bar42foofishhorse", s.apply("bar", arr));
+assertEquals("bar42foofishhorse", s.apply("bar", arr), "apply to string");
 
 function al() {
   assertEquals(345, this);
@@ -118,19 +118,24 @@
     a[j - 1] = 42;
     assertEquals(42 + j, al.apply(345, a));
   } catch (e) {
-    assertTrue(e.toString().indexOf("Function.prototype.apply") != -1);
+    assertTrue(e.toString().indexOf("Function.prototype.apply") != -1,
+              "exception does not contain Function.prototype.apply: " +
+                  e.toString());
     for (; j < 0x40000000; j <<= 1) {
       var caught = false;
       try {
         a = new Array(j);
         a[j - 1] = 42;
         al.apply(345, a);
-        assertEquals("Shouldn't get", "here");
+        assertUnreachable("Apply of arrray with length " + a.length +
+                          " should have thrown");
       } catch (e) {
-        assertTrue(e.toString().indexOf("Function.prototype.apply") != -1);
+        assertTrue(e.toString().indexOf("Function.prototype.apply") != -1,
+                   "exception does not contain Function.prototype.apply [" +
+                   "length = " + j + "]: " + e.toString());
         caught = true;
       }
-      assertTrue(caught);
+      assertTrue(caught, "exception not caught");
     }
     break;
   }
@@ -160,8 +165,8 @@
 var same_primes = Array.prototype.constructor.apply(Array, primes);
 
 for (var i = 0; i < primes.length; i++)
-  assertEquals(primes[i], same_primes[i]);
-assertEquals(primes.length, same_primes.length);
+  assertEquals(primes[i], same_primes[i], "prime" + primes[i]);
+assertEquals(primes.length, same_primes.length, "prime-length");
 
 
 Array.prototype["1"] = "sep";
@@ -170,15 +175,22 @@
 holey[0] = "mor";
 holey[2] = "er";
 
-assertEquals("morseper", String.prototype.concat.apply("", holey));
-assertEquals("morseper", String.prototype.concat.apply("", holey, 1));
-assertEquals("morseper", String.prototype.concat.apply("", holey, 1, 2));
-assertEquals("morseper", String.prototype.concat.apply("", holey, 1, 2, 3));
-assertEquals("morseper", String.prototype.concat.apply("", holey, 1, 2, 3, 4));
+assertEquals("morseper", String.prototype.concat.apply("", holey),
+             "moreseper0");
+assertEquals("morseper", String.prototype.concat.apply("", holey, 1),
+             "moreseper1");
+assertEquals("morseper", String.prototype.concat.apply("", holey, 1, 2),
+             "moreseper2");
+assertEquals("morseper", String.prototype.concat.apply("", holey, 1, 2, 3),
+             "morseper3");
+assertEquals("morseper", String.prototype.concat.apply("", holey, 1, 2, 3, 4),
+             "morseper4");
 
 primes[0] = "";
 primes[1] = holey;
 assertThrows("String.prototype.concat.apply.apply('foo', primes)");
-assertEquals("morseper", String.prototype.concat.apply.apply(String.prototype.concat, primes));
+assertEquals("morseper",
+    String.prototype.concat.apply.apply(String.prototype.concat, primes), 
+    "moreseper-prime");
 
 delete(Array.prototype["1"]);
diff --git a/test/mjsunit/array-reduce.js b/test/mjsunit/array-reduce.js
index e476e1c..83d9023 100644
--- a/test/mjsunit/array-reduce.js
+++ b/test/mjsunit/array-reduce.js
@@ -413,7 +413,7 @@
 
 try {
   [1].reduce("not a function");
-  fail("Reduce callback not a function not throwing");
+  assertUnreachable("Reduce callback not a function not throwing");
 } catch (e) {
   assertTrue(e instanceof TypeError,
              "reduce callback not a function not throwing TypeError");
@@ -423,7 +423,7 @@
 
 try {
   [1].reduceRight("not a function");
-  fail("ReduceRight callback not a function not throwing");
+  assertUnreachable("ReduceRight callback not a function not throwing");
 } catch (e) {
   assertTrue(e instanceof TypeError,
              "reduceRight callback not a function not throwing TypeError");
@@ -434,7 +434,7 @@
 
 try {
   [].reduce(sum);
-  fail("Reduce no initial value not throwing");
+  assertUnreachable("Reduce no initial value not throwing");
 } catch (e) {
   assertTrue(e instanceof TypeError,
              "reduce no initial value not throwing TypeError");
@@ -444,7 +444,7 @@
 
 try {
   [].reduceRight(sum);
-  fail("ReduceRight no initial value not throwing");
+  assertUnreachable("ReduceRight no initial value not throwing");
 } catch (e) {
   assertTrue(e instanceof TypeError,
              "reduceRight no initial value not throwing TypeError");
@@ -455,7 +455,7 @@
 
 try {
   [,,,].reduce(sum);
-  fail("Reduce sparse no initial value not throwing");
+  assertUnreachable("Reduce sparse no initial value not throwing");
 } catch (e) {
   assertTrue(e instanceof TypeError,
              "reduce sparse no initial value not throwing TypeError");
@@ -465,7 +465,7 @@
 
 try {
   [,,,].reduceRight(sum);
-  fail("ReduceRight sparse no initial value not throwing");
+  assertUnreachable("ReduceRight sparse no initial value not throwing");
 } catch (e) {
   assertTrue(e instanceof TypeError,
              "reduceRight sparse no initial value not throwing TypeError");
diff --git a/test/mjsunit/big-array-literal.js b/test/mjsunit/big-array-literal.js
index d64c968..a0fad7c 100644
--- a/test/mjsunit/big-array-literal.js
+++ b/test/mjsunit/big-array-literal.js
@@ -81,7 +81,7 @@
 }
 
 // The sizes to test.
-var sizes = [1, 2, 100, 200, 400];
+var sizes = [1, 2, 100, 200, 300];
 
 // Run the test.
 for (var i = 0; i < sizes.length; i++) {
diff --git a/test/mjsunit/date-parse.js b/test/mjsunit/date-parse.js
index 56ceba3..bb7ecd2 100644
--- a/test/mjsunit/date-parse.js
+++ b/test/mjsunit/date-parse.js
@@ -33,16 +33,16 @@
 
 function testDateParse(string) {
   var d = Date.parse(string);
-  assertEquals(946713600000, d, string);
+  assertEquals(946713600000, d, "parse: " + string);
 };
 
 
 // For local time we just test that parsing returns non-NaN positive
 // number of milliseconds to make it timezone independent.
 function testDateParseLocalTime(string) {
-  var d = Date.parse(string);
-  assertTrue(!isNaN(d), string + " is NaN.");
-  assertTrue(d > 0, string + " <= 0.");
+  var d = Date.parse("parse-local-time:" + string);
+  assertTrue(!isNaN(d), "parse-local-time: " + string + " is NaN.");
+  assertTrue(d > 0, "parse-local-time: " + string + " <= 0.");
 };
 
 
@@ -51,7 +51,7 @@
   var string = array[0];
   var expected = array[1];
   var d = Date.parse(string);
-  assertEquals(expected, d, string);
+  assertEquals(expected, d, "parse-misc: " + string);
 }
 
 
diff --git a/test/mjsunit/debug-backtrace.js b/test/mjsunit/debug-backtrace.js
index 1d2bb9a..0c200ae 100644
--- a/test/mjsunit/debug-backtrace.js
+++ b/test/mjsunit/debug-backtrace.js
@@ -76,167 +76,166 @@
 
 function listener(event, exec_state, event_data, data) {
   try {
-  if (event == Debug.DebugEvent.Break)
-  {
-    // The expected backtrace is
-    // 0: f
-    // 1: m
-    // 2: g
-    // 3: [anonymous]
-    
-    var response;
-    var backtrace;
-    var frame;
-    var source;
-    
-    // Get the debug command processor.
-    var dcp = exec_state.debugCommandProcessor();
+    if (event == Debug.DebugEvent.Break) {
+      // The expected backtrace is
+      // 0: f
+      // 1: m
+      // 2: g
+      // 3: [anonymous]
 
-    // Get the backtrace.
-    var json;
-    json = '{"seq":0,"type":"request","command":"backtrace"}'
-    var resp = dcp.processDebugJSONRequest(json);
-    response = new ParsedResponse(resp);
-    backtrace = response.body();
-    assertEquals(0, backtrace.fromFrame);
-    assertEquals(4, backtrace.toFrame);
-    assertEquals(4, backtrace.totalFrames);
-    var frames = backtrace.frames;
-    assertEquals(4, frames.length);
-    for (var i = 0; i < frames.length; i++) {
-      assertEquals('frame', frames[i].type);
+      var response;
+      var backtrace;
+      var frame;
+      var source;
+
+      // Get the debug command processor.
+      var dcp = exec_state.debugCommandProcessor();
+
+      // Get the backtrace.
+      var json;
+      json = '{"seq":0,"type":"request","command":"backtrace"}'
+      var resp = dcp.processDebugJSONRequest(json);
+      response = new ParsedResponse(resp);
+      backtrace = response.body();
+      assertEquals(0, backtrace.fromFrame);
+      assertEquals(4, backtrace.toFrame);
+      assertEquals(4, backtrace.totalFrames);
+      var frames = backtrace.frames;
+      assertEquals(4, frames.length);
+      for (var i = 0; i < frames.length; i++) {
+        assertEquals('frame', frames[i].type);
+      }
+      assertEquals(0, frames[0].index);
+      assertEquals("f", response.lookup(frames[0].func.ref).name);
+      assertEquals(1, frames[1].index);
+      assertEquals("", response.lookup(frames[1].func.ref).name);
+      assertEquals("m", response.lookup(frames[1].func.ref).inferredName);
+      assertEquals(2, frames[2].index);
+      assertEquals("g", response.lookup(frames[2].func.ref).name);
+      assertEquals(3, frames[3].index);
+      assertEquals("", response.lookup(frames[3].func.ref).name);
+
+      // Get backtrace with two frames.
+      json = '{"seq":0,"type":"request","command":"backtrace","arguments":{"fromFrame":1,"toFrame":3}}'
+      response = new ParsedResponse(dcp.processDebugJSONRequest(json));
+      backtrace = response.body();
+      assertEquals(1, backtrace.fromFrame);
+      assertEquals(3, backtrace.toFrame);
+      assertEquals(4, backtrace.totalFrames);
+      var frames = backtrace.frames;
+      assertEquals(2, frames.length);
+      for (var i = 0; i < frames.length; i++) {
+        assertEquals('frame', frames[i].type);
+      }
+      assertEquals(1, frames[0].index);
+      assertEquals("", response.lookup(frames[0].func.ref).name);
+      assertEquals("m", response.lookup(frames[0].func.ref).inferredName);
+      assertEquals(2, frames[1].index);
+      assertEquals("g", response.lookup(frames[1].func.ref).name);
+
+      // Get backtrace with bottom two frames.
+      json = '{"seq":0,"type":"request","command":"backtrace","arguments":{"fromFrame":0,"toFrame":2, "bottom":true}}'
+      response = new ParsedResponse(dcp.processDebugJSONRequest(json));
+      backtrace = response.body();
+      assertEquals(2, backtrace.fromFrame);
+      assertEquals(4, backtrace.toFrame);
+      assertEquals(4, backtrace.totalFrames);
+      var frames = backtrace.frames;
+      assertEquals(2, frames.length);
+      for (var i = 0; i < frames.length; i++) {
+        assertEquals('frame', frames[i].type);
+      }
+      assertEquals(2, frames[0].index);
+      assertEquals("g", response.lookup(frames[0].func.ref).name);
+      assertEquals(3, frames[1].index);
+      assertEquals("", response.lookup(frames[1].func.ref).name);
+
+      // Get the individual frames.
+      json = '{"seq":0,"type":"request","command":"frame"}'
+      response = new ParsedResponse(dcp.processDebugJSONRequest(json));
+      frame = response.body();
+      assertEquals(0, frame.index);
+      assertEquals("f", response.lookup(frame.func.ref).name);
+      assertTrue(frame.constructCall);
+      assertEquals(31, frame.line);
+      assertEquals(3, frame.column);
+      assertEquals(2, frame.arguments.length);
+      assertEquals('x', frame.arguments[0].name);
+      assertEquals('number', response.lookup(frame.arguments[0].value.ref).type);
+      assertEquals(1, response.lookup(frame.arguments[0].value.ref).value);
+      assertEquals('y', frame.arguments[1].name);
+      assertEquals('undefined', response.lookup(frame.arguments[1].value.ref).type);
+
+      json = '{"seq":0,"type":"request","command":"frame","arguments":{"number":0}}'
+      response = new ParsedResponse(dcp.processDebugJSONRequest(json));
+      frame = response.body();
+      assertEquals(0, frame.index);
+      assertEquals("f", response.lookup(frame.func.ref).name);
+      assertEquals(31, frame.line);
+      assertEquals(3, frame.column);
+      assertEquals(2, frame.arguments.length);
+      assertEquals('x', frame.arguments[0].name);
+      assertEquals('number', response.lookup(frame.arguments[0].value.ref).type);
+      assertEquals(1, response.lookup(frame.arguments[0].value.ref).value);
+      assertEquals('y', frame.arguments[1].name);
+      assertEquals('undefined', response.lookup(frame.arguments[1].value.ref).type);
+
+      json = '{"seq":0,"type":"request","command":"frame","arguments":{"number":1}}'
+      response = new ParsedResponse(dcp.processDebugJSONRequest(json));
+      frame = response.body();
+      assertEquals(1, frame.index);
+      assertEquals("", response.lookup(frame.func.ref).name);
+      assertEquals("m", response.lookup(frame.func.ref).inferredName);
+      assertFalse(frame.constructCall);
+      assertEquals(35, frame.line);
+      assertEquals(2, frame.column);
+      assertEquals(0, frame.arguments.length);
+
+      json = '{"seq":0,"type":"request","command":"frame","arguments":{"number":3}}'
+      response = new ParsedResponse(dcp.processDebugJSONRequest(json));
+      frame = response.body();
+      assertEquals(3, frame.index);
+      assertEquals("", response.lookup(frame.func.ref).name);
+
+      // Source slices for the individual frames (they all refer to this script).
+      json = '{"seq":0,"type":"request","command":"source",' +
+              '"arguments":{"frame":0,"fromLine":30,"toLine":32}}'
+      response = new ParsedResponse(dcp.processDebugJSONRequest(json));
+      source = response.body();
+      assertEquals("function f(x, y) {", source.source.substring(0, 18));
+      assertEquals(30, source.fromLine);
+      assertEquals(32, source.toLine);
+
+      json = '{"seq":0,"type":"request","command":"source",' +
+              '"arguments":{"frame":1,"fromLine":31,"toLine":32}}'
+      response = new ParsedResponse(dcp.processDebugJSONRequest(json));
+      source = response.body();
+      assertEquals("  a=1;", source.source.substring(0, 6));
+      assertEquals(31, source.fromLine);
+      assertEquals(32, source.toLine);
+
+      json = '{"seq":0,"type":"request","command":"source",' +
+              '"arguments":{"frame":2,"fromLine":35,"toLine":36}}'
+      response = new ParsedResponse(dcp.processDebugJSONRequest(json));
+      source = response.body();
+      assertEquals("  new f(1);", source.source.substring(0, 11));
+      assertEquals(35, source.fromLine);
+      assertEquals(36, source.toLine);
+
+      // Test line interval way beyond this script will result in an error.
+      json = '{"seq":0,"type":"request","command":"source",' +
+              '"arguments":{"frame":0,"fromLine":10000,"toLine":20000}}'
+      response = new ParsedResponse(dcp.processDebugJSONRequest(json));
+      assertFalse(response.response().success);
+
+      // Test without arguments.
+      json = '{"seq":0,"type":"request","command":"source"}'
+      response = new ParsedResponse(dcp.processDebugJSONRequest(json));
+      source = response.body();
+      assertEquals(Debug.findScript(f).source, source.source);
+
+      listenerCalled = true;
     }
-    assertEquals(0, frames[0].index);
-    assertEquals("f", response.lookup(frames[0].func.ref).name);
-    assertEquals(1, frames[1].index);
-    assertEquals("", response.lookup(frames[1].func.ref).name);
-    assertEquals("m", response.lookup(frames[1].func.ref).inferredName);
-    assertEquals(2, frames[2].index);
-    assertEquals("g", response.lookup(frames[2].func.ref).name);
-    assertEquals(3, frames[3].index);
-    assertEquals("", response.lookup(frames[3].func.ref).name);
-
-    // Get backtrace with two frames.
-    json = '{"seq":0,"type":"request","command":"backtrace","arguments":{"fromFrame":1,"toFrame":3}}'
-    response = new ParsedResponse(dcp.processDebugJSONRequest(json));
-    backtrace = response.body();
-    assertEquals(1, backtrace.fromFrame);
-    assertEquals(3, backtrace.toFrame);
-    assertEquals(4, backtrace.totalFrames);
-    var frames = backtrace.frames;
-    assertEquals(2, frames.length);
-    for (var i = 0; i < frames.length; i++) {
-      assertEquals('frame', frames[i].type);
-    }
-    assertEquals(1, frames[0].index);
-    assertEquals("", response.lookup(frames[0].func.ref).name);
-    assertEquals("m", response.lookup(frames[0].func.ref).inferredName);
-    assertEquals(2, frames[1].index);
-    assertEquals("g", response.lookup(frames[1].func.ref).name);
-
-    // Get backtrace with bottom two frames.
-    json = '{"seq":0,"type":"request","command":"backtrace","arguments":{"fromFrame":0,"toFrame":2, "bottom":true}}'
-    response = new ParsedResponse(dcp.processDebugJSONRequest(json));
-    backtrace = response.body();
-    assertEquals(2, backtrace.fromFrame);
-    assertEquals(4, backtrace.toFrame);
-    assertEquals(4, backtrace.totalFrames);
-    var frames = backtrace.frames;
-    assertEquals(2, frames.length);
-    for (var i = 0; i < frames.length; i++) {
-      assertEquals('frame', frames[i].type);
-    }
-    assertEquals(2, frames[0].index);
-    assertEquals("g", response.lookup(frames[0].func.ref).name);
-    assertEquals(3, frames[1].index);
-    assertEquals("", response.lookup(frames[1].func.ref).name);
-
-    // Get the individual frames.
-    json = '{"seq":0,"type":"request","command":"frame"}'
-    response = new ParsedResponse(dcp.processDebugJSONRequest(json));
-    frame = response.body();
-    assertEquals(0, frame.index);
-    assertEquals("f", response.lookup(frame.func.ref).name);
-    assertTrue(frame.constructCall);
-    assertEquals(31, frame.line);
-    assertEquals(3, frame.column);
-    assertEquals(2, frame.arguments.length);
-    assertEquals('x', frame.arguments[0].name);
-    assertEquals('number', response.lookup(frame.arguments[0].value.ref).type);
-    assertEquals(1, response.lookup(frame.arguments[0].value.ref).value);
-    assertEquals('y', frame.arguments[1].name);
-    assertEquals('undefined', response.lookup(frame.arguments[1].value.ref).type);
-
-    json = '{"seq":0,"type":"request","command":"frame","arguments":{"number":0}}'
-    response = new ParsedResponse(dcp.processDebugJSONRequest(json));
-    frame = response.body();
-    assertEquals(0, frame.index);
-    assertEquals("f", response.lookup(frame.func.ref).name);
-    assertEquals(31, frame.line);
-    assertEquals(3, frame.column);
-    assertEquals(2, frame.arguments.length);
-    assertEquals('x', frame.arguments[0].name);
-    assertEquals('number', response.lookup(frame.arguments[0].value.ref).type);
-    assertEquals(1, response.lookup(frame.arguments[0].value.ref).value);
-    assertEquals('y', frame.arguments[1].name);
-    assertEquals('undefined', response.lookup(frame.arguments[1].value.ref).type);
-
-    json = '{"seq":0,"type":"request","command":"frame","arguments":{"number":1}}'
-    response = new ParsedResponse(dcp.processDebugJSONRequest(json));
-    frame = response.body();
-    assertEquals(1, frame.index);
-    assertEquals("", response.lookup(frame.func.ref).name);
-    assertEquals("m", response.lookup(frame.func.ref).inferredName);
-    assertFalse(frame.constructCall);
-    assertEquals(35, frame.line);
-    assertEquals(2, frame.column);
-    assertEquals(0, frame.arguments.length);
-
-    json = '{"seq":0,"type":"request","command":"frame","arguments":{"number":3}}'
-    response = new ParsedResponse(dcp.processDebugJSONRequest(json));
-    frame = response.body();
-    assertEquals(3, frame.index);
-    assertEquals("", response.lookup(frame.func.ref).name);
-
-    // Source slices for the individual frames (they all refer to this script).
-    json = '{"seq":0,"type":"request","command":"source",' +
-            '"arguments":{"frame":0,"fromLine":30,"toLine":32}}'
-    response = new ParsedResponse(dcp.processDebugJSONRequest(json));
-    source = response.body();
-    assertEquals("function f(x, y) {", source.source.substring(0, 18));
-    assertEquals(30, source.fromLine);
-    assertEquals(32, source.toLine);
-    
-    json = '{"seq":0,"type":"request","command":"source",' +
-            '"arguments":{"frame":1,"fromLine":31,"toLine":32}}'
-    response = new ParsedResponse(dcp.processDebugJSONRequest(json));
-    source = response.body();
-    assertEquals("  a=1;", source.source.substring(0, 6));
-    assertEquals(31, source.fromLine);
-    assertEquals(32, source.toLine);
-    
-    json = '{"seq":0,"type":"request","command":"source",' +
-            '"arguments":{"frame":2,"fromLine":35,"toLine":36}}'
-    response = new ParsedResponse(dcp.processDebugJSONRequest(json));
-    source = response.body();
-    assertEquals("  new f(1);", source.source.substring(0, 11));
-    assertEquals(35, source.fromLine);
-    assertEquals(36, source.toLine);
-    
-    // Test line interval way beyond this script will result in an error.
-    json = '{"seq":0,"type":"request","command":"source",' +
-            '"arguments":{"frame":0,"fromLine":10000,"toLine":20000}}'
-    response = new ParsedResponse(dcp.processDebugJSONRequest(json));
-    assertFalse(response.response().success);
-    
-    // Test without arguments.
-    json = '{"seq":0,"type":"request","command":"source"}'
-    response = new ParsedResponse(dcp.processDebugJSONRequest(json));
-    source = response.body();
-    assertEquals(Debug.findScript(f).source, source.source);
-    
-    listenerCalled = true;
-  }
   } catch (e) {
     exception = e
   };
diff --git a/test/mjsunit/debug-stepin-function-call.js b/test/mjsunit/debug-stepin-function-call.js
new file mode 100644
index 0000000..9f24c01
--- /dev/null
+++ b/test/mjsunit/debug-stepin-function-call.js
@@ -0,0 +1,149 @@
+// Copyright 2008 the V8 project authors. All rights reserved.

+// Redistribution and use in source and binary forms, with or without

+// modification, are permitted provided that the following conditions are

+// met:

+//

+//     * Redistributions of source code must retain the above copyright

+//       notice, this list of conditions and the following disclaimer.

+//     * Redistributions in binary form must reproduce the above

+//       copyright notice, this list of conditions and the following

+//       disclaimer in the documentation and/or other materials provided

+//       with the distribution.

+//     * Neither the name of Google Inc. nor the names of its

+//       contributors may be used to endorse or promote products derived

+//       from this software without specific prior written permission.

+//

+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+

+// Flags: --expose-debug-as debug

+// Get the Debug object exposed from the debug context global object.

+Debug = debug.Debug

+

+var exception = null;

+var state = 0;

+

+// Simple debug event handler which first time will cause 'step in' action

+// to get into g.call and than check that execution is pauesed inside

+// function 'g'.

+function listener(event, exec_state, event_data, data) {

+  try {

+    if (event == Debug.DebugEvent.Break) {

+      if (state == 0) {

+        // Step into f2.call:

+        exec_state.prepareStep(Debug.StepAction.StepIn, 2);

+        state = 2;

+      } else if (state == 2) {

+        assertEquals('g', event_data.func().name());

+        assertEquals('  return t + 1; // expected line',

+                     event_data.sourceLineText());

+        state = 3;

+      }

+    }

+  } catch(e) {

+    exception = e;

+  }

+};

+

+// Add the debug event listener.

+Debug.setListener(listener);

+

+

+// Sample functions.

+function g(t) {

+  return t + 1; // expected line

+}

+

+// Test step into function call from a function without local variables.

+function call1() {

+  debugger;

+  g.call(null, 3);

+}

+

+

+// Test step into function call from a function with some local variables.

+function call2() {

+  var aLocalVar = 'test';

+  var anotherLocalVar  = g(aLocalVar) + 's';

+  var yetAnotherLocal = 10;

+  debugger;

+  g.call(null, 3);

+}

+

+// Test step into function call which is a part of an expression.

+function call3() {

+  var alias = g;

+  debugger;

+  var r = 10 + alias.call(null, 3);

+  var aLocalVar = 'test';

+  var anotherLocalVar  = g(aLocalVar) + 's';

+  var yetAnotherLocal = 10;

+}

+

+// Test step into function call from a function with some local variables.

+function call4() {

+  var alias = g;

+  debugger;

+  alias.call(null, 3);

+  var aLocalVar = 'test';

+  var anotherLocalVar  = g(aLocalVar) + 's';

+  var yetAnotherLocal = 10;

+}

+

+// Test step into function apply from a function without local variables.

+function apply1() {

+  debugger;

+  g.apply(null, [3]);

+}

+

+

+// Test step into function apply from a function with some local variables.

+function apply2() {

+  var aLocalVar = 'test';

+  var anotherLocalVar  = g(aLocalVar) + 's';

+  var yetAnotherLocal = 10;

+  debugger;

+  g.apply(null, [3, 4]);

+}

+

+// Test step into function apply which is a part of an expression.

+function apply3() {

+  var alias = g;

+  debugger;

+  var r = 10 + alias.apply(null, [3, 'unused arg']);

+  var aLocalVar = 'test';

+  var anotherLocalVar  = g(aLocalVar) + 's';

+  var yetAnotherLocal = 10;

+}

+

+// Test step into function apply from a function with some local variables.

+function apply4() {

+  var alias = g;

+  debugger;

+  alias.apply(null, [3]);

+  var aLocalVar = 'test';

+  var anotherLocalVar  = g(aLocalVar) + 's';

+  var yetAnotherLocal = 10;

+}

+

+var testFunctions =

+    [call1, call2, call3, call4, apply1, apply2, apply3, apply4];

+

+for (var i = 0; i < testFunctions.length; i++) {

+  state = 0;

+  testFunctions[i]();

+  assertNull(exception);

+  assertEquals(3, state);

+}

+

+// Get rid of the debug event listener.

+Debug.setListener(null);
\ No newline at end of file
diff --git a/test/mjsunit/global-ic.js b/test/mjsunit/global-ic.js
new file mode 100644
index 0000000..22c49ab
--- /dev/null
+++ b/test/mjsunit/global-ic.js
@@ -0,0 +1,48 @@
+// Copyright 2009 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.
+
+function f() {
+  return 87;
+}
+
+function LoadFromGlobal(global) { return global.x; }
+function StoreToGlobal(global, value) { global.x = value; }
+function CallOnGlobal(global) { return global.f(); }
+
+// Initialize the ICs in the functions.
+for (var i = 0; i < 3; i++) {
+  StoreToGlobal(this, 42 + i);
+  assertEquals(42 + i, LoadFromGlobal(this));
+  assertEquals(87, CallOnGlobal(this));
+}
+
+// Try the ICs with a smi. This should not crash.
+for (var i = 0; i < 3; i++) {
+  StoreToGlobal(i, 42 + i);
+  assertTrue(typeof LoadFromGlobal(i) == "undefined");
+  assertThrows("CallOnGlobal(" + i + ")");
+}
diff --git a/test/mjsunit/mjsunit.status b/test/mjsunit/mjsunit.status
index dea9db1..962e4d3 100644
--- a/test/mjsunit/mjsunit.status
+++ b/test/mjsunit/mjsunit.status
@@ -59,6 +59,7 @@
 debug-setbreakpoint: CRASH || FAIL || PASS
 debug-step-stub-callfunction: SKIP
 debug-stepin-constructor: CRASH, FAIL
+debug-stepin-function-call: CRASH || FAIL
 debug-step: SKIP
 debug-breakpoints: PASS || FAIL
 debug-handle: CRASH || FAIL || PASS
@@ -67,3 +68,41 @@
 # Bug number 130 http://code.google.com/p/v8/issues/detail?id=130
 # Fails on real ARM hardware but not on the simulator.
 string-compare-alignment: PASS || FAIL
+
+
+[ $arch == x64 ]
+
+debug-backtrace.js: CRASH || FAIL
+date-parse.js: CRASH || FAIL
+debug-backtrace-text.js: CRASH || FAIL
+debug-multiple-breakpoints.js: CRASH || FAIL
+debug-breakpoints.js: CRASH || FAIL
+debug-changebreakpoint.js: CRASH || FAIL
+debug-clearbreakpoint.js: CRASH || FAIL
+debug-conditional-breakpoints.js: CRASH || FAIL
+debug-constructor.js: CRASH || FAIL
+debug-continue.js: CRASH || FAIL
+debug-enable-disable-breakpoints.js: CRASH || FAIL
+debug-evaluate-recursive.js: CRASH || FAIL
+debug-event-listener.js: CRASH || FAIL
+debug-evaluate.js: CRASH || FAIL
+debug-ignore-breakpoints.js: CRASH || FAIL
+debug-setbreakpoint.js: CRASH || FAIL
+debug-step-stub-callfunction.js: CRASH || FAIL
+debug-step.js: CRASH || FAIL
+mirror-date.js: CRASH || FAIL
+invalid-lhs.js: CRASH || FAIL
+debug-stepin-constructor.js: CRASH || FAIL
+new.js: CRASH || FAIL
+fuzz-natives.js: CRASH || FAIL
+greedy.js: CRASH || FAIL
+debug-handle.js: CRASH || FAIL
+string-indexof.js: CRASH || FAIL
+debug-clearbreakpointgroup.js: CRASH || FAIL
+regress/regress-269.js: CRASH || FAIL
+div-mod.js: CRASH || FAIL
+unicode-test.js: CRASH || FAIL
+regress/regress-392.js: CRASH || FAIL
+regress/regress-1200351.js: CRASH || FAIL
+regress/regress-998565.js: CRASH || FAIL
+tools/tickprocessor.js: CRASH || FAIL
diff --git a/test/mjsunit/regress/regress-244.js b/test/mjsunit/regress/regress-244.js
index ffddcf8..dc5336f 100644
--- a/test/mjsunit/regress/regress-244.js
+++ b/test/mjsunit/regress/regress-244.js
@@ -57,7 +57,7 @@
     var threw = false;
     try {
       decodeURI(value);
-      fail(value);
+      assertUnreachable(value);
     } catch (e) {
       assertInstanceof(e, URIError);
     }
diff --git a/test/mjsunit/smi-ops.js b/test/mjsunit/smi-ops.js
index 5520327..284050d 100644
--- a/test/mjsunit/smi-ops.js
+++ b/test/mjsunit/smi-ops.js
@@ -56,15 +56,15 @@
 
 assertEquals(1, Add1(0));  // fast case
 assertEquals(1, Add1Reversed(0));  // fast case
-assertEquals(SMI_MAX + ONE, Add1(SMI_MAX));  // overflow
-assertEquals(SMI_MAX + ONE, Add1Reversed(SMI_MAX));  // overflow
+assertEquals(SMI_MAX + ONE, Add1(SMI_MAX), "smimax + 1");
+assertEquals(SMI_MAX + ONE, Add1Reversed(SMI_MAX), "1 + smimax");
 assertEquals(42 + ONE, Add1(OBJ_42));  // non-smi
 assertEquals(42 + ONE, Add1Reversed(OBJ_42));  // non-smi
 
 assertEquals(100, Add100(0));  // fast case
 assertEquals(100, Add100Reversed(0));  // fast case
-assertEquals(SMI_MAX + ONE_HUNDRED, Add100(SMI_MAX));  // overflow
-assertEquals(SMI_MAX + ONE_HUNDRED, Add100Reversed(SMI_MAX));  // overflow
+assertEquals(SMI_MAX + ONE_HUNDRED, Add100(SMI_MAX), "smimax + 100");
+assertEquals(SMI_MAX + ONE_HUNDRED, Add100Reversed(SMI_MAX), " 100 + smimax");
 assertEquals(42 + ONE_HUNDRED, Add100(OBJ_42));  // non-smi
 assertEquals(42 + ONE_HUNDRED, Add100Reversed(OBJ_42));  // non-smi
 
@@ -148,8 +148,8 @@
 assertEquals(0, Shr1Reversed(OBJ_42));
 assertEquals(0, Sar1Reversed(OBJ_42));
 
-assertEquals(6, Shr100(100));
-assertEquals(6, Sar100(100));
+assertEquals(6, Shr100(100), "100 >>> 100");
+assertEquals(6, Sar100(100), "100 >> 100");
 assertEquals(12, Shr100Reversed(99));
 assertEquals(12, Sar100Reversed(99));
 assertEquals(201326592, Shr100(SMI_MIN));
@@ -201,17 +201,17 @@
 var v = 0;
 assertEquals(-1, ~v);
 v = SMI_MIN;
-assertEquals(0x3fffffff, ~v);
+assertEquals(0x3fffffff, ~v, "~smimin");
 v = SMI_MAX;
-assertEquals(-0x40000000, ~v);
+assertEquals(-0x40000000, ~v, "~smimax");
 
 // Overflowing ++ and --.
 v = SMI_MAX;
 v++;
-assertEquals(0x40000000, v);
+assertEquals(0x40000000, v, "smimax++");
 v = SMI_MIN;
 v--;
-assertEquals(-0x40000001, v);
+assertEquals(-0x40000001, v, "smimin--");
 
 // Not actually Smi operations.
 // Check that relations on unary ops work.
@@ -234,14 +234,14 @@
 var x1 = 0x10000000;
 var x2 = 0x40000002;
 var x3 = 0x40000000;
-assertEquals(0x40000000, x1 << (x2 - x3));
+assertEquals(0x40000000, x1 << (x2 - x3), "0x10000000<<1(1)");
 
 // Smi input to bitop gives non-smi result where the rhs could be overwritten
 // if it were a float, but it isn't.
 x1 = 0x10000000
 x2 = 4
 x3 = 2
-assertEquals(0x40000000, x1 << (x2 - x3));
+assertEquals(0x40000000, x1 << (x2 - x3), "0x10000000<<2(2)");
 
 
 // Test shift operators on non-smi inputs, giving smi and non-smi results.
@@ -258,12 +258,12 @@
   assertEquals(neg_non_smi, (neg_non_smi) >> 0);
   assertEquals(neg_non_smi + 0x100000000, (neg_non_smi) >>> 0);
   assertEquals(neg_non_smi, (neg_non_smi) << 0);
-  assertEquals(pos_smi, (pos_smi) >> 0);
-  assertEquals(pos_smi, (pos_smi) >>> 0);
-  assertEquals(pos_smi, (pos_smi) << 0);
-  assertEquals(neg_smi, (neg_smi) >> 0);
-  assertEquals(neg_smi + 0x100000000, (neg_smi) >>> 0);
-  assertEquals(neg_smi, (neg_smi) << 0);
+  assertEquals(pos_smi, (pos_smi) >> 0, "possmi >> 0");
+  assertEquals(pos_smi, (pos_smi) >>> 0, "possmi >>>0");
+  assertEquals(pos_smi, (pos_smi) << 0, "possmi << 0");
+  assertEquals(neg_smi, (neg_smi) >> 0, "negsmi >> 0");
+  assertEquals(neg_smi + 0x100000000, (neg_smi) >>> 0, "negsmi >>> 0");
+  assertEquals(neg_smi, (neg_smi) << 0), "negsmi << 0";
 
   assertEquals(pos_non_smi / 2, (pos_non_smi) >> 1);
   assertEquals(pos_non_smi / 2, (pos_non_smi) >>> 1);
@@ -283,18 +283,22 @@
   assertEquals(-0x46536000, (pos_non_smi + 0.5) << 3);
   assertEquals(0x73594000, (pos_non_smi + 0.5) << 4);
 
-  assertEquals(neg_non_smi / 2, (neg_non_smi) >> 1);
-  assertEquals(neg_non_smi / 2 + 0x100000000 / 2, (neg_non_smi) >>> 1);
+  assertEquals(neg_non_smi / 2, (neg_non_smi) >> 1, "negnonsmi >> 1");
+
+  assertEquals(neg_non_smi / 2 + 0x100000000 / 2, (neg_non_smi) >>> 1,
+               "negnonsmi >>> 1");
   assertEquals(0x1194D800, (neg_non_smi) << 1);
   assertEquals(neg_non_smi / 8, (neg_non_smi) >> 3);
   assertEquals(neg_non_smi / 8 + 0x100000000 / 8, (neg_non_smi) >>> 3);
   assertEquals(0x46536000, (neg_non_smi) << 3);
   assertEquals(-0x73594000, (neg_non_smi) << 4);
   assertEquals(neg_non_smi, (neg_non_smi - 0.5) >> 0);
-  assertEquals(neg_non_smi + 0x100000000, (neg_non_smi - 0.5) >>> 0);
+  assertEquals(neg_non_smi + 0x100000000, (neg_non_smi - 0.5) >>> 0,
+               "negnonsmi.5 >>> 0");
   assertEquals(neg_non_smi, (neg_non_smi - 0.5) << 0);
   assertEquals(neg_non_smi / 2, (neg_non_smi - 0.5) >> 1);
-  assertEquals(neg_non_smi / 2 + 0x100000000 / 2, (neg_non_smi - 0.5) >>> 1);
+  assertEquals(neg_non_smi / 2 + 0x100000000 / 2, (neg_non_smi - 0.5) >>> 1,
+               "negnonsmi.5 >>> 1");
   assertEquals(0x1194D800, (neg_non_smi - 0.5) << 1);
   assertEquals(neg_non_smi / 8, (neg_non_smi - 0.5) >> 3);
   assertEquals(neg_non_smi / 8 + 0x100000000 / 8, (neg_non_smi - 0.5) >>> 3);
@@ -308,9 +312,9 @@
   assertEquals(pos_smi / 8, (pos_smi) >>> 3);
   assertEquals(-0x2329b000, (pos_smi) << 3);
   assertEquals(0x73594000, (pos_smi) << 5);
-  assertEquals(pos_smi, (pos_smi + 0.5) >> 0);
-  assertEquals(pos_smi, (pos_smi + 0.5) >>> 0);
-  assertEquals(pos_smi, (pos_smi + 0.5) << 0);
+  assertEquals(pos_smi, (pos_smi + 0.5) >> 0, "possmi.5 >> 0");
+  assertEquals(pos_smi, (pos_smi + 0.5) >>> 0, "possmi.5 >>> 0");
+  assertEquals(pos_smi, (pos_smi + 0.5) << 0, "possmi.5 << 0");
   assertEquals(pos_smi / 2, (pos_smi + 0.5) >> 1);
   assertEquals(pos_smi / 2, (pos_smi + 0.5) >>> 1);
   assertEquals(pos_non_smi, (pos_smi + 0.5) << 1);
@@ -326,9 +330,9 @@
   assertEquals(neg_smi / 8 + 0x100000000 / 8, (neg_smi) >>> 3);
   assertEquals(0x46536000, (neg_smi) << 4);
   assertEquals(-0x73594000, (neg_smi) << 5);
-  assertEquals(neg_smi, (neg_smi - 0.5) >> 0);
-  assertEquals(neg_smi + 0x100000000, (neg_smi - 0.5) >>> 0);
-  assertEquals(neg_smi, (neg_smi - 0.5) << 0);
+  assertEquals(neg_smi, (neg_smi - 0.5) >> 0, "negsmi.5 >> 0");
+  assertEquals(neg_smi + 0x100000000, (neg_smi - 0.5) >>> 0, "negsmi.5 >>> 0");
+  assertEquals(neg_smi, (neg_smi - 0.5) << 0, "negsmi.5 << 0");
   assertEquals(neg_smi / 2, (neg_smi - 0.5) >> 1);
   assertEquals(neg_smi / 2 + 0x100000000 / 2, (neg_smi - 0.5) >>> 1);
   assertEquals(neg_non_smi, (neg_smi - 0.5) << 1);
@@ -349,12 +353,12 @@
   assertEquals(neg_non_smi, (neg_32 + neg_non_smi) >> 0);
   assertEquals(neg_non_smi + 0x100000000, (neg_32 + neg_non_smi) >>> 0);
   assertEquals(neg_non_smi, (neg_32 + neg_non_smi) << 0);
-  assertEquals(pos_smi, (two_32 + pos_smi) >> 0);
-  assertEquals(pos_smi, (two_32 + pos_smi) >>> 0);
-  assertEquals(pos_smi, (two_32 + pos_smi) << 0);
-  assertEquals(neg_smi, (neg_32 + neg_smi) >> 0);
+  assertEquals(pos_smi, (two_32 + pos_smi) >> 0, "2^32+possmi >> 0");
+  assertEquals(pos_smi, (two_32 + pos_smi) >>> 0, "2^32+possmi >>> 0");
+  assertEquals(pos_smi, (two_32 + pos_smi) << 0, "2^32+possmi << 0");
+  assertEquals(neg_smi, (neg_32 + neg_smi) >> 0, "2^32+negsmi >> 0");
   assertEquals(neg_smi + 0x100000000, (neg_32 + neg_smi) >>> 0);
-  assertEquals(neg_smi, (neg_32 + neg_smi) << 0);
+  assertEquals(neg_smi, (neg_32 + neg_smi) << 0, "2^32+negsmi << 0");
 
   assertEquals(pos_non_smi / 2, (two_32 + pos_non_smi) >> 1);
   assertEquals(pos_non_smi / 2, (two_32 + pos_non_smi) >>> 1);
@@ -419,9 +423,9 @@
   assertEquals((neg_smi + 0x100000000) / 8, (neg_32 + neg_smi) >>> 3);
   assertEquals(0x46536000, (neg_32 + neg_smi) << 4);
   assertEquals(-0x73594000, (neg_32 + neg_smi) << 5);
-  assertEquals(neg_smi, (neg_32 + neg_smi - 0.5) >> 0);
+  assertEquals(neg_smi, (neg_32 + neg_smi - 0.5) >> 0, "-2^32+negsmi.5 >> 0");
   assertEquals(neg_smi + 0x100000000, (neg_32 + neg_smi - 0.5) >>> 0);
-  assertEquals(neg_smi, (neg_32 + neg_smi - 0.5) << 0);
+  assertEquals(neg_smi, (neg_32 + neg_smi - 0.5) << 0, "-2^32+negsmi.5 << 0");
   assertEquals(neg_smi / 2, (neg_32 + neg_smi - 0.5) >> 1);
   assertEquals(neg_smi / 2 + 0x100000000 / 2, (neg_32 + neg_smi - 0.5) >>> 1);
   assertEquals(neg_non_smi, (neg_32 + neg_smi - 0.5) << 1);
@@ -447,9 +451,9 @@
   assertEquals(pos_smi, (pos_smi) >> zero);
   assertEquals(pos_smi, (pos_smi) >>> zero);
   assertEquals(pos_smi, (pos_smi) << zero);
-  assertEquals(neg_smi, (neg_smi) >> zero);
+  assertEquals(neg_smi, (neg_smi) >> zero, "negsmi >> zero");
   assertEquals(neg_smi + 0x100000000, (neg_smi) >>> zero);
-  assertEquals(neg_smi, (neg_smi) << zero);
+  assertEquals(neg_smi, (neg_smi) << zero, "negsmi << zero");
 
   assertEquals(pos_non_smi / 2, (pos_non_smi) >> one);
   assertEquals(pos_non_smi / 2, (pos_non_smi) >>> one);
@@ -543,9 +547,9 @@
   assertEquals(pos_smi, (pos_smi) >> zero);
   assertEquals(pos_smi, (pos_smi) >>> zero);
   assertEquals(pos_smi, (pos_smi) << zero);
-  assertEquals(neg_smi, (neg_smi) >> zero);
+  assertEquals(neg_smi, (neg_smi) >> zero, "negsmi >> zero(2)");
   assertEquals(neg_smi + 0x100000000, (neg_smi) >>> zero);
-  assertEquals(neg_smi, (neg_smi) << zero);
+  assertEquals(neg_smi, (neg_smi) << zero, "negsmi << zero(2)");
 
   assertEquals(pos_non_smi / 2, (pos_non_smi) >> one);
   assertEquals(pos_non_smi / 2, (pos_non_smi) >>> one);
@@ -609,9 +613,9 @@
   assertEquals(neg_smi / 8 + 0x100000000 / 8, (neg_smi) >>> three);
   assertEquals(0x46536000, (neg_smi) << four);
   assertEquals(-0x73594000, (neg_smi) << five);
-  assertEquals(neg_smi, (neg_smi - 0.5) >> zero);
+  assertEquals(neg_smi, (neg_smi - 0.5) >> zero, "negsmi.5 >> zero");
   assertEquals(neg_smi + 0x100000000, (neg_smi - 0.5) >>> zero);
-  assertEquals(neg_smi, (neg_smi - 0.5) << zero);
+  assertEquals(neg_smi, (neg_smi - 0.5) << zero, "negsmi.5 << zero");
   assertEquals(neg_smi / 2, (neg_smi - 0.5) >> one);
   assertEquals(neg_smi / 2 + 0x100000000 / 2, (neg_smi - 0.5) >>> one);
   assertEquals(neg_non_smi, (neg_smi - 0.5) << one);
diff --git a/test/mjsunit/testcfg.py b/test/mjsunit/testcfg.py
index 9c7e028..96840f5 100644
--- a/test/mjsunit/testcfg.py
+++ b/test/mjsunit/testcfg.py
@@ -29,10 +29,12 @@
 import os
 from os.path import join, dirname, exists
 import re
+import tempfile
 
 
 FLAGS_PATTERN = re.compile(r"//\s+Flags:(.*)")
 FILES_PATTERN = re.compile(r"//\s+Files:(.*)")
+SELF_SCRIPT_PATTERN = re.compile(r"//\s+Env: TEST_FILE_NAME")
 
 
 class MjsunitTestCase(test.TestCase):
@@ -42,6 +44,7 @@
     self.file = file
     self.config = config
     self.mode = mode
+    self.self_script = False
 
   def GetLabel(self):
     return "%s %s" % (self.mode, self.GetName())
@@ -55,19 +58,43 @@
     flags_match = FLAGS_PATTERN.search(source)
     if flags_match:
       result += flags_match.group(1).strip().split()
-    files_match = FILES_PATTERN.search(source);
     additional_files = []
-    if files_match:
-      additional_files += files_match.group(1).strip().split()
+    files_match = FILES_PATTERN.search(source);
+    # Accept several lines of 'Files:'
+    while True:
+      if files_match:
+        additional_files += files_match.group(1).strip().split()
+        files_match = FILES_PATTERN.search(source, files_match.end())
+      else:
+        break
     for a_file in additional_files:
       result.append(join(dirname(self.config.root), '..', a_file))
     framework = join(dirname(self.config.root), 'mjsunit', 'mjsunit.js')
+    if SELF_SCRIPT_PATTERN.search(source):
+      result.append(self.CreateSelfScript())
     result += [framework, self.file]
     return result
 
   def GetSource(self):
     return open(self.file).read()
 
+  def CreateSelfScript(self):
+    (fd_self_script, self_script) = tempfile.mkstemp(suffix=".js")
+    def MakeJsConst(name, value):
+      return "var %(name)s=\'%(value)s\';\n" % \
+             {'name': name, \
+              'value': value.replace('\\', '\\\\').replace('\'', '\\\'') }
+    try:
+      os.write(fd_self_script, MakeJsConst('TEST_FILE_NAME', self.file))
+    except IOError, e:
+      test.PrintError("write() " + str(e))
+    os.close(fd_self_script)
+    self.self_script = self_script
+    return self_script
+
+  def Cleanup(self):
+    if self.self_script:
+      test.CheckedUnlink(self.self_script)
 
 class MjsunitTestConfiguration(test.TestConfiguration):
 
diff --git a/test/mjsunit/tools/tickprocessor-test.default b/test/mjsunit/tools/tickprocessor-test.default
new file mode 100644
index 0000000..a689ea8
--- /dev/null
+++ b/test/mjsunit/tools/tickprocessor-test.default
@@ -0,0 +1,60 @@
+Statistical profiling result from v8.log, (13 ticks, 2 unaccounted, 0 excluded).
+
+ [Unknown]:
+   ticks  total  nonlib   name
+      2   15.4%
+
+ [Shared libraries]:
+   ticks  total  nonlib   name
+      2   15.4%    0.0%  /lib32/libm-2.7.so
+      1    7.7%    0.0%  ffffe000-fffff000
+
+ [JavaScript]:
+   ticks  total  nonlib   name
+      1    7.7%   10.0%  LazyCompile: exp native math.js:41
+
+ [C++]:
+   ticks  total  nonlib   name
+      2   15.4%   20.0%  v8::internal::Runtime_Math_exp(v8::internal::Arguments)
+      1    7.7%   10.0%  v8::internal::JSObject::LocalLookupRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*)
+      1    7.7%   10.0%  v8::internal::HashTable<v8::internal::StringDictionaryShape, v8::internal::String*>::FindEntry(v8::internal::String*)
+      1    7.7%   10.0%  fegetexcept
+      1    7.7%   10.0%  exp
+
+ [GC]:
+   ticks  total  nonlib   name
+      0    0.0%
+
+ [Bottom up (heavy) profile]:
+  Note: percentage shows a share of a particular caller in the total
+  amount of its parent calls.
+  Callers occupying less than 2.0% are not shown.
+
+   ticks parent  name
+      2   15.4%  v8::internal::Runtime_Math_exp(v8::internal::Arguments)
+      2  100.0%    LazyCompile: exp native math.js:41
+      2  100.0%      Script: exp.js
+
+      2   15.4%  /lib32/libm-2.7.so
+      2  100.0%    LazyCompile: exp native math.js:41
+      2  100.0%      Script: exp.js
+
+      1    7.7%  v8::internal::JSObject::LocalLookupRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*)
+      1  100.0%    Script: exp.js
+
+      1    7.7%  v8::internal::HashTable<v8::internal::StringDictionaryShape, v8::internal::String*>::FindEntry(v8::internal::String*)
+      1  100.0%    Script: exp.js
+
+      1    7.7%  ffffe000-fffff000
+
+      1    7.7%  fegetexcept
+      1  100.0%    LazyCompile: exp native math.js:41
+      1  100.0%      Script: exp.js
+
+      1    7.7%  exp
+      1  100.0%    LazyCompile: exp native math.js:41
+      1  100.0%      Script: exp.js
+
+      1    7.7%  LazyCompile: exp native math.js:41
+      1  100.0%    Script: exp.js
+
diff --git a/test/mjsunit/tools/tickprocessor-test.gc-state b/test/mjsunit/tools/tickprocessor-test.gc-state
new file mode 100644
index 0000000..40f90db
--- /dev/null
+++ b/test/mjsunit/tools/tickprocessor-test.gc-state
@@ -0,0 +1,21 @@
+Statistical profiling result from v8.log, (13 ticks, 0 unaccounted, 13 excluded).
+
+ [Shared libraries]:
+   ticks  total  nonlib   name
+
+ [JavaScript]:
+   ticks  total  nonlib   name
+
+ [C++]:
+   ticks  total  nonlib   name
+
+ [GC]:
+   ticks  total  nonlib   name
+      0    0.0%
+
+ [Bottom up (heavy) profile]:
+  Note: percentage shows a share of a particular caller in the total
+  amount of its parent calls.
+  Callers occupying less than 2.0% are not shown.
+
+   ticks parent  name
diff --git a/test/mjsunit/tools/tickprocessor-test.ignore-unknown b/test/mjsunit/tools/tickprocessor-test.ignore-unknown
new file mode 100644
index 0000000..87beb08
--- /dev/null
+++ b/test/mjsunit/tools/tickprocessor-test.ignore-unknown
@@ -0,0 +1,56 @@
+Statistical profiling result from v8.log, (13 ticks, 2 unaccounted, 0 excluded).
+
+ [Shared libraries]:
+   ticks  total  nonlib   name
+      2   18.2%    0.0%  /lib32/libm-2.7.so
+      1    9.1%    0.0%  ffffe000-fffff000
+
+ [JavaScript]:
+   ticks  total  nonlib   name
+      1    9.1%   12.5%  LazyCompile: exp native math.js:41
+
+ [C++]:
+   ticks  total  nonlib   name
+      2   18.2%   25.0%  v8::internal::Runtime_Math_exp(v8::internal::Arguments)
+      1    9.1%   12.5%  v8::internal::JSObject::LocalLookupRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*)
+      1    9.1%   12.5%  v8::internal::HashTable<v8::internal::StringDictionaryShape, v8::internal::String*>::FindEntry(v8::internal::String*)
+      1    9.1%   12.5%  fegetexcept
+      1    9.1%   12.5%  exp
+
+ [GC]:
+   ticks  total  nonlib   name
+      0    0.0%
+
+ [Bottom up (heavy) profile]:
+  Note: percentage shows a share of a particular caller in the total
+  amount of its parent calls.
+  Callers occupying less than 2.0% are not shown.
+
+   ticks parent  name
+      2   18.2%  v8::internal::Runtime_Math_exp(v8::internal::Arguments)
+      2  100.0%    LazyCompile: exp native math.js:41
+      2  100.0%      Script: exp.js
+
+      2   18.2%  /lib32/libm-2.7.so
+      2  100.0%    LazyCompile: exp native math.js:41
+      2  100.0%      Script: exp.js
+
+      1    9.1%  v8::internal::JSObject::LocalLookupRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*)
+      1  100.0%    Script: exp.js
+
+      1    9.1%  v8::internal::HashTable<v8::internal::StringDictionaryShape, v8::internal::String*>::FindEntry(v8::internal::String*)
+      1  100.0%    Script: exp.js
+
+      1    9.1%  ffffe000-fffff000
+
+      1    9.1%  fegetexcept
+      1  100.0%    LazyCompile: exp native math.js:41
+      1  100.0%      Script: exp.js
+
+      1    9.1%  exp
+      1  100.0%    LazyCompile: exp native math.js:41
+      1  100.0%      Script: exp.js
+
+      1    9.1%  LazyCompile: exp native math.js:41
+      1  100.0%    Script: exp.js
+
diff --git a/test/mjsunit/tools/tickprocessor-test.log b/test/mjsunit/tools/tickprocessor-test.log
new file mode 100644
index 0000000..75daad6
--- /dev/null
+++ b/test/mjsunit/tools/tickprocessor-test.log
@@ -0,0 +1,24 @@
+shared-library,"shell",0x08048000,0x081ee000
+shared-library,"/lib32/libm-2.7.so",0xf7db6000,0xf7dd9000
+shared-library,"ffffe000-fffff000",0xffffe000,0xfffff000
+profiler,"begin",1
+code-creation,Stub,0xf540a100,474,"CEntryStub"
+code-creation,Script,0xf541cd80,736,"exp.js"
+code-creation,Stub,0xf541d0e0,47,"RuntimeStub_Math_exp"
+code-creation,LazyCompile,0xf541d120,145,"exp native math.js:41"
+code-creation,LoadIC,0xf541d280,117,"j"
+code-creation,LoadIC,0xf541d360,63,"i"
+tick,0x80f82d1,0xffdfe880,0,0xf541ce5c
+tick,0x80f89a1,0xffdfecf0,0,0xf541ce5c
+tick,0x8123b5c,0xffdff1a0,0,0xf541d1a1,0xf541ceea
+tick,0x8123b65,0xffdff1a0,0,0xf541d1a1,0xf541ceea
+tick,0xf541d2be,0xffdff1e4,0
+tick,0xf541d320,0xffdff1dc,0
+tick,0xf541d384,0xffdff1d8,0
+tick,0xf7db94da,0xffdff0ec,0,0xf541d1a1,0xf541ceea
+tick,0xf7db951c,0xffdff0f0,0,0xf541d1a1,0xf541ceea
+tick,0xf7dbc508,0xffdff14c,0,0xf541d1a1,0xf541ceea
+tick,0xf7dbff21,0xffdff198,0,0xf541d1a1,0xf541ceea
+tick,0xf7edec90,0xffdff0ec,0,0xf541d1a1,0xf541ceea
+tick,0xffffe402,0xffdff488,0
+profiler,"end"
diff --git a/test/mjsunit/tools/tickprocessor-test.separate-ic b/test/mjsunit/tools/tickprocessor-test.separate-ic
new file mode 100644
index 0000000..7eb3d9a
--- /dev/null
+++ b/test/mjsunit/tools/tickprocessor-test.separate-ic
@@ -0,0 +1,66 @@
+Statistical profiling result from v8.log, (13 ticks, 2 unaccounted, 0 excluded).
+
+ [Unknown]:
+   ticks  total  nonlib   name
+      2   15.4%
+
+ [Shared libraries]:
+   ticks  total  nonlib   name
+      2   15.4%    0.0%  /lib32/libm-2.7.so
+      1    7.7%    0.0%  ffffe000-fffff000
+
+ [JavaScript]:
+   ticks  total  nonlib   name
+      1    7.7%   10.0%  LoadIC: j
+      1    7.7%   10.0%  LoadIC: i
+      1    7.7%   10.0%  LazyCompile: exp native math.js:41
+
+ [C++]:
+   ticks  total  nonlib   name
+      2   15.4%   20.0%  v8::internal::Runtime_Math_exp(v8::internal::Arguments)
+      1    7.7%   10.0%  v8::internal::JSObject::LocalLookupRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*)
+      1    7.7%   10.0%  v8::internal::HashTable<v8::internal::StringDictionaryShape, v8::internal::String*>::FindEntry(v8::internal::String*)
+      1    7.7%   10.0%  fegetexcept
+      1    7.7%   10.0%  exp
+
+ [GC]:
+   ticks  total  nonlib   name
+      0    0.0%
+
+ [Bottom up (heavy) profile]:
+  Note: percentage shows a share of a particular caller in the total
+  amount of its parent calls.
+  Callers occupying less than 2.0% are not shown.
+
+   ticks parent  name
+      2   15.4%  v8::internal::Runtime_Math_exp(v8::internal::Arguments)
+      2  100.0%    LazyCompile: exp native math.js:41
+      2  100.0%      Script: exp.js
+
+      2   15.4%  /lib32/libm-2.7.so
+      2  100.0%    LazyCompile: exp native math.js:41
+      2  100.0%      Script: exp.js
+
+      1    7.7%  v8::internal::JSObject::LocalLookupRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*)
+      1  100.0%    Script: exp.js
+
+      1    7.7%  v8::internal::HashTable<v8::internal::StringDictionaryShape, v8::internal::String*>::FindEntry(v8::internal::String*)
+      1  100.0%    Script: exp.js
+
+      1    7.7%  ffffe000-fffff000
+
+      1    7.7%  fegetexcept
+      1  100.0%    LazyCompile: exp native math.js:41
+      1  100.0%      Script: exp.js
+
+      1    7.7%  exp
+      1  100.0%    LazyCompile: exp native math.js:41
+      1  100.0%      Script: exp.js
+
+      1    7.7%  LoadIC: j
+
+      1    7.7%  LoadIC: i
+
+      1    7.7%  LazyCompile: exp native math.js:41
+      1  100.0%    Script: exp.js
+
diff --git a/test/mjsunit/tools/tickprocessor.js b/test/mjsunit/tools/tickprocessor.js
new file mode 100644
index 0000000..587106a
--- /dev/null
+++ b/test/mjsunit/tools/tickprocessor.js
@@ -0,0 +1,268 @@
+// Copyright 2009 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.
+
+// Load implementations from <project root>/tools.
+// Files: tools/splaytree.js tools/codemap.js tools/csvparser.js
+// Files: tools/consarray.js tools/profile.js tools/profile_view.js
+// Files: tools/logreader.js tools/tickprocessor.js
+// Env: TEST_FILE_NAME
+
+(function testArgumentsProcessor() {
+  var p_default = new ArgumentsProcessor([]);
+  assertTrue(p_default.parse());
+  assertEquals(ArgumentsProcessor.DEFAULTS, p_default.result());
+
+  var p_logFile = new ArgumentsProcessor(['logfile.log']);
+  assertTrue(p_logFile.parse());
+  assertEquals('logfile.log', p_logFile.result().logFileName);
+
+  var p_platformAndLog = new ArgumentsProcessor(['--windows', 'winlog.log']);
+  assertTrue(p_platformAndLog.parse());
+  assertEquals('windows', p_platformAndLog.result().platform);
+  assertEquals('winlog.log', p_platformAndLog.result().logFileName);
+
+  var p_flags = new ArgumentsProcessor(['--gc', '--separate-ic']);
+  assertTrue(p_flags.parse());
+  assertEquals(TickProcessor.VmStates.GC, p_flags.result().stateFilter);
+  assertTrue(p_flags.result().separateIc);
+
+  var p_nmAndLog = new ArgumentsProcessor(['--nm=mn', 'nmlog.log']);
+  assertTrue(p_nmAndLog.parse());
+  assertEquals('mn', p_nmAndLog.result().nm);
+  assertEquals('nmlog.log', p_nmAndLog.result().logFileName);
+
+  var p_bad = new ArgumentsProcessor(['--unknown', 'badlog.log']);
+  assertFalse(p_bad.parse());
+})();
+
+
+(function testUnixCppEntriesProvider() {
+  var oldLoadSymbols = UnixCppEntriesProvider.prototype.loadSymbols;
+
+  // shell executable
+  UnixCppEntriesProvider.prototype.loadSymbols = function(libName) {
+    this.symbols = [[
+      '         U operator delete[](void*)@@GLIBCXX_3.4',
+      '08049790 T _init',
+      '08049f50 T _start',
+      '08139150 t v8::internal::Runtime_StringReplaceRegExpWithString(v8::internal::Arguments)',
+      '08139ca0 T v8::internal::Runtime::GetElementOrCharAt(v8::internal::Handle<v8::internal::Object>, unsigned int)',
+      '0813a0b0 t v8::internal::Runtime_DebugGetPropertyDetails(v8::internal::Arguments)',
+      '08181d30 W v8::internal::RegExpMacroAssemblerIrregexp::stack_limit_slack()',
+      '         w __gmon_start__',
+      '081f08a0 B stdout'
+    ].join('\n'), ''];
+  };
+
+  var shell_prov = new UnixCppEntriesProvider();
+  var shell_syms = [];
+  shell_prov.parseVmSymbols('shell', 0x08048000, 0x081ee000,
+      function (name, start, end) {
+        shell_syms.push(Array.prototype.slice.apply(arguments, [0]));
+      });
+  assertEquals(
+      [['_init', 0x08049790, 0x08049f50],
+       ['_start', 0x08049f50, 0x08139150],
+       ['v8::internal::Runtime_StringReplaceRegExpWithString(v8::internal::Arguments)', 0x08139150, 0x08139ca0],
+       ['v8::internal::Runtime::GetElementOrCharAt(v8::internal::Handle<v8::internal::Object>, unsigned int)', 0x08139ca0, 0x0813a0b0],
+       ['v8::internal::Runtime_DebugGetPropertyDetails(v8::internal::Arguments)', 0x0813a0b0, 0x08181d30],
+       ['v8::internal::RegExpMacroAssemblerIrregexp::stack_limit_slack()', 0x08181d30, 0x081ee000]],
+      shell_syms);
+
+  // libc library
+  UnixCppEntriesProvider.prototype.loadSymbols = function(libName) {
+    this.symbols = [[
+        '000162a0 T __libc_init_first',
+        '0002a5f0 T __isnan',
+        '0002a5f0 W isnan',
+        '0002aaa0 W scalblnf',
+        '0002aaa0 W scalbnf',
+        '0011a340 T __libc_thread_freeres',
+        '00128860 R _itoa_lower_digits'].join('\n'), ''];
+  };
+  var libc_prov = new UnixCppEntriesProvider();
+  var libc_syms = [];
+  libc_prov.parseVmSymbols('libc', 0xf7c5c000, 0xf7da5000,
+      function (name, start, end) {
+        libc_syms.push(Array.prototype.slice.apply(arguments, [0]));
+      });
+  assertEquals(
+      [['__libc_init_first', 0xf7c5c000 + 0x000162a0, 0xf7c5c000 + 0x0002a5f0],
+       ['isnan', 0xf7c5c000 + 0x0002a5f0, 0xf7c5c000 + 0x0002aaa0],
+       ['scalbnf', 0xf7c5c000 + 0x0002aaa0, 0xf7c5c000 + 0x0011a340],
+       ['__libc_thread_freeres', 0xf7c5c000 + 0x0011a340, 0xf7da5000]],
+      libc_syms);
+
+  UnixCppEntriesProvider.prototype.loadSymbols = oldLoadSymbols;
+})();
+
+
+(function testWindowsCppEntriesProvider() {
+  var oldLoadSymbols = WindowsCppEntriesProvider.prototype.loadSymbols;
+
+  WindowsCppEntriesProvider.prototype.loadSymbols = function(libName) {
+    this.symbols = [
+      ' Start         Length     Name                   Class',
+      ' 0001:00000000 000ac902H .text                   CODE',
+      ' 0001:000ac910 000005e2H .text$yc                CODE',
+      '  Address         Publics by Value              Rva+Base       Lib:Object',
+      ' 0000:00000000       __except_list              00000000     <absolute>',
+      ' 0001:00000000       ?ReadFile@@YA?AV?$Handle@VString@v8@@@v8@@PBD@Z 00401000 f   shell.obj',
+      ' 0001:000000a0       ?Print@@YA?AV?$Handle@VValue@v8@@@v8@@ABVArguments@2@@Z 004010a0 f   shell.obj',
+      ' 0001:00001230       ??1UTF8Buffer@internal@v8@@QAE@XZ 00402230 f   v8_snapshot:scanner.obj',
+      ' 0001:00001230       ??1Utf8Value@String@v8@@QAE@XZ 00402230 f   v8_snapshot:api.obj',
+      ' 0001:000954ba       __fclose_nolock            004964ba f   LIBCMT:fclose.obj',
+      ' 0002:00000000       __imp__SetThreadPriority@8 004af000     kernel32:KERNEL32.dll',
+      ' 0003:00000418       ?in_use_list_@PreallocatedStorage@internal@v8@@0V123@A 00544418     v8_snapshot:allocation.obj',
+      ' Static symbols',
+      ' 0001:00000b70       ?DefaultFatalErrorHandler@v8@@YAXPBD0@Z 00401b70 f   v8_snapshot:api.obj',
+      ' 0001:000010b0       ?EnsureInitialized@v8@@YAXPBD@Z 004020b0 f   v8_snapshot:api.obj',
+      ' 0001:000ad17b       ??__Fnomem@?5???2@YAPAXI@Z@YAXXZ 004ae17b f   LIBCMT:new.obj'
+    ].join('\r\n');
+  };
+  var shell_prov = new WindowsCppEntriesProvider();
+  var shell_syms = [];
+  shell_prov.parseVmSymbols('shell.exe', 0x00400000, 0x0057c000,
+      function (name, start, end) {
+        shell_syms.push(Array.prototype.slice.apply(arguments, [0]));
+      });
+  assertEquals(
+      [['ReadFile', 0x00401000, 0x004010a0],
+       ['Print', 0x004010a0, 0x00402230],
+       ['v8::String::?1Utf8Value', 0x00402230, 0x004964ba],
+       ['v8::DefaultFatalErrorHandler', 0x00401b70, 0x004020b0],
+       ['v8::EnsureInitialized', 0x004020b0, 0x0057c000]],
+      shell_syms);
+
+  WindowsCppEntriesProvider.prototype.loadSymbols = oldLoadSymbols;
+})();
+
+
+function CppEntriesProviderMock() {
+};
+
+
+CppEntriesProviderMock.prototype.parseVmSymbols = function(
+    name, startAddr, endAddr, symbolAdder) {
+  var symbols = {
+    'shell':
+        [['v8::internal::JSObject::LocalLookupRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*)', 0x080f8800, 0x080f8d90],
+         ['v8::internal::HashTable<v8::internal::StringDictionaryShape, v8::internal::String*>::FindEntry(v8::internal::String*)', 0x080f8210, 0x080f8800],
+         ['v8::internal::Runtime_Math_exp(v8::internal::Arguments)', 0x08123b20, 0x08123b80]],
+    '/lib32/libm-2.7.so':
+        [['exp', startAddr + 0x00009e80, startAddr + 0x00009f30],
+         ['fegetexcept', startAddr + 0x000061e0, startAddr + 0x00008b10]],
+    'ffffe000-fffff000': []};
+  assertTrue(name in symbols);
+  var syms = symbols[name];
+  for (var i = 0; i < syms.length; ++i) {
+    symbolAdder.apply(null, syms[i]);
+  }
+};
+
+
+function PrintMonitor(outputOrFileName) {
+  var expectedOut = typeof outputOrFileName == 'string' ?
+      this.loadExpectedOutput(outputOrFileName) : outputOrFileName;
+  var outputPos = 0;
+  var diffs = this.diffs = [];
+  var realOut = this.realOut = [];
+
+  this.oldPrint = print;
+  print = function(str) {
+    var strSplit = str.split('\n');
+    for (var i = 0; i < strSplit.length; ++i) {
+      s = strSplit[i];
+      realOut.push(s);
+      assertTrue(outputPos < expectedOut.length,
+          'unexpected output: "' + s + '"');
+      if (expectedOut[outputPos] != s) {
+        diffs.push('line ' + outputPos + ': expected <' +
+                   expectedOut[outputPos] + '> found <' + s + '>\n');
+      }
+      outputPos++;
+    }
+  };
+};
+
+
+PrintMonitor.prototype.loadExpectedOutput = function(fileName) {
+  var output = readFile(fileName);
+  return output.split('\n');
+};
+
+
+PrintMonitor.prototype.finish = function() {
+  print = this.oldPrint;
+  if (this.diffs.length > 0) {
+    print(this.realOut.join('\n'));
+    assertEquals([], this.diffs);
+  }
+};
+
+
+function driveTickProcessorTest(
+    separateIc, ignoreUnknown, stateFilter, logInput, refOutput) {
+  // TEST_FILE_NAME must be provided by test runner.
+  assertEquals('string', typeof TEST_FILE_NAME);
+  var pathLen = TEST_FILE_NAME.lastIndexOf('/');
+  if (pathLen == -1) {
+    pathLen = TEST_FILE_NAME.lastIndexOf('\\');
+  }
+  assertTrue(pathLen != -1);
+  var testsPath = TEST_FILE_NAME.substr(0, pathLen + 1);
+  var tp = new TickProcessor(
+      new CppEntriesProviderMock(), separateIc, ignoreUnknown, stateFilter);
+  var pm = new PrintMonitor(testsPath + refOutput);
+  tp.processLogFile(testsPath + logInput);
+  // Hack file name to avoid dealing with platform specifics.
+  tp.lastLogFileName_ = 'v8.log';
+  tp.printStatistics();
+  pm.finish();
+};
+
+
+(function testProcessing() {
+  var testData = {
+    'Default': [
+      false, false, null,
+      'tickprocessor-test.log', 'tickprocessor-test.default'],
+    'SeparateIc': [
+      true, false, null,
+      'tickprocessor-test.log', 'tickprocessor-test.separate-ic'],
+    'IgnoreUnknown': [
+      false, true, null,
+      'tickprocessor-test.log', 'tickprocessor-test.ignore-unknown'],
+    'GcState': [
+      false, false, TickProcessor.VmStates.GC,
+      'tickprocessor-test.log', 'tickprocessor-test.gc-state']
+  };
+  for (var testName in testData) {
+    print('=== testProcessing-' + testName + ' ===');
+    driveTickProcessorTest.apply(null, testData[testName]);
+  }
+})();
diff --git a/tools/linux-tick-processor b/tools/linux-tick-processor
index c5130ff..ca1c721 100644
--- a/tools/linux-tick-processor
+++ b/tools/linux-tick-processor
@@ -20,4 +20,5 @@
 $d8_exec $tools_path/splaytree.js $tools_path/codemap.js \
   $tools_path/csvparser.js $tools_path/consarray.js \
   $tools_path/profile.js $tools_path/profile_view.js \
-  $tools_path/logreader.js $tools_path/tickprocessor.js -- $@ 2>/dev/null
+  $tools_path/logreader.js $tools_path/tickprocessor.js \
+  $tools_path/tickprocessor-driver.js -- $@ 2>/dev/null
diff --git a/tools/test.py b/tools/test.py
index f701ceb..05eb9fd 100755
--- a/tools/test.py
+++ b/tools/test.py
@@ -356,11 +356,15 @@
   def RunCommand(self, command):
     full_command = self.context.processor(command)
     output = Execute(full_command, self.context, self.context.timeout)
+    self.Cleanup()
     return TestOutput(self, full_command, output)
 
   def Run(self):
     return self.RunCommand(self.GetCommand())
 
+  def Cleanup(self):
+    return
+
 
 class TestOutput(object):
 
@@ -473,6 +477,13 @@
   sys.stderr.write('\n')
 
 
+def CheckedUnlink(name):
+  try:
+    os.unlink(name)
+  except OSError, e:
+    PrintError("os.unlink() " + str(e))
+
+
 def Execute(args, context, timeout=None):
   (fd_out, outname) = tempfile.mkstemp()
   (fd_err, errname) = tempfile.mkstemp()
@@ -487,11 +498,6 @@
   os.close(fd_err)
   output = file(outname).read()
   errors = file(errname).read()
-  def CheckedUnlink(name):
-    try:
-      os.unlink(name)
-    except OSError, e:
-      PrintError("os.unlink() " + str(e))
   CheckedUnlink(outname)
   CheckedUnlink(errname)
   return CommandOutput(exit_code, timed_out, output, errors)
diff --git a/tools/tickprocessor-driver.js b/tools/tickprocessor-driver.js
new file mode 100644
index 0000000..f7cfd13
--- /dev/null
+++ b/tools/tickprocessor-driver.js
@@ -0,0 +1,49 @@
+// Copyright 2009 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.
+
+
+// Tick Processor's code flow.
+
+function processArguments(args) {
+  var processor = new ArgumentsProcessor(args);
+  if (processor.parse()) {
+    return processor.result();
+  } else {
+    processor.printUsageAndExit();
+  }
+}
+
+
+var params = processArguments(arguments);
+var tickProcessor = new TickProcessor(
+  params.platform == 'unix' ? new UnixCppEntriesProvider(params.nm) :
+    new WindowsCppEntriesProvider(),
+  params.separateIc,
+  params.ignoreUnknown,
+  params.stateFilter);
+tickProcessor.processLogFile(params.logFileName);
+tickProcessor.printStatistics();
diff --git a/tools/tickprocessor.js b/tools/tickprocessor.js
index 4afc69f..c95a4e6 100644
--- a/tools/tickprocessor.js
+++ b/tools/tickprocessor.js
@@ -288,7 +288,11 @@
 function padLeft(s, len) {
   s = s.toString();
   if (s.length < len) {
-    s = (new Array(len - s.length + 1).join(' ')) + s;
+    var padLength = len - s.length;
+    if (!(padLength in padLeft)) {
+      padLeft[padLength] = new Array(padLength + 1).join(' ');
+    }
+    s = padLeft[padLength] + s;
   }
   return s;
 };
@@ -511,25 +515,11 @@
 };
 
 
-function padRight(s, len) {
-  s = s.toString();
-  if (s.length < len) {
-    s = s + (new Array(len - s.length + 1).join(' '));
-  }
-  return s;
-};
+function ArgumentsProcessor(args) {
+  this.args_ = args;
+  this.result_ = ArgumentsProcessor.DEFAULTS;
 
-
-function processArguments(args) {
-  var result = {
-    logFileName: 'v8.log',
-    platform: 'unix',
-    stateFilter: null,
-    ignoreUnknown: false,
-    separateIc: false,
-    nm: 'nm'
-  };
-  var argsDispatch = {
+  this.argsDispatch_ = {
     '-j': ['stateFilter', TickProcessor.VmStates.JS,
         'Show only ticks from JS VM state'],
     '-g': ['stateFilter', TickProcessor.VmStates.GC,
@@ -551,63 +541,82 @@
     '--nm': ['nm', 'nm',
         'Specify the \'nm\' executable to use (e.g. --nm=/my_dir/nm)']
   };
-  argsDispatch['--js'] = argsDispatch['-j'];
-  argsDispatch['--gc'] = argsDispatch['-g'];
-  argsDispatch['--compiler'] = argsDispatch['-c'];
-  argsDispatch['--other'] = argsDispatch['-o'];
-  argsDispatch['--external'] = argsDispatch['-e'];
+  this.argsDispatch_['--js'] = this.argsDispatch_['-j'];
+  this.argsDispatch_['--gc'] = this.argsDispatch_['-g'];
+  this.argsDispatch_['--compiler'] = this.argsDispatch_['-c'];
+  this.argsDispatch_['--other'] = this.argsDispatch_['-o'];
+  this.argsDispatch_['--external'] = this.argsDispatch_['-e'];
+};
 
-  function printUsageAndExit() {
-    print('Cmdline args: [options] [log-file-name]\n' +
-          'Default log file name is "v8.log".\n');
-    print('Options:');
-    for (var arg in argsDispatch) {
-      var synonims = [arg];
-      var dispatch = argsDispatch[arg];
-      for (var synArg in argsDispatch) {
-        if (arg !== synArg && dispatch === argsDispatch[synArg]) {
-          synonims.push(synArg);
-          delete argsDispatch[synArg];
-        }
-      }
-      print('  ' + padRight(synonims.join(', '), 20) + dispatch[2]);
-    }
-    quit(2);
-  }
 
-  while (args.length) {
-    var arg = args[0];
+ArgumentsProcessor.DEFAULTS = {
+  logFileName: 'v8.log',
+  platform: 'unix',
+  stateFilter: null,
+  ignoreUnknown: false,
+  separateIc: false,
+  nm: 'nm'
+};
+
+
+ArgumentsProcessor.prototype.parse = function() {
+  while (this.args_.length) {
+    var arg = this.args_[0];
     if (arg.charAt(0) != '-') {
       break;
     }
-    args.shift();
+    this.args_.shift();
     var userValue = null;
     var eqPos = arg.indexOf('=');
     if (eqPos != -1) {
       userValue = arg.substr(eqPos + 1);
       arg = arg.substr(0, eqPos);
     }
-    if (arg in argsDispatch) {
-      var dispatch = argsDispatch[arg];
-      result[dispatch[0]] = userValue == null ? dispatch[1] : userValue;
+    if (arg in this.argsDispatch_) {
+      var dispatch = this.argsDispatch_[arg];
+      this.result_[dispatch[0]] = userValue == null ? dispatch[1] : userValue;
     } else {
-      printUsageAndExit();
+      return false;
     }
   }
 
-  if (args.length >= 1) {
-      result.logFileName = args.shift();
+  if (this.args_.length >= 1) {
+      this.result_.logFileName = this.args_.shift();
   }
-  return result;
+  return true;
 };
 
 
-var params = processArguments(arguments);
-var tickProcessor = new TickProcessor(
-    params.platform == 'unix' ? new UnixCppEntriesProvider(params.nm) :
-        new WindowsCppEntriesProvider(),
-    params.separateIc,
-    params.ignoreUnknown,
-    params.stateFilter);
-tickProcessor.processLogFile(params.logFileName);
-tickProcessor.printStatistics();
+ArgumentsProcessor.prototype.result = function() {
+  return this.result_;
+};
+
+
+ArgumentsProcessor.prototype.printUsageAndExit = function() {
+
+  function padRight(s, len) {
+    s = s.toString();
+    if (s.length < len) {
+      s = s + (new Array(len - s.length + 1).join(' '));
+    }
+    return s;
+  }
+
+  print('Cmdline args: [options] [log-file-name]\n' +
+        'Default log file name is "' +
+        ArgumentsProcessor.DEFAULTS.logFileName + '".\n');
+  print('Options:');
+  for (var arg in this.argsDispatch_) {
+    var synonims = [arg];
+    var dispatch = this.argsDispatch_[arg];
+    for (var synArg in this.argsDispatch_) {
+      if (arg !== synArg && dispatch === this.argsDispatch_[synArg]) {
+        synonims.push(synArg);
+        delete this.argsDispatch_[synArg];
+      }
+    }
+    print('  ' + padRight(synonims.join(', '), 20) + dispatch[2]);
+  }
+  quit(2);
+};
+
diff --git a/tools/windows-tick-processor.bat b/tools/windows-tick-processor.bat
index 67cbe98..6743f68 100644
--- a/tools/windows-tick-processor.bat
+++ b/tools/windows-tick-processor.bat
@@ -2,4 +2,4 @@
 
 SET tools_dir=%~dp0
 
-%tools_dir%..\d8 %tools_dir%splaytree.js %tools_dir%codemap.js %tools_dir%csvparser.js %tools_dir%consarray.js %tools_dir%profile.js %tools_dir%profile_view.js %tools_dir%logreader.js %tools_dir%tickprocessor.js -- --windows %*
+%tools_dir%..\d8 %tools_dir%splaytree.js %tools_dir%codemap.js %tools_dir%csvparser.js %tools_dir%consarray.js %tools_dir%profile.js %tools_dir%profile_view.js %tools_dir%logreader.js %tools_dir%tickprocessor.js %tools_dir%tickprocessor-driver.js -- --windows %*