Version 2.0.3

Optimized handling and adding of strings, for-in and Array.join.

Heap serialization is now non-destructive.

Improved profiler support with information on time spend in C++ callbacks registered through the API.

Added commands to the debugger protocol for starting/stopping profiling.

Enabled the non-optimizing compiler for top-level code.

Changed the API to only allow strings to be set as data objects on Contexts and scripts to avoid potentially keeping global objects around for too long (issue 528).

OpenBSD support patch by Peter Valchev <pvalchev@gmail.com>.

Fixed bugs.


git-svn-id: http://v8.googlecode.com/svn/trunk@3423 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/SConscript b/src/SConscript
index cfa462f..3b0df17 100755
--- a/src/SConscript
+++ b/src/SConscript
@@ -159,6 +159,7 @@
     """),
   'simulator:arm': ['arm/simulator-arm.cc'],
   'os:freebsd': ['platform-freebsd.cc', 'platform-posix.cc'],
+  'os:openbsd': ['platform-openbsd.cc', 'platform-posix.cc'],
   'os:linux':   ['platform-linux.cc', 'platform-posix.cc'],
   'os:android': ['platform-linux.cc', 'platform-posix.cc'],
   'os:macos':   ['platform-macos.cc', 'platform-posix.cc'],
@@ -187,6 +188,9 @@
   'os:freebsd': [
     'd8-posix.cc'
   ],
+  'os:openbsd': [
+    'd8-posix.cc'
+  ],
   'os:win32': [
     'd8-windows.cc'
   ],
diff --git a/src/api.cc b/src/api.cc
index eaff862..93807a7 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -125,8 +125,49 @@
 
 // When V8 cannot allocated memory FatalProcessOutOfMemory is called.
 // The default fatal error handler is called and execution is stopped.
-static void ExecuteFatalProcessOutOfMemory(const char* location,
-                                           i::HeapStats* heap_stats) {
+void i::V8::FatalProcessOutOfMemory(const char* location) {
+  i::HeapStats heap_stats;
+  int start_marker;
+  heap_stats.start_marker = &start_marker;
+  int new_space_size;
+  heap_stats.new_space_size = &new_space_size;
+  int new_space_capacity;
+  heap_stats.new_space_capacity = &new_space_capacity;
+  int old_pointer_space_size;
+  heap_stats.old_pointer_space_size = &old_pointer_space_size;
+  int old_pointer_space_capacity;
+  heap_stats.old_pointer_space_capacity = &old_pointer_space_capacity;
+  int old_data_space_size;
+  heap_stats.old_data_space_size = &old_data_space_size;
+  int old_data_space_capacity;
+  heap_stats.old_data_space_capacity = &old_data_space_capacity;
+  int code_space_size;
+  heap_stats.code_space_size = &code_space_size;
+  int code_space_capacity;
+  heap_stats.code_space_capacity = &code_space_capacity;
+  int map_space_size;
+  heap_stats.map_space_size = &map_space_size;
+  int map_space_capacity;
+  heap_stats.map_space_capacity = &map_space_capacity;
+  int cell_space_size;
+  heap_stats.cell_space_size = &cell_space_size;
+  int cell_space_capacity;
+  heap_stats.cell_space_capacity = &cell_space_capacity;
+  int lo_space_size;
+  heap_stats.lo_space_size = &lo_space_size;
+  int global_handle_count;
+  heap_stats.global_handle_count = &global_handle_count;
+  int weak_global_handle_count;
+  heap_stats.weak_global_handle_count = &weak_global_handle_count;
+  int pending_global_handle_count;
+  heap_stats.pending_global_handle_count = &pending_global_handle_count;
+  int near_death_global_handle_count;
+  heap_stats.near_death_global_handle_count = &near_death_global_handle_count;
+  int destroyed_global_handle_count;
+  heap_stats.destroyed_global_handle_count = &destroyed_global_handle_count;
+  int end_marker;
+  heap_stats.end_marker = &end_marker;
+  i::Heap::RecordStats(&heap_stats);
   i::V8::SetFatalError();
   FatalErrorCallback callback = GetFatalErrorHandler();
   {
@@ -138,13 +179,6 @@
 }
 
 
-void i::V8::FatalProcessOutOfMemory(const char* location) {
-  i::HeapStats heap_stats;
-  i::Heap::RecordStats(&heap_stats);
-  ExecuteFatalProcessOutOfMemory(location, &heap_stats);
-}
-
-
 void V8::SetFatalErrorHandler(FatalErrorCallback that) {
   exception_behavior = that;
 }
diff --git a/src/arm/assembler-arm.h b/src/arm/assembler-arm.h
index ca0184e..86bc18a 100644
--- a/src/arm/assembler-arm.h
+++ b/src/arm/assembler-arm.h
@@ -566,6 +566,7 @@
   // register.
   static const int kPcLoadDelta = 8;
 
+  static const int kJSReturnSequenceLength = 4;
 
   // ---------------------------------------------------------------------------
   // Code generation
diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc
index c62756d..ea3df6c 100644
--- a/src/arm/codegen-arm.cc
+++ b/src/arm/codegen-arm.cc
@@ -326,7 +326,7 @@
     // Calculate the exact length of the return sequence and make sure that
     // the constant pool is not emitted inside of the return sequence.
     int32_t sp_delta = (scope_->num_parameters() + 1) * kPointerSize;
-    int return_sequence_length = Debug::kARMJSReturnSequenceLength;
+    int return_sequence_length = Assembler::kJSReturnSequenceLength;
     if (!masm_->ImmediateFitsAddrMode1Instruction(sp_delta)) {
       // Additional mov instruction generated.
       return_sequence_length++;
@@ -1560,7 +1560,7 @@
   CheckStack();  // TODO(1222600): ignore if body contains calls.
   VisitAndSpill(node->body());
 
-      // Compile the test.
+  // Compile the test.
   switch (info) {
     case ALWAYS_TRUE:
       // If control can fall off the end of the body, jump back to the
@@ -1775,19 +1775,77 @@
 
   jsobject.Bind();
   // Get the set of properties (as a FixedArray or Map).
-  frame_->EmitPush(r0);  // duplicate the object being enumerated
-  frame_->EmitPush(r0);
+  // r0: value to be iterated over
+  frame_->EmitPush(r0);  // Push the object being iterated over.
+
+  // Check cache validity in generated code. This is a fast case for
+  // the JSObject::IsSimpleEnum cache validity checks. If we cannot
+  // guarantee cache validity, call the runtime system to check cache
+  // validity or get the property names in a fixed array.
+  JumpTarget call_runtime;
+  JumpTarget loop(JumpTarget::BIDIRECTIONAL);
+  JumpTarget check_prototype;
+  JumpTarget use_cache;
+  __ mov(r1, Operand(r0));
+  loop.Bind();
+  // Check that there are no elements.
+  __ ldr(r2, FieldMemOperand(r1, JSObject::kElementsOffset));
+  __ LoadRoot(r4, Heap::kEmptyFixedArrayRootIndex);
+  __ cmp(r2, r4);
+  call_runtime.Branch(ne);
+  // Check that instance descriptors are not empty so that we can
+  // check for an enum cache.  Leave the map in r3 for the subsequent
+  // prototype load.
+  __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
+  __ ldr(r2, FieldMemOperand(r3, Map::kInstanceDescriptorsOffset));
+  __ LoadRoot(ip, Heap::kEmptyDescriptorArrayRootIndex);
+  __ cmp(r2, ip);
+  call_runtime.Branch(eq);
+  // Check that there in an enum cache in the non-empty instance
+  // descriptors.  This is the case if the next enumeration index
+  // field does not contain a smi.
+  __ ldr(r2, FieldMemOperand(r2, DescriptorArray::kEnumerationIndexOffset));
+  __ tst(r2, Operand(kSmiTagMask));
+  call_runtime.Branch(eq);
+  // For all objects but the receiver, check that the cache is empty.
+  // r4: empty fixed array root.
+  __ cmp(r1, r0);
+  check_prototype.Branch(eq);
+  __ ldr(r2, FieldMemOperand(r2, DescriptorArray::kEnumCacheBridgeCacheOffset));
+  __ cmp(r2, r4);
+  call_runtime.Branch(ne);
+  check_prototype.Bind();
+  // Load the prototype from the map and loop if non-null.
+  __ ldr(r1, FieldMemOperand(r3, Map::kPrototypeOffset));
+  __ LoadRoot(ip, Heap::kNullValueRootIndex);
+  __ cmp(r1, ip);
+  loop.Branch(ne);
+  // The enum cache is valid.  Load the map of the object being
+  // iterated over and use the cache for the iteration.
+  __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset));
+  use_cache.Jump();
+
+  call_runtime.Bind();
+  // Call the runtime to get the property names for the object.
+  frame_->EmitPush(r0);  // push the object (slot 4) for the runtime call
   frame_->CallRuntime(Runtime::kGetPropertyNamesFast, 1);
 
-  // If we got a Map, we can do a fast modification check.
-  // Otherwise, we got a FixedArray, and we have to do a slow check.
+  // If we got a map from the runtime call, we can do a fast
+  // modification check. Otherwise, we got a fixed array, and we have
+  // to do a slow check.
+  // r0: map or fixed array (result from call to
+  // Runtime::kGetPropertyNamesFast)
   __ mov(r2, Operand(r0));
   __ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset));
   __ LoadRoot(ip, Heap::kMetaMapRootIndex);
   __ cmp(r1, ip);
   fixed_array.Branch(ne);
 
+  use_cache.Bind();
   // Get enum cache
+  // r0: map (either the result from a call to
+  // Runtime::kGetPropertyNamesFast or has been fetched directly from
+  // the object)
   __ mov(r1, Operand(r0));
   __ ldr(r1, FieldMemOperand(r1, Map::kInstanceDescriptorsOffset));
   __ ldr(r1, FieldMemOperand(r1, DescriptorArray::kEnumerationIndexOffset));
@@ -3308,9 +3366,6 @@
 
   // Now r2 has the string type.
   __ ldr(r3, FieldMemOperand(r1, String::kLengthOffset));
-  __ and_(r4, r2, Operand(kStringSizeMask));
-  __ add(r4, r4, Operand(String::kLongLengthShift));
-  __ mov(r3, Operand(r3, LSR, r4));
   // Now r3 has the length of the string.  Compare with the index.
   __ cmp(r3, Operand(r0, LSR, kSmiTagSize));
   __ b(le, &slow);
@@ -3508,6 +3563,17 @@
 }
 
 
+void CodeGenerator::GenerateStringAdd(ZoneList<Expression*>* args) {
+  ASSERT_EQ(2, args->length());
+
+  Load(args->at(0));
+  Load(args->at(1));
+
+  frame_->CallRuntime(Runtime::kStringAdd, 2);
+  frame_->EmitPush(r0);
+}
+
+
 void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) {
   VirtualFrame::SpilledScope spilled_scope;
   ASSERT(args->length() == 2);
@@ -5149,8 +5215,53 @@
   // We jump to here if something goes wrong (one param is not a number of any
   // sort or new-space allocation fails).
   __ bind(&slow);
+
+  // Push arguments to the stack
   __ push(r1);
   __ push(r0);
+
+  if (Token::ADD == operation) {
+    // Test for string arguments before calling runtime.
+    // r1 : first argument
+    // r0 : second argument
+    // sp[0] : second argument
+    // sp[1] : first argument
+
+    Label not_strings, not_string1, string1;
+    __ tst(r1, Operand(kSmiTagMask));
+    __ b(eq, &not_string1);
+    __ CompareObjectType(r1, r2, r2, FIRST_NONSTRING_TYPE);
+    __ b(ge, &not_string1);
+
+    // First argument is a a string, test second.
+    __ tst(r0, Operand(kSmiTagMask));
+    __ b(eq, &string1);
+    __ CompareObjectType(r0, r2, r2, FIRST_NONSTRING_TYPE);
+    __ b(ge, &string1);
+
+    // First and second argument are strings.
+    __ TailCallRuntime(ExternalReference(Runtime::kStringAdd), 2, 1);
+
+    // Only first argument is a string.
+    __ bind(&string1);
+    __ mov(r0, Operand(2));  // Set number of arguments.
+    __ InvokeBuiltin(Builtins::STRING_ADD_LEFT, JUMP_JS);
+
+    // First argument was not a string, test second.
+    __ bind(&not_string1);
+    __ tst(r0, Operand(kSmiTagMask));
+    __ b(eq, &not_strings);
+    __ CompareObjectType(r0, r2, r2, FIRST_NONSTRING_TYPE);
+    __ b(ge, &not_strings);
+
+    // Only second argument is a string.
+    __ b(&not_strings);
+    __ mov(r0, Operand(2));  // Set number of arguments.
+    __ InvokeBuiltin(Builtins::STRING_ADD_RIGHT, JUMP_JS);
+
+    __ bind(&not_strings);
+  }
+
   __ mov(r0, Operand(1));  // Set number of arguments.
   __ InvokeBuiltin(builtin, JUMP_JS);  // Tail call.  No return.
 
@@ -6388,7 +6499,7 @@
   __ b(eq, &adaptor);
 
   // Check index against formal parameters count limit passed in
-  // through register eax. Use unsigned comparison to get negative
+  // through register r0. Use unsigned comparison to get negative
   // check for free.
   __ cmp(r1, r0);
   __ b(cs, &slow);
diff --git a/src/arm/codegen-arm.h b/src/arm/codegen-arm.h
index 30a1ae5..ba7f936 100644
--- a/src/arm/codegen-arm.h
+++ b/src/arm/codegen-arm.h
@@ -366,6 +366,9 @@
   inline void GenerateMathSin(ZoneList<Expression*>* args);
   inline void GenerateMathCos(ZoneList<Expression*>* args);
 
+  // Fast support for StringAdd.
+  void GenerateStringAdd(ZoneList<Expression*>* args);
+
   // Simple condition analysis.
   enum ConditionAnalysis {
     ALWAYS_TRUE,
diff --git a/src/arm/constants-arm.h b/src/arm/constants-arm.h
index 58396f8..9432207 100644
--- a/src/arm/constants-arm.h
+++ b/src/arm/constants-arm.h
@@ -43,24 +43,27 @@
 # define USE_THUMB_INTERWORK 1
 #endif
 
-#if defined(__ARM_ARCH_5T__) || \
-    defined(__ARM_ARCH_5TE__) || \
-    defined(__ARM_ARCH_6__) || \
-    defined(__ARM_ARCH_7A__) || \
+#if defined(__ARM_ARCH_7A__) || \
+    defined(__ARM_ARCH_7R__) || \
     defined(__ARM_ARCH_7__)
-# define CAN_USE_ARMV5_INSTRUCTIONS 1
-# define CAN_USE_THUMB_INSTRUCTIONS 1
+# define CAN_USE_ARMV7_INSTRUCTIONS 1
 #endif
 
-#if defined(__ARM_ARCH_6__) || \
-    defined(__ARM_ARCH_7A__) || \
-    defined(__ARM_ARCH_7__)
+#if defined(__ARM_ARCH_6__) ||   \
+    defined(__ARM_ARCH_6J__) ||  \
+    defined(__ARM_ARCH_6K__) ||  \
+    defined(__ARM_ARCH_6Z__) ||  \
+    defined(__ARM_ARCH_6ZK__) || \
+    defined(__ARM_ARCH_6T2__) || \
+    defined(CAN_USE_ARMV7_INSTRUCTIONS)
 # define CAN_USE_ARMV6_INSTRUCTIONS 1
 #endif
 
-#if defined(__ARM_ARCH_7A__) || \
-    defined(__ARM_ARCH_7__)
-# define CAN_USE_ARMV7_INSTRUCTIONS 1
+#if defined(__ARM_ARCH_5T__)            || \
+    defined(__ARM_ARCH_5TE__)           || \
+    defined(CAN_USE_ARMV6_INSTRUCTIONS)
+# define CAN_USE_ARMV5_INSTRUCTIONS 1
+# define CAN_USE_THUMB_INSTRUCTIONS 1
 #endif
 
 // Simulator should support ARM5 instructions.
diff --git a/src/arm/debug-arm.cc b/src/arm/debug-arm.cc
index 102952d..fc9808d 100644
--- a/src/arm/debug-arm.cc
+++ b/src/arm/debug-arm.cc
@@ -61,7 +61,7 @@
 // Restore the JS frame exit code.
 void BreakLocationIterator::ClearDebugBreakAtReturn() {
   rinfo()->PatchCode(original_rinfo()->pc(),
-                     Debug::kARMJSReturnSequenceLength);
+                     Assembler::kJSReturnSequenceLength);
 }
 
 
diff --git a/src/arm/fast-codegen-arm.cc b/src/arm/fast-codegen-arm.cc
index 6d0510e..ab636b6 100644
--- a/src/arm/fast-codegen-arm.cc
+++ b/src/arm/fast-codegen-arm.cc
@@ -73,16 +73,46 @@
 
   bool function_in_register = true;
 
+  // Possibly allocate a local context.
+  if (fun->scope()->num_heap_slots() > 0) {
+    Comment cmnt(masm_, "[ Allocate local context");
+    // Argument to NewContext is the function, which is in r1.
+    __ push(r1);
+    __ CallRuntime(Runtime::kNewContext, 1);
+    function_in_register = false;
+    // Context is returned in both r0 and cp.  It replaces the context
+    // passed to us.  It's saved in the stack and kept live in cp.
+    __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+    // Copy any necessary parameters into the context.
+    int num_parameters = fun->scope()->num_parameters();
+    for (int i = 0; i < num_parameters; i++) {
+      Slot* slot = fun->scope()->parameter(i)->slot();
+      if (slot != NULL && slot->type() == Slot::CONTEXT) {
+        int parameter_offset = StandardFrameConstants::kCallerSPOffset +
+                               (num_parameters - 1 - i) * kPointerSize;
+        // Load parameter from stack.
+        __ ldr(r0, MemOperand(fp, parameter_offset));
+        // Store it in the context
+        __ str(r0, MemOperand(cp, Context::SlotOffset(slot->index())));
+      }
+    }
+  }
+
   Variable* arguments = fun->scope()->arguments()->AsVariable();
   if (arguments != NULL) {
     // Function uses arguments object.
     Comment cmnt(masm_, "[ Allocate arguments object");
-    __ mov(r3, r1);
+    if (!function_in_register) {
+      // Load this again, if it's used by the local context below.
+      __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+    } else {
+      __ mov(r3, r1);
+    }
     // Receiver is just before the parameters on the caller's stack.
     __ add(r2, fp, Operand(StandardFrameConstants::kCallerSPOffset +
                                fun->num_parameters() * kPointerSize));
     __ mov(r1, Operand(Smi::FromInt(fun->num_parameters())));
-    __ stm(db_w, sp, r1.bit() | r2.bit() | r3.bit());
+    __ stm(db_w, sp, r3.bit() | r2.bit() | r1.bit());
 
     // Arguments to ArgumentsAccessStub:
     //   function, receiver address, parameter count.
@@ -90,33 +120,12 @@
     // stack frame was an arguments adapter frame.
     ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
     __ CallStub(&stub);
-    __ str(r0, MemOperand(fp, SlotOffset(arguments->slot())));
+    // Duplicate the value; move-to-slot operation might clobber registers.
+    __ mov(r3, r0);
+    Move(arguments->slot(), r0, r1, r2);
     Slot* dot_arguments_slot =
         fun->scope()->arguments_shadow()->AsVariable()->slot();
-    __ str(r0, MemOperand(fp, SlotOffset(dot_arguments_slot)));
-    function_in_register = false;
-  }
-
-  // Possibly allocate a local context.
-  if (fun->scope()->num_heap_slots() > 0) {
-    Comment cmnt(masm_, "[ Allocate local context");
-    if (!function_in_register) {
-      // Load this again, if it's used by the local context below.
-      __ ldr(r1, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
-    }
-    // Argument to NewContext is the function, which is in r1.
-    __ push(r1);
-    __ CallRuntime(Runtime::kNewContext, 1);
-    // Context is returned in both r0 and cp.  It replaces the context
-    // passed to us.  It's saved in the stack and kept live in cp.
-    __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
-#ifdef DEBUG
-    // Assert we do not have to copy any parameters into the context.
-    for (int i = 0, len = fun->scope()->num_parameters(); i < len; i++) {
-      Slot* slot = fun->scope()->parameter(i)->slot();
-      ASSERT(slot != NULL && slot->type() != Slot::CONTEXT);
-    }
-#endif
+    Move(dot_arguments_slot, r3, r1, r2);
   }
 
   // Check the stack for overflow or break request.
@@ -179,7 +188,7 @@
     // the constant pool is not emitted inside of the return sequence.
     int num_parameters = function_->scope()->num_parameters();
     int32_t sp_delta = (num_parameters + 1) * kPointerSize;
-    int return_sequence_length = Debug::kARMJSReturnSequenceLength;
+    int return_sequence_length = Assembler::kJSReturnSequenceLength;
     if (!masm_->ImmediateFitsAddrMode1Instruction(sp_delta)) {
       // Additional mov instruction generated.
       return_sequence_length++;
@@ -238,7 +247,42 @@
 }
 
 
-void FastCodeGenerator::Move(Expression::Context context, Slot* source) {
+template <>
+MemOperand FastCodeGenerator::CreateSlotOperand<MemOperand>(
+    Slot* source,
+    Register scratch) {
+  switch (source->type()) {
+    case Slot::PARAMETER:
+    case Slot::LOCAL:
+      return MemOperand(fp, SlotOffset(source));
+    case Slot::CONTEXT: {
+      int context_chain_length =
+          function_->scope()->ContextChainLength(source->var()->scope());
+      __ LoadContext(scratch, context_chain_length);
+      return CodeGenerator::ContextOperand(scratch, source->index());
+      break;
+    }
+    case Slot::LOOKUP:
+      UNIMPLEMENTED();
+      // Fall-through.
+    default:
+      UNREACHABLE();
+      return MemOperand(r0, 0);  // Dead code to make the compiler happy.
+  }
+}
+
+
+void FastCodeGenerator::Move(Register dst, Slot* source) {
+  // Use dst as scratch.
+  MemOperand location = CreateSlotOperand<MemOperand>(source, dst);
+  __ ldr(dst, location);
+}
+
+
+
+void FastCodeGenerator::Move(Expression::Context context,
+                             Slot* source,
+                             Register scratch) {
   switch (context) {
     case Expression::kUninitialized:
       UNREACHABLE();
@@ -248,8 +292,8 @@
     case Expression::kTest:  // Fall through.
     case Expression::kValueTest:  // Fall through.
     case Expression::kTestValue:
-      __ ldr(ip, MemOperand(fp, SlotOffset(source)));
-      Move(context, ip);
+      Move(scratch, source);
+      Move(context, scratch);
       break;
   }
 }
@@ -272,24 +316,60 @@
 }
 
 
+void FastCodeGenerator::Move(Slot* dst,
+                             Register src,
+                             Register scratch1,
+                             Register scratch2) {
+  switch (dst->type()) {
+    case Slot::PARAMETER:
+    case Slot::LOCAL:
+      __ str(src, MemOperand(fp, SlotOffset(dst)));
+      break;
+    case Slot::CONTEXT: {
+      int context_chain_length =
+          function_->scope()->ContextChainLength(dst->var()->scope());
+      __ LoadContext(scratch1, context_chain_length);
+      int index = Context::SlotOffset(dst->index());
+      __ mov(scratch2, Operand(index));
+      __ str(src, MemOperand(scratch1, index));
+      __ RecordWrite(scratch1, scratch2, src);
+      break;
+    }
+    case Slot::LOOKUP:
+      UNIMPLEMENTED();
+    default:
+      UNREACHABLE();
+  }
+}
+
+
+
 void FastCodeGenerator::DropAndMove(Expression::Context context,
-                                    Register source) {
+                                    Register source,
+                                    int drop_count) {
+  ASSERT(drop_count > 0);
   switch (context) {
     case Expression::kUninitialized:
       UNREACHABLE();
     case Expression::kEffect:
-      __ pop();
+      __ add(sp, sp, Operand(drop_count * kPointerSize));
       break;
     case Expression::kValue:
+      if (drop_count > 1) {
+        __ add(sp, sp, Operand((drop_count - 1) * kPointerSize));
+      }
       __ str(source, MemOperand(sp));
       break;
     case Expression::kTest:
       ASSERT(!source.is(sp));
-      __ pop();
+      __ add(sp, sp, Operand(drop_count * kPointerSize));
       TestAndBranch(source, true_label_, false_label_);
       break;
     case Expression::kValueTest: {
       Label discard;
+      if (drop_count > 1) {
+        __ add(sp, sp, Operand((drop_count - 1) * kPointerSize));
+      }
       __ str(source, MemOperand(sp));
       TestAndBranch(source, true_label_, &discard);
       __ bind(&discard);
@@ -299,6 +379,9 @@
     }
     case Expression::kTestValue: {
       Label discard;
+      if (drop_count > 1) {
+        __ add(sp, sp, Operand((drop_count - 1) * kPointerSize));
+      }
       __ str(source, MemOperand(sp));
       TestAndBranch(source, &discard, false_label_);
       __ bind(&discard);
@@ -376,26 +459,26 @@
         __ mov(r0, Operand(Factory::the_hole_value()));
         if (FLAG_debug_code) {
           // Check if we have the correct context pointer.
-          __ ldr(r1, CodeGenerator::ContextOperand(
-              cp, Context::FCONTEXT_INDEX));
+          __ ldr(r1, CodeGenerator::ContextOperand(cp,
+                                                   Context::FCONTEXT_INDEX));
           __ cmp(r1, cp);
           __ Check(eq, "Unexpected declaration in current context.");
         }
         __ str(r0, CodeGenerator::ContextOperand(cp, slot->index()));
         // No write barrier since the_hole_value is in old space.
-        ASSERT(Heap::InNewSpace(*Factory::the_hole_value()));
+        ASSERT(!Heap::InNewSpace(*Factory::the_hole_value()));
       } else if (decl->fun() != NULL) {
         Visit(decl->fun());
         __ pop(r0);
         if (FLAG_debug_code) {
           // Check if we have the correct context pointer.
-          __ ldr(r1, CodeGenerator::ContextOperand(
-              cp, Context::FCONTEXT_INDEX));
+          __ ldr(r1, CodeGenerator::ContextOperand(cp,
+                                                   Context::FCONTEXT_INDEX));
           __ cmp(r1, cp);
           __ Check(eq, "Unexpected declaration in current context.");
         }
         __ str(r0, CodeGenerator::ContextOperand(cp, slot->index()));
-        int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
+        int offset = Context::SlotOffset(slot->index());
         __ mov(r2, Operand(offset));
         // We know that we have written a function, which is not a smi.
         __ RecordWrite(cp, r2, r0);
@@ -467,53 +550,60 @@
     DropAndMove(expr->context(), r0);
   } else if (rewrite->AsSlot() != NULL) {
     Slot* slot = rewrite->AsSlot();
-    ASSERT_NE(NULL, slot);
-    switch (slot->type()) {
-      case Slot::LOCAL:
-      case Slot::PARAMETER: {
-        Comment cmnt(masm_, "Stack slot");
-        Move(expr->context(), rewrite->AsSlot());
-        break;
-      }
-
-      case Slot::CONTEXT: {
-        Comment cmnt(masm_, "Context slot");
-        int chain_length =
-            function_->scope()->ContextChainLength(slot->var()->scope());
-        if (chain_length > 0) {
-          // Move up the chain of contexts to the context containing the slot.
-          __ ldr(r0, CodeGenerator::ContextOperand(cp, Context::CLOSURE_INDEX));
-          // Load the function context (which is the incoming, outer context).
-          __ ldr(r0, FieldMemOperand(r0, JSFunction::kContextOffset));
-          for (int i = 1; i < chain_length; i++) {
-            __ ldr(r0,
-                   CodeGenerator::ContextOperand(r0, Context::CLOSURE_INDEX));
-            // Load the function context (which is the incoming, outer context).
-            __ ldr(r0, FieldMemOperand(r0, JSFunction::kContextOffset));
-          }
-          // The context may be an intermediate context, not a function context.
-          __ ldr(r0,
-                 CodeGenerator::ContextOperand(r0, Context::FCONTEXT_INDEX));
-        } else {  // Slot is in the current context.
-          __ ldr(r0,
-                 CodeGenerator::ContextOperand(cp, Context::FCONTEXT_INDEX));
+    if (FLAG_debug_code) {
+      switch (slot->type()) {
+        case Slot::LOCAL:
+        case Slot::PARAMETER: {
+          Comment cmnt(masm_, "Stack slot");
+          break;
         }
-        __ ldr(r0, CodeGenerator::ContextOperand(r0, slot->index()));
-        Move(expr->context(), r0);
-        break;
+        case Slot::CONTEXT: {
+          Comment cmnt(masm_, "Context slot");
+          break;
+        }
+        case Slot::LOOKUP:
+          UNIMPLEMENTED();
+          break;
+        default:
+          UNREACHABLE();
       }
-
-      case Slot::LOOKUP:
-        UNREACHABLE();
-        break;
     }
+    Move(expr->context(), slot, r0);
   } else {
-    // The parameter variable has been rewritten into an explict access to
-    // the arguments object.
+    // A variable has been rewritten into an explicit access to
+    // an object property.
     Property* property = rewrite->AsProperty();
     ASSERT_NOT_NULL(property);
-    ASSERT_EQ(expr->context(), property->context());
-    Visit(property);
+
+    // Currently the only parameter expressions that can occur are
+    // on the form "slot[literal]".
+
+    // Check that the object is in a slot.
+    Variable* object_var = property->obj()->AsVariableProxy()->AsVariable();
+    ASSERT_NOT_NULL(object_var);
+    Slot* object_slot = object_var->slot();
+    ASSERT_NOT_NULL(object_slot);
+
+    // Load the object.
+    Move(r2, object_slot);
+
+    // Check that the key is a smi.
+    Literal* key_literal = property->key()->AsLiteral();
+    ASSERT_NOT_NULL(key_literal);
+    ASSERT(key_literal->handle()->IsSmi());
+
+    // Load the key.
+    __ mov(r1, Operand(key_literal->handle()));
+
+    // Push both as arguments to ic.
+    __ stm(db_w, sp, r2.bit() | r1.bit());
+
+    // Do a KEYED property load.
+    Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+    __ Call(ic, RelocInfo::CODE_TARGET);
+
+    // Drop key and object left on the stack by IC, and push the result.
+    DropAndMove(expr->context(), r0, 2);
   }
 }
 
@@ -575,8 +665,9 @@
     __ CallRuntime(Runtime::kCloneShallowLiteralBoilerplate, 1);
   }
 
-  // If result_saved == true: the result is saved on top of the stack.
-  // If result_saved == false: the result is in r0.
+  // If result_saved == true: The result is saved on top of the
+  //  stack and in r0.
+  // If result_saved == false: The result not on the stack, just in r0.
   bool result_saved = false;
 
   for (int i = 0; i < expr->properties()->length(); i++) {
@@ -604,6 +695,7 @@
           Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
           __ Call(ic, RelocInfo::CODE_TARGET);
           // StoreIC leaves the receiver on the stack.
+          __ ldr(r0, MemOperand(sp));  // Restore result into r0.
           break;
         }
         // Fall through.
@@ -615,7 +707,7 @@
         Visit(value);
         ASSERT_EQ(Expression::kValue, value->context());
         __ CallRuntime(Runtime::kSetProperty, 3);
-        __ ldr(r0, MemOperand(sp));  // Restore result into r0
+        __ ldr(r0, MemOperand(sp));  // Restore result into r0.
         break;
 
       case ObjectLiteral::Property::GETTER:  // Fall through.
@@ -785,7 +877,7 @@
     // Overwrite the global object on the stack with the result if needed.
     DropAndMove(expr->context(), r0);
 
-  } else {
+  } else if (var->slot()) {
     Slot* slot = var->slot();
     ASSERT_NOT_NULL(slot);  // Variables rewritten as properties not handled.
     switch (slot->type()) {
@@ -884,6 +976,35 @@
         UNREACHABLE();
         break;
     }
+  } else {
+    Property* property = var->rewrite()->AsProperty();
+    ASSERT_NOT_NULL(property);
+
+    // Load object and key onto the stack.
+    Slot* object_slot = property->obj()->AsSlot();
+    ASSERT_NOT_NULL(object_slot);
+    Move(Expression::kValue, object_slot, r0);
+
+    Literal* key_literal = property->key()->AsLiteral();
+    ASSERT_NOT_NULL(key_literal);
+    Move(Expression::kValue, key_literal);
+
+    // Value to store was pushed before object and key on the stack.
+    __ ldr(r0, MemOperand(sp, 2 * kPointerSize));
+
+    // Arguments to ic is value in r0, object and key on stack.
+    Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
+    __ Call(ic, RelocInfo::CODE_TARGET);
+
+    if (expr->context() == Expression::kEffect) {
+      __ add(sp, sp, Operand(3 * kPointerSize));
+    } else if (expr->context() == Expression::kValue) {
+      // Value is still on the stack in esp[2 * kPointerSize]
+      __ add(sp, sp, Operand(2 * kPointerSize));
+    } else {
+      __ ldr(r0, MemOperand(sp, 2 * kPointerSize));
+      DropAndMove(expr->context(), r0, 3);
+    }
   }
 }
 
@@ -1134,9 +1255,14 @@
 void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
   Comment cmnt(masm_, "[ CallRuntime");
   ZoneList<Expression*>* args = expr->arguments();
-  Runtime::Function* function = expr->function();
 
-  ASSERT(function != NULL);
+  if (expr->is_jsruntime()) {
+    // Prepare for calling JS runtime function.
+    __ mov(r1, Operand(expr->name()));
+    __ ldr(r0, CodeGenerator::GlobalObject());
+    __ ldr(r0, FieldMemOperand(r0, GlobalObject::kBuiltinsOffset));
+    __ stm(db_w, sp, r1.bit() | r0.bit());
+  }
 
   // Push the arguments ("left-to-right").
   int arg_count = args->length();
@@ -1145,8 +1271,20 @@
     ASSERT_EQ(Expression::kValue, args->at(i)->context());
   }
 
-  __ CallRuntime(function, arg_count);
-  Move(expr->context(), r0);
+  if (expr->is_jsruntime()) {
+    // Call the JS runtime function.
+    Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count,
+                                                           NOT_IN_LOOP);
+    __ Call(ic, RelocInfo::CODE_TARGET);
+    // Restore context register.
+    __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+    // Discard the function left on TOS.
+    DropAndMove(expr->context(), r0);
+  } else {
+    // Call the C runtime function.
+    __ CallRuntime(expr->function(), arg_count);
+    Move(expr->context(), r0);
+  }
 }
 
 
diff --git a/src/arm/ic-arm.cc b/src/arm/ic-arm.cc
index ba83645..c56f414 100644
--- a/src/arm/ic-arm.cc
+++ b/src/arm/ic-arm.cc
@@ -107,12 +107,17 @@
   static const int kProbes = 4;
   for (int i = 0; i < kProbes; i++) {
     // Compute the masked index: (hash + i + i * i) & mask.
-    __ ldr(t1, FieldMemOperand(r2, String::kLengthOffset));
-    __ mov(t1, Operand(t1, LSR, String::kHashShift));
+    __ ldr(t1, FieldMemOperand(r2, String::kHashFieldOffset));
     if (i > 0) {
-      __ add(t1, t1, Operand(StringDictionary::GetProbeOffset(i)));
+      // Add the probe offset (i + i * i) left shifted to avoid right shifting
+      // the hash in a separate instruction. The value hash + i + i * i is right
+      // shifted in the following and instruction.
+      ASSERT(StringDictionary::GetProbeOffset(i) <
+             1 << (32 - String::kHashFieldOffset));
+      __ add(t1, t1, Operand(
+          StringDictionary::GetProbeOffset(i) << String::kHashShift));
     }
-    __ and_(t1, t1, Operand(r3));
+    __ and_(t1, r3, Operand(t1, LSR, String::kHashShift));
 
     // Scale the index by multiplying by the element size.
     ASSERT(StringDictionary::kEntrySize == 3);
diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc
index a668cb1..aa6570c 100644
--- a/src/arm/macro-assembler-arm.cc
+++ b/src/arm/macro-assembler-arm.cc
@@ -155,6 +155,15 @@
 }
 
 
+void MacroAssembler::StackLimitCheck(Label* on_stack_overflow) {
+  LoadRoot(ip, Heap::kStackLimitRootIndex);
+  cmp(sp, Operand(ip));
+  b(lo, on_stack_overflow);
+}
+
+
+
+
 void MacroAssembler::SmiJumpTable(Register index, Vector<Label*> targets) {
   // Empty the const pool.
   CheckConstPool(true, true);
@@ -785,15 +794,13 @@
   mov(scratch1, Operand(new_space_allocation_top));
   if ((flags & RESULT_CONTAINS_TOP) == 0) {
     ldr(result, MemOperand(scratch1));
-  } else {
-#ifdef DEBUG
+  } else if (FLAG_debug_code) {
     // Assert that result actually contains top on entry. scratch2 is used
     // immediately below so this use of scratch2 does not cause difference with
     // respect to register content between debug and release mode.
     ldr(scratch2, MemOperand(scratch1));
     cmp(result, scratch2);
     Check(eq, "Unexpected allocation top");
-#endif
   }
 
   // Calculate new top and bail out if new space is exhausted. Use result
@@ -806,7 +813,11 @@
   cmp(result, Operand(scratch2));
   b(hi, gc_required);
 
-  // Update allocation top. result temporarily holds the new top,
+  // Update allocation top. result temporarily holds the new top.
+  if (FLAG_debug_code) {
+    tst(result, Operand(kObjectAlignmentMask));
+    Check(eq, "Unaligned allocation in new space");
+  }
   str(result, MemOperand(scratch1));
 
   // Tag and adjust back to start of new object.
@@ -835,15 +846,13 @@
   mov(scratch1, Operand(new_space_allocation_top));
   if ((flags & RESULT_CONTAINS_TOP) == 0) {
     ldr(result, MemOperand(scratch1));
-  } else {
-#ifdef DEBUG
+  } else if (FLAG_debug_code) {
     // Assert that result actually contains top on entry. scratch2 is used
     // immediately below so this use of scratch2 does not cause difference with
     // respect to register content between debug and release mode.
     ldr(scratch2, MemOperand(scratch1));
     cmp(result, scratch2);
     Check(eq, "Unexpected allocation top");
-#endif
   }
 
   // Calculate new top and bail out if new space is exhausted. Use result
@@ -857,7 +866,11 @@
   cmp(result, Operand(scratch2));
   b(hi, gc_required);
 
-  // Update allocation top. result temporarily holds the new top,
+  // Update allocation top. result temporarily holds the new top.
+  if (FLAG_debug_code) {
+    tst(result, Operand(kObjectAlignmentMask));
+    Check(eq, "Unaligned allocation in new space");
+  }
   str(result, MemOperand(scratch1));
 
   // Adjust back to start of new object.
@@ -1153,6 +1166,9 @@
     RecordComment(msg);
   }
 #endif
+  // Disable stub call restrictions to always allow calls to abort.
+  set_allow_stub_calls(true);
+
   mov(r0, Operand(p0));
   push(r0);
   mov(r0, Operand(Smi::FromInt(p1 - p0)));
@@ -1162,6 +1178,26 @@
 }
 
 
+void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
+  if (context_chain_length > 0) {
+    // Move up the chain of contexts to the context containing the slot.
+    ldr(dst, MemOperand(cp, Context::SlotOffset(Context::CLOSURE_INDEX)));
+    // Load the function context (which is the incoming, outer context).
+    ldr(dst, FieldMemOperand(dst, JSFunction::kContextOffset));
+    for (int i = 1; i < context_chain_length; i++) {
+      ldr(dst, MemOperand(dst, Context::SlotOffset(Context::CLOSURE_INDEX)));
+      ldr(dst, FieldMemOperand(dst, JSFunction::kContextOffset));
+    }
+    // The context may be an intermediate context, not a function context.
+    ldr(dst, MemOperand(dst, Context::SlotOffset(Context::FCONTEXT_INDEX)));
+  } else {  // Slot is in the current function context.
+    // The context may be an intermediate context, not a function context.
+    ldr(dst, MemOperand(cp, Context::SlotOffset(Context::FCONTEXT_INDEX)));
+  }
+}
+
+
+
 #ifdef ENABLE_DEBUGGER_SUPPORT
 CodePatcher::CodePatcher(byte* address, int instructions)
     : address_(address),
diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h
index 8c247bf..0974329 100644
--- a/src/arm/macro-assembler-arm.h
+++ b/src/arm/macro-assembler-arm.h
@@ -79,6 +79,11 @@
   void RecordWrite(Register object, Register offset, Register scratch);
 
   // ---------------------------------------------------------------------------
+  // Stack limit support
+
+  void StackLimitCheck(Label* on_stack_limit_hit);
+
+  // ---------------------------------------------------------------------------
   // Activation frames
 
   void EnterInternalFrame() { EnterFrame(StackFrame::INTERNAL); }
@@ -99,6 +104,8 @@
   // Align the stack by optionally pushing a Smi zero.
   void AlignStack(int offset);
 
+  void LoadContext(Register dst, int context_chain_length);
+
   // ---------------------------------------------------------------------------
   // JavaScript invokes
 
diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc
index 8282655..efccaf4 100644
--- a/src/arm/stub-cache-arm.cc
+++ b/src/arm/stub-cache-arm.cc
@@ -105,7 +105,7 @@
   __ b(eq, &miss);
 
   // Get the map of the receiver and compute the hash.
-  __ ldr(scratch, FieldMemOperand(name, String::kLengthOffset));
+  __ ldr(scratch, FieldMemOperand(name, String::kHashFieldOffset));
   __ ldr(ip, FieldMemOperand(receiver, HeapObject::kMapOffset));
   __ add(scratch, scratch, Operand(ip));
   __ eor(scratch, scratch, Operand(flags));
@@ -229,10 +229,7 @@
                       miss, &check_wrapper);
 
   // Load length directly from the string.
-  __ and_(scratch1, scratch1, Operand(kStringSizeMask));
-  __ add(scratch1, scratch1, Operand(String::kHashShift));
   __ ldr(r0, FieldMemOperand(receiver, String::kLengthOffset));
-  __ mov(r0, Operand(r0, LSR, scratch1));
   __ mov(r0, Operand(r0, LSL, kSmiTagSize));
   __ Ret();
 
diff --git a/src/array.js b/src/array.js
index 94d74a5..20d884e 100644
--- a/src/array.js
+++ b/src/array.js
@@ -77,7 +77,8 @@
     var key = keys[i];
     if (key != last_key) {
       var e = array[key];
-      builder.add(convert(e));
+      if (typeof(e) !== 'string') e = convert(e);
+      builder.add(e);
       last_key = key;
     }
   }
@@ -114,17 +115,36 @@
     if (length == 1) {
       var e = array[0];
       if (!IS_UNDEFINED(e) || (0 in array)) {
+        if (typeof(e) === 'string') return e;
         return convert(e);
       }
     }
 
     var builder = new StringBuilder();
 
-    for (var i = 0; i < length; i++) {
-      var e = array[i];
-      if (i != 0) builder.add(separator);
-      if (!IS_UNDEFINED(e) || (i in array)) {
-        builder.add(convert(e));
+    // We pull the empty separator check outside the loop for speed!
+    if (separator.length == 0) {
+      for (var i = 0; i < length; i++) {
+        var e = array[i];
+        if (!IS_UNDEFINED(e) || (i in array)) {
+          if (typeof(e) !== 'string') e = convert(e);
+          if (e.length > 0) {
+            var elements = builder.elements;
+            elements[elements.length] = e;
+          }
+        }
+      }
+    } else {
+      for (var i = 0; i < length; i++) {
+        var e = array[i];
+        if (i != 0) builder.add(separator);
+        if (!IS_UNDEFINED(e) || (i in array)) {
+          if (typeof(e) !== 'string') e = convert(e);
+          if (e.length > 0) {
+            var elements = builder.elements;
+            elements[elements.length] = e;
+          }
+        }
       }
     }
     return builder.generate();
@@ -136,12 +156,14 @@
 
 
 function ConvertToString(e) {
+  if (typeof(e) === 'string') return e;
   if (e == null) return '';
   else return ToString(e);
 }
 
 
 function ConvertToLocaleString(e) {
+  if (typeof(e) === 'string') return e;
   if (e == null) return '';
   else {
     // e_obj's toLocaleString might be overwritten, check if it is a function.
@@ -149,7 +171,7 @@
     // See issue 877615.
     var e_obj = ToObject(e);
     if (IS_FUNCTION(e_obj.toLocaleString))
-      return e_obj.toLocaleString();
+      return ToString(e_obj.toLocaleString());
     else
       return ToString(e);
   }
diff --git a/src/ast.h b/src/ast.h
index 560470f..c27d558 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -1080,6 +1080,7 @@
   Handle<String> name() const { return name_; }
   Runtime::Function* function() const { return function_; }
   ZoneList<Expression*>* arguments() const { return arguments_; }
+  bool is_jsruntime() const { return function_ == NULL; }
 
  private:
   Handle<String> name_;
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index 6918464..deda96f 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -1346,8 +1346,6 @@
   ASSERT(Top::has_pending_exception() != result);
   if (!result) {
     Top::clear_pending_exception();
-    v8::Utils::ReportApiFailure(
-        "v8::Context::New()", "Error installing extension");
   }
   current->set_state(v8::INSTALLED);
   return result;
diff --git a/src/code-stubs.h b/src/code-stubs.h
index 6c50c6d..25a2d0f 100644
--- a/src/code-stubs.h
+++ b/src/code-stubs.h
@@ -36,6 +36,7 @@
 #define CODE_STUB_LIST_ALL_PLATFORMS(V)  \
   V(CallFunction)                        \
   V(GenericBinaryOp)                     \
+  V(StringAdd)                           \
   V(SmiOp)                               \
   V(Compare)                             \
   V(RecordWrite)                         \
diff --git a/src/codegen.cc b/src/codegen.cc
index a6d5fb4..26e8d7d 100644
--- a/src/codegen.cc
+++ b/src/codegen.cc
@@ -346,6 +346,7 @@
   {&CodeGenerator::GenerateMathCos, "_Math_cos"},
   {&CodeGenerator::GenerateIsObject, "_IsObject"},
   {&CodeGenerator::GenerateIsFunction, "_IsFunction"},
+  {&CodeGenerator::GenerateStringAdd, "_StringAdd"},
 };
 
 
diff --git a/src/compiler.cc b/src/compiler.cc
index d3c031c..22b0a03 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -124,9 +124,12 @@
     // If there is no shared function info, try the fast code
     // generator for code in the global scope.  Otherwise obey the
     // explicit hint in the shared function info.
-    if (shared.is_null() && !literal->scope()->is_global_scope()) {
+    // If always_fast_compiler is true, always try the fast compiler.
+    if (shared.is_null() && !literal->scope()->is_global_scope() &&
+        !FLAG_always_fast_compiler) {
       if (FLAG_trace_bailout) PrintF("Non-global scope\n");
-    } else if (!shared.is_null() && !shared->try_fast_codegen()) {
+    } else if (!shared.is_null() && !shared->try_fast_codegen() &&
+               !FLAG_always_fast_compiler) {
       if (FLAG_trace_bailout) PrintF("No hint to try fast\n");
     } else {
       CodeGenSelector selector;
@@ -600,11 +603,6 @@
     }
   }
 
-  if (scope->arguments() != NULL) {
-    if (FLAG_trace_bailout) PrintF("function uses 'arguments'\n");
-    return NORMAL;
-  }
-
   has_supported_syntax_ = true;
   VisitDeclarations(scope->declarations());
   if (!has_supported_syntax_) return NORMAL;
@@ -803,7 +801,17 @@
         BAILOUT("Lookup slot");
       }
     } else {
-      BAILOUT("access to arguments object");
+#ifdef DEBUG
+      // Only remaining possibility is a property where the object is
+      // a slotted variable and the key is a smi.
+      Property* property = rewrite->AsProperty();
+      ASSERT_NOT_NULL(property);
+      Variable* object = property->obj()->AsVariableProxy()->AsVariable();
+      ASSERT_NOT_NULL(object);
+      ASSERT_NOT_NULL(object->slot());
+      ASSERT_NOT_NULL(property->key()->AsLiteral());
+      ASSERT(property->key()->AsLiteral()->handle()->IsSmi());
+#endif
     }
   }
 }
@@ -887,12 +895,21 @@
     // All global variables are supported.
     if (!var->is_global()) {
       if (var->slot() == NULL) {
-        // This is a parameter that has rewritten to an arguments access.
-        BAILOUT("non-global/non-slot assignment");
-      }
-      Slot::Type type = var->slot()->type();
-      if (type == Slot::LOOKUP) {
-        BAILOUT("Lookup slot");
+        Property* property = var->AsProperty();
+        if (property == NULL) {
+          BAILOUT("non-global/non-slot/non-property assignment");
+        }
+        if (property->obj()->AsSlot() == NULL) {
+          BAILOUT("variable rewritten to property non slot object assignment");
+        }
+        if (property->key()->AsLiteral() == NULL) {
+          BAILOUT("variable rewritten to property non literal key assignment");
+        }
+      } else {
+        Slot::Type type = var->slot()->type();
+        if (type == Slot::LOOKUP) {
+          BAILOUT("Lookup slot");
+        }
       }
     }
   } else if (prop != NULL) {
@@ -980,8 +997,6 @@
 
 
 void CodeGenSelector::VisitCallRuntime(CallRuntime* expr) {
-  // In case of JS runtime function bail out.
-  if (expr->function() == NULL) BAILOUT("call JS runtime function");
   // Check for inline runtime call
   if (expr->name()->Get(0) == '_' &&
       CodeGenerator::FindInlineRuntimeLUT(expr->name()) != NULL) {
diff --git a/src/d8.cc b/src/d8.cc
index e4658b1..dedbd55 100644
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -159,7 +159,11 @@
       printf(" ");
     }
     v8::String::Utf8Value str(args[i]);
-    fwrite(*str, sizeof(**str), str.length(), stdout);
+    int n = fwrite(*str, sizeof(**str), str.length(), stdout);
+    if (n != str.length()) {
+      printf("Error in fwrite\n");
+      exit(1);
+    }
   }
   return Undefined();
 }
@@ -203,7 +207,7 @@
       return ThrowException(String::New("Error loading file"));
     }
     if (!ExecuteString(source, String::New(*file), false, false)) {
-      return ThrowException(String::New("Error executing  file"));
+      return ThrowException(String::New("Error executing file"));
     }
   }
   return Undefined();
diff --git a/src/debug-delay.js b/src/debug-delay.js
index 35f7fcd..04fde1f 100644
--- a/src/debug-delay.js
+++ b/src/debug-delay.js
@@ -1245,6 +1245,8 @@
         this.suspendRequest_(request, response);
       } else if (request.command == 'version') {
         this.versionRequest_(request, response);
+      } else if (request.command == 'profile') {
+        this.profileRequest_(request, response);
       } else {
         throw new Error('Unknown command "' + request.command + '" in request');
       }
@@ -1924,6 +1926,25 @@
 };
 
 
+DebugCommandProcessor.prototype.profileRequest_ = function(request, response) {
+  if (!request.arguments) {
+    return response.failed('Missing arguments');
+  }
+  var modules = parseInt(request.arguments.modules);
+  if (isNaN(modules)) {
+    return response.failed('Modules is not an integer');
+  }
+  if (request.arguments.command == 'resume') {
+    %ProfilerResume(modules);
+  } else if (request.arguments.command == 'pause') {
+    %ProfilerPause(modules);
+  } else {
+    return response.failed('Unknown command');
+  }
+  response.body = {};
+};
+
+
 // Check whether the previously processed command caused the VM to become
 // running.
 DebugCommandProcessor.prototype.isRunning = function() {
diff --git a/src/debug.h b/src/debug.h
index c5c6b5e..24f0db4 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -370,17 +370,6 @@
   // Garbage collection notifications.
   static void AfterGarbageCollection();
 
-  // Code generation assumptions.
-  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 kX64CallInstructionLength = 13;
-  static const int kX64JSReturnSequenceLength = 13;
-
-  static const int kARMJSReturnSequenceLength = 4;
-
   // Code generator routines.
   static void GenerateLoadICDebugBreak(MacroAssembler* masm);
   static void GenerateStoreICDebugBreak(MacroAssembler* masm);
diff --git a/src/dtoa-config.c b/src/dtoa-config.c
index bc0a58a..a1acd2d 100644
--- a/src/dtoa-config.c
+++ b/src/dtoa-config.c
@@ -38,7 +38,7 @@
  */
 
 #if !(defined(__APPLE__) && defined(__MACH__)) && \
-    !defined(WIN32) && !defined(__FreeBSD__)
+    !defined(WIN32) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
 #include <endian.h>
 #endif
 #include <math.h>
@@ -47,14 +47,16 @@
 /* The floating point word order on ARM is big endian when floating point
  * emulation is used, even if the byte order is little endian */
 #if !(defined(__APPLE__) && defined(__MACH__)) && !defined(WIN32) && \
-    !defined(__FreeBSD__) && __FLOAT_WORD_ORDER == __BIG_ENDIAN
+    !defined(__FreeBSD__) && !defined(__OpenBSD__) && \
+    __FLOAT_WORD_ORDER == __BIG_ENDIAN
 #define  IEEE_MC68k
 #else
 #define  IEEE_8087
 #endif
 
 #define __MATH_H__
-#if defined(__APPLE__) && defined(__MACH__) || defined(__FreeBSD__)
+#if defined(__APPLE__) && defined(__MACH__) || defined(__FreeBSD__) || \
+    defined(__OpenBSD__)
 /* stdlib.h on FreeBSD and Apple's 10.5 and later SDKs will mangle the
  * name of strtod.  If it's included after strtod is redefined as
  * gay_strtod, it will mangle the name of gay_strtod, which is
diff --git a/src/fast-codegen.cc b/src/fast-codegen.cc
index 53fcf31..20de808 100644
--- a/src/fast-codegen.cc
+++ b/src/fast-codegen.cc
@@ -305,12 +305,15 @@
 void FastCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
   Comment cmnt(masm_, "[ DoWhileStatement");
   increment_loop_depth();
-  Label body, exit;
+  Label body, exit, stack_limit_hit, stack_check_success;
 
-  // Emit the test at the bottom of the loop.
   __ bind(&body);
   Visit(stmt->body());
 
+  // Check stack before looping.
+  __ StackLimitCheck(&stack_limit_hit);
+  __ bind(&stack_check_success);
+
   // We are not in an expression context because we have been compiling
   // statements.  Set up a test expression context for the condition.
   ASSERT_EQ(NULL, true_label_);
@@ -322,6 +325,11 @@
   true_label_ = NULL;
   false_label_ = NULL;
 
+  __ bind(&stack_limit_hit);
+  StackCheckStub stack_stub;
+  __ CallStub(&stack_stub);
+  __ jmp(&stack_check_success);
+
   __ bind(&exit);
 
   decrement_loop_depth();
@@ -331,7 +339,7 @@
 void FastCodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
   Comment cmnt(masm_, "[ WhileStatement");
   increment_loop_depth();
-  Label test, body, exit;
+  Label test, body, exit, stack_limit_hit, stack_check_success;
 
   // Emit the test at the bottom of the loop.
   __ jmp(&test);
@@ -340,6 +348,10 @@
   Visit(stmt->body());
 
   __ bind(&test);
+  // Check stack before looping.
+  __ StackLimitCheck(&stack_limit_hit);
+  __ bind(&stack_check_success);
+
   // We are not in an expression context because we have been compiling
   // statements.  Set up a test expression context for the condition.
   ASSERT_EQ(NULL, true_label_);
@@ -351,6 +363,11 @@
   true_label_ = NULL;
   false_label_ = NULL;
 
+  __ bind(&stack_limit_hit);
+  StackCheckStub stack_stub;
+  __ CallStub(&stack_stub);
+  __ jmp(&stack_check_success);
+
   __ bind(&exit);
 
   decrement_loop_depth();
@@ -359,7 +376,7 @@
 
 void FastCodeGenerator::VisitForStatement(ForStatement* stmt) {
   Comment cmnt(masm_, "[ ForStatement");
-  Label test, body, exit;
+  Label test, body, exit, stack_limit_hit, stack_check_success;
   if (stmt->init() != NULL) Visit(stmt->init());
 
   increment_loop_depth();
@@ -367,9 +384,15 @@
   __ jmp(&test);
   __ bind(&body);
   Visit(stmt->body());
+
+  // Check stack before looping.
+  __ StackLimitCheck(&stack_limit_hit);
+  __ bind(&stack_check_success);
+
   if (stmt->next() != NULL) Visit(stmt->next());
 
   __ bind(&test);
+
   if (stmt->cond() == NULL) {
     // For an empty test jump to the top of the loop.
     __ jmp(&body);
@@ -378,6 +401,7 @@
     // statements.  Set up a test expression context for the condition.
     ASSERT_EQ(NULL, true_label_);
     ASSERT_EQ(NULL, false_label_);
+
     true_label_ = &body;
     false_label_ = &exit;
     ASSERT(stmt->cond()->context() == Expression::kTest);
@@ -386,6 +410,11 @@
     false_label_ = NULL;
   }
 
+  __ bind(&stack_limit_hit);
+  StackCheckStub stack_stub;
+  __ CallStub(&stack_stub);
+  __ jmp(&stack_check_success);
+
   __ bind(&exit);
   decrement_loop_depth();
 }
diff --git a/src/fast-codegen.h b/src/fast-codegen.h
index ee2e1d3..9b262a7 100644
--- a/src/fast-codegen.h
+++ b/src/fast-codegen.h
@@ -56,14 +56,21 @@
 
  private:
   int SlotOffset(Slot* slot);
-
   void Move(Expression::Context destination, Register source);
-  void Move(Expression::Context destination, Slot* source);
+  void Move(Expression::Context destination, Slot* source, Register scratch);
   void Move(Expression::Context destination, Literal* source);
+  void Move(Slot* dst, Register source, Register scratch1, Register scratch2);
+  void Move(Register dst, Slot* source);
+
+  // Templated to allow for Operand on intel and MemOperand on ARM.
+  template <typename MemoryLocation>
+  MemoryLocation CreateSlotOperand(Slot* slot, Register scratch);
 
   // Drop the TOS, and store source to destination.
   // If destination is TOS, just overwrite TOS with source.
-  void DropAndMove(Expression::Context destination, Register source);
+  void DropAndMove(Expression::Context destination,
+                   Register source,
+                   int drop_count = 1);
 
   // Test the JavaScript value in source as if in a test context, compile
   // control flow to a pair of labels.
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index 8c9bb22..88fda12 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -143,10 +143,12 @@
 DEFINE_bool(strict, false, "strict error checking")
 DEFINE_int(min_preparse_length, 1024,
            "minimum length for automatic enable preparsing")
-DEFINE_bool(fast_compiler, false,
+DEFINE_bool(fast_compiler, true,
             "use the fast-mode compiler for some top-level code")
 DEFINE_bool(trace_bailout, false,
             "print reasons for failing to use fast compilation")
+DEFINE_bool(always_fast_compiler, false,
+            "always try using the fast compiler")
 
 // compilation-cache.cc
 DEFINE_bool(compilation_cache, true, "enable compilation cache")
@@ -154,9 +156,9 @@
 // debug.cc
 DEFINE_bool(remote_debugging, false, "enable remote debugging")
 DEFINE_bool(trace_debug_json, false, "trace debugging JSON request/response")
-DEFINE_bool(debugger_auto_break, false,
+DEFINE_bool(debugger_auto_break, true,
             "automatically set the debug break flag when debugger commands are "
-            "in the queue (experimental)")
+            "in the queue")
 
 // frames.cc
 DEFINE_int(max_stack_trace_source_length, 300,
diff --git a/src/global-handles.cc b/src/global-handles.cc
index 5b01f61..f3b2b0c 100644
--- a/src/global-handles.cc
+++ b/src/global-handles.cc
@@ -430,21 +430,21 @@
 GlobalHandles::Node* GlobalHandles::first_deallocated_ = NULL;
 
 void GlobalHandles::RecordStats(HeapStats* stats) {
-  stats->global_handle_count = 0;
-  stats->weak_global_handle_count = 0;
-  stats->pending_global_handle_count = 0;
-  stats->near_death_global_handle_count = 0;
-  stats->destroyed_global_handle_count = 0;
+  *stats->global_handle_count = 0;
+  *stats->weak_global_handle_count = 0;
+  *stats->pending_global_handle_count = 0;
+  *stats->near_death_global_handle_count = 0;
+  *stats->destroyed_global_handle_count = 0;
   for (Node* current = head_; current != NULL; current = current->next()) {
-    stats->global_handle_count++;
+    *stats->global_handle_count++;
     if (current->state_ == Node::WEAK) {
-      stats->weak_global_handle_count++;
+      *stats->weak_global_handle_count++;
     } else if (current->state_ == Node::PENDING) {
-      stats->pending_global_handle_count++;
+      *stats->pending_global_handle_count++;
     } else if (current->state_ == Node::NEAR_DEATH) {
-      stats->near_death_global_handle_count++;
+      *stats->near_death_global_handle_count++;
     } else if (current->state_ == Node::DESTROYED) {
-      stats->destroyed_global_handle_count++;
+      *stats->destroyed_global_handle_count++;
     }
   }
 }
diff --git a/src/handles.cc b/src/handles.cc
index 53fa01b..d551e21 100644
--- a/src/handles.cc
+++ b/src/handles.cc
@@ -548,6 +548,12 @@
 Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object,
                                           KeyCollectionType type) {
   Handle<FixedArray> content = Factory::empty_fixed_array();
+  Handle<JSObject> arguments_boilerplate =
+      Handle<JSObject>(
+          Top::context()->global_context()->arguments_boilerplate());
+  Handle<JSFunction> arguments_function =
+      Handle<JSFunction>(
+          JSFunction::cast(arguments_boilerplate->map()->constructor()));
 
   // Only collect keys if access is permitted.
   for (Handle<Object> p = object;
@@ -577,8 +583,21 @@
         content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result));
     }
 
-    // Compute the property keys.
-    content = UnionOfKeys(content, GetEnumPropertyKeys(current));
+    // We can cache the computed property keys if access checks are
+    // not needed and no interceptors are involved.
+    //
+    // We do not use the cache if the object has elements and
+    // therefore it does not make sense to cache the property names
+    // for arguments objects.  Arguments objects will always have
+    // elements.
+    bool cache_enum_keys =
+        ((current->map()->constructor() != *arguments_function) &&
+         !current->IsAccessCheckNeeded() &&
+         !current->HasNamedInterceptor() &&
+         !current->HasIndexedInterceptor());
+    // Compute the property keys and cache them if possible.
+    content =
+        UnionOfKeys(content, GetEnumPropertyKeys(current, cache_enum_keys));
 
     // Add the property keys from the interceptor.
     if (current->HasNamedInterceptor()) {
@@ -605,7 +624,8 @@
 }
 
 
-Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object) {
+Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
+                                       bool cache_result) {
   int index = 0;
   if (object->HasFastProperties()) {
     if (object->map()->instance_descriptors()->HasEnumCache()) {
@@ -628,10 +648,12 @@
       }
     }
     (*storage)->SortPairs(*sort_array, sort_array->length());
-    Handle<FixedArray> bridge_storage =
-        Factory::NewFixedArray(DescriptorArray::kEnumCacheBridgeLength);
-    DescriptorArray* desc = object->map()->instance_descriptors();
-    desc->SetEnumCache(*bridge_storage, *storage);
+    if (cache_result) {
+      Handle<FixedArray> bridge_storage =
+          Factory::NewFixedArray(DescriptorArray::kEnumCacheBridgeLength);
+      DescriptorArray* desc = object->map()->instance_descriptors();
+      desc->SetEnumCache(*bridge_storage, *storage);
+    }
     ASSERT(storage->length() == index);
     return storage;
   } else {
diff --git a/src/handles.h b/src/handles.h
index f610a34..fe820d5 100644
--- a/src/handles.h
+++ b/src/handles.h
@@ -277,7 +277,8 @@
 Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object,
                                           KeyCollectionType type);
 Handle<JSArray> GetKeysFor(Handle<JSObject> object);
-Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object);
+Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
+                                       bool cache_result);
 
 // Computes the union of keys and return the result.
 // Used for implementing "for (n in object) { }"
diff --git a/src/heap-inl.h b/src/heap-inl.h
index 0646878..eccd5ee 100644
--- a/src/heap-inl.h
+++ b/src/heap-inl.h
@@ -41,10 +41,10 @@
 
 Object* Heap::AllocateSymbol(Vector<const char> str,
                              int chars,
-                             uint32_t length_field) {
+                             uint32_t hash_field) {
   unibrow::Utf8InputBuffer<> buffer(str.start(),
                                     static_cast<unsigned>(str.length()));
-  return AllocateInternalSymbol(&buffer, chars, length_field);
+  return AllocateInternalSymbol(&buffer, chars, hash_field);
 }
 
 
diff --git a/src/heap.cc b/src/heap.cc
index 5acfb02..4e4cd1c 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -1187,34 +1187,14 @@
     roots_[entry.index] = Map::cast(obj);
   }
 
-  obj = AllocateMap(SHORT_STRING_TYPE, SeqTwoByteString::kAlignedSize);
+  obj = AllocateMap(STRING_TYPE, SeqTwoByteString::kAlignedSize);
   if (obj->IsFailure()) return false;
-  set_undetectable_short_string_map(Map::cast(obj));
+  set_undetectable_string_map(Map::cast(obj));
   Map::cast(obj)->set_is_undetectable();
 
-  obj = AllocateMap(MEDIUM_STRING_TYPE, SeqTwoByteString::kAlignedSize);
+  obj = AllocateMap(ASCII_STRING_TYPE, SeqAsciiString::kAlignedSize);
   if (obj->IsFailure()) return false;
-  set_undetectable_medium_string_map(Map::cast(obj));
-  Map::cast(obj)->set_is_undetectable();
-
-  obj = AllocateMap(LONG_STRING_TYPE, SeqTwoByteString::kAlignedSize);
-  if (obj->IsFailure()) return false;
-  set_undetectable_long_string_map(Map::cast(obj));
-  Map::cast(obj)->set_is_undetectable();
-
-  obj = AllocateMap(SHORT_ASCII_STRING_TYPE, SeqAsciiString::kAlignedSize);
-  if (obj->IsFailure()) return false;
-  set_undetectable_short_ascii_string_map(Map::cast(obj));
-  Map::cast(obj)->set_is_undetectable();
-
-  obj = AllocateMap(MEDIUM_ASCII_STRING_TYPE, SeqAsciiString::kAlignedSize);
-  if (obj->IsFailure()) return false;
-  set_undetectable_medium_ascii_string_map(Map::cast(obj));
-  Map::cast(obj)->set_is_undetectable();
-
-  obj = AllocateMap(LONG_ASCII_STRING_TYPE, SeqAsciiString::kAlignedSize);
-  if (obj->IsFailure()) return false;
-  set_undetectable_long_ascii_string_map(Map::cast(obj));
+  set_undetectable_ascii_string_map(Map::cast(obj));
   Map::cast(obj)->set_is_undetectable();
 
   obj = AllocateMap(BYTE_ARRAY_TYPE, ByteArray::kAlignedSize);
@@ -1839,10 +1819,19 @@
       // Copy the characters into the new object.
       char* dest = SeqAsciiString::cast(result)->GetChars();
       // Copy first part.
-      char* src = SeqAsciiString::cast(first)->GetChars();
+      const char* src;
+      if (first->IsExternalString()) {
+        src = ExternalAsciiString::cast(first)->resource()->data();
+      } else {
+        src = SeqAsciiString::cast(first)->GetChars();
+      }
       for (int i = 0; i < first_length; i++) *dest++ = src[i];
       // Copy second part.
-      src = SeqAsciiString::cast(second)->GetChars();
+      if (second->IsExternalString()) {
+        src = ExternalAsciiString::cast(second)->resource()->data();
+      } else {
+        src = SeqAsciiString::cast(second)->GetChars();
+      }
       for (int i = 0; i < second_length; i++) *dest++ = src[i];
       return result;
     } else {
@@ -1856,26 +1845,17 @@
     }
   }
 
-  Map* map;
-  if (length <= String::kMaxShortSize) {
-    map = is_ascii ? short_cons_ascii_string_map()
-      : short_cons_string_map();
-  } else if (length <= String::kMaxMediumSize) {
-    map = is_ascii ? medium_cons_ascii_string_map()
-      : medium_cons_string_map();
-  } else {
-    map = is_ascii ? long_cons_ascii_string_map()
-      : long_cons_string_map();
-  }
+  Map* map = is_ascii ? cons_ascii_string_map() : cons_string_map();
 
   Object* result = Allocate(map,
                             always_allocate() ? OLD_POINTER_SPACE : NEW_SPACE);
   if (result->IsFailure()) return result;
   ConsString* cons_string = ConsString::cast(result);
   WriteBarrierMode mode = cons_string->GetWriteBarrierMode();
+  cons_string->set_length(length);
+  cons_string->set_hash_field(String::kEmptyHashField);
   cons_string->set_first(first, mode);
   cons_string->set_second(second, mode);
-  cons_string->set_length(length);
   return result;
 }
 
@@ -1925,25 +1905,20 @@
 
 Object* Heap::AllocateExternalStringFromAscii(
     ExternalAsciiString::Resource* resource) {
-  Map* map;
   size_t length = resource->length();
-  if (length <= static_cast<size_t>(String::kMaxShortSize)) {
-    map = short_external_ascii_string_map();
-  } else if (length <= static_cast<size_t>(String::kMaxMediumSize)) {
-    map = medium_external_ascii_string_map();
-  } else if (length <= static_cast<size_t>(String::kMaxLength)) {
-    map = long_external_ascii_string_map();
-  } else {
+  if (length > static_cast<size_t>(String::kMaxLength)) {
     Top::context()->mark_out_of_memory();
     return Failure::OutOfMemoryException();
   }
 
+  Map* map = external_ascii_string_map();
   Object* result = Allocate(map,
                             always_allocate() ? OLD_DATA_SPACE : NEW_SPACE);
   if (result->IsFailure()) return result;
 
   ExternalAsciiString* external_string = ExternalAsciiString::cast(result);
   external_string->set_length(static_cast<int>(length));
+  external_string->set_hash_field(String::kEmptyHashField);
   external_string->set_resource(resource);
 
   return result;
@@ -1957,13 +1932,15 @@
     Top::context()->mark_out_of_memory();
     return Failure::OutOfMemoryException();
   }
-  Map* map = ExternalTwoByteString::StringMap(static_cast<int>(length));
+
+  Map* map = Heap::external_string_map();
   Object* result = Allocate(map,
                             always_allocate() ? OLD_DATA_SPACE : NEW_SPACE);
   if (result->IsFailure()) return result;
 
   ExternalTwoByteString* external_string = ExternalTwoByteString::cast(result);
   external_string->set_length(static_cast<int>(length));
+  external_string->set_hash_field(String::kEmptyHashField);
   external_string->set_resource(resource);
 
   return result;
@@ -2604,48 +2581,12 @@
 
   // Find the corresponding symbol map for strings.
   Map* map = string->map();
-
-  if (map == short_ascii_string_map()) return short_ascii_symbol_map();
-  if (map == medium_ascii_string_map()) return medium_ascii_symbol_map();
-  if (map == long_ascii_string_map()) return long_ascii_symbol_map();
-
-  if (map == short_string_map()) return short_symbol_map();
-  if (map == medium_string_map()) return medium_symbol_map();
-  if (map == long_string_map()) return long_symbol_map();
-
-  if (map == short_cons_string_map()) return short_cons_symbol_map();
-  if (map == medium_cons_string_map()) return medium_cons_symbol_map();
-  if (map == long_cons_string_map()) return long_cons_symbol_map();
-
-  if (map == short_cons_ascii_string_map()) {
-    return short_cons_ascii_symbol_map();
-  }
-  if (map == medium_cons_ascii_string_map()) {
-    return medium_cons_ascii_symbol_map();
-  }
-  if (map == long_cons_ascii_string_map()) {
-    return long_cons_ascii_symbol_map();
-  }
-
-  if (map == short_external_string_map()) {
-    return short_external_symbol_map();
-  }
-  if (map == medium_external_string_map()) {
-    return medium_external_symbol_map();
-  }
-  if (map == long_external_string_map()) {
-    return long_external_symbol_map();
-  }
-
-  if (map == short_external_ascii_string_map()) {
-    return short_external_ascii_symbol_map();
-  }
-  if (map == medium_external_ascii_string_map()) {
-    return medium_external_ascii_symbol_map();
-  }
-  if (map == long_external_ascii_string_map()) {
-    return long_external_ascii_symbol_map();
-  }
+  if (map == ascii_string_map()) return ascii_symbol_map();
+  if (map == string_map()) return symbol_map();
+  if (map == cons_string_map()) return cons_symbol_map();
+  if (map == cons_ascii_string_map()) return cons_ascii_symbol_map();
+  if (map == external_string_map()) return external_symbol_map();
+  if (map == external_ascii_string_map()) return external_ascii_symbol_map();
 
   // No match found.
   return NULL;
@@ -2654,7 +2595,7 @@
 
 Object* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer,
                                      int chars,
-                                     uint32_t length_field) {
+                                     uint32_t hash_field) {
   // Ensure the chars matches the number of characters in the buffer.
   ASSERT(static_cast<unsigned>(chars) == buffer->Length());
   // Determine whether the string is ascii.
@@ -2669,22 +2610,10 @@
   Map* map;
 
   if (is_ascii) {
-    if (chars <= String::kMaxShortSize) {
-      map = short_ascii_symbol_map();
-    } else if (chars <= String::kMaxMediumSize) {
-      map = medium_ascii_symbol_map();
-    } else {
-      map = long_ascii_symbol_map();
-    }
+    map = ascii_symbol_map();
     size = SeqAsciiString::SizeFor(chars);
   } else {
-    if (chars <= String::kMaxShortSize) {
-      map = short_symbol_map();
-    } else if (chars <= String::kMaxMediumSize) {
-      map = medium_symbol_map();
-    } else {
-      map = long_symbol_map();
-    }
+    map = symbol_map();
     size = SeqTwoByteString::SizeFor(chars);
   }
 
@@ -2695,9 +2624,10 @@
   if (result->IsFailure()) return result;
 
   reinterpret_cast<HeapObject*>(result)->set_map(map);
-  // The hash value contains the length of the string.
+  // Set length and hash fields of the allocated string.
   String* answer = String::cast(result);
-  answer->set_length_field(length_field);
+  answer->set_length(chars);
+  answer->set_hash_field(hash_field);
 
   ASSERT_EQ(size, answer->Size());
 
@@ -2728,19 +2658,10 @@
   }
   if (result->IsFailure()) return result;
 
-  // Determine the map based on the string's length.
-  Map* map;
-  if (length <= String::kMaxShortSize) {
-    map = short_ascii_string_map();
-  } else if (length <= String::kMaxMediumSize) {
-    map = medium_ascii_string_map();
-  } else {
-    map = long_ascii_string_map();
-  }
-
   // Partially initialize the object.
-  HeapObject::cast(result)->set_map(map);
+  HeapObject::cast(result)->set_map(ascii_string_map());
   String::cast(result)->set_length(length);
+  String::cast(result)->set_hash_field(String::kEmptyHashField);
   ASSERT_EQ(size, HeapObject::cast(result)->Size());
   return result;
 }
@@ -2765,19 +2686,10 @@
   }
   if (result->IsFailure()) return result;
 
-  // Determine the map based on the string's length.
-  Map* map;
-  if (length <= String::kMaxShortSize) {
-    map = short_string_map();
-  } else if (length <= String::kMaxMediumSize) {
-    map = medium_string_map();
-  } else {
-    map = long_string_map();
-  }
-
   // Partially initialize the object.
-  HeapObject::cast(result)->set_map(map);
+  HeapObject::cast(result)->set_map(string_map());
   String::cast(result)->set_length(length);
+  String::cast(result)->set_hash_field(String::kEmptyHashField);
   ASSERT_EQ(size, HeapObject::cast(result)->Size());
   return result;
 }
@@ -2998,6 +2910,11 @@
     last_gc_count = gc_count_;
 
   } else if (number_idle_notifications == kIdlesBeforeMarkSweep) {
+    // Before doing the mark-sweep collections we clear the
+    // compilation cache to avoid hanging on to source code and
+    // generated code for cached functions.
+    CompilationCache::Clear();
+
     CollectAllGarbage(false);
     new_space_.Shrink();
     last_gc_count = gc_count_;
@@ -3357,19 +3274,21 @@
 
 
 void Heap::RecordStats(HeapStats* stats) {
-  stats->new_space_size = new_space_.Size();
-  stats->new_space_capacity = new_space_.Capacity();
-  stats->old_pointer_space_size = old_pointer_space_->Size();
-  stats->old_pointer_space_capacity = old_pointer_space_->Capacity();
-  stats->old_data_space_size = old_data_space_->Size();
-  stats->old_data_space_capacity = old_data_space_->Capacity();
-  stats->code_space_size = code_space_->Size();
-  stats->code_space_capacity = code_space_->Capacity();
-  stats->map_space_size = map_space_->Size();
-  stats->map_space_capacity = map_space_->Capacity();
-  stats->cell_space_size = cell_space_->Size();
-  stats->cell_space_capacity = cell_space_->Capacity();
-  stats->lo_space_size = lo_space_->Size();
+  *stats->start_marker = 0xDECADE00;
+  *stats->end_marker = 0xDECADE01;
+  *stats->new_space_size = new_space_.Size();
+  *stats->new_space_capacity = new_space_.Capacity();
+  *stats->old_pointer_space_size = old_pointer_space_->Size();
+  *stats->old_pointer_space_capacity = old_pointer_space_->Capacity();
+  *stats->old_data_space_size = old_data_space_->Size();
+  *stats->old_data_space_capacity = old_data_space_->Capacity();
+  *stats->code_space_size = code_space_->Size();
+  *stats->code_space_capacity = code_space_->Capacity();
+  *stats->map_space_size = map_space_->Size();
+  *stats->map_space_capacity = map_space_->Capacity();
+  *stats->cell_space_size = cell_space_->Size();
+  *stats->cell_space_capacity = cell_space_->Capacity();
+  *stats->lo_space_size = lo_space_->Size();
   GlobalHandles::RecordStats(stats);
 }
 
diff --git a/src/heap.h b/src/heap.h
index 965eb0b..b37fe4b 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -59,50 +59,20 @@
   V(Object, termination_exception, TerminationException)                       \
   V(Map, hash_table_map, HashTableMap)                                         \
   V(FixedArray, empty_fixed_array, EmptyFixedArray)                            \
-  V(Map, short_string_map, ShortStringMap)                                     \
-  V(Map, medium_string_map, MediumStringMap)                                   \
-  V(Map, long_string_map, LongStringMap)                                       \
-  V(Map, short_ascii_string_map, ShortAsciiStringMap)                          \
-  V(Map, medium_ascii_string_map, MediumAsciiStringMap)                        \
-  V(Map, long_ascii_string_map, LongAsciiStringMap)                            \
-  V(Map, short_symbol_map, ShortSymbolMap)                                     \
-  V(Map, medium_symbol_map, MediumSymbolMap)                                   \
-  V(Map, long_symbol_map, LongSymbolMap)                                       \
-  V(Map, short_ascii_symbol_map, ShortAsciiSymbolMap)                          \
-  V(Map, medium_ascii_symbol_map, MediumAsciiSymbolMap)                        \
-  V(Map, long_ascii_symbol_map, LongAsciiSymbolMap)                            \
-  V(Map, short_cons_symbol_map, ShortConsSymbolMap)                            \
-  V(Map, medium_cons_symbol_map, MediumConsSymbolMap)                          \
-  V(Map, long_cons_symbol_map, LongConsSymbolMap)                              \
-  V(Map, short_cons_ascii_symbol_map, ShortConsAsciiSymbolMap)                 \
-  V(Map, medium_cons_ascii_symbol_map, MediumConsAsciiSymbolMap)               \
-  V(Map, long_cons_ascii_symbol_map, LongConsAsciiSymbolMap)                   \
-  V(Map, short_external_symbol_map, ShortExternalSymbolMap)                    \
-  V(Map, medium_external_symbol_map, MediumExternalSymbolMap)                  \
-  V(Map, long_external_symbol_map, LongExternalSymbolMap)                      \
-  V(Map, short_external_ascii_symbol_map, ShortExternalAsciiSymbolMap)         \
-  V(Map, medium_external_ascii_symbol_map, MediumExternalAsciiSymbolMap)       \
-  V(Map, long_external_ascii_symbol_map, LongExternalAsciiSymbolMap)           \
-  V(Map, short_cons_string_map, ShortConsStringMap)                            \
-  V(Map, medium_cons_string_map, MediumConsStringMap)                          \
-  V(Map, long_cons_string_map, LongConsStringMap)                              \
-  V(Map, short_cons_ascii_string_map, ShortConsAsciiStringMap)                 \
-  V(Map, medium_cons_ascii_string_map, MediumConsAsciiStringMap)               \
-  V(Map, long_cons_ascii_string_map, LongConsAsciiStringMap)                   \
-  V(Map, short_external_string_map, ShortExternalStringMap)                    \
-  V(Map, medium_external_string_map, MediumExternalStringMap)                  \
-  V(Map, long_external_string_map, LongExternalStringMap)                      \
-  V(Map, short_external_ascii_string_map, ShortExternalAsciiStringMap)         \
-  V(Map, medium_external_ascii_string_map, MediumExternalAsciiStringMap)       \
-  V(Map, long_external_ascii_string_map, LongExternalAsciiStringMap)           \
-  V(Map, undetectable_short_string_map, UndetectableShortStringMap)            \
-  V(Map, undetectable_medium_string_map, UndetectableMediumStringMap)          \
-  V(Map, undetectable_long_string_map, UndetectableLongStringMap)              \
-  V(Map, undetectable_short_ascii_string_map, UndetectableShortAsciiStringMap) \
-  V(Map,                                                                       \
-    undetectable_medium_ascii_string_map,                                      \
-    UndetectableMediumAsciiStringMap)                                          \
-  V(Map, undetectable_long_ascii_string_map, UndetectableLongAsciiStringMap)   \
+  V(Map, string_map, StringMap)                                                \
+  V(Map, ascii_string_map, AsciiStringMap)                                     \
+  V(Map, symbol_map, SymbolMap)                                                \
+  V(Map, ascii_symbol_map, AsciiSymbolMap)                                     \
+  V(Map, cons_symbol_map, ConsSymbolMap)                                       \
+  V(Map, cons_ascii_symbol_map, ConsAsciiSymbolMap)                            \
+  V(Map, external_symbol_map, ExternalSymbolMap)                               \
+  V(Map, external_ascii_symbol_map, ExternalAsciiSymbolMap)                    \
+  V(Map, cons_string_map, ConsStringMap)                                       \
+  V(Map, cons_ascii_string_map, ConsAsciiStringMap)                            \
+  V(Map, external_string_map, ExternalStringMap)                               \
+  V(Map, external_ascii_string_map, ExternalAsciiStringMap)                    \
+  V(Map, undetectable_string_map, UndetectableStringMap)                       \
+  V(Map, undetectable_ascii_string_map, UndetectableAsciiStringMap)            \
   V(Map, pixel_array_map, PixelArrayMap)                                       \
   V(Map, external_byte_array_map, ExternalByteArrayMap)                        \
   V(Map, external_unsigned_byte_array_map, ExternalUnsignedByteArrayMap)       \
@@ -410,11 +380,11 @@
   // Please note this function does not perform a garbage collection.
   static inline Object* AllocateSymbol(Vector<const char> str,
                                        int chars,
-                                       uint32_t length_field);
+                                       uint32_t hash_field);
 
   static Object* AllocateInternalSymbol(unibrow::CharacterStream* buffer,
                                         int chars,
-                                        uint32_t length_field);
+                                        uint32_t hash_field);
 
   static Object* AllocateExternalSymbol(Vector<const char> str,
                                         int chars);
@@ -913,7 +883,10 @@
   static int linear_allocation_scope_depth_;
   static bool context_disposed_pending_;
 
-  static const int kMaxMapSpaceSize = 8*MB;
+  // The number of MapSpace pages is limited by the way we pack
+  // Map pointers during GC.
+  static const int kMaxMapSpaceSize =
+      (1 << MapWord::kMapPageIndexBits) * Page::kPageSize;
 
 #if defined(V8_TARGET_ARCH_X64)
   static const int kMaxObjectSizeInNewSpace = 512*KB;
@@ -1132,24 +1105,26 @@
 
 class HeapStats {
  public:
-  int new_space_size;
-  int new_space_capacity;
-  int old_pointer_space_size;
-  int old_pointer_space_capacity;
-  int old_data_space_size;
-  int old_data_space_capacity;
-  int code_space_size;
-  int code_space_capacity;
-  int map_space_size;
-  int map_space_capacity;
-  int cell_space_size;
-  int cell_space_capacity;
-  int lo_space_size;
-  int global_handle_count;
-  int weak_global_handle_count;
-  int pending_global_handle_count;
-  int near_death_global_handle_count;
-  int destroyed_global_handle_count;
+  int *start_marker;
+  int *new_space_size;
+  int *new_space_capacity;
+  int *old_pointer_space_size;
+  int *old_pointer_space_capacity;
+  int *old_data_space_size;
+  int *old_data_space_capacity;
+  int *code_space_size;
+  int *code_space_capacity;
+  int *map_space_size;
+  int *map_space_capacity;
+  int *cell_space_size;
+  int *cell_space_capacity;
+  int *lo_space_size;
+  int *global_handle_count;
+  int *weak_global_handle_count;
+  int *pending_global_handle_count;
+  int *near_death_global_handle_count;
+  int *destroyed_global_handle_count;
+  int *end_marker;
 };
 
 
diff --git a/src/ia32/assembler-ia32.h b/src/ia32/assembler-ia32.h
index 962206f..662ebc9 100644
--- a/src/ia32/assembler-ia32.h
+++ b/src/ia32/assembler-ia32.h
@@ -464,6 +464,8 @@
   // to jump to.
   static const int kPatchReturnSequenceAddressOffset = 1;  // JMP imm32.
 
+  static const int kCallInstructionLength = 5;
+  static const int kJSReturnSequenceLength = 6;
 
   // ---------------------------------------------------------------------------
   // Code generation
diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc
index ac2a7a0..7c8ff31 100644
--- a/src/ia32/codegen-ia32.cc
+++ b/src/ia32/codegen-ia32.cc
@@ -2490,7 +2490,7 @@
 #ifdef ENABLE_DEBUGGER_SUPPORT
   // Check that the size of the code used for returning matches what is
   // expected by the debugger.
-  ASSERT_EQ(Debug::kIa32JSReturnSequenceLength,
+  ASSERT_EQ(Assembler::kJSReturnSequenceLength,
             masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
 #endif
 }
@@ -3056,13 +3056,59 @@
   jsobject.Bind();
   // Get the set of properties (as a FixedArray or Map).
   // eax: value to be iterated over
-  frame_->EmitPush(eax);  // push the object being iterated over (slot 4)
+  frame_->EmitPush(eax);  // Push the object being iterated over.
 
+  // Check cache validity in generated code. This is a fast case for
+  // the JSObject::IsSimpleEnum cache validity checks. If we cannot
+  // guarantee cache validity, call the runtime system to check cache
+  // validity or get the property names in a fixed array.
+  JumpTarget call_runtime;
+  JumpTarget loop(JumpTarget::BIDIRECTIONAL);
+  JumpTarget check_prototype;
+  JumpTarget use_cache;
+  __ mov(ecx, eax);
+  loop.Bind();
+  // Check that there are no elements.
+  __ mov(edx, FieldOperand(ecx, JSObject::kElementsOffset));
+  __ cmp(Operand(edx), Immediate(Factory::empty_fixed_array()));
+  call_runtime.Branch(not_equal);
+  // Check that instance descriptors are not empty so that we can
+  // check for an enum cache.  Leave the map in ebx for the subsequent
+  // prototype load.
+  __ mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset));
+  __ mov(edx, FieldOperand(ebx, Map::kInstanceDescriptorsOffset));
+  __ cmp(Operand(edx), Immediate(Factory::empty_descriptor_array()));
+  call_runtime.Branch(equal);
+  // Check that there in an enum cache in the non-empty instance
+  // descriptors.  This is the case if the next enumeration index
+  // field does not contain a smi.
+  __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumerationIndexOffset));
+  __ test(edx, Immediate(kSmiTagMask));
+  call_runtime.Branch(zero);
+  // For all objects but the receiver, check that the cache is empty.
+  __ cmp(ecx, Operand(eax));
+  check_prototype.Branch(equal);
+  __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumCacheBridgeCacheOffset));
+  __ cmp(Operand(edx), Immediate(Factory::empty_fixed_array()));
+  call_runtime.Branch(not_equal);
+  check_prototype.Bind();
+  // Load the prototype from the map and loop if non-null.
+  __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset));
+  __ cmp(Operand(ecx), Immediate(Factory::null_value()));
+  loop.Branch(not_equal);
+  // The enum cache is valid.  Load the map of the object being
+  // iterated over and use the cache for the iteration.
+  __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
+  use_cache.Jump();
+
+  call_runtime.Bind();
+  // Call the runtime to get the property names for the object.
   frame_->EmitPush(eax);  // push the Object (slot 4) for the runtime call
   frame_->CallRuntime(Runtime::kGetPropertyNamesFast, 1);
 
-  // If we got a Map, we can do a fast modification check.
-  // Otherwise, we got a FixedArray, and we have to do a slow check.
+  // If we got a map from the runtime call, we can do a fast
+  // modification check. Otherwise, we got a fixed array, and we have
+  // to do a slow check.
   // eax: map or fixed array (result from call to
   // Runtime::kGetPropertyNamesFast)
   __ mov(edx, Operand(eax));
@@ -3070,9 +3116,13 @@
   __ cmp(ecx, Factory::meta_map());
   fixed_array.Branch(not_equal);
 
+  use_cache.Bind();
   // Get enum cache
-  // eax: map (result from call to Runtime::kGetPropertyNamesFast)
+  // eax: map (either the result from a call to
+  // Runtime::kGetPropertyNamesFast or has been fetched directly from
+  // the object)
   __ mov(ecx, Operand(eax));
+
   __ mov(ecx, FieldOperand(ecx, Map::kInstanceDescriptorsOffset));
   // Get the bridge array held in the enumeration index field.
   __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset));
@@ -4777,18 +4827,8 @@
   __ test(ecx, Immediate(kIsNotStringMask));
   __ j(not_zero, &slow_case);
 
-  // Here we make assumptions about the tag values and the shifts needed.
-  // See the comment in objects.h.
-  ASSERT(kLongStringTag == 0);
-  ASSERT(kMediumStringTag + String::kLongLengthShift ==
-         String::kMediumLengthShift);
-  ASSERT(kShortStringTag + String::kLongLengthShift ==
-         String::kShortLengthShift);
-  __ and_(ecx, kStringSizeMask);
-  __ add(Operand(ecx), Immediate(String::kLongLengthShift));
   // Fetch the length field into the temporary register.
   __ mov(temp.reg(), FieldOperand(object.reg(), String::kLengthOffset));
-  __ shr_cl(temp.reg());
   // Check for index out of range.
   __ cmp(index.reg(), Operand(temp.reg()));
   __ j(greater_equal, &slow_case);
@@ -5222,6 +5262,18 @@
 }
 
 
+void CodeGenerator::GenerateStringAdd(ZoneList<Expression*>* args) {
+  ASSERT_EQ(2, args->length());
+
+  Load(args->at(0));
+  Load(args->at(1));
+
+  StringAddStub stub(NO_STRING_ADD_FLAGS);
+  Result answer = frame_->CallStub(&stub, 2);
+  frame_->Push(&answer);
+}
+
+
 void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
   if (CheckForInlineRuntimeCall(node)) {
     return;
@@ -6502,11 +6554,8 @@
   // String value => false iff empty.
   __ cmp(ecx, FIRST_NONSTRING_TYPE);
   __ j(above_equal, &not_string);
-  __ and_(ecx, kStringSizeMask);
-  __ cmp(ecx, kShortStringTag);
-  __ j(not_equal, &true_result);  // Empty string is always short.
   __ mov(edx, FieldOperand(eax, String::kLengthOffset));
-  __ shr(edx, String::kShortLengthShift);
+  __ test(edx, Operand(edx));
   __ j(zero, &false_result);
   __ jmp(&true_result);
 
@@ -7042,7 +7091,7 @@
   switch (op_) {
     case Token::ADD: {
       // Test for string arguments before calling runtime.
-      Label not_strings, both_strings, not_string1, string1;
+      Label not_strings, not_string1, string1;
       Result answer;
       __ mov(eax, Operand(esp, 2 * kPointerSize));  // First argument.
       __ mov(edx, Operand(esp, 1 * kPointerSize));  // Second argument.
@@ -7057,8 +7106,9 @@
       __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, edx);
       __ j(above_equal, &string1);
 
-      // First and second argument are strings.
-      __ TailCallRuntime(ExternalReference(Runtime::kStringAdd), 2, 1);
+      // First and second argument are strings. Jump to the string add stub.
+      StringAddStub stub(NO_STRING_CHECK_IN_STUB);
+      __ TailCallStub(&stub);
 
       // Only first argument is a string.
       __ bind(&string1);
@@ -8185,6 +8235,224 @@
   return (static_cast<unsigned>(cc_) << 1) | (strict_ ? 1 : 0);
 }
 
+
+void StringAddStub::Generate(MacroAssembler* masm) {
+  Label string_add_runtime;
+
+  // Load the two arguments.
+  __ mov(eax, Operand(esp, 2 * kPointerSize));  // First argument.
+  __ mov(edx, Operand(esp, 1 * kPointerSize));  // Second argument.
+
+  // Make sure that both arguments are strings if not known in advance.
+  if (string_check_) {
+    __ test(eax, Immediate(kSmiTagMask));
+    __ j(zero, &string_add_runtime);
+    __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ebx);
+    __ j(above_equal, &string_add_runtime);
+
+    // First argument is a a string, test second.
+    __ test(edx, Immediate(kSmiTagMask));
+    __ j(zero, &string_add_runtime);
+    __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, ebx);
+    __ j(above_equal, &string_add_runtime);
+  }
+
+  // Both arguments are strings.
+  // eax: first string
+  // edx: second string
+  // Check if either of the strings are empty. In that case return the other.
+  Label second_not_zero_length, both_not_zero_length;
+  __ mov(ecx, FieldOperand(edx, String::kLengthOffset));
+  __ test(ecx, Operand(ecx));
+  __ j(not_zero, &second_not_zero_length);
+  // Second string is empty, result is first string which is already in eax.
+  __ IncrementCounter(&Counters::string_add_native, 1);
+  __ ret(2 * kPointerSize);
+  __ bind(&second_not_zero_length);
+  __ mov(ebx, FieldOperand(eax, String::kLengthOffset));
+  __ test(ebx, Operand(ebx));
+  __ j(not_zero, &both_not_zero_length);
+  // First string is empty, result is second string which is in edx.
+  __ mov(eax, edx);
+  __ IncrementCounter(&Counters::string_add_native, 1);
+  __ ret(2 * kPointerSize);
+
+  // Both strings are non-empty.
+  // eax: first string
+  // ebx: length of first string
+  // ecx: length of second string
+  // edx: second string
+  // Look at the length of the result of adding the two strings.
+  Label string_add_flat_result;
+  __ bind(&both_not_zero_length);
+  __ add(ebx, Operand(ecx));
+  // Use the runtime system when adding two one character strings, as it
+  // contains optimizations for this specific case using the symbol table.
+  __ cmp(ebx, 2);
+  __ j(equal, &string_add_runtime);
+  // Check if resulting string will be flat.
+  __ cmp(ebx, String::kMinNonFlatLength);
+  __ j(below, &string_add_flat_result);
+  // Handle exceptionally long strings in the runtime system.
+  ASSERT((String::kMaxLength & 0x80000000) == 0);
+  __ cmp(ebx, String::kMaxLength);
+  __ j(above, &string_add_runtime);
+
+  // If result is not supposed to be flat allocate a cons string object. If both
+  // strings are ascii the result is an ascii cons string.
+  Label non_ascii, allocated;
+  __ mov(edi, FieldOperand(eax, HeapObject::kMapOffset));
+  __ movzx_b(ecx, FieldOperand(edi, Map::kInstanceTypeOffset));
+  __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
+  __ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset));
+  __ and_(ecx, Operand(edi));
+  __ test(ecx, Immediate(kAsciiStringTag));
+  __ j(zero, &non_ascii);
+  // Allocate an acsii cons string.
+  __ AllocateAsciiConsString(ecx, edi, no_reg, &string_add_runtime);
+  __ bind(&allocated);
+  // Fill the fields of the cons string.
+  __ mov(FieldOperand(ecx, ConsString::kLengthOffset), ebx);
+  __ mov(FieldOperand(ecx, ConsString::kHashFieldOffset),
+         Immediate(String::kEmptyHashField));
+  __ mov(FieldOperand(ecx, ConsString::kFirstOffset), eax);
+  __ mov(FieldOperand(ecx, ConsString::kSecondOffset), edx);
+  __ mov(eax, ecx);
+  __ IncrementCounter(&Counters::string_add_native, 1);
+  __ ret(2 * kPointerSize);
+  __ bind(&non_ascii);
+  // Allocate a two byte cons string.
+  __ AllocateConsString(ecx, edi, no_reg, &string_add_runtime);
+  __ jmp(&allocated);
+
+  // Handle creating a flat result. First check that both strings are not
+  // external strings.
+  // eax: first string
+  // ebx: length of resulting flat string
+  // edx: second string
+  __ bind(&string_add_flat_result);
+  __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
+  __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
+  __ and_(ecx, kStringRepresentationMask);
+  __ cmp(ecx, kExternalStringTag);
+  __ j(equal, &string_add_runtime);
+  __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
+  __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
+  __ and_(ecx, kStringRepresentationMask);
+  __ cmp(ecx, kExternalStringTag);
+  __ j(equal, &string_add_runtime);
+  // Now check if both strings are ascii strings.
+  // eax: first string
+  // ebx: length of resulting flat string
+  // edx: second string
+  Label non_ascii_string_add_flat_result;
+  __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
+  __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
+  ASSERT(kAsciiStringTag != 0);
+  __ test(ecx, Immediate(kAsciiStringTag));
+  __ j(zero, &non_ascii_string_add_flat_result);
+  __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
+  __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
+  __ test(ecx, Immediate(kAsciiStringTag));
+  __ j(zero, &string_add_runtime);
+  // Both strings are ascii strings. As they are short they are both flat.
+  __ AllocateAsciiString(eax, ebx, ecx, edx, edi, &string_add_runtime);
+  // eax: result string
+  __ mov(ecx, eax);
+  // Locate first character of result.
+  __ add(Operand(ecx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
+  // Load first argument and locate first character.
+  __ mov(edx, Operand(esp, 2 * kPointerSize));
+  __ mov(edi, FieldOperand(edx, String::kLengthOffset));
+  __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
+  // eax: result string
+  // ecx: first character of result
+  // edx: first char of first argument
+  // edi: length of first argument
+  GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true);
+  // Load second argument and locate first character.
+  __ mov(edx, Operand(esp, 1 * kPointerSize));
+  __ mov(edi, FieldOperand(edx, String::kLengthOffset));
+  __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
+  // eax: result string
+  // ecx: next character of result
+  // edx: first char of second argument
+  // edi: length of second argument
+  GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true);
+  __ IncrementCounter(&Counters::string_add_native, 1);
+  __ ret(2 * kPointerSize);
+
+  // Handle creating a flat two byte result.
+  // eax: first string - known to be two byte
+  // ebx: length of resulting flat string
+  // edx: second string
+  __ bind(&non_ascii_string_add_flat_result);
+  __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
+  __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
+  __ and_(ecx, kAsciiStringTag);
+  __ j(not_zero, &string_add_runtime);
+  // Both strings are two byte strings. As they are short they are both
+  // flat.
+  __ AllocateTwoByteString(eax, ebx, ecx, edx, edi, &string_add_runtime);
+  // eax: result string
+  __ mov(ecx, eax);
+  // Locate first character of result.
+  __ add(Operand(ecx),
+         Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
+  // Load first argument and locate first character.
+  __ mov(edx, Operand(esp, 2 * kPointerSize));
+  __ mov(edi, FieldOperand(edx, String::kLengthOffset));
+  __ add(Operand(edx),
+         Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
+  // eax: result string
+  // ecx: first character of result
+  // edx: first char of first argument
+  // edi: length of first argument
+  GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false);
+  // Load second argument and locate first character.
+  __ mov(edx, Operand(esp, 1 * kPointerSize));
+  __ mov(edi, FieldOperand(edx, String::kLengthOffset));
+  __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
+  // eax: result string
+  // ecx: next character of result
+  // edx: first char of second argument
+  // edi: length of second argument
+  GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false);
+  __ IncrementCounter(&Counters::string_add_native, 1);
+  __ ret(2 * kPointerSize);
+
+  // Just jump to runtime to add the two strings.
+  __ bind(&string_add_runtime);
+  __ TailCallRuntime(ExternalReference(Runtime::kStringAdd), 2, 1);
+}
+
+
+void StringAddStub::GenerateCopyCharacters(MacroAssembler* masm,
+                                           Register dest,
+                                           Register src,
+                                           Register count,
+                                           Register scratch,
+                                           bool ascii) {
+  Label loop;
+  __ bind(&loop);
+  // This loop just copies one character at a time, as it is only used for very
+  // short strings.
+  if (ascii) {
+    __ mov_b(scratch, Operand(src, 0));
+    __ mov_b(Operand(dest, 0), scratch);
+    __ add(Operand(src), Immediate(1));
+    __ add(Operand(dest), Immediate(1));
+  } else {
+    __ mov_w(scratch, Operand(src, 0));
+    __ mov_w(Operand(dest, 0), scratch);
+    __ add(Operand(src), Immediate(2));
+    __ add(Operand(dest), Immediate(2));
+  }
+  __ sub(Operand(count), Immediate(1));
+  __ j(not_zero, &loop);
+}
+
+
 #undef __
 
 } }  // namespace v8::internal
diff --git a/src/ia32/codegen-ia32.h b/src/ia32/codegen-ia32.h
index ebab3ca..11a5163 100644
--- a/src/ia32/codegen-ia32.h
+++ b/src/ia32/codegen-ia32.h
@@ -546,6 +546,9 @@
   inline void GenerateMathSin(ZoneList<Expression*>* args);
   inline void GenerateMathCos(ZoneList<Expression*>* args);
 
+  // Fast support for StringAdd.
+  void GenerateStringAdd(ZoneList<Expression*>* args);
+
   // Simple condition analysis.
   enum ConditionAnalysis {
     ALWAYS_TRUE,
@@ -737,6 +740,37 @@
 };
 
 
+// Flag that indicates how to generate code for the stub StringAddStub.
+enum StringAddFlags {
+  NO_STRING_ADD_FLAGS = 0,
+  NO_STRING_CHECK_IN_STUB = 1 << 0  // Omit string check in stub.
+};
+
+
+class StringAddStub: public CodeStub {
+ public:
+  explicit StringAddStub(StringAddFlags flags) {
+    string_check_ = ((flags & NO_STRING_CHECK_IN_STUB) == 0);
+  }
+
+ private:
+  Major MajorKey() { return StringAdd; }
+  int MinorKey() { return string_check_ ? 0 : 1; }
+
+  void Generate(MacroAssembler* masm);
+
+  void GenerateCopyCharacters(MacroAssembler* masm,
+                                   Register desc,
+                                   Register src,
+                                   Register count,
+                                   Register scratch,
+                                   bool ascii);
+
+  // Should the stub check whether arguments are strings?
+  bool string_check_;
+};
+
+
 } }  // namespace v8::internal
 
 #endif  // V8_IA32_CODEGEN_IA32_H_
diff --git a/src/ia32/debug-ia32.cc b/src/ia32/debug-ia32.cc
index 2d20117..5ebe1e0 100644
--- a/src/ia32/debug-ia32.cc
+++ b/src/ia32/debug-ia32.cc
@@ -45,17 +45,17 @@
 // CodeGenerator::VisitReturnStatement and VirtualFrame::Exit in codegen-ia32.cc
 // for the precise return instructions sequence.
 void BreakLocationIterator::SetDebugBreakAtReturn() {
-  ASSERT(Debug::kIa32JSReturnSequenceLength >=
-         Debug::kIa32CallInstructionLength);
+  ASSERT(Assembler::kJSReturnSequenceLength >=
+         Assembler::kCallInstructionLength);
   rinfo()->PatchCodeWithCall(Debug::debug_break_return()->entry(),
-      Debug::kIa32JSReturnSequenceLength - Debug::kIa32CallInstructionLength);
+      Assembler::kJSReturnSequenceLength - Assembler::kCallInstructionLength);
 }
 
 
 // Restore the JS frame exit code.
 void BreakLocationIterator::ClearDebugBreakAtReturn() {
   rinfo()->PatchCode(original_rinfo()->pc(),
-                     Debug::kIa32JSReturnSequenceLength);
+                     Assembler::kJSReturnSequenceLength);
 }
 
 
diff --git a/src/ia32/fast-codegen-ia32.cc b/src/ia32/fast-codegen-ia32.cc
index a01d754..c5d5441 100644
--- a/src/ia32/fast-codegen-ia32.cc
+++ b/src/ia32/fast-codegen-ia32.cc
@@ -74,11 +74,41 @@
 
   bool function_in_register = true;
 
+  // Possibly allocate a local context.
+  if (fun->scope()->num_heap_slots() > 0) {
+    Comment cmnt(masm_, "[ Allocate local context");
+    // Argument to NewContext is the function, which is still in edi.
+    __ push(edi);
+    __ CallRuntime(Runtime::kNewContext, 1);
+    function_in_register = false;
+    // Context is returned in both eax and esi.  It replaces the context
+    // passed to us.  It's saved in the stack and kept live in esi.
+    __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
+
+    // Copy parameters into context if necessary.
+    int num_parameters = fun->scope()->num_parameters();
+    for (int i = 0; i < num_parameters; i++) {
+      Slot* slot = fun->scope()->parameter(i)->slot();
+      if (slot != NULL && slot->type() == Slot::CONTEXT) {
+        int parameter_offset = StandardFrameConstants::kCallerSPOffset +
+                               (num_parameters - 1 - i) * kPointerSize;
+        // Load parameter from stack.
+        __ mov(eax, Operand(ebp, parameter_offset));
+        // Store it in the context
+        __ mov(Operand(esi, Context::SlotOffset(slot->index())), eax);
+      }
+    }
+  }
+
   Variable* arguments = fun->scope()->arguments()->AsVariable();
   if (arguments != NULL) {
     // Function uses arguments object.
     Comment cmnt(masm_, "[ Allocate arguments object");
-    __ push(edi);
+    if (function_in_register) {
+      __ push(edi);
+    } else {
+      __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
+    }
     // Receiver is just before the parameters on the caller's stack.
     __ lea(edx, Operand(ebp, StandardFrameConstants::kCallerSPOffset +
                                  fun->num_parameters() * kPointerSize));
@@ -90,36 +120,13 @@
     // stack frame was an arguments adapter frame.
     ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
     __ CallStub(&stub);
-    __ mov(Operand(ebp, SlotOffset(arguments->slot())), eax);
+    __ mov(ecx, eax);  // Duplicate result.
+    Move(arguments->slot(), eax, ebx, edx);
     Slot* dot_arguments_slot =
         fun->scope()->arguments_shadow()->AsVariable()->slot();
-    __ mov(Operand(ebp, SlotOffset(dot_arguments_slot)), eax);
-
-    function_in_register = false;
+    Move(dot_arguments_slot, ecx, ebx, edx);
   }
 
-  // Possibly allocate a local context.
-  if (fun->scope()->num_heap_slots() > 0) {
-    Comment cmnt(masm_, "[ Allocate local context");
-    if (function_in_register) {
-      // Argument to NewContext is the function, still in edi.
-      __ push(edi);
-    } else {
-      // Argument to NewContext is the function, no longer in edi.
-      __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
-    }
-    __ CallRuntime(Runtime::kNewContext, 1);
-    // Context is returned in both eax and esi.  It replaces the context
-    // passed to us.  It's saved in the stack and kept live in esi.
-    __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
-#ifdef DEBUG
-    // Assert we do not have to copy any parameters into the context.
-    for (int i = 0, len = fun->scope()->num_parameters(); i < len; i++) {
-      Slot* slot = fun->scope()->parameter(i)->slot();
-      ASSERT(slot != NULL && slot->type() != Slot::CONTEXT);
-    }
-#endif
-  }
 
   { Comment cmnt(masm_, "[ Declarations");
     VisitDeclarations(fun->scope()->declarations());
@@ -180,7 +187,7 @@
 #ifdef ENABLE_DEBUGGER_SUPPORT
     // Check that the size of the code used for returning matches what is
     // expected by the debugger.
-    ASSERT_EQ(Debug::kIa32JSReturnSequenceLength,
+    ASSERT_EQ(Assembler::kJSReturnSequenceLength,
             masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
 #endif
   }
@@ -220,20 +227,54 @@
 }
 
 
-void FastCodeGenerator::Move(Expression::Context context, Slot* source) {
+template <>
+Operand FastCodeGenerator::CreateSlotOperand<Operand>(Slot* source,
+                                                      Register scratch) {
+  switch (source->type()) {
+    case Slot::PARAMETER:
+    case Slot::LOCAL:
+      return Operand(ebp, SlotOffset(source));
+    case Slot::CONTEXT: {
+      int context_chain_length =
+          function_->scope()->ContextChainLength(source->var()->scope());
+      __ LoadContext(scratch, context_chain_length);
+      return CodeGenerator::ContextOperand(scratch, source->index());
+      break;
+    }
+    case Slot::LOOKUP:
+      UNIMPLEMENTED();
+      // Fall-through.
+    default:
+      UNREACHABLE();
+      return Operand(eax, 0);  // Dead code to make the compiler happy.
+  }
+}
+
+
+void FastCodeGenerator::Move(Register dst, Slot* source) {
+  Operand location = CreateSlotOperand<Operand>(source, dst);
+  __ mov(dst, location);
+}
+
+
+void FastCodeGenerator::Move(Expression::Context context,
+                             Slot* source,
+                             Register scratch) {
   switch (context) {
     case Expression::kUninitialized:
       UNREACHABLE();
     case Expression::kEffect:
       break;
-    case Expression::kValue:
-      __ push(Operand(ebp, SlotOffset(source)));
+    case Expression::kValue: {
+      Operand location = CreateSlotOperand<Operand>(source, scratch);
+      __ push(location);
       break;
+    }
     case Expression::kTest:  // Fall through.
     case Expression::kValueTest:  // Fall through.
     case Expression::kTestValue:
-      __ mov(eax, Operand(ebp, SlotOffset(source)));
-      Move(context, eax);
+      Move(scratch, source);
+      Move(context, scratch);
       break;
   }
 }
@@ -258,24 +299,61 @@
 }
 
 
+void FastCodeGenerator::Move(Slot* dst,
+                             Register src,
+                             Register scratch1,
+                             Register scratch2) {
+  switch (dst->type()) {
+    case Slot::PARAMETER:
+    case Slot::LOCAL:
+      __ mov(Operand(ebp, SlotOffset(dst)), src);
+      break;
+    case Slot::CONTEXT: {
+      ASSERT(!src.is(scratch1));
+      ASSERT(!src.is(scratch2));
+      ASSERT(!scratch1.is(scratch2));
+      int context_chain_length =
+          function_->scope()->ContextChainLength(dst->var()->scope());
+      __ LoadContext(scratch1, context_chain_length);
+      __ mov(Operand(scratch1, Context::SlotOffset(dst->index())), src);
+      int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize;
+      __ RecordWrite(scratch1, offset, src, scratch2);
+      break;
+    }
+    case Slot::LOOKUP:
+      UNIMPLEMENTED();
+    default:
+      UNREACHABLE();
+  }
+}
+
+
 void FastCodeGenerator::DropAndMove(Expression::Context context,
-                                    Register source) {
+                                    Register source,
+                                    int count) {
+  ASSERT(count > 0);
   switch (context) {
     case Expression::kUninitialized:
       UNREACHABLE();
     case Expression::kEffect:
-      __ add(Operand(esp), Immediate(kPointerSize));
+      __ add(Operand(esp), Immediate(count * kPointerSize));
       break;
     case Expression::kValue:
+      if (count > 1) {
+        __ add(Operand(esp), Immediate((count - 1) * kPointerSize));
+      }
       __ mov(Operand(esp, 0), source);
       break;
     case Expression::kTest:
       ASSERT(!source.is(esp));
-      __ add(Operand(esp), Immediate(kPointerSize));
+      __ add(Operand(esp), Immediate(count * kPointerSize));
       TestAndBranch(source, true_label_, false_label_);
       break;
     case Expression::kValueTest: {
       Label discard;
+      if (count > 1) {
+        __ add(Operand(esp), Immediate((count - 1) * kPointerSize));
+      }
       __ mov(Operand(esp, 0), source);
       TestAndBranch(source, true_label_, &discard);
       __ bind(&discard);
@@ -285,6 +363,9 @@
     }
     case Expression::kTestValue: {
       Label discard;
+      if (count > 1) {
+        __ add(Operand(esp), Immediate((count - 1) * kPointerSize));
+      }
       __ mov(Operand(esp, 0), source);
       TestAndBranch(source, &discard, false_label_);
       __ bind(&discard);
@@ -380,6 +461,7 @@
         }
         __ mov(CodeGenerator::ContextOperand(esi, slot->index()), eax);
         // No write barrier since the_hole_value is in old space.
+        ASSERT(!Heap::InNewSpace(*Factory::the_hole_value()));
       } else if (decl->fun() != NULL) {
         Visit(decl->fun());
         __ pop(eax);
@@ -391,7 +473,7 @@
           __ Check(equal, "Unexpected declaration in current context.");
         }
         __ mov(CodeGenerator::ContextOperand(esi, slot->index()), eax);
-        int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
+        int offset = Context::SlotOffset(slot->index());
         __ RecordWrite(esi, offset, eax, ecx);
       }
       break;
@@ -464,53 +546,61 @@
     DropAndMove(expr->context(), eax);
   } else if (rewrite->AsSlot() != NULL) {
     Slot* slot = rewrite->AsSlot();
-    switch (slot->type()) {
-      case Slot::LOCAL:
-      case Slot::PARAMETER: {
-        Comment cmnt(masm_, "Stack slot");
-        Move(expr->context(), slot);
-        break;
-      }
-
-      case Slot::CONTEXT: {
-        Comment cmnt(masm_, "Context slot");
-         int chain_length =
-            function_->scope()->ContextChainLength(slot->var()->scope());
-        if (chain_length > 0) {
-          // Move up the chain of contexts to the context containing the slot.
-          __ mov(eax,
-                 Operand(esi, Context::SlotOffset(Context::CLOSURE_INDEX)));
-          // Load the function context (which is the incoming, outer context).
-          __ mov(eax, FieldOperand(eax, JSFunction::kContextOffset));
-          for (int i = 1; i < chain_length; i++) {
-            __ mov(eax,
-                   Operand(eax, Context::SlotOffset(Context::CLOSURE_INDEX)));
-            __ mov(eax, FieldOperand(eax, JSFunction::kContextOffset));
-          }
-          // The context may be an intermediate context, not a function context.
-          __ mov(eax,
-                 Operand(eax, Context::SlotOffset(Context::FCONTEXT_INDEX)));
-        } else {  // Slot is in the current function context.
-          // The context may be an intermediate context, not a function context.
-          __ mov(eax,
-                 Operand(esi, Context::SlotOffset(Context::FCONTEXT_INDEX)));
+    if (FLAG_debug_code) {
+      switch (slot->type()) {
+        case Slot::LOCAL:
+        case Slot::PARAMETER: {
+          Comment cmnt(masm_, "Stack slot");
+          break;
         }
-        __ mov(eax, Operand(eax, Context::SlotOffset(slot->index())));
-        Move(expr->context(), eax);
-        break;
+        case Slot::CONTEXT: {
+          Comment cmnt(masm_, "Context slot");
+          break;
+        }
+        case Slot::LOOKUP:
+          UNIMPLEMENTED();
+          break;
+        default:
+          UNREACHABLE();
       }
-
-      case Slot::LOOKUP:
-        UNREACHABLE();
-        break;
     }
+    Move(expr->context(), slot, eax);
   } else {
-    // The parameter variable has been rewritten into an explict access to
-    // the arguments object.
+    Comment cmnt(masm_, "Variable rewritten to Property");
+    // A variable has been rewritten into an explicit access to
+    // an object property.
     Property* property = rewrite->AsProperty();
     ASSERT_NOT_NULL(property);
-    ASSERT_EQ(expr->context(), property->context());
-    Visit(property);
+
+    // Currently the only parameter expressions that can occur are
+    // on the form "slot[literal]".
+
+    // Check that the object is in a slot.
+    Variable* object_var = property->obj()->AsVariableProxy()->AsVariable();
+    ASSERT_NOT_NULL(object_var);
+    Slot* object_slot = object_var->slot();
+    ASSERT_NOT_NULL(object_slot);
+
+    // Load the object.
+    Move(Expression::kValue, object_slot, eax);
+
+    // Check that the key is a smi.
+    Literal* key_literal = property->key()->AsLiteral();
+    ASSERT_NOT_NULL(key_literal);
+    ASSERT(key_literal->handle()->IsSmi());
+
+    // Load the key.
+    Move(Expression::kValue, key_literal);
+
+    // Do a KEYED property load.
+    Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+    __ call(ic, RelocInfo::CODE_TARGET);
+    // Notice: We must not have a "test eax, ..." instruction after
+    // the call. It is treated specially by the LoadIC code.
+    __ nop();
+
+    // Drop key and object left on the stack by IC, and push the result.
+    DropAndMove(expr->context(), eax, 2);
   }
 }
 
@@ -575,8 +665,9 @@
     __ CallRuntime(Runtime::kCloneLiteralBoilerplate, 1);
   }
 
-  // If result_saved == true: the result is saved on top of the stack.
-  // If result_saved == false: the result not on the stack, just is in eax.
+  // If result_saved == true: The result is saved on top of the
+  //  stack and in eax.
+  // If result_saved == false: The result not on the stack, just in eax.
   bool result_saved = false;
 
   for (int i = 0; i < expr->properties()->length(); i++) {
@@ -601,6 +692,7 @@
           Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
           __ call(ic, RelocInfo::CODE_TARGET);
           // StoreIC leaves the receiver on the stack.
+          __ mov(eax, Operand(esp, 0));  // Restore result into eax.
           break;
         }
         // fall through
@@ -776,34 +868,34 @@
     // Overwrite the receiver on the stack with the result if needed.
     DropAndMove(expr->context(), eax);
 
-  } else {
+  } else if (var->slot() != NULL) {
     Slot* slot = var->slot();
-    ASSERT_NOT_NULL(slot);  // Variables rewritten as properties not handled.
     switch (slot->type()) {
       case Slot::LOCAL:
       case Slot::PARAMETER: {
+        Operand target = Operand(ebp, SlotOffset(var->slot()));
         switch (expr->context()) {
           case Expression::kUninitialized:
             UNREACHABLE();
           case Expression::kEffect:
             // Perform assignment and discard value.
-            __ pop(Operand(ebp, SlotOffset(var->slot())));
+            __ pop(target);
             break;
           case Expression::kValue:
             // Perform assignment and preserve value.
             __ mov(eax, Operand(esp, 0));
-            __ mov(Operand(ebp, SlotOffset(var->slot())), eax);
+            __ mov(target, eax);
             break;
           case Expression::kTest:
             // Perform assignment and test (and discard) value.
             __ pop(eax);
-            __ mov(Operand(ebp, SlotOffset(var->slot())), eax);
+            __ mov(target, eax);
             TestAndBranch(eax, true_label_, false_label_);
             break;
           case Expression::kValueTest: {
             Label discard;
             __ mov(eax, Operand(esp, 0));
-            __ mov(Operand(ebp, SlotOffset(var->slot())), eax);
+            __ mov(target, eax);
             TestAndBranch(eax, true_label_, &discard);
             __ bind(&discard);
             __ add(Operand(esp), Immediate(kPointerSize));
@@ -813,7 +905,7 @@
           case Expression::kTestValue: {
             Label discard;
             __ mov(eax, Operand(esp, 0));
-            __ mov(Operand(ebp, SlotOffset(var->slot())), eax);
+            __ mov(target, eax);
             TestAndBranch(eax, &discard, false_label_);
             __ bind(&discard);
             __ add(Operand(esp), Immediate(kPointerSize));
@@ -868,6 +960,35 @@
         UNREACHABLE();
         break;
     }
+  } else {
+    Property* property = var->rewrite()->AsProperty();
+    ASSERT_NOT_NULL(property);
+
+    // Load object and key onto the stack.
+    Slot* object_slot = property->obj()->AsSlot();
+    ASSERT_NOT_NULL(object_slot);
+    Move(Expression::kValue, object_slot, eax);
+
+    Literal* key_literal = property->key()->AsLiteral();
+    ASSERT_NOT_NULL(key_literal);
+    Move(Expression::kValue, key_literal);
+
+    // Value to store was pushed before object and key on the stack.
+    __ mov(eax, Operand(esp, 2 * kPointerSize));
+
+    // Arguments to ic is value in eax, object and key on stack.
+    Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
+    __ call(ic, RelocInfo::CODE_TARGET);
+
+    if (expr->context() == Expression::kEffect) {
+      __ add(Operand(esp), Immediate(3 * kPointerSize));
+    } else if (expr->context() == Expression::kValue) {
+      // Value is still on the stack in esp[2 * kPointerSize]
+      __ add(Operand(esp), Immediate(2 * kPointerSize));
+    } else {
+      __ mov(eax, Operand(esp, 2 * kPointerSize));
+      DropAndMove(expr->context(), eax, 3);
+    }
   }
 }
 
@@ -1127,9 +1248,13 @@
 void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
   Comment cmnt(masm_, "[ CallRuntime");
   ZoneList<Expression*>* args = expr->arguments();
-  Runtime::Function* function = expr->function();
 
-  ASSERT(function != NULL);
+  if (expr->is_jsruntime()) {
+    // Prepare for calling JS runtime function.
+    __ push(Immediate(expr->name()));
+    __ mov(eax, CodeGenerator::GlobalObject());
+    __ push(FieldOperand(eax, GlobalObject::kBuiltinsOffset));
+  }
 
   // Push the arguments ("left-to-right").
   int arg_count = args->length();
@@ -1138,8 +1263,20 @@
     ASSERT_EQ(Expression::kValue, args->at(i)->context());
   }
 
-  __ CallRuntime(function, arg_count);
-  Move(expr->context(), eax);
+  if (expr->is_jsruntime()) {
+    // Call the JS runtime function.
+    Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count,
+                                                           NOT_IN_LOOP);
+    __ call(ic, RelocInfo::CODE_TARGET);
+      // Restore context register.
+    __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
+    // Discard the function left on TOS.
+    DropAndMove(expr->context(), eax);
+  } else {
+    // Call the C runtime function.
+    __ CallRuntime(expr->function(), arg_count);
+    Move(expr->context(), eax);
+  }
 }
 
 
diff --git a/src/ia32/ic-ia32.cc b/src/ia32/ic-ia32.cc
index 3aa3c34..6988fe0 100644
--- a/src/ia32/ic-ia32.cc
+++ b/src/ia32/ic-ia32.cc
@@ -31,6 +31,7 @@
 #include "ic-inl.h"
 #include "runtime.h"
 #include "stub-cache.h"
+#include "utils.h"
 
 namespace v8 {
 namespace internal {
@@ -108,7 +109,7 @@
       StringDictionary::kElementsStartIndex * kPointerSize;
   for (int i = 0; i < kProbes; i++) {
     // Compute the masked index: (hash + i + i * i) & mask.
-    __ mov(r1, FieldOperand(name, String::kLengthOffset));
+    __ mov(r1, FieldOperand(name, String::kHashFieldOffset));
     __ shr(r1, String::kHashShift);
     if (i > 0) {
       __ add(Operand(r1), Immediate(StringDictionary::GetProbeOffset(i)));
@@ -216,18 +217,6 @@
 }
 
 
-#ifdef DEBUG
-// For use in assert below.
-static int TenToThe(int exponent) {
-  ASSERT(exponent <= 9);
-  ASSERT(exponent >= 1);
-  int answer = 10;
-  for (int i = 1; i < exponent; i++) answer *= 10;
-  return answer;
-}
-#endif
-
-
 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
   // ----------- S t a t e -------------
   //  -- esp[0] : return address
@@ -309,7 +298,7 @@
   __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx);
   __ j(above_equal, &slow);
   // Is the string an array index, with cached numeric value?
-  __ mov(ebx, FieldOperand(eax, String::kLengthOffset));
+  __ mov(ebx, FieldOperand(eax, String::kHashFieldOffset));
   __ test(ebx, Immediate(String::kIsArrayIndexMask));
   __ j(not_zero, &index_string, not_taken);
 
@@ -324,20 +313,16 @@
   __ mov(eax, Operand(ecx));
   __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1);
   __ ret(0);
-  // Array index string: If short enough use cache in length/hash field (ebx).
-  // We assert that there are enough bits in an int32_t after the hash shift
-  // bits have been subtracted to allow space for the length and the cached
-  // array index.
+  // If the hash field contains an array index pick it out. The assert checks
+  // that the constants for the maximum number of digits for an array index
+  // cached in the hash field and the number of bits reserved for it does not
+  // conflict.
   ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
-         (1 << (String::kShortLengthShift - String::kHashShift)));
+         (1 << String::kArrayIndexValueBits));
   __ bind(&index_string);
-  const int kLengthFieldLimit =
-      (String::kMaxCachedArrayIndexLength + 1) << String::kShortLengthShift;
-  __ cmp(ebx, kLengthFieldLimit);
-  __ j(above_equal, &slow);
   __ mov(eax, Operand(ebx));
-  __ and_(eax, (1 << String::kShortLengthShift) - 1);
-  __ shr(eax, String::kLongLengthShift);
+  __ and_(eax, String::kArrayIndexHashMask);
+  __ shr(eax, String::kHashShift);
   __ jmp(&index_int);
 }
 
@@ -403,13 +388,13 @@
       __ movsx_b(eax, Operand(ecx, eax, times_1, 0));
       break;
     case kExternalUnsignedByteArray:
-      __ mov_b(eax, Operand(ecx, eax, times_1, 0));
+      __ movzx_b(eax, Operand(ecx, eax, times_1, 0));
       break;
     case kExternalShortArray:
       __ movsx_w(eax, Operand(ecx, eax, times_2, 0));
       break;
     case kExternalUnsignedShortArray:
-      __ mov_w(eax, Operand(ecx, eax, times_2, 0));
+      __ movzx_w(eax, Operand(ecx, eax, times_2, 0));
       break;
     case kExternalIntArray:
     case kExternalUnsignedIntArray:
diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc
index 010433e..b91caa8 100644
--- a/src/ia32/macro-assembler-ia32.cc
+++ b/src/ia32/macro-assembler-ia32.cc
@@ -213,6 +213,13 @@
 }
 
 
+void MacroAssembler::StackLimitCheck(Label* on_stack_overflow) {
+  cmp(esp,
+      Operand::StaticVariable(ExternalReference::address_of_stack_limit()));
+  j(below, on_stack_overflow);
+}
+
+
 #ifdef ENABLE_DEBUGGER_SUPPORT
 void MacroAssembler::SaveRegistersToMemory(RegList regs) {
   ASSERT((regs & ~kJSCallerSaved) == 0);
@@ -680,6 +687,11 @@
 
 void MacroAssembler::UpdateAllocationTopHelper(Register result_end,
                                                Register scratch) {
+  if (FLAG_debug_code) {
+    test(result_end, Immediate(kObjectAlignmentMask));
+    Check(zero, "Unaligned allocation in new space");
+  }
+
   ExternalReference new_space_allocation_top =
       ExternalReference::new_space_allocation_top_address();
 
@@ -813,6 +825,109 @@
 }
 
 
+void MacroAssembler::AllocateTwoByteString(Register result,
+                                           Register length,
+                                           Register scratch1,
+                                           Register scratch2,
+                                           Register scratch3,
+                                           Label* gc_required) {
+  // Calculate the number of bytes needed for the characters in the string while
+  // observing object alignment.
+  ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
+  mov(scratch1, length);
+  ASSERT(kShortSize == 2);
+  shl(scratch1, 1);
+  add(Operand(scratch1), Immediate(kObjectAlignmentMask));
+  and_(Operand(scratch1), Immediate(~kObjectAlignmentMask));
+
+  // Allocate two byte string in new space.
+  AllocateInNewSpace(SeqTwoByteString::kHeaderSize,
+                     times_1,
+                     scratch1,
+                     result,
+                     scratch2,
+                     scratch3,
+                     gc_required,
+                     TAG_OBJECT);
+
+  // Set the map, length and hash field.
+  mov(FieldOperand(result, HeapObject::kMapOffset),
+      Immediate(Factory::string_map()));
+  mov(FieldOperand(result, String::kLengthOffset), length);
+  mov(FieldOperand(result, String::kHashFieldOffset),
+      Immediate(String::kEmptyHashField));
+}
+
+
+void MacroAssembler::AllocateAsciiString(Register result,
+                                         Register length,
+                                         Register scratch1,
+                                         Register scratch2,
+                                         Register scratch3,
+                                         Label* gc_required) {
+  // Calculate the number of bytes needed for the characters in the string while
+  // observing object alignment.
+  ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0);
+  mov(scratch1, length);
+  ASSERT(kCharSize == 1);
+  add(Operand(scratch1), Immediate(kObjectAlignmentMask));
+  and_(Operand(scratch1), Immediate(~kObjectAlignmentMask));
+
+  // Allocate ascii string in new space.
+  AllocateInNewSpace(SeqAsciiString::kHeaderSize,
+                     times_1,
+                     scratch1,
+                     result,
+                     scratch2,
+                     scratch3,
+                     gc_required,
+                     TAG_OBJECT);
+
+  // Set the map, length and hash field.
+  mov(FieldOperand(result, HeapObject::kMapOffset),
+      Immediate(Factory::ascii_string_map()));
+  mov(FieldOperand(result, String::kLengthOffset), length);
+  mov(FieldOperand(result, String::kHashFieldOffset),
+      Immediate(String::kEmptyHashField));
+}
+
+
+void MacroAssembler::AllocateConsString(Register result,
+                                        Register scratch1,
+                                        Register scratch2,
+                                        Label* gc_required) {
+  // Allocate heap number in new space.
+  AllocateInNewSpace(ConsString::kSize,
+                     result,
+                     scratch1,
+                     scratch2,
+                     gc_required,
+                     TAG_OBJECT);
+
+  // Set the map. The other fields are left uninitialized.
+  mov(FieldOperand(result, HeapObject::kMapOffset),
+      Immediate(Factory::cons_string_map()));
+}
+
+
+void MacroAssembler::AllocateAsciiConsString(Register result,
+                                             Register scratch1,
+                                             Register scratch2,
+                                             Label* gc_required) {
+  // Allocate heap number in new space.
+  AllocateInNewSpace(ConsString::kSize,
+                     result,
+                     scratch1,
+                     scratch2,
+                     gc_required,
+                     TAG_OBJECT);
+
+  // Set the map. The other fields are left uninitialized.
+  mov(FieldOperand(result, HeapObject::kMapOffset),
+      Immediate(Factory::cons_ascii_string_map()));
+}
+
+
 void MacroAssembler::NegativeZeroTest(CodeGenerator* cgen,
                                       Register result,
                                       Register op,
@@ -906,6 +1021,12 @@
 }
 
 
+void MacroAssembler::TailCallStub(CodeStub* stub) {
+  ASSERT(allow_stub_calls());  // calls are not allowed in some stubs
+  jmp(stub->GetCode(), RelocInfo::CODE_TARGET);
+}
+
+
 void MacroAssembler::StubReturn(int argc) {
   ASSERT(argc >= 1 && generating_stub());
   ret((argc - 1) * kPointerSize);
@@ -1185,6 +1306,26 @@
 }
 
 
+void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
+  if (context_chain_length > 0) {
+    // Move up the chain of contexts to the context containing the slot.
+    mov(dst, Operand(esi, Context::SlotOffset(Context::CLOSURE_INDEX)));
+    // Load the function context (which is the incoming, outer context).
+    mov(dst, FieldOperand(dst, JSFunction::kContextOffset));
+    for (int i = 1; i < context_chain_length; i++) {
+      mov(dst, Operand(dst, Context::SlotOffset(Context::CLOSURE_INDEX)));
+      mov(dst, FieldOperand(dst, JSFunction::kContextOffset));
+    }
+    // The context may be an intermediate context, not a function context.
+    mov(dst, Operand(dst, Context::SlotOffset(Context::FCONTEXT_INDEX)));
+  } else {  // Slot is in the current function context.
+    // The context may be an intermediate context, not a function context.
+    mov(dst, Operand(esi, Context::SlotOffset(Context::FCONTEXT_INDEX)));
+  }
+}
+
+
+
 void MacroAssembler::Ret() {
   ret(0);
 }
@@ -1252,11 +1393,15 @@
     RecordComment(msg);
   }
 #endif
+  // Disable stub call restrictions to always allow calls to abort.
+  set_allow_stub_calls(true);
+
   push(eax);
   push(Immediate(p0));
   push(Immediate(reinterpret_cast<intptr_t>(Smi::FromInt(p1 - p0))));
   CallRuntime(Runtime::kAbort, 2);
   // will not return here
+  int3();
 }
 
 
diff --git a/src/ia32/macro-assembler-ia32.h b/src/ia32/macro-assembler-ia32.h
index 248aa77..a41d42e 100644
--- a/src/ia32/macro-assembler-ia32.h
+++ b/src/ia32/macro-assembler-ia32.h
@@ -69,6 +69,12 @@
 #endif
 
   // ---------------------------------------------------------------------------
+  // Stack limit support
+
+  // Do simple test for stack overflow. This doesn't handle an overflow.
+  void StackLimitCheck(Label* on_stack_limit_hit);
+
+  // ---------------------------------------------------------------------------
   // Activation frames
 
   void EnterInternalFrame() { EnterFrame(StackFrame::INTERNAL); }
@@ -90,6 +96,8 @@
   // argument in register esi.
   void LeaveExitFrame(ExitFrame::Mode mode);
 
+  // Find the function context up the context chain.
+  void LoadContext(Register dst, int context_chain_length);
 
   // ---------------------------------------------------------------------------
   // JavaScript invokes
@@ -175,7 +183,7 @@
   // scratch can be passed as no_reg in which case an additional object
   // reference will be added to the reloc info. The returned pointers in result
   // and result_end have not yet been tagged as heap objects. If
-  // result_contains_top_on_entry is true the contnt of result is known to be
+  // result_contains_top_on_entry is true the content of result is known to be
   // the allocation top on entry (could be result_end from a previous call to
   // AllocateInNewSpace). If result_contains_top_on_entry is true scratch
   // should be no_reg as it is never used.
@@ -217,6 +225,32 @@
                           Register scratch2,
                           Label* gc_required);
 
+  // Allocate a sequential string. All the header fields of the string object
+  // are initialized.
+  void AllocateTwoByteString(Register result,
+                             Register length,
+                             Register scratch1,
+                             Register scratch2,
+                             Register scratch3,
+                             Label* gc_required);
+  void AllocateAsciiString(Register result,
+                           Register length,
+                           Register scratch1,
+                           Register scratch2,
+                           Register scratch3,
+                           Label* gc_required);
+
+  // Allocate a raw cons string object. Only the map field of the result is
+  // initialized.
+  void AllocateConsString(Register result,
+                          Register scratch1,
+                          Register scratch2,
+                          Label* gc_required);
+  void AllocateAsciiConsString(Register result,
+                               Register scratch1,
+                               Register scratch2,
+                               Label* gc_required);
+
   // ---------------------------------------------------------------------------
   // Support functions.
 
@@ -254,6 +288,9 @@
   // Call a code stub.
   void CallStub(CodeStub* stub);
 
+  // Tail call a code stub (jump).
+  void TailCallStub(CodeStub* stub);
+
   // Return from a code stub after popping its arguments.
   void StubReturn(int argc);
 
diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc
index f9f986a..425c51d 100644
--- a/src/ia32/stub-cache-ia32.cc
+++ b/src/ia32/stub-cache-ia32.cc
@@ -126,7 +126,7 @@
   __ j(zero, &miss, not_taken);
 
   // Get the map of the receiver and compute the hash.
-  __ mov(scratch, FieldOperand(name, String::kLengthOffset));
+  __ mov(scratch, FieldOperand(name, String::kHashFieldOffset));
   __ add(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
   __ xor_(scratch, flags);
   __ and_(scratch, (kPrimaryTableSize - 1) << kHeapObjectTagSize);
@@ -135,7 +135,7 @@
   ProbeTable(masm, flags, kPrimary, name, scratch, extra);
 
   // Primary miss: Compute hash for secondary probe.
-  __ mov(scratch, FieldOperand(name, String::kLengthOffset));
+  __ mov(scratch, FieldOperand(name, String::kHashFieldOffset));
   __ add(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
   __ xor_(scratch, flags);
   __ and_(scratch, (kPrimaryTableSize - 1) << kHeapObjectTagSize);
@@ -234,13 +234,9 @@
   // scratch register.
   GenerateStringCheck(masm, receiver, scratch, miss, &check_wrapper);
 
-  // Load length directly from the string.
+  // Load length from the string and convert to a smi.
   __ bind(&load_length);
-  __ and_(scratch, kStringSizeMask);
   __ mov(eax, FieldOperand(receiver, String::kLengthOffset));
-  // ecx is also the receiver.
-  __ lea(ecx, Operand(scratch, String::kLongLengthShift));
-  __ shr_cl(eax);
   __ shl(eax, kSmiTagSize);
   __ ret(0);
 
diff --git a/src/log.cc b/src/log.cc
index aec813d..bbce926 100644
--- a/src/log.cc
+++ b/src/log.cc
@@ -680,22 +680,51 @@
 #endif  // ENABLE_LOGGING_AND_PROFILING
 
 
-void Logger::CallbackEvent(String* name, Address entry_point) {
 #ifdef ENABLE_LOGGING_AND_PROFILING
+void Logger::CallbackEventInternal(const char* prefix, const char* name,
+                                   Address entry_point) {
   if (!Log::IsEnabled() || !FLAG_log_code) return;
   LogMessageBuilder msg;
   msg.Append("%s,%s,",
              log_events_[CODE_CREATION_EVENT], log_events_[CALLBACK_TAG]);
   msg.AppendAddress(entry_point);
-  SmartPointer<char> str =
-      name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
-  msg.Append(",1,\"%s\"", *str);
+  msg.Append(",1,\"%s%s\"", prefix, name);
   if (FLAG_compress_log) {
     ASSERT(compression_helper_ != NULL);
     if (!compression_helper_->HandleMessage(&msg)) return;
   }
   msg.Append('\n');
   msg.WriteToLogFile();
+}
+#endif
+
+
+void Logger::CallbackEvent(String* name, Address entry_point) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  if (!Log::IsEnabled() || !FLAG_log_code) return;
+  SmartPointer<char> str =
+      name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
+  CallbackEventInternal("", *str, entry_point);
+#endif
+}
+
+
+void Logger::GetterCallbackEvent(String* name, Address entry_point) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  if (!Log::IsEnabled() || !FLAG_log_code) return;
+  SmartPointer<char> str =
+      name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
+  CallbackEventInternal("get ", *str, entry_point);
+#endif
+}
+
+
+void Logger::SetterCallbackEvent(String* name, Address entry_point) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  if (!Log::IsEnabled() || !FLAG_log_code) return;
+  SmartPointer<char> str =
+      name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
+  CallbackEventInternal("set ", *str, entry_point);
 #endif
 }
 
@@ -1098,6 +1127,7 @@
       LOG(UncheckedStringEvent("profiler", "resume"));
       FLAG_log_code = true;
       LogCompiledFunctions();
+      LogAccessorCallbacks();
       if (!FLAG_sliding_state_window) ticker_->Start();
     }
     profiler_->resume();
@@ -1242,6 +1272,28 @@
   DeleteArray(sfis);
 }
 
+
+void Logger::LogAccessorCallbacks() {
+  AssertNoAllocation no_alloc;
+  HeapIterator iterator;
+  while (iterator.has_next()) {
+    HeapObject* obj = iterator.next();
+    ASSERT(obj != NULL);
+    if (!obj->IsAccessorInfo()) continue;
+    AccessorInfo* ai = AccessorInfo::cast(obj);
+    if (!ai->name()->IsString()) continue;
+    String* name = String::cast(ai->name());
+    Address getter_entry = v8::ToCData<Address>(ai->getter());
+    if (getter_entry != 0) {
+      LOG(GetterCallbackEvent(name, getter_entry));
+    }
+    Address setter_entry = v8::ToCData<Address>(ai->setter());
+    if (setter_entry != 0) {
+      LOG(SetterCallbackEvent(name, setter_entry));
+    }
+  }
+}
+
 #endif
 
 
diff --git a/src/log.h b/src/log.h
index f099f02..4d5acce 100644
--- a/src/log.h
+++ b/src/log.h
@@ -208,6 +208,8 @@
   // ==== Events logged by --log-code. ====
   // Emits a code event for a callback function.
   static void CallbackEvent(String* name, Address entry_point);
+  static void GetterCallbackEvent(String* name, Address entry_point);
+  static void SetterCallbackEvent(String* name, Address entry_point);
   // Emits a code create event.
   static void CodeCreateEvent(LogEventsAndTags tag,
                               Code* code, const char* source);
@@ -273,6 +275,8 @@
 
   // Logs all compiled functions found in the heap.
   static void LogCompiledFunctions();
+  // Logs all accessor callbacks found in the heap.
+  static void LogAccessorCallbacks();
   // Used for logging stubs found in the snapshot.
   static void LogCodeObject(Object* code_object);
 
@@ -287,6 +291,11 @@
   // Emits the profiler's first message.
   static void ProfilerBeginEvent();
 
+  // Emits callback event messages.
+  static void CallbackEventInternal(const char* prefix,
+                                    const char* name,
+                                    Address entry_point);
+
   // Emits aliases for compressed messages.
   static void LogAliases();
 
diff --git a/src/objects-debug.cc b/src/objects-debug.cc
index a259ca9..36f65ee 100644
--- a/src/objects-debug.cc
+++ b/src/objects-debug.cc
@@ -547,42 +547,18 @@
     case INVALID_TYPE: return "INVALID";
     case MAP_TYPE: return "MAP";
     case HEAP_NUMBER_TYPE: return "HEAP_NUMBER";
-    case SHORT_SYMBOL_TYPE:
-    case MEDIUM_SYMBOL_TYPE:
-    case LONG_SYMBOL_TYPE: return "SYMBOL";
-    case SHORT_ASCII_SYMBOL_TYPE:
-    case MEDIUM_ASCII_SYMBOL_TYPE:
-    case LONG_ASCII_SYMBOL_TYPE: return "ASCII_SYMBOL";
-    case SHORT_CONS_SYMBOL_TYPE:
-    case MEDIUM_CONS_SYMBOL_TYPE:
-    case LONG_CONS_SYMBOL_TYPE: return "CONS_SYMBOL";
-    case SHORT_CONS_ASCII_SYMBOL_TYPE:
-    case MEDIUM_CONS_ASCII_SYMBOL_TYPE:
-    case LONG_CONS_ASCII_SYMBOL_TYPE: return "CONS_ASCII_SYMBOL";
-    case SHORT_EXTERNAL_ASCII_SYMBOL_TYPE:
-    case MEDIUM_EXTERNAL_ASCII_SYMBOL_TYPE:
-    case LONG_EXTERNAL_ASCII_SYMBOL_TYPE:
-    case SHORT_EXTERNAL_SYMBOL_TYPE:
-    case MEDIUM_EXTERNAL_SYMBOL_TYPE:
-    case LONG_EXTERNAL_SYMBOL_TYPE: return "EXTERNAL_SYMBOL";
-    case SHORT_ASCII_STRING_TYPE:
-    case MEDIUM_ASCII_STRING_TYPE:
-    case LONG_ASCII_STRING_TYPE: return "ASCII_STRING";
-    case SHORT_STRING_TYPE:
-    case MEDIUM_STRING_TYPE:
-    case LONG_STRING_TYPE: return "TWO_BYTE_STRING";
-    case SHORT_CONS_STRING_TYPE:
-    case MEDIUM_CONS_STRING_TYPE:
-    case LONG_CONS_STRING_TYPE:
-    case SHORT_CONS_ASCII_STRING_TYPE:
-    case MEDIUM_CONS_ASCII_STRING_TYPE:
-    case LONG_CONS_ASCII_STRING_TYPE: return "CONS_STRING";
-    case SHORT_EXTERNAL_ASCII_STRING_TYPE:
-    case MEDIUM_EXTERNAL_ASCII_STRING_TYPE:
-    case LONG_EXTERNAL_ASCII_STRING_TYPE:
-    case SHORT_EXTERNAL_STRING_TYPE:
-    case MEDIUM_EXTERNAL_STRING_TYPE:
-    case LONG_EXTERNAL_STRING_TYPE: return "EXTERNAL_STRING";
+    case SYMBOL_TYPE: return "SYMBOL";
+    case ASCII_SYMBOL_TYPE: return "ASCII_SYMBOL";
+    case CONS_SYMBOL_TYPE: return "CONS_SYMBOL";
+    case CONS_ASCII_SYMBOL_TYPE: return "CONS_ASCII_SYMBOL";
+    case EXTERNAL_ASCII_SYMBOL_TYPE:
+    case EXTERNAL_SYMBOL_TYPE: return "EXTERNAL_SYMBOL";
+    case ASCII_STRING_TYPE: return "ASCII_STRING";
+    case STRING_TYPE: return "TWO_BYTE_STRING";
+    case CONS_STRING_TYPE:
+    case CONS_ASCII_STRING_TYPE: return "CONS_STRING";
+    case EXTERNAL_ASCII_STRING_TYPE:
+    case EXTERNAL_STRING_TYPE: return "EXTERNAL_STRING";
     case FIXED_ARRAY_TYPE: return "FIXED_ARRAY";
     case BYTE_ARRAY_TYPE: return "BYTE_ARRAY";
     case PIXEL_ARRAY_TYPE: return "PIXEL_ARRAY";
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 6919620..8514a41 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -280,11 +280,6 @@
              Internals::kFullStringRepresentationMask);
 
 
-uint32_t StringShape::size_tag() {
-  return (type_ & kStringSizeMask);
-}
-
-
 bool StringShape::IsSequentialAscii() {
   return full_representation_tag() == (kSeqStringTag | kAsciiStringTag);
 }
@@ -921,25 +916,6 @@
 }
 
 
-bool MapWord::IsSerializationAddress() {
-  return HAS_SMI_TAG(reinterpret_cast<Object*>(value_));
-}
-
-
-MapWord MapWord::FromSerializationAddress(int raw) {
-  // When the map word is being used as a serialization address we Smi-encode
-  // the serialization address (which is always a smallish positive integer).
-  return MapWord(reinterpret_cast<uintptr_t>(Smi::FromInt(raw)));
-}
-
-
-int MapWord::ToSerializationAddress() {
-  // When the map word is being used as a serialization address we treat the
-  // map word as a Smi and get the small integer that it encodes.
-  return reinterpret_cast<Smi*>(value_)->value();
-}
-
-
 bool MapWord::IsMarked() {
   return (value_ & kMarkingMask) == 0;
 }
@@ -1635,6 +1611,19 @@
 INT_ACCESSORS(Array, length, kLengthOffset)
 
 
+INT_ACCESSORS(String, length, kLengthOffset)
+
+
+uint32_t String::hash_field() {
+  return READ_UINT32_FIELD(this, kHashFieldOffset);
+}
+
+
+void String::set_hash_field(uint32_t value) {
+  WRITE_UINT32_FIELD(this, kHashFieldOffset, value);
+}
+
+
 bool String::Equals(String* other) {
   if (other == this) return true;
   if (StringShape(this).IsSymbol() && StringShape(other).IsSymbol()) {
@@ -1644,38 +1633,6 @@
 }
 
 
-int String::length() {
-  uint32_t len = READ_INT_FIELD(this, kLengthOffset);
-
-  ASSERT(kShortStringTag + kLongLengthShift == kShortLengthShift);
-  ASSERT(kMediumStringTag + kLongLengthShift == kMediumLengthShift);
-  ASSERT(kLongStringTag == 0);
-
-  return len >> (StringShape(this).size_tag() + kLongLengthShift);
-}
-
-
-void String::set_length(int value) {
-  ASSERT(kShortStringTag + kLongLengthShift == kShortLengthShift);
-  ASSERT(kMediumStringTag + kLongLengthShift == kMediumLengthShift);
-  ASSERT(kLongStringTag == 0);
-
-  WRITE_INT_FIELD(this,
-                  kLengthOffset,
-                  value << (StringShape(this).size_tag() + kLongLengthShift));
-}
-
-
-uint32_t String::length_field() {
-  return READ_UINT32_FIELD(this, kLengthOffset);
-}
-
-
-void String::set_length_field(uint32_t value) {
-  WRITE_UINT32_FIELD(this, kLengthOffset, value);
-}
-
-
 Object* String::TryFlattenIfNotFlat() {
   // We don't need to flatten strings that are already flat.  Since this code
   // is inlined, it can be helpful in the flat case to not call out to Flatten.
@@ -1779,30 +1736,12 @@
 
 int SeqTwoByteString::SeqTwoByteStringSize(InstanceType instance_type) {
   uint32_t length = READ_INT_FIELD(this, kLengthOffset);
-
-  ASSERT(kShortStringTag + kLongLengthShift == kShortLengthShift);
-  ASSERT(kMediumStringTag + kLongLengthShift == kMediumLengthShift);
-  ASSERT(kLongStringTag == 0);
-
-  // Use the map (and not 'this') to compute the size tag, since
-  // TwoByteStringSize is called during GC when maps are encoded.
-  length >>= StringShape(instance_type).size_tag() + kLongLengthShift;
-
   return SizeFor(length);
 }
 
 
 int SeqAsciiString::SeqAsciiStringSize(InstanceType instance_type) {
   uint32_t length = READ_INT_FIELD(this, kLengthOffset);
-
-  ASSERT(kShortStringTag + kLongLengthShift == kShortLengthShift);
-  ASSERT(kMediumStringTag + kLongLengthShift == kMediumLengthShift);
-  ASSERT(kLongStringTag == 0);
-
-  // Use the map (and not 'this') to compute the size tag, since
-  // AsciiStringSize is called during GC when maps are encoded.
-  length >>= StringShape(instance_type).size_tag() + kLongLengthShift;
-
   return SizeFor(length);
 }
 
@@ -1850,34 +1789,6 @@
 }
 
 
-Map* ExternalAsciiString::StringMap(int length) {
-  Map* map;
-  // Number of characters: determines the map.
-  if (length <= String::kMaxShortSize) {
-    map = Heap::short_external_ascii_string_map();
-  } else if (length <= String::kMaxMediumSize) {
-    map = Heap::medium_external_ascii_string_map();
-  } else {
-    map = Heap::long_external_ascii_string_map();
-  }
-  return map;
-}
-
-
-Map* ExternalAsciiString::SymbolMap(int length) {
-  Map* map;
-  // Number of characters: determines the map.
-  if (length <= String::kMaxShortSize) {
-    map = Heap::short_external_ascii_symbol_map();
-  } else if (length <= String::kMaxMediumSize) {
-    map = Heap::medium_external_ascii_symbol_map();
-  } else {
-    map = Heap::long_external_ascii_symbol_map();
-  }
-  return map;
-}
-
-
 ExternalTwoByteString::Resource* ExternalTwoByteString::resource() {
   return *reinterpret_cast<Resource**>(FIELD_ADDR(this, kResourceOffset));
 }
@@ -1889,34 +1800,6 @@
 }
 
 
-Map* ExternalTwoByteString::StringMap(int length) {
-  Map* map;
-  // Number of characters: determines the map.
-  if (length <= String::kMaxShortSize) {
-    map = Heap::short_external_string_map();
-  } else if (length <= String::kMaxMediumSize) {
-    map = Heap::medium_external_string_map();
-  } else {
-    map = Heap::long_external_string_map();
-  }
-  return map;
-}
-
-
-Map* ExternalTwoByteString::SymbolMap(int length) {
-  Map* map;
-  // Number of characters: determines the map.
-  if (length <= String::kMaxShortSize) {
-    map = Heap::short_external_symbol_map();
-  } else if (length <= String::kMaxMediumSize) {
-    map = Heap::medium_external_symbol_map();
-  } else {
-    map = Heap::long_external_symbol_map();
-  }
-  return map;
-}
-
-
 byte ByteArray::get(int index) {
   ASSERT(index >= 0 && index < this->length());
   return READ_BYTE_FIELD(this, kHeaderSize + index * kCharSize);
@@ -2899,13 +2782,13 @@
 
 
 bool String::HasHashCode() {
-  return (length_field() & kHashComputedMask) != 0;
+  return (hash_field() & kHashComputedMask) != 0;
 }
 
 
 uint32_t String::Hash() {
   // Fast case: has hash code already been computed?
-  uint32_t field = length_field();
+  uint32_t field = hash_field();
   if (field & kHashComputedMask) return field >> kHashShift;
   // Slow case: compute hash code and set it.
   return ComputeAndSetHash();
@@ -2922,7 +2805,7 @@
 
 
 bool StringHasher::has_trivial_hash() {
-  return length_ > String::kMaxMediumSize;
+  return length_ > String::kMaxHashCalcLength;
 }
 
 
@@ -2978,7 +2861,7 @@
 
 
 bool String::AsArrayIndex(uint32_t* index) {
-  uint32_t field = length_field();
+  uint32_t field = hash_field();
   if ((field & kHashComputedMask) && !(field & kIsArrayIndexMask)) return false;
   return SlowAsArrayIndex(index);
 }
diff --git a/src/objects.cc b/src/objects.cc
index f376585..0f8dca3 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -37,6 +37,7 @@
 #include "scanner.h"
 #include "scopeinfo.h"
 #include "string-stream.h"
+#include "utils.h"
 
 #ifdef ENABLE_DISASSEMBLER
 #include "disassembler.h"
@@ -754,19 +755,21 @@
   ASSERT(size >= ExternalString::kSize);
   bool is_symbol = this->IsSymbol();
   int length = this->length();
+  int hash_field = this->hash_field();
 
   // Morph the object to an external string by adjusting the map and
   // reinitializing the fields.
-  this->set_map(ExternalTwoByteString::StringMap(length));
+  this->set_map(Heap::external_string_map());
   ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
   self->set_length(length);
+  self->set_hash_field(hash_field);
   self->set_resource(resource);
   // Additionally make the object into an external symbol if the original string
   // was a symbol to start with.
   if (is_symbol) {
     self->Hash();  // Force regeneration of the hash value.
     // Now morph this external string into a external symbol.
-    self->set_map(ExternalTwoByteString::SymbolMap(length));
+    this->set_map(Heap::external_symbol_map());
   }
 
   // Fill the remainder of the string with dead wood.
@@ -798,19 +801,21 @@
   ASSERT(size >= ExternalString::kSize);
   bool is_symbol = this->IsSymbol();
   int length = this->length();
+  int hash_field = this->hash_field();
 
   // Morph the object to an external string by adjusting the map and
   // reinitializing the fields.
-  this->set_map(ExternalAsciiString::StringMap(length));
+  this->set_map(Heap::external_ascii_string_map());
   ExternalAsciiString* self = ExternalAsciiString::cast(this);
   self->set_length(length);
+  self->set_hash_field(hash_field);
   self->set_resource(resource);
   // Additionally make the object into an external symbol if the original string
   // was a symbol to start with.
   if (is_symbol) {
     self->Hash();  // Force regeneration of the hash value.
     // Now morph this external string into a external symbol.
-    self->set_map(ExternalAsciiString::SymbolMap(length));
+    this->set_map(Heap::external_ascii_symbol_map());
   }
 
   // Fill the remainder of the string with dead wood.
@@ -822,7 +827,7 @@
 
 void String::StringShortPrint(StringStream* accumulator) {
   int len = length();
-  if (len > kMaxMediumSize) {
+  if (len > kMaxShortPrintLength) {
     accumulator->Add("<Very long string[%u]>", len);
     return;
   }
@@ -2628,33 +2633,24 @@
 
 
 // Tests for the fast common case for property enumeration:
-// - this object has an enum cache
-// - this object has no elements
-// - no prototype has enumerable properties/elements
-// - neither this object nor any prototype has interceptors
+// - This object and all prototypes has an enum cache (which means that it has
+//   no interceptors and needs no access checks).
+// - This object has no elements.
+// - No prototype has enumerable properties/elements.
 bool JSObject::IsSimpleEnum() {
-  JSObject* arguments_boilerplate =
-      Top::context()->global_context()->arguments_boilerplate();
-  JSFunction* arguments_function =
-      JSFunction::cast(arguments_boilerplate->map()->constructor());
-  if (IsAccessCheckNeeded()) return false;
-  if (map()->constructor() == arguments_function) return false;
-
   for (Object* o = this;
        o != Heap::null_value();
        o = JSObject::cast(o)->GetPrototype()) {
     JSObject* curr = JSObject::cast(o);
-    if (!curr->HasFastProperties()) return false;
     if (!curr->map()->instance_descriptors()->HasEnumCache()) return false;
+    ASSERT(!curr->HasNamedInterceptor());
+    ASSERT(!curr->HasIndexedInterceptor());
+    ASSERT(!curr->IsAccessCheckNeeded());
     if (curr->NumberOfEnumElements() > 0) return false;
-    if (curr->HasNamedInterceptor()) return false;
-    if (curr->HasIndexedInterceptor()) return false;
     if (curr != this) {
       FixedArray* curr_fixed_array =
           FixedArray::cast(curr->map()->instance_descriptors()->GetEnumCache());
-      if (curr_fixed_array->length() > 0) {
-        return false;
-      }
+      if (curr_fixed_array->length() > 0) return false;
     }
   }
   return true;
@@ -4484,23 +4480,11 @@
   if (StringShape(this).IsSymbol()) return false;
 
   Map* map = this->map();
-  if (map == Heap::short_string_map()) {
-    this->set_map(Heap::undetectable_short_string_map());
+  if (map == Heap::string_map()) {
+    this->set_map(Heap::undetectable_string_map());
     return true;
-  } else if (map == Heap::medium_string_map()) {
-    this->set_map(Heap::undetectable_medium_string_map());
-    return true;
-  } else if (map == Heap::long_string_map()) {
-    this->set_map(Heap::undetectable_long_string_map());
-    return true;
-  } else if (map == Heap::short_ascii_string_map()) {
-    this->set_map(Heap::undetectable_short_ascii_string_map());
-    return true;
-  } else if (map == Heap::medium_ascii_string_map()) {
-    this->set_map(Heap::undetectable_medium_ascii_string_map());
-    return true;
-  } else if (map == Heap::long_ascii_string_map()) {
-    this->set_map(Heap::undetectable_long_ascii_string_map());
+  } else if (map == Heap::ascii_string_map()) {
+    this->set_map(Heap::undetectable_ascii_string_map());
     return true;
   }
   // Rest cannot be marked as undetectable
@@ -4523,17 +4507,17 @@
 
 uint32_t String::ComputeAndSetHash() {
   // Should only be called if hash code has not yet been computed.
-  ASSERT(!(length_field() & kHashComputedMask));
+  ASSERT(!(hash_field() & kHashComputedMask));
 
   // Compute the hash code.
   StringInputBuffer buffer(this);
-  uint32_t field = ComputeLengthAndHashField(&buffer, length());
+  uint32_t field = ComputeHashField(&buffer, length());
 
   // Store the hash code in the object.
-  set_length_field(field);
+  set_hash_field(field);
 
   // Check the hash code is there.
-  ASSERT(length_field() & kHashComputedMask);
+  ASSERT(hash_field() & kHashComputedMask);
   uint32_t result = field >> kHashShift;
   ASSERT(result != 0);  // Ensure that the hash value of 0 is never computed.
   return result;
@@ -4573,9 +4557,10 @@
 bool String::SlowAsArrayIndex(uint32_t* index) {
   if (length() <= kMaxCachedArrayIndexLength) {
     Hash();  // force computation of hash code
-    uint32_t field = length_field();
+    uint32_t field = hash_field();
     if ((field & kIsArrayIndexMask) == 0) return false;
-    *index = (field & ((1 << kShortLengthShift) - 1)) >> kLongLengthShift;
+    // Isolate the array index form the full hash field.
+    *index = (kArrayIndexHashMask & field) >> kHashShift;
     return true;
   } else {
     StringInputBuffer buffer(this);
@@ -4584,37 +4569,42 @@
 }
 
 
-static inline uint32_t HashField(uint32_t hash, bool is_array_index) {
+static inline uint32_t HashField(uint32_t hash,
+                                 bool is_array_index,
+                                 int length = -1) {
   uint32_t result =
-      (hash << String::kLongLengthShift) | String::kHashComputedMask;
-  if (is_array_index) result |= String::kIsArrayIndexMask;
+      (hash << String::kHashShift) | String::kHashComputedMask;
+  if (is_array_index) {
+    // For array indexes mix the length into the hash as an array index could
+    // be zero.
+    ASSERT(length > 0);
+    ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
+           (1 << String::kArrayIndexValueBits));
+    result |= String::kIsArrayIndexMask;
+    result |= length << String::kArrayIndexHashLengthShift;
+  }
   return result;
 }
 
 
 uint32_t StringHasher::GetHashField() {
   ASSERT(is_valid());
-  if (length_ <= String::kMaxShortSize) {
-    uint32_t payload;
+  if (length_ <= String::kMaxHashCalcLength) {
     if (is_array_index()) {
-      payload = v8::internal::HashField(array_index(), true);
+      return v8::internal::HashField(array_index(), true, length_);
     } else {
-      payload = v8::internal::HashField(GetHash(), false);
+      return v8::internal::HashField(GetHash(), false);
     }
-    return (payload & ((1 << String::kShortLengthShift) - 1)) |
-           (length_ << String::kShortLengthShift);
-  } else if (length_ <= String::kMaxMediumSize) {
     uint32_t payload = v8::internal::HashField(GetHash(), false);
-    return (payload & ((1 << String::kMediumLengthShift) - 1)) |
-           (length_ << String::kMediumLengthShift);
+    return payload;
   } else {
     return v8::internal::HashField(length_, false);
   }
 }
 
 
-uint32_t String::ComputeLengthAndHashField(unibrow::CharacterStream* buffer,
-                                           int length) {
+uint32_t String::ComputeHashField(unibrow::CharacterStream* buffer,
+                                  int length) {
   StringHasher hasher(length);
 
   // Very long strings have a trivial hash that doesn't inspect the
@@ -6177,6 +6167,7 @@
   return pt->GetPropertyWithReceiver(receiver, name, attributes);
 }
 
+
 Object* JSObject::GetLocalPropertyPostInterceptor(
     JSObject* receiver,
     String* name,
@@ -6478,6 +6469,15 @@
 
 
 int JSObject::NumberOfEnumElements() {
+  // Fast case for objects with no elements.
+  if (!IsJSValue() && HasFastElements()) {
+    uint32_t length = IsJSArray() ?
+        static_cast<uint32_t>(
+            Smi::cast(JSArray::cast(this)->length())->value()) :
+        static_cast<uint32_t>(FixedArray::cast(elements())->length());
+    if (length == 0) return 0;
+  }
+  // Compute the number of enumerable elements.
   return NumberOfLocalElements(static_cast<PropertyAttributes>(DONT_ENUM));
 }
 
@@ -6737,19 +6737,19 @@
 class Utf8SymbolKey : public HashTableKey {
  public:
   explicit Utf8SymbolKey(Vector<const char> string)
-      : string_(string), length_field_(0) { }
+      : string_(string), hash_field_(0) { }
 
   bool IsMatch(Object* string) {
     return String::cast(string)->IsEqualTo(string_);
   }
 
   uint32_t Hash() {
-    if (length_field_ != 0) return length_field_ >> String::kHashShift;
+    if (hash_field_ != 0) return hash_field_ >> String::kHashShift;
     unibrow::Utf8InputBuffer<> buffer(string_.start(),
                                       static_cast<unsigned>(string_.length()));
     chars_ = buffer.Length();
-    length_field_ = String::ComputeLengthAndHashField(&buffer, chars_);
-    uint32_t result = length_field_ >> String::kHashShift;
+    hash_field_ = String::ComputeHashField(&buffer, chars_);
+    uint32_t result = hash_field_ >> String::kHashShift;
     ASSERT(result != 0);  // Ensure that the hash value of 0 is never computed.
     return result;
   }
@@ -6759,12 +6759,12 @@
   }
 
   Object* AsObject() {
-    if (length_field_ == 0) Hash();
-    return Heap::AllocateSymbol(string_, chars_, length_field_);
+    if (hash_field_ == 0) Hash();
+    return Heap::AllocateSymbol(string_, chars_, hash_field_);
   }
 
   Vector<const char> string_;
-  uint32_t length_field_;
+  uint32_t hash_field_;
   int chars_;  // Caches the number of characters when computing the hash code.
 };
 
@@ -6805,7 +6805,7 @@
     StringInputBuffer buffer(string_);
     return Heap::AllocateInternalSymbol(&buffer,
                                         string_->length(),
-                                        string_->length_field());
+                                        string_->hash_field());
   }
 
   static uint32_t StringHash(Object* obj) {
diff --git a/src/objects.h b/src/objects.h
index 0dc3a1e..671978a 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -221,248 +221,128 @@
 // NOTE: Everything following JS_VALUE_TYPE is considered a
 // JSObject for GC purposes. The first four entries here have typeof
 // 'object', whereas JS_FUNCTION_TYPE has typeof 'function'.
-#define INSTANCE_TYPE_LIST_ALL(V)               \
-  V(SHORT_SYMBOL_TYPE)                          \
-  V(MEDIUM_SYMBOL_TYPE)                         \
-  V(LONG_SYMBOL_TYPE)                           \
-  V(SHORT_ASCII_SYMBOL_TYPE)                    \
-  V(MEDIUM_ASCII_SYMBOL_TYPE)                   \
-  V(LONG_ASCII_SYMBOL_TYPE)                     \
-  V(SHORT_CONS_SYMBOL_TYPE)                     \
-  V(MEDIUM_CONS_SYMBOL_TYPE)                    \
-  V(LONG_CONS_SYMBOL_TYPE)                      \
-  V(SHORT_CONS_ASCII_SYMBOL_TYPE)               \
-  V(MEDIUM_CONS_ASCII_SYMBOL_TYPE)              \
-  V(LONG_CONS_ASCII_SYMBOL_TYPE)                \
-  V(SHORT_EXTERNAL_SYMBOL_TYPE)                 \
-  V(MEDIUM_EXTERNAL_SYMBOL_TYPE)                \
-  V(LONG_EXTERNAL_SYMBOL_TYPE)                  \
-  V(SHORT_EXTERNAL_ASCII_SYMBOL_TYPE)           \
-  V(MEDIUM_EXTERNAL_ASCII_SYMBOL_TYPE)          \
-  V(LONG_EXTERNAL_ASCII_SYMBOL_TYPE)            \
-  V(SHORT_STRING_TYPE)                          \
-  V(MEDIUM_STRING_TYPE)                         \
-  V(LONG_STRING_TYPE)                           \
-  V(SHORT_ASCII_STRING_TYPE)                    \
-  V(MEDIUM_ASCII_STRING_TYPE)                   \
-  V(LONG_ASCII_STRING_TYPE)                     \
-  V(SHORT_CONS_STRING_TYPE)                     \
-  V(MEDIUM_CONS_STRING_TYPE)                    \
-  V(LONG_CONS_STRING_TYPE)                      \
-  V(SHORT_CONS_ASCII_STRING_TYPE)               \
-  V(MEDIUM_CONS_ASCII_STRING_TYPE)              \
-  V(LONG_CONS_ASCII_STRING_TYPE)                \
-  V(SHORT_EXTERNAL_STRING_TYPE)                 \
-  V(MEDIUM_EXTERNAL_STRING_TYPE)                \
-  V(LONG_EXTERNAL_STRING_TYPE)                  \
-  V(SHORT_EXTERNAL_ASCII_STRING_TYPE)           \
-  V(MEDIUM_EXTERNAL_ASCII_STRING_TYPE)          \
-  V(LONG_EXTERNAL_ASCII_STRING_TYPE)            \
-  V(LONG_PRIVATE_EXTERNAL_ASCII_STRING_TYPE)    \
-                                                \
-  V(MAP_TYPE)                                   \
-  V(HEAP_NUMBER_TYPE)                           \
-  V(FIXED_ARRAY_TYPE)                           \
-  V(CODE_TYPE)                                  \
-  V(JS_GLOBAL_PROPERTY_CELL_TYPE)               \
-  V(ODDBALL_TYPE)                               \
-  V(PROXY_TYPE)                                 \
-  V(BYTE_ARRAY_TYPE)                            \
-  V(PIXEL_ARRAY_TYPE)                           \
-  /* Note: the order of these external array */ \
-  /* types is relied upon in */                 \
-  /* Object::IsExternalArray(). */              \
-  V(EXTERNAL_BYTE_ARRAY_TYPE)                   \
-  V(EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE)          \
-  V(EXTERNAL_SHORT_ARRAY_TYPE)                  \
-  V(EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE)         \
-  V(EXTERNAL_INT_ARRAY_TYPE)                    \
-  V(EXTERNAL_UNSIGNED_INT_ARRAY_TYPE)           \
-  V(EXTERNAL_FLOAT_ARRAY_TYPE)                  \
-  V(FILLER_TYPE)                                \
-                                                \
-  V(ACCESSOR_INFO_TYPE)                         \
-  V(ACCESS_CHECK_INFO_TYPE)                     \
-  V(INTERCEPTOR_INFO_TYPE)                      \
-  V(SHARED_FUNCTION_INFO_TYPE)                  \
-  V(CALL_HANDLER_INFO_TYPE)                     \
-  V(FUNCTION_TEMPLATE_INFO_TYPE)                \
-  V(OBJECT_TEMPLATE_INFO_TYPE)                  \
-  V(SIGNATURE_INFO_TYPE)                        \
-  V(TYPE_SWITCH_INFO_TYPE)                      \
-  V(SCRIPT_TYPE)                                \
-                                                \
-  V(JS_VALUE_TYPE)                              \
-  V(JS_OBJECT_TYPE)                             \
-  V(JS_CONTEXT_EXTENSION_OBJECT_TYPE)           \
-  V(JS_GLOBAL_OBJECT_TYPE)                      \
-  V(JS_BUILTINS_OBJECT_TYPE)                    \
-  V(JS_GLOBAL_PROXY_TYPE)                       \
-  V(JS_ARRAY_TYPE)                              \
-  V(JS_REGEXP_TYPE)                             \
-                                                \
-  V(JS_FUNCTION_TYPE)                           \
+#define INSTANCE_TYPE_LIST_ALL(V)                                              \
+  V(SYMBOL_TYPE)                                                               \
+  V(ASCII_SYMBOL_TYPE)                                                         \
+  V(CONS_SYMBOL_TYPE)                                                          \
+  V(CONS_ASCII_SYMBOL_TYPE)                                                    \
+  V(EXTERNAL_SYMBOL_TYPE)                                                      \
+  V(EXTERNAL_ASCII_SYMBOL_TYPE)                                                \
+  V(STRING_TYPE)                                                               \
+  V(ASCII_STRING_TYPE)                                                         \
+  V(CONS_STRING_TYPE)                                                          \
+  V(CONS_ASCII_STRING_TYPE)                                                    \
+  V(EXTERNAL_STRING_TYPE)                                                      \
+  V(EXTERNAL_ASCII_STRING_TYPE)                                                \
+  V(PRIVATE_EXTERNAL_ASCII_STRING_TYPE)                                        \
+                                                                               \
+  V(MAP_TYPE)                                                                  \
+  V(HEAP_NUMBER_TYPE)                                                          \
+  V(FIXED_ARRAY_TYPE)                                                          \
+  V(CODE_TYPE)                                                                 \
+  V(JS_GLOBAL_PROPERTY_CELL_TYPE)                                              \
+  V(ODDBALL_TYPE)                                                              \
+  V(PROXY_TYPE)                                                                \
+  V(BYTE_ARRAY_TYPE)                                                           \
+  V(PIXEL_ARRAY_TYPE)                                                          \
+  /* Note: the order of these external array */                                \
+  /* types is relied upon in */                                                \
+  /* Object::IsExternalArray(). */                                             \
+  V(EXTERNAL_BYTE_ARRAY_TYPE)                                                  \
+  V(EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE)                                         \
+  V(EXTERNAL_SHORT_ARRAY_TYPE)                                                 \
+  V(EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE)                                        \
+  V(EXTERNAL_INT_ARRAY_TYPE)                                                   \
+  V(EXTERNAL_UNSIGNED_INT_ARRAY_TYPE)                                          \
+  V(EXTERNAL_FLOAT_ARRAY_TYPE)                                                 \
+  V(FILLER_TYPE)                                                               \
+                                                                               \
+  V(ACCESSOR_INFO_TYPE)                                                        \
+  V(ACCESS_CHECK_INFO_TYPE)                                                    \
+  V(INTERCEPTOR_INFO_TYPE)                                                     \
+  V(SHARED_FUNCTION_INFO_TYPE)                                                 \
+  V(CALL_HANDLER_INFO_TYPE)                                                    \
+  V(FUNCTION_TEMPLATE_INFO_TYPE)                                               \
+  V(OBJECT_TEMPLATE_INFO_TYPE)                                                 \
+  V(SIGNATURE_INFO_TYPE)                                                       \
+  V(TYPE_SWITCH_INFO_TYPE)                                                     \
+  V(SCRIPT_TYPE)                                                               \
+                                                                               \
+  V(JS_VALUE_TYPE)                                                             \
+  V(JS_OBJECT_TYPE)                                                            \
+  V(JS_CONTEXT_EXTENSION_OBJECT_TYPE)                                          \
+  V(JS_GLOBAL_OBJECT_TYPE)                                                     \
+  V(JS_BUILTINS_OBJECT_TYPE)                                                   \
+  V(JS_GLOBAL_PROXY_TYPE)                                                      \
+  V(JS_ARRAY_TYPE)                                                             \
+  V(JS_REGEXP_TYPE)                                                            \
+                                                                               \
+  V(JS_FUNCTION_TYPE)                                                          \
 
 #ifdef ENABLE_DEBUGGER_SUPPORT
-#define INSTANCE_TYPE_LIST_DEBUGGER(V)          \
-  V(DEBUG_INFO_TYPE)                            \
+#define INSTANCE_TYPE_LIST_DEBUGGER(V)                                         \
+  V(DEBUG_INFO_TYPE)                                                           \
   V(BREAK_POINT_INFO_TYPE)
 #else
 #define INSTANCE_TYPE_LIST_DEBUGGER(V)
 #endif
 
-#define INSTANCE_TYPE_LIST(V)                   \
-  INSTANCE_TYPE_LIST_ALL(V)                     \
+#define INSTANCE_TYPE_LIST(V)                                                  \
+  INSTANCE_TYPE_LIST_ALL(V)                                                    \
   INSTANCE_TYPE_LIST_DEBUGGER(V)
 
 
 // Since string types are not consecutive, this macro is used to
 // iterate over them.
 #define STRING_TYPE_LIST(V)                                                    \
-  V(SHORT_SYMBOL_TYPE,                                                         \
+  V(SYMBOL_TYPE,                                                               \
     SeqTwoByteString::kAlignedSize,                                            \
-    short_symbol,                                                              \
-    ShortSymbol)                                                               \
-  V(MEDIUM_SYMBOL_TYPE,                                                        \
+    symbol,                                                                    \
+    Symbol)                                                                    \
+  V(ASCII_SYMBOL_TYPE,                                                         \
+    SeqAsciiString::kAlignedSize,                                              \
+    ascii_symbol,                                                              \
+    AsciiSymbol)                                                               \
+  V(CONS_SYMBOL_TYPE,                                                          \
+    ConsString::kSize,                                                         \
+    cons_symbol,                                                               \
+    ConsSymbol)                                                                \
+  V(CONS_ASCII_SYMBOL_TYPE,                                                    \
+    ConsString::kSize,                                                         \
+    cons_ascii_symbol,                                                         \
+    ConsAsciiSymbol)                                                           \
+  V(EXTERNAL_SYMBOL_TYPE,                                                      \
+    ExternalTwoByteString::kSize,                                              \
+    external_symbol,                                                           \
+    ExternalSymbol)                                                            \
+  V(EXTERNAL_ASCII_SYMBOL_TYPE,                                                \
+    ExternalAsciiString::kSize,                                                \
+    external_ascii_symbol,                                                     \
+    ExternalAsciiSymbol)                                                       \
+  V(STRING_TYPE,                                                               \
     SeqTwoByteString::kAlignedSize,                                            \
-    medium_symbol,                                                             \
-    MediumSymbol)                                                              \
-  V(LONG_SYMBOL_TYPE,                                                          \
-    SeqTwoByteString::kAlignedSize,                                            \
-    long_symbol,                                                               \
-    LongSymbol)                                                                \
-  V(SHORT_ASCII_SYMBOL_TYPE,                                                   \
+    string,                                                                    \
+    String)                                                                    \
+  V(ASCII_STRING_TYPE,                                                         \
     SeqAsciiString::kAlignedSize,                                              \
-    short_ascii_symbol,                                                        \
-    ShortAsciiSymbol)                                                          \
-  V(MEDIUM_ASCII_SYMBOL_TYPE,                                                  \
-    SeqAsciiString::kAlignedSize,                                              \
-    medium_ascii_symbol,                                                       \
-    MediumAsciiSymbol)                                                         \
-  V(LONG_ASCII_SYMBOL_TYPE,                                                    \
-    SeqAsciiString::kAlignedSize,                                              \
-    long_ascii_symbol,                                                         \
-    LongAsciiSymbol)                                                           \
-  V(SHORT_CONS_SYMBOL_TYPE,                                                    \
+    ascii_string,                                                              \
+    AsciiString)                                                               \
+  V(CONS_STRING_TYPE,                                                          \
     ConsString::kSize,                                                         \
-    short_cons_symbol,                                                         \
-    ShortConsSymbol)                                                           \
-  V(MEDIUM_CONS_SYMBOL_TYPE,                                                   \
+    cons_string,                                                               \
+    ConsString)                                                                \
+  V(CONS_ASCII_STRING_TYPE,                                                    \
     ConsString::kSize,                                                         \
-    medium_cons_symbol,                                                        \
-    MediumConsSymbol)                                                          \
-  V(LONG_CONS_SYMBOL_TYPE,                                                     \
-    ConsString::kSize,                                                         \
-    long_cons_symbol,                                                          \
-    LongConsSymbol)                                                            \
-  V(SHORT_CONS_ASCII_SYMBOL_TYPE,                                              \
-    ConsString::kSize,                                                         \
-    short_cons_ascii_symbol,                                                   \
-    ShortConsAsciiSymbol)                                                      \
-  V(MEDIUM_CONS_ASCII_SYMBOL_TYPE,                                             \
-    ConsString::kSize,                                                         \
-    medium_cons_ascii_symbol,                                                  \
-    MediumConsAsciiSymbol)                                                     \
-  V(LONG_CONS_ASCII_SYMBOL_TYPE,                                               \
-    ConsString::kSize,                                                         \
-    long_cons_ascii_symbol,                                                    \
-    LongConsAsciiSymbol)                                                       \
-  V(SHORT_EXTERNAL_SYMBOL_TYPE,                                                \
+    cons_ascii_string,                                                         \
+    ConsAsciiString)                                                           \
+  V(EXTERNAL_STRING_TYPE,                                                      \
     ExternalTwoByteString::kSize,                                              \
-    short_external_symbol,                                                     \
-    ShortExternalSymbol)                                                       \
-  V(MEDIUM_EXTERNAL_SYMBOL_TYPE,                                               \
-    ExternalTwoByteString::kSize,                                              \
-    medium_external_symbol,                                                    \
-    MediumExternalSymbol)                                                      \
-  V(LONG_EXTERNAL_SYMBOL_TYPE,                                                 \
-    ExternalTwoByteString::kSize,                                              \
-    long_external_symbol,                                                      \
-    LongExternalSymbol)                                                        \
-  V(SHORT_EXTERNAL_ASCII_SYMBOL_TYPE,                                          \
+    external_string,                                                           \
+    ExternalString)                                                            \
+  V(EXTERNAL_ASCII_STRING_TYPE,                                                \
     ExternalAsciiString::kSize,                                                \
-    short_external_ascii_symbol,                                               \
-    ShortExternalAsciiSymbol)                                                  \
-  V(MEDIUM_EXTERNAL_ASCII_SYMBOL_TYPE,                                         \
-    ExternalAsciiString::kSize,                                                \
-    medium_external_ascii_symbol,                                              \
-    MediumExternalAsciiSymbol)                                                 \
-  V(LONG_EXTERNAL_ASCII_SYMBOL_TYPE,                                           \
-    ExternalAsciiString::kSize,                                                \
-    long_external_ascii_symbol,                                                \
-    LongExternalAsciiSymbol)                                                   \
-  V(SHORT_STRING_TYPE,                                                         \
-    SeqTwoByteString::kAlignedSize,                                            \
-    short_string,                                                              \
-    ShortString)                                                               \
-  V(MEDIUM_STRING_TYPE,                                                        \
-    SeqTwoByteString::kAlignedSize,                                            \
-    medium_string,                                                             \
-    MediumString)                                                              \
-  V(LONG_STRING_TYPE,                                                          \
-    SeqTwoByteString::kAlignedSize,                                            \
-    long_string,                                                               \
-    LongString)                                                                \
-  V(SHORT_ASCII_STRING_TYPE,                                                   \
-    SeqAsciiString::kAlignedSize,                                              \
-    short_ascii_string,                                                        \
-    ShortAsciiString)                                                          \
-  V(MEDIUM_ASCII_STRING_TYPE,                                                  \
-    SeqAsciiString::kAlignedSize,                                              \
-    medium_ascii_string,                                                       \
-    MediumAsciiString)                                                         \
-  V(LONG_ASCII_STRING_TYPE,                                                    \
-    SeqAsciiString::kAlignedSize,                                              \
-    long_ascii_string,                                                         \
-    LongAsciiString)                                                           \
-  V(SHORT_CONS_STRING_TYPE,                                                    \
-    ConsString::kSize,                                                         \
-    short_cons_string,                                                         \
-    ShortConsString)                                                           \
-  V(MEDIUM_CONS_STRING_TYPE,                                                   \
-    ConsString::kSize,                                                         \
-    medium_cons_string,                                                        \
-    MediumConsString)                                                          \
-  V(LONG_CONS_STRING_TYPE,                                                     \
-    ConsString::kSize,                                                         \
-    long_cons_string,                                                          \
-    LongConsString)                                                            \
-  V(SHORT_CONS_ASCII_STRING_TYPE,                                              \
-    ConsString::kSize,                                                         \
-    short_cons_ascii_string,                                                   \
-    ShortConsAsciiString)                                                      \
-  V(MEDIUM_CONS_ASCII_STRING_TYPE,                                             \
-    ConsString::kSize,                                                         \
-    medium_cons_ascii_string,                                                  \
-    MediumConsAsciiString)                                                     \
-  V(LONG_CONS_ASCII_STRING_TYPE,                                               \
-    ConsString::kSize,                                                         \
-    long_cons_ascii_string,                                                    \
-    LongConsAsciiString)                                                       \
-  V(SHORT_EXTERNAL_STRING_TYPE,                                                \
-    ExternalTwoByteString::kSize,                                              \
-    short_external_string,                                                     \
-    ShortExternalString)                                                       \
-  V(MEDIUM_EXTERNAL_STRING_TYPE,                                               \
-    ExternalTwoByteString::kSize,                                              \
-    medium_external_string,                                                    \
-    MediumExternalString)                                                      \
-  V(LONG_EXTERNAL_STRING_TYPE,                                                 \
-    ExternalTwoByteString::kSize,                                              \
-    long_external_string,                                                      \
-    LongExternalString)                                                        \
-  V(SHORT_EXTERNAL_ASCII_STRING_TYPE,                                          \
-    ExternalAsciiString::kSize,                                                \
-    short_external_ascii_string,                                               \
-    ShortExternalAsciiString)                                                  \
-  V(MEDIUM_EXTERNAL_ASCII_STRING_TYPE,                                         \
-    ExternalAsciiString::kSize,                                                \
-    medium_external_ascii_string,                                              \
-    MediumExternalAsciiString)                                                 \
-  V(LONG_EXTERNAL_ASCII_STRING_TYPE,                                           \
-    ExternalAsciiString::kSize,                                                \
-    long_external_ascii_string,                                                \
-    LongExternalAsciiString)
+    external_ascii_string,                                                     \
+    ExternalAsciiString)                                                       \
 
 // A struct is a simple object a set of object-valued fields.  Including an
 // object type in this causes the compiler to generate most of the boilerplate
@@ -473,27 +353,27 @@
 // Note that for subtle reasons related to the ordering or numerical values of
 // type tags, elements in this list have to be added to the INSTANCE_TYPE_LIST
 // manually.
-#define STRUCT_LIST_ALL(V)                                                \
-  V(ACCESSOR_INFO, AccessorInfo, accessor_info)                           \
-  V(ACCESS_CHECK_INFO, AccessCheckInfo, access_check_info)                \
-  V(INTERCEPTOR_INFO, InterceptorInfo, interceptor_info)                  \
-  V(CALL_HANDLER_INFO, CallHandlerInfo, call_handler_info)                \
-  V(FUNCTION_TEMPLATE_INFO, FunctionTemplateInfo, function_template_info) \
-  V(OBJECT_TEMPLATE_INFO, ObjectTemplateInfo, object_template_info)       \
-  V(SIGNATURE_INFO, SignatureInfo, signature_info)                        \
-  V(TYPE_SWITCH_INFO, TypeSwitchInfo, type_switch_info)                   \
+#define STRUCT_LIST_ALL(V)                                                     \
+  V(ACCESSOR_INFO, AccessorInfo, accessor_info)                                \
+  V(ACCESS_CHECK_INFO, AccessCheckInfo, access_check_info)                     \
+  V(INTERCEPTOR_INFO, InterceptorInfo, interceptor_info)                       \
+  V(CALL_HANDLER_INFO, CallHandlerInfo, call_handler_info)                     \
+  V(FUNCTION_TEMPLATE_INFO, FunctionTemplateInfo, function_template_info)      \
+  V(OBJECT_TEMPLATE_INFO, ObjectTemplateInfo, object_template_info)            \
+  V(SIGNATURE_INFO, SignatureInfo, signature_info)                             \
+  V(TYPE_SWITCH_INFO, TypeSwitchInfo, type_switch_info)                        \
   V(SCRIPT, Script, script)
 
 #ifdef ENABLE_DEBUGGER_SUPPORT
-#define STRUCT_LIST_DEBUGGER(V)                                           \
-  V(DEBUG_INFO, DebugInfo, debug_info)                                    \
+#define STRUCT_LIST_DEBUGGER(V)                                                \
+  V(DEBUG_INFO, DebugInfo, debug_info)                                         \
   V(BREAK_POINT_INFO, BreakPointInfo, break_point_info)
 #else
 #define STRUCT_LIST_DEBUGGER(V)
 #endif
 
-#define STRUCT_LIST(V)                                                    \
-  STRUCT_LIST_ALL(V)                                                      \
+#define STRUCT_LIST(V)                                                         \
+  STRUCT_LIST_ALL(V)                                                           \
   STRUCT_LIST_DEBUGGER(V)
 
 // We use the full 8 bits of the instance_type field to encode heap object
@@ -509,15 +389,6 @@
 const uint32_t kNotSymbolTag = 0x0;
 const uint32_t kSymbolTag = 0x20;
 
-// If bit 7 is clear, bits 3 and 4 are the string's size (short, medium or
-// long).  These values are very special in that they are also used to shift
-// the length field to get the length, removing the hash value.  This avoids
-// using if or switch when getting the length of a string.
-const uint32_t kStringSizeMask = 0x18;
-const uint32_t kShortStringTag = 0x18;
-const uint32_t kMediumStringTag = 0x10;
-const uint32_t kLongStringTag = 0x00;
-
 // If bit 7 is clear then bit 2 indicates whether the string consists of
 // two-byte characters or one-byte characters.
 const uint32_t kStringEncodingMask = 0x4;
@@ -547,60 +418,20 @@
 
 
 enum InstanceType {
-  SHORT_SYMBOL_TYPE = kShortStringTag | kSymbolTag | kSeqStringTag,
-  MEDIUM_SYMBOL_TYPE = kMediumStringTag | kSymbolTag | kSeqStringTag,
-  LONG_SYMBOL_TYPE = kLongStringTag | kSymbolTag | kSeqStringTag,
-  SHORT_ASCII_SYMBOL_TYPE =
-      kShortStringTag | kAsciiStringTag | kSymbolTag | kSeqStringTag,
-  MEDIUM_ASCII_SYMBOL_TYPE =
-      kMediumStringTag | kAsciiStringTag | kSymbolTag | kSeqStringTag,
-  LONG_ASCII_SYMBOL_TYPE =
-      kLongStringTag | kAsciiStringTag | kSymbolTag | kSeqStringTag,
-  SHORT_CONS_SYMBOL_TYPE = kShortStringTag | kSymbolTag | kConsStringTag,
-  MEDIUM_CONS_SYMBOL_TYPE = kMediumStringTag | kSymbolTag | kConsStringTag,
-  LONG_CONS_SYMBOL_TYPE = kLongStringTag | kSymbolTag | kConsStringTag,
-  SHORT_CONS_ASCII_SYMBOL_TYPE =
-      kShortStringTag | kAsciiStringTag | kSymbolTag | kConsStringTag,
-  MEDIUM_CONS_ASCII_SYMBOL_TYPE =
-      kMediumStringTag | kAsciiStringTag | kSymbolTag | kConsStringTag,
-  LONG_CONS_ASCII_SYMBOL_TYPE =
-      kLongStringTag | kAsciiStringTag | kSymbolTag | kConsStringTag,
-  SHORT_EXTERNAL_SYMBOL_TYPE =
-      kShortStringTag | kSymbolTag | kExternalStringTag,
-  MEDIUM_EXTERNAL_SYMBOL_TYPE =
-      kMediumStringTag | kSymbolTag | kExternalStringTag,
-  LONG_EXTERNAL_SYMBOL_TYPE = kLongStringTag | kSymbolTag | kExternalStringTag,
-  SHORT_EXTERNAL_ASCII_SYMBOL_TYPE =
-      kShortStringTag | kAsciiStringTag | kSymbolTag | kExternalStringTag,
-  MEDIUM_EXTERNAL_ASCII_SYMBOL_TYPE =
-      kMediumStringTag | kAsciiStringTag | kSymbolTag | kExternalStringTag,
-  LONG_EXTERNAL_ASCII_SYMBOL_TYPE =
-      kLongStringTag | kAsciiStringTag | kSymbolTag | kExternalStringTag,
-  SHORT_STRING_TYPE = kShortStringTag | kSeqStringTag,
-  MEDIUM_STRING_TYPE = kMediumStringTag | kSeqStringTag,
-  LONG_STRING_TYPE = kLongStringTag | kSeqStringTag,
-  SHORT_ASCII_STRING_TYPE = kShortStringTag | kAsciiStringTag | kSeqStringTag,
-  MEDIUM_ASCII_STRING_TYPE = kMediumStringTag | kAsciiStringTag | kSeqStringTag,
-  LONG_ASCII_STRING_TYPE = kLongStringTag | kAsciiStringTag | kSeqStringTag,
-  SHORT_CONS_STRING_TYPE = kShortStringTag | kConsStringTag,
-  MEDIUM_CONS_STRING_TYPE = kMediumStringTag | kConsStringTag,
-  LONG_CONS_STRING_TYPE = kLongStringTag | kConsStringTag,
-  SHORT_CONS_ASCII_STRING_TYPE =
-      kShortStringTag | kAsciiStringTag | kConsStringTag,
-  MEDIUM_CONS_ASCII_STRING_TYPE =
-      kMediumStringTag | kAsciiStringTag | kConsStringTag,
-  LONG_CONS_ASCII_STRING_TYPE =
-      kLongStringTag | kAsciiStringTag | kConsStringTag,
-  SHORT_EXTERNAL_STRING_TYPE = kShortStringTag | kExternalStringTag,
-  MEDIUM_EXTERNAL_STRING_TYPE = kMediumStringTag | kExternalStringTag,
-  LONG_EXTERNAL_STRING_TYPE = kLongStringTag | kExternalStringTag,
-  SHORT_EXTERNAL_ASCII_STRING_TYPE =
-      kShortStringTag | kAsciiStringTag | kExternalStringTag,
-  MEDIUM_EXTERNAL_ASCII_STRING_TYPE =
-      kMediumStringTag | kAsciiStringTag | kExternalStringTag,
-  LONG_EXTERNAL_ASCII_STRING_TYPE =
-      kLongStringTag | kAsciiStringTag | kExternalStringTag,
-  LONG_PRIVATE_EXTERNAL_ASCII_STRING_TYPE = LONG_EXTERNAL_ASCII_STRING_TYPE,
+  SYMBOL_TYPE = kSymbolTag | kSeqStringTag,
+  ASCII_SYMBOL_TYPE = kAsciiStringTag | kSymbolTag | kSeqStringTag,
+  CONS_SYMBOL_TYPE = kSymbolTag | kConsStringTag,
+  CONS_ASCII_SYMBOL_TYPE = kAsciiStringTag | kSymbolTag | kConsStringTag,
+  EXTERNAL_SYMBOL_TYPE = kSymbolTag | kExternalStringTag,
+  EXTERNAL_ASCII_SYMBOL_TYPE =
+      kAsciiStringTag | kSymbolTag | kExternalStringTag,
+  STRING_TYPE = kSeqStringTag,
+  ASCII_STRING_TYPE = kAsciiStringTag | kSeqStringTag,
+  CONS_STRING_TYPE = kConsStringTag,
+  CONS_ASCII_STRING_TYPE = kAsciiStringTag | kConsStringTag,
+  EXTERNAL_STRING_TYPE = kExternalStringTag,
+  EXTERNAL_ASCII_STRING_TYPE = kAsciiStringTag | kExternalStringTag,
+  PRIVATE_EXTERNAL_ASCII_STRING_TYPE = EXTERNAL_ASCII_STRING_TYPE,
 
   MAP_TYPE = kNotStringTag,
   HEAP_NUMBER_TYPE,
@@ -999,16 +830,6 @@
   // View this map word as a forwarding address.
   inline HeapObject* ToForwardingAddress();
 
-  // True if this map word is a serialization address.  This will only be the
-  // case during a destructive serialization of the heap.
-  inline bool IsSerializationAddress();
-
-  // Create a map word from a serialization address.
-  static inline MapWord FromSerializationAddress(int raw);
-
-  // View this map word as a serialization address.
-  inline int ToSerializationAddress();
-
   // Marking phase of full collection: the map word of live objects is
   // marked, and may be marked as overflowed (eg, the object is live, its
   // children have not been visited, and it does not fit in the marking
@@ -3899,12 +3720,9 @@
   inline int length();
   inline void set_length(int value);
 
-  // Get and set the uninterpreted length field of the string.  Notice
-  // that the length field is also used to cache the hash value of
-  // strings.  In order to get or set the actual length of the string
-  // use the length() and set_length methods.
-  inline uint32_t length_field();
-  inline void set_length_field(uint32_t value);
+  // Get and set the hash field of the string.
+  inline uint32_t hash_field();
+  inline void set_hash_field(uint32_t value);
 
   inline bool IsAsciiRepresentation();
   inline bool IsTwoByteRepresentation();
@@ -3975,8 +3793,8 @@
   // Returns a hash value used for the property table
   inline uint32_t Hash();
 
-  static uint32_t ComputeLengthAndHashField(unibrow::CharacterStream* buffer,
-                                            int length);
+  static uint32_t ComputeHashField(unibrow::CharacterStream* buffer,
+                                   int length);
 
   static bool ComputeArrayIndex(unibrow::CharacterStream* buffer,
                                 uint32_t* index,
@@ -4007,7 +3825,8 @@
 
   // Layout description.
   static const int kLengthOffset = HeapObject::kHeaderSize;
-  static const int kSize = kLengthOffset + kIntSize;
+  static const int kHashFieldOffset = kLengthOffset + kIntSize;
+  static const int kSize = kHashFieldOffset + kIntSize;
   // Notice: kSize is not pointer-size aligned if pointers are 64-bit.
 
   // Maximum number of characters to consider when trying to convert a string
@@ -4031,22 +3850,30 @@
   static const int kIsArrayIndexMask = 1 << 1;
   static const int kNofLengthBitFields = 2;
 
+  // Shift constant retrieving hash code from hash field.
+  static const int kHashShift = kNofLengthBitFields;
+
   // Array index strings this short can keep their index in the hash
   // field.
   static const int kMaxCachedArrayIndexLength = 7;
 
-  // Shift constants for retrieving length and hash code from
-  // length/hash field.
-  static const int kHashShift = kNofLengthBitFields;
-  static const int kShortLengthShift = kHashShift + kShortStringTag;
-  static const int kMediumLengthShift = kHashShift + kMediumStringTag;
-  static const int kLongLengthShift = kHashShift + kLongStringTag;
+  // For strings which are array indexes the hash value has the string length
+  // mixed into the hash, mainly to avoid a hash value of zero which would be
+  // the case for the string '0'. 24 bits are used for the array index value.
+  static const int kArrayIndexHashLengthShift = 24 + kNofLengthBitFields;
+  static const int kArrayIndexHashMask = (1 << kArrayIndexHashLengthShift) - 1;
+  static const int kArrayIndexValueBits =
+      kArrayIndexHashLengthShift - kHashShift;
 
-  // Maximal string length that can be stored in the hash/length field for
-  // different types of strings.
-  static const int kMaxShortSize = (1 << (32 - kShortLengthShift)) - 1;
-  static const int kMaxMediumSize = (1 << (32 - kMediumLengthShift)) - 1;
-  static const int kMaxLength = (1 << (32 - kLongLengthShift)) - 1;
+  // Value of empty hash field indicating that the hash is not computed.
+  static const int kEmptyHashField = 0;
+
+  // Maximal string length.
+  static const int kMaxLength = (1 << (32 - 2)) - 1;
+
+  // Max length for computing hash. For strings longer than this limit the
+  // string length is used as the hash value.
+  static const int kMaxHashCalcLength = 16383;
 
   // Limit for truncation in short printing.
   static const int kMaxShortPrintLength = 1024;
@@ -4328,9 +4155,6 @@
                                                      unsigned* offset,
                                                      unsigned chars);
 
-  // Identify the map for the external string/symbol with a particular length.
-  static inline Map* StringMap(int length);
-  static inline Map* SymbolMap(int length);
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalAsciiString);
 };
@@ -4363,9 +4187,6 @@
                                                 unsigned* offset_ptr,
                                                 unsigned chars);
 
-  // Identify the map for the external string/symbol with a particular length.
-  static inline Map* StringMap(int length);
-  static inline Map* SymbolMap(int length);
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalTwoByteString);
 };
diff --git a/src/platform-freebsd.cc b/src/platform-freebsd.cc
index 9b452fa..353d165 100644
--- a/src/platform-freebsd.cc
+++ b/src/platform-freebsd.cc
@@ -89,11 +89,6 @@
 }
 
 
-double OS::nan_value() {
-  return NAN;
-}
-
-
 int OS::ActivationFrameAlignment() {
   // 16 byte alignment on FreeBSD
   return 16;
diff --git a/src/platform-linux.cc b/src/platform-linux.cc
index 9ce0be0..bfcd8fb 100644
--- a/src/platform-linux.cc
+++ b/src/platform-linux.cc
@@ -95,11 +95,6 @@
 }
 
 
-double OS::nan_value() {
-  return NAN;
-}
-
-
 #ifdef __arm__
 bool OS::ArmCpuHasFeature(CpuFeature feature) {
   const char* search_string = NULL;
diff --git a/src/platform-macos.cc b/src/platform-macos.cc
index d79cff1..0d5be45 100644
--- a/src/platform-macos.cc
+++ b/src/platform-macos.cc
@@ -252,11 +252,6 @@
 }
 
 
-double OS::nan_value() {
-  return NAN;
-}
-
-
 int OS::ActivationFrameAlignment() {
   // OS X activation frames must be 16 byte-aligned; see "Mac OS X ABI
   // Function Call Guide".
diff --git a/src/platform-openbsd.cc b/src/platform-openbsd.cc
new file mode 100644
index 0000000..6d27304
--- /dev/null
+++ b/src/platform-openbsd.cc
@@ -0,0 +1,597 @@
+// Copyright 2006-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.
+
+// Platform specific code for OpenBSD goes here. For the POSIX comaptible parts
+// the implementation is in platform-posix.cc.
+
+#include <pthread.h>
+#include <semaphore.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/types.h>
+#include <stdlib.h>
+
+#include <sys/types.h>  // mmap & munmap
+#include <sys/mman.h>   // mmap & munmap
+#include <sys/stat.h>   // open
+#include <sys/fcntl.h>  // open
+#include <unistd.h>     // getpagesize
+#include <execinfo.h>   // backtrace, backtrace_symbols
+#include <strings.h>    // index
+#include <errno.h>
+#include <stdarg.h>
+#include <limits.h>
+
+#undef MAP_TYPE
+
+#include "v8.h"
+
+#include "platform.h"
+
+
+namespace v8 {
+namespace internal {
+
+// 0 is never a valid thread id on OpenBSD since tids and pids share a
+// name space and pid 0 is used to kill the group (see man 2 kill).
+static const pthread_t kNoThread = (pthread_t) 0;
+
+
+double ceiling(double x) {
+    // Correct as on OS X
+    if (-1.0 < x && x < 0.0) {
+        return -0.0;
+    } else {
+        return ceil(x);
+    }
+}
+
+
+void OS::Setup() {
+  // Seed the random number generator.
+  // Convert the current time to a 64-bit integer first, before converting it
+  // to an unsigned. Going directly can cause an overflow and the seed to be
+  // set to all ones. The seed will be identical for different instances that
+  // call this setup code within the same millisecond.
+  uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
+  srandom(static_cast<unsigned int>(seed));
+}
+
+
+uint64_t OS::CpuFeaturesImpliedByPlatform() {
+  return 0;  // OpenBSD runs on anything.
+}
+
+
+int OS::ActivationFrameAlignment() {
+  // 16 byte alignment on OpenBSD
+  return 16;
+}
+
+
+// We keep the lowest and highest addresses mapped as a quick way of
+// determining that pointers are outside the heap (used mostly in assertions
+// and verification).  The estimate is conservative, ie, not all addresses in
+// 'allocated' space are actually allocated to our heap.  The range is
+// [lowest, highest), inclusive on the low and and exclusive on the high end.
+static void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
+static void* highest_ever_allocated = reinterpret_cast<void*>(0);
+
+
+static void UpdateAllocatedSpaceLimits(void* address, int size) {
+  lowest_ever_allocated = Min(lowest_ever_allocated, address);
+  highest_ever_allocated =
+      Max(highest_ever_allocated,
+          reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
+}
+
+
+bool OS::IsOutsideAllocatedSpace(void* address) {
+  return address < lowest_ever_allocated || address >= highest_ever_allocated;
+}
+
+
+size_t OS::AllocateAlignment() {
+  return getpagesize();
+}
+
+
+void* OS::Allocate(const size_t requested,
+                   size_t* allocated,
+                   bool executable) {
+  const size_t msize = RoundUp(requested, getpagesize());
+  int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
+  void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
+
+  if (mbase == MAP_FAILED) {
+    LOG(StringEvent("OS::Allocate", "mmap failed"));
+    return NULL;
+  }
+  *allocated = msize;
+  UpdateAllocatedSpaceLimits(mbase, msize);
+  return mbase;
+}
+
+
+void OS::Free(void* buf, const size_t length) {
+  int result = munmap(buf, length);
+  USE(result);
+  ASSERT(result == 0);
+}
+
+
+#ifdef ENABLE_HEAP_PROTECTION
+
+void OS::Protect(void* address, size_t size) {
+  UNIMPLEMENTED();
+}
+
+
+void OS::Unprotect(void* address, size_t size, bool is_executable) {
+  UNIMPLEMENTED();
+}
+
+#endif
+
+
+void OS::Sleep(int milliseconds) {
+  unsigned int ms = static_cast<unsigned int>(milliseconds);
+  usleep(1000 * ms);
+}
+
+
+void OS::Abort() {
+  // Redirect to std abort to signal abnormal program termination.
+  abort();
+}
+
+
+void OS::DebugBreak() {
+#if defined(__arm__) || defined(__thumb__)
+  asm("bkpt 0");
+#else
+  asm("int $3");
+#endif
+}
+
+
+class PosixMemoryMappedFile : public OS::MemoryMappedFile {
+ public:
+  PosixMemoryMappedFile(FILE* file, void* memory, int size)
+    : file_(file), memory_(memory), size_(size) { }
+  virtual ~PosixMemoryMappedFile();
+  virtual void* memory() { return memory_; }
+ private:
+  FILE* file_;
+  void* memory_;
+  int size_;
+};
+
+
+OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
+    void* initial) {
+  FILE* file = fopen(name, "w+");
+  if (file == NULL) return NULL;
+  int result = fwrite(initial, size, 1, file);
+  if (result < 1) {
+    fclose(file);
+    return NULL;
+  }
+  void* memory =
+      mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
+  return new PosixMemoryMappedFile(file, memory, size);
+}
+
+
+PosixMemoryMappedFile::~PosixMemoryMappedFile() {
+  if (memory_) munmap(memory_, size_);
+  fclose(file_);
+}
+
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+static unsigned StringToLong(char* buffer) {
+  return static_cast<unsigned>(strtol(buffer, NULL, 16));  // NOLINT
+}
+#endif
+
+
+void OS::LogSharedLibraryAddresses() {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  static const int MAP_LENGTH = 1024;
+  int fd = open("/proc/self/maps", O_RDONLY);
+  if (fd < 0) return;
+  while (true) {
+    char addr_buffer[11];
+    addr_buffer[0] = '0';
+    addr_buffer[1] = 'x';
+    addr_buffer[10] = 0;
+    int result = read(fd, addr_buffer + 2, 8);
+    if (result < 8) break;
+    unsigned start = StringToLong(addr_buffer);
+    result = read(fd, addr_buffer + 2, 1);
+    if (result < 1) break;
+    if (addr_buffer[2] != '-') break;
+    result = read(fd, addr_buffer + 2, 8);
+    if (result < 8) break;
+    unsigned end = StringToLong(addr_buffer);
+    char buffer[MAP_LENGTH];
+    int bytes_read = -1;
+    do {
+      bytes_read++;
+      if (bytes_read >= MAP_LENGTH - 1)
+        break;
+      result = read(fd, buffer + bytes_read, 1);
+      if (result < 1) break;
+    } while (buffer[bytes_read] != '\n');
+    buffer[bytes_read] = 0;
+    // Ignore mappings that are not executable.
+    if (buffer[3] != 'x') continue;
+    char* start_of_path = index(buffer, '/');
+    // There may be no filename in this line.  Skip to next.
+    if (start_of_path == NULL) continue;
+    buffer[bytes_read] = 0;
+    LOG(SharedLibraryEvent(start_of_path, start, end));
+  }
+  close(fd);
+#endif
+}
+
+
+int OS::StackWalk(Vector<OS::StackFrame> frames) {
+  UNIMPLEMENTED();
+  return 1;
+}
+
+
+// Constants used for mmap.
+static const int kMmapFd = -1;
+static const int kMmapFdOffset = 0;
+
+
+VirtualMemory::VirtualMemory(size_t size) {
+  address_ = mmap(NULL, size, PROT_NONE,
+                  MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
+                  kMmapFd, kMmapFdOffset);
+  size_ = size;
+}
+
+
+VirtualMemory::~VirtualMemory() {
+  if (IsReserved()) {
+    if (0 == munmap(address(), size())) address_ = MAP_FAILED;
+  }
+}
+
+
+bool VirtualMemory::IsReserved() {
+  return address_ != MAP_FAILED;
+}
+
+
+bool VirtualMemory::Commit(void* address, size_t size, bool executable) {
+  int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
+  if (MAP_FAILED == mmap(address, size, prot,
+                         MAP_PRIVATE | MAP_ANON | MAP_FIXED,
+                         kMmapFd, kMmapFdOffset)) {
+    return false;
+  }
+
+  UpdateAllocatedSpaceLimits(address, size);
+  return true;
+}
+
+
+bool VirtualMemory::Uncommit(void* address, size_t size) {
+  return mmap(address, size, PROT_NONE,
+              MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
+              kMmapFd, kMmapFdOffset) != MAP_FAILED;
+}
+
+
+class ThreadHandle::PlatformData : public Malloced {
+ public:
+  explicit PlatformData(ThreadHandle::Kind kind) {
+    Initialize(kind);
+  }
+
+  void Initialize(ThreadHandle::Kind kind) {
+    switch (kind) {
+      case ThreadHandle::SELF: thread_ = pthread_self(); break;
+      case ThreadHandle::INVALID: thread_ = kNoThread; break;
+    }
+  }
+  pthread_t thread_;  // Thread handle for pthread.
+};
+
+
+ThreadHandle::ThreadHandle(Kind kind) {
+  data_ = new PlatformData(kind);
+}
+
+
+void ThreadHandle::Initialize(ThreadHandle::Kind kind) {
+  data_->Initialize(kind);
+}
+
+
+ThreadHandle::~ThreadHandle() {
+  delete data_;
+}
+
+
+bool ThreadHandle::IsSelf() const {
+  return pthread_equal(data_->thread_, pthread_self());
+}
+
+
+bool ThreadHandle::IsValid() const {
+  return data_->thread_ != kNoThread;
+}
+
+
+Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) {
+}
+
+
+Thread::~Thread() {
+}
+
+
+static void* ThreadEntry(void* arg) {
+  Thread* thread = reinterpret_cast<Thread*>(arg);
+  // This is also initialized by the first argument to pthread_create() but we
+  // don't know which thread will run first (the original thread or the new
+  // one) so we initialize it here too.
+  thread->thread_handle_data()->thread_ = pthread_self();
+  ASSERT(thread->IsValid());
+  thread->Run();
+  return NULL;
+}
+
+
+void Thread::Start() {
+  pthread_create(&thread_handle_data()->thread_, NULL, ThreadEntry, this);
+  ASSERT(IsValid());
+}
+
+
+void Thread::Join() {
+  pthread_join(thread_handle_data()->thread_, NULL);
+}
+
+
+Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
+  pthread_key_t key;
+  int result = pthread_key_create(&key, NULL);
+  USE(result);
+  ASSERT(result == 0);
+  return static_cast<LocalStorageKey>(key);
+}
+
+
+void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
+  pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
+  int result = pthread_key_delete(pthread_key);
+  USE(result);
+  ASSERT(result == 0);
+}
+
+
+void* Thread::GetThreadLocal(LocalStorageKey key) {
+  pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
+  return pthread_getspecific(pthread_key);
+}
+
+
+void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
+  pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
+  pthread_setspecific(pthread_key, value);
+}
+
+
+void Thread::YieldCPU() {
+  sched_yield();
+}
+
+
+class OpenBSDMutex : public Mutex {
+ public:
+
+  OpenBSDMutex() {
+    pthread_mutexattr_t attrs;
+    int result = pthread_mutexattr_init(&attrs);
+    ASSERT(result == 0);
+    result = pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_RECURSIVE);
+    ASSERT(result == 0);
+    result = pthread_mutex_init(&mutex_, &attrs);
+    ASSERT(result == 0);
+  }
+
+  virtual ~OpenBSDMutex() { pthread_mutex_destroy(&mutex_); }
+
+  virtual int Lock() {
+    int result = pthread_mutex_lock(&mutex_);
+    return result;
+  }
+
+  virtual int Unlock() {
+    int result = pthread_mutex_unlock(&mutex_);
+    return result;
+  }
+
+ private:
+  pthread_mutex_t mutex_;   // Pthread mutex for POSIX platforms.
+};
+
+
+Mutex* OS::CreateMutex() {
+  return new OpenBSDMutex();
+}
+
+
+class OpenBSDSemaphore : public Semaphore {
+ public:
+  explicit OpenBSDSemaphore(int count) {  sem_init(&sem_, 0, count); }
+  virtual ~OpenBSDSemaphore() { sem_destroy(&sem_); }
+
+  virtual void Wait();
+  virtual bool Wait(int timeout);
+  virtual void Signal() { sem_post(&sem_); }
+ private:
+  sem_t sem_;
+};
+
+
+void OpenBSDSemaphore::Wait() {
+  while (true) {
+    int result = sem_wait(&sem_);
+    if (result == 0) return;  // Successfully got semaphore.
+    CHECK(result == -1 && errno == EINTR);  // Signal caused spurious wakeup.
+  }
+}
+
+
+bool OpenBSDSemaphore::Wait(int timeout) {
+  const long kOneSecondMicros = 1000000;  // NOLINT
+
+  // Split timeout into second and nanosecond parts.
+  struct timeval delta;
+  delta.tv_usec = timeout % kOneSecondMicros;
+  delta.tv_sec = timeout / kOneSecondMicros;
+
+  struct timeval current_time;
+  // Get the current time.
+  if (gettimeofday(&current_time, NULL) == -1) {
+    return false;
+  }
+
+  // Calculate time for end of timeout.
+  struct timeval end_time;
+  timeradd(&current_time, &delta, &end_time);
+
+  struct timespec ts;
+  TIMEVAL_TO_TIMESPEC(&end_time, &ts);
+  while (true) {
+    int result = sem_trywait(&sem_);
+    if (result == 0) return true;  // Successfully got semaphore.
+    if (result == -1 && errno == ETIMEDOUT) return false;  // Timeout.
+    CHECK(result == -1 && errno == EINTR);  // Signal caused spurious wakeup.
+  }
+}
+
+
+Semaphore* OS::CreateSemaphore(int count) {
+  return new OpenBSDSemaphore(count);
+}
+
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+
+static Sampler* active_sampler_ = NULL;
+
+static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
+  USE(info);
+  if (signal != SIGPROF) return;
+  if (active_sampler_ == NULL) return;
+
+  TickSample sample;
+
+  // We always sample the VM state.
+  sample.state = Logger::state();
+
+  active_sampler_->Tick(&sample);
+}
+
+
+class Sampler::PlatformData : public Malloced {
+ public:
+  PlatformData() {
+    signal_handler_installed_ = false;
+  }
+
+  bool signal_handler_installed_;
+  struct sigaction old_signal_handler_;
+  struct itimerval old_timer_value_;
+};
+
+
+Sampler::Sampler(int interval, bool profiling)
+    : interval_(interval), profiling_(profiling), active_(false) {
+  data_ = new PlatformData();
+}
+
+
+Sampler::~Sampler() {
+  delete data_;
+}
+
+
+void Sampler::Start() {
+  // There can only be one active sampler at the time on POSIX
+  // platforms.
+  if (active_sampler_ != NULL) return;
+
+  // Request profiling signals.
+  struct sigaction sa;
+  sa.sa_sigaction = ProfilerSignalHandler;
+  sigemptyset(&sa.sa_mask);
+  sa.sa_flags = SA_SIGINFO;
+  if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0) return;
+  data_->signal_handler_installed_ = true;
+
+  // Set the itimer to generate a tick for each interval.
+  itimerval itimer;
+  itimer.it_interval.tv_sec = interval_ / 1000;
+  itimer.it_interval.tv_usec = (interval_ % 1000) * 1000;
+  itimer.it_value.tv_sec = itimer.it_interval.tv_sec;
+  itimer.it_value.tv_usec = itimer.it_interval.tv_usec;
+  setitimer(ITIMER_PROF, &itimer, &data_->old_timer_value_);
+
+  // Set this sampler as the active sampler.
+  active_sampler_ = this;
+  active_ = true;
+}
+
+
+void Sampler::Stop() {
+  // Restore old signal handler
+  if (data_->signal_handler_installed_) {
+    setitimer(ITIMER_PROF, &data_->old_timer_value_, NULL);
+    sigaction(SIGPROF, &data_->old_signal_handler_, 0);
+    data_->signal_handler_installed_ = false;
+  }
+
+  // This sampler is no longer the active sampler.
+  active_sampler_ = NULL;
+  active_ = false;
+}
+
+#endif  // ENABLE_LOGGING_AND_PROFILING
+
+} }  // namespace v8::internal
diff --git a/src/platform-posix.cc b/src/platform-posix.cc
index 1e1245c..41e0e64 100644
--- a/src/platform-posix.cc
+++ b/src/platform-posix.cc
@@ -27,7 +27,7 @@
 
 // Platform specific code for POSIX goes here. This is not a platform on its
 // own but contains the parts which are the same across POSIX platforms Linux,
-// Mac OS and FreeBSD.
+// Mac OS, FreeBSD and OpenBSD.
 
 #include <unistd.h>
 #include <errno.h>
@@ -61,6 +61,13 @@
   return fmod(x, y);
 }
 
+
+double OS::nan_value() {
+  // NAN from math.h is defined in C99 and not in POSIX.
+  return NAN;
+}
+
+
 // ----------------------------------------------------------------------------
 // POSIX date/time support.
 //
diff --git a/src/runtime.cc b/src/runtime.cc
index 6ae2233..65dfd13 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -788,51 +788,72 @@
   // case of callbacks in the prototype chain (this rules out using
   // SetProperty).  We have IgnoreAttributesAndSetLocalProperty for
   // this.
+  // Note that objects can have hidden prototypes, so we need to traverse
+  // the whole chain of hidden prototypes to do a 'local' lookup.
+  JSObject* real_holder = global;
   LookupResult lookup;
-  global->LocalLookup(*name, &lookup);
-  if (!lookup.IsProperty()) {
-    if (assign) {
-      return global->IgnoreAttributesAndSetLocalProperty(*name,
-                                                         args[1],
-                                                         attributes);
+  while (true) {
+    real_holder->LocalLookup(*name, &lookup);
+    if (lookup.IsProperty()) {
+      // Determine if this is a redeclaration of something read-only.
+      if (lookup.IsReadOnly()) {
+        // If we found readonly property on one of hidden prototypes,
+        // just shadow it.
+        if (real_holder != Top::context()->global()) break;
+        return ThrowRedeclarationError("const", name);
+      }
+
+      // Determine if this is a redeclaration of an intercepted read-only
+      // property and figure out if the property exists at all.
+      bool found = true;
+      PropertyType type = lookup.type();
+      if (type == INTERCEPTOR) {
+        HandleScope handle_scope;
+        Handle<JSObject> holder(real_holder);
+        PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
+        real_holder = *holder;
+        if (intercepted == ABSENT) {
+          // The interceptor claims the property isn't there. We need to
+          // make sure to introduce it.
+          found = false;
+        } else if ((intercepted & READ_ONLY) != 0) {
+          // The property is present, but read-only. Since we're trying to
+          // overwrite it with a variable declaration we must throw a
+          // re-declaration error.  However if we found readonly property
+          // on one of hidden prototypes, just shadow it.
+          if (real_holder != Top::context()->global()) break;
+          return ThrowRedeclarationError("const", name);
+        }
+      }
+
+      if (found && !assign) {
+        // The global property is there and we're not assigning any value
+        // to it. Just return.
+        return Heap::undefined_value();
+      }
+
+      // Assign the value (or undefined) to the property.
+      Object* value = (assign) ? args[1] : Heap::undefined_value();
+      return real_holder->SetProperty(&lookup, *name, value, attributes);
     }
-    return Heap::undefined_value();
+
+    Object* proto = real_holder->GetPrototype();
+    if (!proto->IsJSObject())
+      break;
+
+    if (!JSObject::cast(proto)->map()->is_hidden_prototype())
+      break;
+
+    real_holder = JSObject::cast(proto);
   }
 
-  // Determine if this is a redeclaration of something read-only.
-  if (lookup.IsReadOnly()) {
-    return ThrowRedeclarationError("const", name);
+  global = Top::context()->global();
+  if (assign) {
+    return global->IgnoreAttributesAndSetLocalProperty(*name,
+                                                       args[1],
+                                                       attributes);
   }
-
-  // Determine if this is a redeclaration of an intercepted read-only
-  // property and figure out if the property exists at all.
-  bool found = true;
-  PropertyType type = lookup.type();
-  if (type == INTERCEPTOR) {
-    PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
-    if (intercepted == ABSENT) {
-      // The interceptor claims the property isn't there. We need to
-      // make sure to introduce it.
-      found = false;
-    } else if ((intercepted & READ_ONLY) != 0) {
-      // The property is present, but read-only. Since we're trying to
-      // overwrite it with a variable declaration we must throw a
-      // re-declaration error.
-      return ThrowRedeclarationError("const", name);
-    }
-    // Restore global object from context (in case of GC).
-    global = Top::context()->global();
-  }
-
-  if (found && !assign) {
-    // The global property is there and we're not assigning any value
-    // to it. Just return.
-    return Heap::undefined_value();
-  }
-
-  // Assign the value (or undefined) to the property.
-  Object* value = (assign) ? args[1] : Heap::undefined_value();
-  return global->SetProperty(&lookup, *name, value, attributes);
+  return Heap::undefined_value();
 }
 
 
@@ -3762,6 +3783,7 @@
   ASSERT(args.length() == 2);
   CONVERT_CHECKED(String, str1, args[0]);
   CONVERT_CHECKED(String, str2, args[1]);
+  Counters::string_add_runtime.Increment();
   return Heap::AllocateConsString(str1, str2);
 }
 
@@ -4987,6 +5009,9 @@
     PrintF("DebugPrint: ");
   }
   args[0]->Print();
+  if (args[0]->IsHeapObject()) {
+    HeapObject::cast(args[0])->map()->Print();
+  }
 #else
   // ShortPrint is available in release mode. Print is not.
   args[0]->ShortPrint();
@@ -7667,8 +7692,31 @@
   CONVERT_CHECKED(JSFunction, f, args[0]);
   return f->shared()->inferred_name();
 }
+
 #endif  // ENABLE_DEBUGGER_SUPPORT
 
+#ifdef ENABLE_LOGGING_AND_PROFILING
+
+static Object* Runtime_ProfilerResume(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  CONVERT_CHECKED(Smi, smi_modules, args[0]);
+  v8::V8::ResumeProfilerEx(smi_modules->value());
+  return Heap::undefined_value();
+}
+
+
+static Object* Runtime_ProfilerPause(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  CONVERT_CHECKED(Smi, smi_modules, args[0]);
+  v8::V8::PauseProfilerEx(smi_modules->value());
+  return Heap::undefined_value();
+}
+
+#endif  // ENABLE_LOGGING_AND_PROFILING
 
 // Finds the script object from the script data. NOTE: This operation uses
 // heap traversal to find the function generated for the source position
diff --git a/src/runtime.h b/src/runtime.h
index c05ae6b..8580233 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -318,6 +318,14 @@
 #define RUNTIME_FUNCTION_LIST_DEBUGGER_SUPPORT(F)
 #endif
 
+#ifdef ENABLE_LOGGING_AND_PROFILING
+#define RUNTIME_FUNCTION_LIST_PROFILER_SUPPORT(F) \
+  F(ProfilerResume, 1, 1) \
+  F(ProfilerPause, 1, 1)
+#else
+#define RUNTIME_FUNCTION_LIST_PROFILER_SUPPORT(F)
+#endif
+
 #ifdef DEBUG
 #define RUNTIME_FUNCTION_LIST_DEBUG(F) \
   /* Testing */ \
@@ -336,7 +344,8 @@
   RUNTIME_FUNCTION_LIST_ALWAYS_1(F) \
   RUNTIME_FUNCTION_LIST_ALWAYS_2(F) \
   RUNTIME_FUNCTION_LIST_DEBUG(F) \
-  RUNTIME_FUNCTION_LIST_DEBUGGER_SUPPORT(F)
+  RUNTIME_FUNCTION_LIST_DEBUGGER_SUPPORT(F) \
+  RUNTIME_FUNCTION_LIST_PROFILER_SUPPORT(F)
 
 // ----------------------------------------------------------------------------
 // Runtime provides access to all C++ runtime functions.
diff --git a/src/runtime.js b/src/runtime.js
index ba19871..105749a 100644
--- a/src/runtime.js
+++ b/src/runtime.js
@@ -146,16 +146,16 @@
 function ADD(x) {
   // Fast case: Check for number operands and do the addition.
   if (IS_NUMBER(this) && IS_NUMBER(x)) return %NumberAdd(this, x);
-  if (IS_STRING(this) && IS_STRING(x)) return %StringAdd(this, x);
+  if (IS_STRING(this) && IS_STRING(x)) return %_StringAdd(this, x);
 
   // Default implementation.
   var a = %ToPrimitive(this, NO_HINT);
   var b = %ToPrimitive(x, NO_HINT);
 
   if (IS_STRING(a)) {
-    return %StringAdd(a, %ToString(b));
+    return %_StringAdd(a, %ToString(b));
   } else if (IS_STRING(b)) {
-    return %StringAdd(%ToString(a), b);
+    return %_StringAdd(%ToString(a), b);
   } else {
     return %NumberAdd(%ToNumber(a), %ToNumber(b));
   }
@@ -173,7 +173,7 @@
           : %ToString(%ToPrimitive(y, NO_HINT));
     }
   }
-  return %StringAdd(this, y);
+  return %_StringAdd(this, y);
 }
 
 
@@ -189,7 +189,7 @@
           : %ToString(%ToPrimitive(x, NO_HINT));
     }
   }
-  return %StringAdd(x, y);
+  return %_StringAdd(x, y);
 }
 
 
diff --git a/src/serialize.cc b/src/serialize.cc
index 00cd69e..899e2e7 100644
--- a/src/serialize.cc
+++ b/src/serialize.cc
@@ -44,6 +44,69 @@
 namespace v8 {
 namespace internal {
 
+// Mapping objects to their location after deserialization.
+// This is used during building, but not at runtime by V8.
+class SerializationAddressMapper {
+ public:
+  static bool IsMapped(HeapObject* obj) {
+    EnsureMapExists();
+    return serialization_map_->Lookup(Key(obj), Hash(obj), false) != NULL;
+  }
+
+  static int MappedTo(HeapObject* obj) {
+    ASSERT(IsMapped(obj));
+    return reinterpret_cast<intptr_t>(serialization_map_->Lookup(Key(obj),
+                                      Hash(obj),
+                                      false)->value);
+  }
+
+  static void Map(HeapObject* obj, int to) {
+    EnsureMapExists();
+    ASSERT(!IsMapped(obj));
+    HashMap::Entry* entry =
+        serialization_map_->Lookup(Key(obj), Hash(obj), true);
+    entry->value = Value(to);
+  }
+
+  static void Zap() {
+    if (serialization_map_ != NULL) {
+      delete serialization_map_;
+    }
+    serialization_map_ = NULL;
+  }
+
+ private:
+  static bool SerializationMatchFun(void* key1, void* key2) {
+    return key1 == key2;
+  }
+
+  static uint32_t Hash(HeapObject* obj) {
+    return reinterpret_cast<intptr_t>(obj->address());
+  }
+
+  static void* Key(HeapObject* obj) {
+    return reinterpret_cast<void*>(obj->address());
+  }
+
+  static void* Value(int v) {
+    return reinterpret_cast<void*>(v);
+  }
+
+  static void EnsureMapExists() {
+    if (serialization_map_ == NULL) {
+      serialization_map_ = new HashMap(&SerializationMatchFun);
+    }
+  }
+
+  static HashMap* serialization_map_;
+};
+
+
+HashMap* SerializationAddressMapper::serialization_map_ = NULL;
+
+
+
+
 // -----------------------------------------------------------------------------
 // Coding of external references.
 
@@ -871,6 +934,7 @@
   Heap::IterateRoots(this, VISIT_ONLY_STRONG);
   delete external_reference_encoder_;
   external_reference_encoder_ = NULL;
+  SerializationAddressMapper::Zap();
 }
 
 
@@ -894,10 +958,9 @@
     ReferenceRepresentation reference_representation) {
   CHECK(o->IsHeapObject());
   HeapObject* heap_object = HeapObject::cast(o);
-  MapWord map_word = heap_object->map_word();
-  if (map_word.IsSerializationAddress()) {
+  if (SerializationAddressMapper::IsMapped(heap_object)) {
     int space = SpaceOfAlreadySerializedObject(heap_object);
-    int address = map_word.ToSerializationAddress();
+    int address = SerializationAddressMapper::MappedTo(heap_object);
     int offset = CurrentAllocationAddress(space) - address;
     bool from_start = true;
     if (SpaceIsPaged(space)) {
@@ -965,24 +1028,23 @@
   }
   sink_->PutInt(size >> kObjectAlignmentBits, "Size in words");
 
-  // Get the map before overwriting it.
-  Map* map = object_->map();
   // Mark this object as already serialized.
   bool start_new_page;
-  object_->set_map_word(MapWord::FromSerializationAddress(
-      serializer_->Allocate(space, size, &start_new_page)));
+  SerializationAddressMapper::Map(
+    object_,
+    serializer_->Allocate(space, size, &start_new_page));
   if (start_new_page) {
     sink_->Put(START_NEW_PAGE_SERIALIZATION, "NewPage");
     sink_->PutSection(space, "NewPageSpace");
   }
 
   // Serialize the map (first word of the object).
-  serializer_->SerializeObject(map, TAGGED_REPRESENTATION);
+  serializer_->SerializeObject(object_->map(), TAGGED_REPRESENTATION);
 
   // Serialize the rest of the object.
   CHECK_EQ(0, bytes_processed_so_far_);
   bytes_processed_so_far_ = kPointerSize;
-  object_->IterateBody(map->instance_type(), size, this);
+  object_->IterateBody(object_->map()->instance_type(), size, this);
   OutputRawData(object_->address() + size);
 }
 
@@ -1044,12 +1106,9 @@
   Address references_start = reinterpret_cast<Address>(resource_pointer);
   OutputRawData(references_start);
   for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
-    // Use raw_unchecked when maps are munged.
-    Object* source = Heap::raw_unchecked_natives_source_cache()->get(i);
+    Object* source = Heap::natives_source_cache()->get(i);
     if (!source->IsUndefined()) {
-      // Don't use cast when maps are munged.
-      ExternalAsciiString* string =
-          reinterpret_cast<ExternalAsciiString*>(source);
+      ExternalAsciiString* string = ExternalAsciiString::cast(source);
       typedef v8::String::ExternalAsciiStringResource Resource;
       Resource* resource = string->resource();
       if (resource == *resource_pointer) {
diff --git a/src/string-stream.cc b/src/string-stream.cc
index eb5d1e3..d1859a2 100644
--- a/src/string-stream.cc
+++ b/src/string-stream.cc
@@ -188,7 +188,7 @@
 void StringStream::PrintObject(Object* o) {
   o->ShortPrint(this);
   if (o->IsString()) {
-    if (String::cast(o)->length() <= String::kMaxMediumSize) {
+    if (String::cast(o)->length() <= String::kMaxShortPrintLength) {
       return;
     }
   } else if (o->IsNumber() || o->IsOddball()) {
diff --git a/src/stub-cache.cc b/src/stub-cache.cc
index a399e45..51d9ddb 100644
--- a/src/stub-cache.cc
+++ b/src/stub-cache.cc
@@ -750,6 +750,9 @@
   {
     // Leaving JavaScript.
     VMState state(EXTERNAL);
+#ifdef ENABLE_LOGGING_AND_PROFILING
+    state.set_external_callback(getter_address);
+#endif
     result = fun(v8::Utils::ToLocal(args.at<String>(4)), info);
   }
   RETURN_IF_SCHEDULED_EXCEPTION();
@@ -773,6 +776,9 @@
   {
     // Leaving JavaScript.
     VMState state(EXTERNAL);
+#ifdef ENABLE_LOGGING_AND_PROFILING
+    state.set_external_callback(setter_address);
+#endif
     fun(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), info);
   }
   RETURN_IF_SCHEDULED_EXCEPTION();
diff --git a/src/stub-cache.h b/src/stub-cache.h
index e268920..788c532 100644
--- a/src/stub-cache.h
+++ b/src/stub-cache.h
@@ -226,9 +226,9 @@
     // hash code would effectively throw away two bits of the hash
     // code.
     ASSERT(kHeapObjectTagSize == String::kHashShift);
-    // Compute the hash of the name (use entire length field).
+    // Compute the hash of the name (use entire hash field).
     ASSERT(name->HasHashCode());
-    uint32_t field = name->length_field();
+    uint32_t field = name->hash_field();
     // Using only the low bits in 64-bit mode is unlikely to increase the
     // risk of collision even if the heap is spread over an area larger than
     // 4Gb (and not at all if it isn't).
diff --git a/src/utils.cc b/src/utils.cc
index ce5aced..08ee16f 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -309,4 +309,13 @@
   return buffer_.start();
 }
 
+
+int TenToThe(int exponent) {
+  ASSERT(exponent <= 9);
+  ASSERT(exponent >= 1);
+  int answer = 10;
+  for (int i = 1; i < exponent; i++) answer *= 10;
+  return answer;
+}
+
 } }  // namespace v8::internal
diff --git a/src/utils.h b/src/utils.h
index c271ae1..0fd24ec 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -584,6 +584,9 @@
 }
 
 
+// Calculate 10^exponent.
+int TenToThe(int exponent);
+
 } }  // namespace v8::internal
 
 #endif  // V8_UTILS_H_
diff --git a/src/v8-counters.h b/src/v8-counters.h
index b3f29f5..d6f53fa 100644
--- a/src/v8-counters.h
+++ b/src/v8-counters.h
@@ -153,8 +153,9 @@
   SC(zone_segment_bytes, V8.ZoneSegmentBytes)                       \
   SC(compute_entry_frame, V8.ComputeEntryFrame)                     \
   SC(generic_binary_stub_calls, V8.GenericBinaryStubCalls)          \
-  SC(generic_binary_stub_calls_regs, V8.GenericBinaryStubCallsRegs)
-
+  SC(generic_binary_stub_calls_regs, V8.GenericBinaryStubCallsRegs) \
+  SC(string_add_runtime, V8.StringAddRuntime)                       \
+  SC(string_add_native, V8.StringAddNative)
 
 // This file contains all the v8 counters that are in use.
 class Counters : AllStatic {
diff --git a/src/version.cc b/src/version.cc
index 2101e6a..36a42f8 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,8 +34,8 @@
 // cannot be changed without changing the SCons build script.
 #define MAJOR_VERSION     2
 #define MINOR_VERSION     0
-#define BUILD_NUMBER      2
-#define PATCH_LEVEL       3
+#define BUILD_NUMBER      3 
+#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.h b/src/x64/assembler-x64.h
index 50f4e0e..fa7d33b 100644
--- a/src/x64/assembler-x64.h
+++ b/src/x64/assembler-x64.h
@@ -482,6 +482,12 @@
   static const int kPatchReturnSequenceAddressOffset = 13 - 4;
   // TODO(X64): Rename this, removing the "Real", after changing the above.
   static const int kRealPatchReturnSequenceAddressOffset = 2;
+
+  // 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 kCallInstructionLength = 13;
+  static const int kJSReturnSequenceLength = 13;
+
   // ---------------------------------------------------------------------------
   // Code generation
   //
diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc
index b323572..36f0e63 100644
--- a/src/x64/codegen-x64.cc
+++ b/src/x64/codegen-x64.cc
@@ -505,13 +505,13 @@
   // Add padding that will be overwritten by a debugger breakpoint.
   // frame_->Exit() generates "movq rsp, rbp; pop rbp; ret k"
   // with length 7 (3 + 1 + 3).
-  const int kPadding = Debug::kX64JSReturnSequenceLength - 7;
+  const int kPadding = Assembler::kJSReturnSequenceLength - 7;
   for (int i = 0; i < kPadding; ++i) {
     masm_->int3();
   }
   // Check that the size of the code used for returning matches what is
   // expected by the debugger.
-  ASSERT_EQ(Debug::kX64JSReturnSequenceLength,
+  ASSERT_EQ(Assembler::kJSReturnSequenceLength,
             masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
 #endif
   DeleteFrame();
@@ -1662,8 +1662,54 @@
   jsobject.Bind();
   // Get the set of properties (as a FixedArray or Map).
   // rax: value to be iterated over
-  frame_->EmitPush(rax);  // push the object being iterated over (slot 4)
+  frame_->EmitPush(rax);  // Push the object being iterated over.
 
+
+  // Check cache validity in generated code. This is a fast case for
+  // the JSObject::IsSimpleEnum cache validity checks. If we cannot
+  // guarantee cache validity, call the runtime system to check cache
+  // validity or get the property names in a fixed array.
+  JumpTarget call_runtime;
+  JumpTarget loop(JumpTarget::BIDIRECTIONAL);
+  JumpTarget check_prototype;
+  JumpTarget use_cache;
+  __ movq(rcx, rax);
+  loop.Bind();
+  // Check that there are no elements.
+  __ movq(rdx, FieldOperand(rcx, JSObject::kElementsOffset));
+  __ CompareRoot(rdx, Heap::kEmptyFixedArrayRootIndex);
+  call_runtime.Branch(not_equal);
+  // Check that instance descriptors are not empty so that we can
+  // check for an enum cache.  Leave the map in ebx for the subsequent
+  // prototype load.
+  __ movq(rbx, FieldOperand(rcx, HeapObject::kMapOffset));
+  __ movq(rdx, FieldOperand(rbx, Map::kInstanceDescriptorsOffset));
+  __ CompareRoot(rdx, Heap::kEmptyDescriptorArrayRootIndex);
+  call_runtime.Branch(equal);
+  // Check that there in an enum cache in the non-empty instance
+  // descriptors.  This is the case if the next enumeration index
+  // field does not contain a smi.
+  __ movq(rdx, FieldOperand(rdx, DescriptorArray::kEnumerationIndexOffset));
+  is_smi = masm_->CheckSmi(rdx);
+  call_runtime.Branch(is_smi);
+  // For all objects but the receiver, check that the cache is empty.
+  __ cmpq(rcx, rax);
+  check_prototype.Branch(equal);
+  __ movq(rdx, FieldOperand(rdx, DescriptorArray::kEnumCacheBridgeCacheOffset));
+  __ CompareRoot(rdx, Heap::kEmptyFixedArrayRootIndex);
+  call_runtime.Branch(not_equal);
+  check_prototype.Bind();
+  // Load the prototype from the map and loop if non-null.
+  __ movq(rcx, FieldOperand(rbx, Map::kPrototypeOffset));
+  __ CompareRoot(rcx, Heap::kNullValueRootIndex);
+  loop.Branch(not_equal);
+  // The enum cache is valid.  Load the map of the object being
+  // iterated over and use the cache for the iteration.
+  __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset));
+  use_cache.Jump();
+
+  call_runtime.Bind();
+  // Call the runtime to get the property names for the object.
   frame_->EmitPush(rax);  // push the Object (slot 4) for the runtime call
   frame_->CallRuntime(Runtime::kGetPropertyNamesFast, 1);
 
@@ -1676,8 +1722,11 @@
   __ CompareRoot(rcx, Heap::kMetaMapRootIndex);
   fixed_array.Branch(not_equal);
 
+  use_cache.Bind();
   // Get enum cache
-  // rax: map (result from call to Runtime::kGetPropertyNamesFast)
+  // rax: map (either the result from a call to
+  // Runtime::kGetPropertyNamesFast or has been fetched directly from
+  // the object)
   __ movq(rcx, rax);
   __ movq(rcx, FieldOperand(rcx, Map::kInstanceDescriptorsOffset));
   // Get the bridge array held in the enumeration index field.
@@ -3767,20 +3816,8 @@
   __ testb(rcx, Immediate(kIsNotStringMask));
   __ j(not_zero, &slow_case);
 
-  // Here we make assumptions about the tag values and the shifts needed.
-  // See the comment in objects.h.
-  ASSERT(kLongStringTag == 0);
-  ASSERT(kMediumStringTag + String::kLongLengthShift ==
-         String::kMediumLengthShift);
-  ASSERT(kShortStringTag + String::kLongLengthShift ==
-         String::kShortLengthShift);
-  __ and_(rcx, Immediate(kStringSizeMask));
-  __ addq(rcx, Immediate(String::kLongLengthShift));
-  // Fetch the length field into the temporary register.
-  __ movl(temp.reg(), FieldOperand(object.reg(), String::kLengthOffset));
-  __ shrl_cl(temp.reg());
   // Check for index out of range.
-  __ cmpl(index.reg(), temp.reg());
+  __ cmpl(index.reg(), FieldOperand(object.reg(), String::kLengthOffset));
   __ j(greater_equal, &slow_case);
   // Reload the instance type (into the temp register this time)..
   __ movq(temp.reg(), FieldOperand(object.reg(), HeapObject::kMapOffset));
@@ -4008,6 +4045,17 @@
 }
 
 
+void CodeGenerator::GenerateStringAdd(ZoneList<Expression*>* args) {
+  ASSERT_EQ(2, args->length());
+
+  Load(args->at(0));
+  Load(args->at(1));
+
+  Result answer = frame_->CallRuntime(Runtime::kStringAdd, 2);
+  frame_->Push(&answer);
+}
+
+
 void CodeGenerator::GenerateClassOf(ZoneList<Expression*>* args) {
   ASSERT(args->length() == 1);
   JumpTarget leave, null, function, non_function_constructor;
@@ -6175,11 +6223,8 @@
   // String value => false iff empty.
   __ cmpq(rcx, Immediate(FIRST_NONSTRING_TYPE));
   __ j(above_equal, &not_string);
-  __ and_(rcx, Immediate(kStringSizeMask));
-  __ cmpq(rcx, Immediate(kShortStringTag));
-  __ j(not_equal, &true_result);  // Empty string is always short.
   __ movl(rdx, FieldOperand(rax, String::kLengthOffset));
-  __ shr(rdx, Immediate(String::kShortLengthShift));
+  __ testl(rdx, rdx);
   __ j(zero, &false_result);
   __ jmp(&true_result);
 
@@ -7732,9 +7777,47 @@
     __ push(rcx);
   }
   switch (op_) {
-    case Token::ADD:
+    case Token::ADD: {
+      // Test for string arguments before calling runtime.
+      Label not_strings, both_strings, not_string1, string1;
+      Condition is_smi;
+      Result answer;
+      __ movq(rdx, Operand(rsp, 2 * kPointerSize));  // First argument.
+      __ movq(rax, Operand(rsp, 1 * kPointerSize));  // Second argument.
+      is_smi = masm->CheckSmi(rdx);
+      __ j(is_smi, &not_string1);
+      __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, rdx);
+      __ j(above_equal, &not_string1);
+
+      // First argument is a a string, test second.
+      is_smi = masm->CheckSmi(rax);
+      __ j(is_smi, &string1);
+      __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rax);
+      __ j(above_equal, &string1);
+
+      // First and second argument are strings.
+      Runtime::Function* f = Runtime::FunctionForId(Runtime::kStringAdd);
+      __ TailCallRuntime(ExternalReference(f), 2, f->result_size);
+
+      // Only first argument is a string.
+      __ bind(&string1);
+      __ InvokeBuiltin(Builtins::STRING_ADD_LEFT, JUMP_FUNCTION);
+
+      // First argument was not a string, test second.
+      __ bind(&not_string1);
+      is_smi = masm->CheckSmi(rax);
+      __ j(is_smi, &not_strings);
+      __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rax);
+      __ j(above_equal, &not_strings);
+
+      // Only second argument is a string.
+      __ InvokeBuiltin(Builtins::STRING_ADD_RIGHT, JUMP_FUNCTION);
+
+      __ bind(&not_strings);
+      // Neither argument is a string.
       __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION);
       break;
+    }
     case Token::SUB:
       __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION);
       break;
diff --git a/src/x64/codegen-x64.h b/src/x64/codegen-x64.h
index 20df41a..8539884 100644
--- a/src/x64/codegen-x64.h
+++ b/src/x64/codegen-x64.h
@@ -544,6 +544,9 @@
   inline void GenerateMathSin(ZoneList<Expression*>* args);
   inline void GenerateMathCos(ZoneList<Expression*>* args);
 
+  // Fast support for StringAdd.
+  void GenerateStringAdd(ZoneList<Expression*>* args);
+
   // Simple condition analysis.
   enum ConditionAnalysis {
     ALWAYS_TRUE,
diff --git a/src/x64/debug-x64.cc b/src/x64/debug-x64.cc
index 49240b4..bc88d46 100644
--- a/src/x64/debug-x64.cc
+++ b/src/x64/debug-x64.cc
@@ -181,7 +181,7 @@
 
 void BreakLocationIterator::ClearDebugBreakAtReturn() {
   rinfo()->PatchCode(original_rinfo()->pc(),
-                     Debug::kX64JSReturnSequenceLength);
+                     Assembler::kJSReturnSequenceLength);
 }
 
 
@@ -191,9 +191,10 @@
 
 
 void BreakLocationIterator::SetDebugBreakAtReturn()  {
-  ASSERT(Debug::kX64JSReturnSequenceLength >= Debug::kX64CallInstructionLength);
+  ASSERT(Assembler::kJSReturnSequenceLength >=
+         Assembler::kCallInstructionLength);
   rinfo()->PatchCodeWithCall(Debug::debug_break_return()->entry(),
-      Debug::kX64JSReturnSequenceLength - Debug::kX64CallInstructionLength);
+      Assembler::kJSReturnSequenceLength - Assembler::kCallInstructionLength);
 }
 
 #endif  // ENABLE_DEBUGGER_SUPPORT
diff --git a/src/x64/fast-codegen-x64.cc b/src/x64/fast-codegen-x64.cc
index bb85ef5..f73f2b9 100644
--- a/src/x64/fast-codegen-x64.cc
+++ b/src/x64/fast-codegen-x64.cc
@@ -76,11 +76,43 @@
 
   bool function_in_register = true;
 
+  // Possibly allocate a local context.
+  if (fun->scope()->num_heap_slots() > 0) {
+    Comment cmnt(masm_, "[ Allocate local context");
+    // Argument to NewContext is the function, which is still in rdi.
+    __ push(rdi);
+    __ CallRuntime(Runtime::kNewContext, 1);
+    function_in_register = false;
+    // Context is returned in both rax and rsi.  It replaces the context
+    // passed to us.  It's saved in the stack and kept live in rsi.
+    __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
+
+    // Copy any necessary parameters into the context.
+    int num_parameters = fun->scope()->num_parameters();
+    for (int i = 0; i < num_parameters; i++) {
+      Slot* slot = fun->scope()->parameter(i)->slot();
+      if (slot != NULL && slot->type() == Slot::CONTEXT) {
+        int parameter_offset = StandardFrameConstants::kCallerSPOffset +
+                               (num_parameters - 1 - i) * kPointerSize;
+        // Load parameter from stack.
+        __ movq(rax, Operand(rbp, parameter_offset));
+        // Store it in the context
+        __ movq(Operand(rsi, Context::SlotOffset(slot->index())), rax);
+      }
+    }
+  }
+
+  // Possibly allocate an arguments object.
   Variable* arguments = fun->scope()->arguments()->AsVariable();
   if (arguments != NULL) {
-    // Function uses arguments object.
+    // Arguments object must be allocated after the context object, in
+    // case the "arguments" or ".arguments" variables are in the context.
     Comment cmnt(masm_, "[ Allocate arguments object");
-    __ push(rdi);
+    if (function_in_register) {
+      __ push(rdi);
+    } else {
+      __ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
+    }
     // The receiver is just before the parameters on the caller's stack.
     __ lea(rdx, Operand(rbp, StandardFrameConstants::kCallerSPOffset +
                                  fun->num_parameters() * kPointerSize));
@@ -93,34 +125,11 @@
     ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
     __ CallStub(&stub);
     // Store new arguments object in both "arguments" and ".arguments" slots.
-    __ movq(Operand(rbp, SlotOffset(arguments->slot())), rax);
+    __ movq(rcx, rax);
+    Move(arguments->slot(), rax, rbx, rdx);
     Slot* dot_arguments_slot =
         fun->scope()->arguments_shadow()->AsVariable()->slot();
-    __ movq(Operand(rbp, SlotOffset(dot_arguments_slot)), rax);
-    function_in_register = false;
-  }
-
-  // Possibly allocate a local context.
-  if (fun->scope()->num_heap_slots() > 0) {
-    Comment cmnt(masm_, "[ Allocate local context");
-    if (function_in_register) {
-      // Argument to NewContext is the function, still in rdi.
-      __ push(rdi);
-    } else {
-      // Argument to NewContext is the function, no longer in rdi.
-      __ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
-    }
-    __ CallRuntime(Runtime::kNewContext, 1);
-    // Context is returned in both rax and rsi.  It replaces the context
-    // passed to us.  It's saved in the stack and kept live in rsi.
-    __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
-#ifdef DEBUG
-    // Assert we do not have to copy any parameters into the context.
-    for (int i = 0, len = fun->scope()->num_parameters(); i < len; i++) {
-      Slot* slot = fun->scope()->parameter(i)->slot();
-      ASSERT(slot != NULL && slot->type() != Slot::CONTEXT);
-    }
-#endif
+    Move(dot_arguments_slot, rcx, rbx, rdx);
   }
 
   { Comment cmnt(masm_, "[ Stack check");
@@ -180,13 +189,13 @@
     // Add padding that will be overwritten by a debugger breakpoint.  We
     // have just generated "movq rsp, rbp; pop rbp; ret k" with length 7
     // (3 + 1 + 3).
-    const int kPadding = Debug::kX64JSReturnSequenceLength - 7;
+    const int kPadding = Assembler::kJSReturnSequenceLength - 7;
     for (int i = 0; i < kPadding; ++i) {
       masm_->int3();
     }
     // Check that the size of the code used for returning matches what is
     // expected by the debugger.
-    ASSERT_EQ(Debug::kX64JSReturnSequenceLength,
+    ASSERT_EQ(Assembler::kJSReturnSequenceLength,
             masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
 #endif
   }
@@ -227,20 +236,54 @@
 }
 
 
-void FastCodeGenerator::Move(Expression::Context context, Slot* source) {
+template <>
+Operand FastCodeGenerator::CreateSlotOperand<Operand>(Slot* source,
+                                                      Register scratch) {
+  switch (source->type()) {
+    case Slot::PARAMETER:
+    case Slot::LOCAL:
+      return Operand(rbp, SlotOffset(source));
+    case Slot::CONTEXT: {
+      int context_chain_length =
+          function_->scope()->ContextChainLength(source->var()->scope());
+      __ LoadContext(scratch, context_chain_length);
+      return CodeGenerator::ContextOperand(scratch, source->index());
+      break;
+    }
+    case Slot::LOOKUP:
+      UNIMPLEMENTED();
+      // Fall-through.
+    default:
+      UNREACHABLE();
+      return Operand(rax, 0);  // Dead code to make the compiler happy.
+  }
+}
+
+
+void FastCodeGenerator::Move(Register dst, Slot* source) {
+  Operand location = CreateSlotOperand<Operand>(source, dst);
+  __ movq(dst, location);
+}
+
+
+void FastCodeGenerator::Move(Expression::Context context,
+                             Slot* source,
+                             Register scratch) {
   switch (context) {
     case Expression::kUninitialized:
       UNREACHABLE();
     case Expression::kEffect:
       break;
-    case Expression::kValue:
-      __ push(Operand(rbp, SlotOffset(source)));
+    case Expression::kValue: {
+      Operand location = CreateSlotOperand<Operand>(source, scratch);
+      __ push(location);
       break;
+    }
     case Expression::kTest:  // Fall through.
     case Expression::kValueTest:  // Fall through.
     case Expression::kTestValue:
-      __ movq(rax, Operand(rbp, SlotOffset(source)));
-      Move(context, rax);
+      Move(scratch, source);
+      Move(context, scratch);
       break;
   }
 }
@@ -265,24 +308,61 @@
 }
 
 
+void FastCodeGenerator::Move(Slot* dst,
+                             Register src,
+                             Register scratch1,
+                             Register scratch2) {
+  switch (dst->type()) {
+    case Slot::PARAMETER:
+    case Slot::LOCAL:
+      __ movq(Operand(rbp, SlotOffset(dst)), src);
+      break;
+    case Slot::CONTEXT: {
+      ASSERT(!src.is(scratch1));
+      ASSERT(!src.is(scratch2));
+      ASSERT(!scratch1.is(scratch2));
+      int context_chain_length =
+          function_->scope()->ContextChainLength(dst->var()->scope());
+      __ LoadContext(scratch1, context_chain_length);
+      __ movq(Operand(scratch1, Context::SlotOffset(dst->index())), src);
+      int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize;
+      __ RecordWrite(scratch1, offset, src, scratch2);
+      break;
+    }
+    case Slot::LOOKUP:
+      UNIMPLEMENTED();
+    default:
+      UNREACHABLE();
+  }
+}
+
+
 void FastCodeGenerator::DropAndMove(Expression::Context context,
-                                    Register source) {
+                                    Register source,
+                                    int drop_count) {
+  ASSERT(drop_count > 0);
   switch (context) {
     case Expression::kUninitialized:
       UNREACHABLE();
     case Expression::kEffect:
-      __ addq(rsp, Immediate(kPointerSize));
+      __ addq(rsp, Immediate(drop_count * kPointerSize));
       break;
     case Expression::kValue:
+      if (drop_count > 1) {
+        __ addq(rsp, Immediate((drop_count - 1) * kPointerSize));
+      }
       __ movq(Operand(rsp, 0), source);
       break;
     case Expression::kTest:
       ASSERT(!source.is(rsp));
-      __ addq(rsp, Immediate(kPointerSize));
+      __ addq(rsp, Immediate(drop_count * kPointerSize));
       TestAndBranch(source, true_label_, false_label_);
       break;
     case Expression::kValueTest: {
       Label discard;
+      if (drop_count > 1) {
+        __ addq(rsp, Immediate((drop_count - 1) * kPointerSize));
+      }
       __ movq(Operand(rsp, 0), source);
       TestAndBranch(source, true_label_, &discard);
       __ bind(&discard);
@@ -382,26 +462,26 @@
         __ Move(rax, Factory::the_hole_value());
         if (FLAG_debug_code) {
           // Check if we have the correct context pointer.
-          __ movq(rbx, CodeGenerator::ContextOperand(
-              rsi, Context::FCONTEXT_INDEX));
+          __ movq(rbx, CodeGenerator::ContextOperand(rsi,
+                                                     Context::FCONTEXT_INDEX));
           __ cmpq(rbx, rsi);
           __ Check(equal, "Unexpected declaration in current context.");
         }
         __ movq(CodeGenerator::ContextOperand(rsi, slot->index()), rax);
         // No write barrier since the_hole_value is in old space.
-        ASSERT(Heap::InNewSpace(*Factory::the_hole_value()));
+        ASSERT(!Heap::InNewSpace(*Factory::the_hole_value()));
       } else if (decl->fun() != NULL) {
         Visit(decl->fun());
         __ pop(rax);
         if (FLAG_debug_code) {
           // Check if we have the correct context pointer.
-          __ movq(rbx, CodeGenerator::ContextOperand(
-              rsi, Context::FCONTEXT_INDEX));
+          __ movq(rbx, CodeGenerator::ContextOperand(rsi,
+                                                     Context::FCONTEXT_INDEX));
           __ cmpq(rbx, rsi);
           __ Check(equal, "Unexpected declaration in current context.");
         }
         __ movq(CodeGenerator::ContextOperand(rsi, slot->index()), rax);
-        int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
+        int offset = Context::SlotOffset(slot->index());
         __ RecordWrite(rsi, offset, rax, rcx);
       }
       break;
@@ -473,53 +553,59 @@
     DropAndMove(expr->context(), rax);
   } else if (rewrite->AsSlot() != NULL) {
     Slot* slot = rewrite->AsSlot();
-    switch (slot->type()) {
-      case Slot::LOCAL:
-      case Slot::PARAMETER: {
-        Comment cmnt(masm_, "Stack slot");
-        Move(expr->context(), slot);
-        break;
-      }
-
-      case Slot::CONTEXT: {
-        Comment cmnt(masm_, "Context slot");
-         int chain_length =
-            function_->scope()->ContextChainLength(slot->var()->scope());
-        if (chain_length > 0) {
-          // Move up the chain of contexts to the context containing the slot.
-          __ movq(rax,
-                  Operand(rsi, Context::SlotOffset(Context::CLOSURE_INDEX)));
-          // Load the function context (which is the incoming, outer context).
-          __ movq(rax, FieldOperand(rax, JSFunction::kContextOffset));
-          for (int i = 1; i < chain_length; i++) {
-            __ movq(rax,
-                    Operand(rax, Context::SlotOffset(Context::CLOSURE_INDEX)));
-            __ movq(rax, FieldOperand(rax, JSFunction::kContextOffset));
-          }
-          // The context may be an intermediate context, not a function context.
-          __ movq(rax,
-                  Operand(rax, Context::SlotOffset(Context::FCONTEXT_INDEX)));
-        } else {  // Slot is in the current function context.
-          // The context may be an intermediate context, not a function context.
-          __ movq(rax,
-                  Operand(rsi, Context::SlotOffset(Context::FCONTEXT_INDEX)));
+    if (FLAG_debug_code) {
+      switch (slot->type()) {
+        case Slot::LOCAL:
+        case Slot::PARAMETER: {
+          Comment cmnt(masm_, "Stack slot");
+          break;
         }
-        __ movq(rax, Operand(rax, Context::SlotOffset(slot->index())));
-        Move(expr->context(), rax);
-        break;
+        case Slot::CONTEXT: {
+          Comment cmnt(masm_, "Context slot");
+          break;
+        }
+        case Slot::LOOKUP:
+          UNIMPLEMENTED();
+          break;
+        default:
+          UNREACHABLE();
       }
-
-      case Slot::LOOKUP:
-        UNREACHABLE();
-        break;
     }
+    Move(expr->context(), slot, rax);
   } else {
-    // The parameter variable has been rewritten into an explict access to
-    // the arguments object.
+    // A variable has been rewritten into an explicit access to
+    // an object property.
     Property* property = rewrite->AsProperty();
     ASSERT_NOT_NULL(property);
-    ASSERT_EQ(expr->context(), property->context());
-    Visit(property);
+
+    // Currently the only parameter expressions that can occur are
+    // on the form "slot[literal]".
+
+    // Check that the object is in a slot.
+    Variable* object = property->obj()->AsVariableProxy()->AsVariable();
+    ASSERT_NOT_NULL(object);
+    Slot* object_slot = object->slot();
+    ASSERT_NOT_NULL(object_slot);
+
+    // Load the object.
+    Move(Expression::kValue, object_slot, rax);
+
+    // Check that the key is a smi.
+    Literal* key_literal = property->key()->AsLiteral();
+    ASSERT_NOT_NULL(key_literal);
+    ASSERT(key_literal->handle()->IsSmi());
+
+    // Load the key.
+    Move(Expression::kValue, key_literal);
+
+    // Do a KEYED property load.
+    Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+    __ call(ic, RelocInfo::CODE_TARGET);
+    // Notice: We must not have a "test rax, ..." instruction after
+    // the call. It is treated specially by the LoadIC code.
+
+    // Drop key and object left on the stack by IC, and push the result.
+    DropAndMove(expr->context(), rax, 2);
   }
 }
 
@@ -580,8 +666,9 @@
     __ CallRuntime(Runtime::kCloneLiteralBoilerplate, 1);
   }
 
-  // If result_saved == true: the result is saved on top of the stack.
-  // If result_saved == false: the result is not on the stack, just in rax.
+  // If result_saved == true: The result is saved on top of the
+  //  stack and in rax.
+  // If result_saved == false: The result not on the stack, just in rax.
   bool result_saved = false;
 
   for (int i = 0; i < expr->properties()->length(); i++) {
@@ -606,6 +693,7 @@
           Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
           __ call(ic, RelocInfo::CODE_TARGET);
           // StoreIC leaves the receiver on the stack.
+          __ movq(rax, Operand(rsp, 0));  // Restore result back into rax.
           break;
         }
         // fall through
@@ -781,7 +869,7 @@
     // Overwrite the global object on the stack with the result if needed.
     DropAndMove(expr->context(), rax);
 
-  } else {
+  } else if (var->slot()) {
     Slot* slot = var->slot();
     ASSERT_NOT_NULL(slot);  // Variables rewritten as properties not handled.
     switch (slot->type()) {
@@ -873,6 +961,36 @@
         UNREACHABLE();
         break;
     }
+  } else {
+    Property* property = var->AsProperty();
+    ASSERT_NOT_NULL(property);
+    // A variable has been rewritten into a property on an object.
+
+    // Load object and key onto the stack.
+    Slot* object_slot = property->obj()->AsSlot();
+    ASSERT_NOT_NULL(object_slot);
+    Move(Expression::kValue, object_slot, rax);
+
+    Literal* key_literal = property->key()->AsLiteral();
+    ASSERT_NOT_NULL(key_literal);
+    Move(Expression::kValue, key_literal);
+
+    // Value to store was pushed before object and key on the stack.
+    __ movq(rax, Operand(rsp, 2 * kPointerSize));
+
+    // Arguments to ic is value in rax, object and key on stack.
+    Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
+    __ call(ic, RelocInfo::CODE_TARGET);
+
+    if (expr->context() == Expression::kEffect) {
+      __ addq(rsp, Immediate(3 * kPointerSize));
+    } else if (expr->context() == Expression::kValue) {
+      // Value is still on the stack in rsp[2 * kPointerSize]
+      __ addq(rsp, Immediate(2 * kPointerSize));
+    } else {
+      __ movq(rax, Operand(rsp, 2 * kPointerSize));
+      DropAndMove(expr->context(), rax, 3);
+    }
   }
 }
 
@@ -969,9 +1087,9 @@
     Visit(expr->key());
     Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
     __ call(ic, RelocInfo::CODE_TARGET);
-    // By emitting a nop we make sure that we do not have a "test rax,..."
-    // instruction after the call it is treated specially by the LoadIC code.
-    __ nop();
+    // Notice: We must not have a "test rax, ..." instruction after
+    // the call. It is treated specially by the LoadIC code.
+
     // Drop key left on the stack by IC.
     __ addq(rsp, Immediate(kPointerSize));
   }
@@ -1054,7 +1172,7 @@
       SetSourcePosition(prop->position());
       Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
       __ call(ic, RelocInfo::CODE_TARGET);
-      // By emitting a nop we make sure that we do not have a "test eax,..."
+      // By emitting a nop we make sure that we do not have a "test rax,..."
       // instruction after the call it is treated specially by the LoadIC code.
       __ nop();
       // Drop key left on the stack by IC.
@@ -1134,9 +1252,13 @@
 void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
   Comment cmnt(masm_, "[ CallRuntime");
   ZoneList<Expression*>* args = expr->arguments();
-  Runtime::Function* function = expr->function();
 
-  ASSERT(function != NULL);
+  if (expr->is_jsruntime()) {
+    // Prepare for calling JS runtime function.
+    __ Push(expr->name());
+    __ movq(rax, CodeGenerator::GlobalObject());
+    __ push(FieldOperand(rax, GlobalObject::kBuiltinsOffset));
+  }
 
   // Push the arguments ("left-to-right").
   int arg_count = args->length();
@@ -1145,8 +1267,19 @@
     ASSERT_EQ(Expression::kValue, args->at(i)->context());
   }
 
-  __ CallRuntime(function, arg_count);
-  Move(expr->context(), rax);
+  if (expr->is_jsruntime()) {
+    // Call the JS runtime function.
+    Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count,
+                                                           NOT_IN_LOOP);
+    __ call(ic, RelocInfo::CODE_TARGET);
+    // Restore context register.
+    __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
+    // Discard the function left on TOS.
+    DropAndMove(expr->context(), rax);
+  } else {
+    __ CallRuntime(expr->function(), arg_count);
+    Move(expr->context(), rax);
+  }
 }
 
 void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
diff --git a/src/x64/ic-x64.cc b/src/x64/ic-x64.cc
index 1642a04..ccbc615 100644
--- a/src/x64/ic-x64.cc
+++ b/src/x64/ic-x64.cc
@@ -31,6 +31,7 @@
 #include "ic-inl.h"
 #include "runtime.h"
 #include "stub-cache.h"
+#include "utils.h"
 
 namespace v8 {
 namespace internal {
@@ -107,7 +108,7 @@
       StringDictionary::kElementsStartIndex * kPointerSize;
   for (int i = 0; i < kProbes; i++) {
     // Compute the masked index: (hash + i + i * i) & mask.
-    __ movl(r1, FieldOperand(name, String::kLengthOffset));
+    __ movl(r1, FieldOperand(name, String::kHashFieldOffset));
     __ shrl(r1, Immediate(String::kHashShift));
     if (i > 0) {
       __ addl(r1, Immediate(StringDictionary::GetProbeOffset(i)));
@@ -239,18 +240,6 @@
 }
 
 
-#ifdef DEBUG
-// For use in assert below.
-static int TenToThe(int exponent) {
-  ASSERT(exponent <= 9);
-  ASSERT(exponent >= 1);
-  int answer = 10;
-  for (int i = 1; i < exponent; i++) answer *= 10;
-  return answer;
-}
-#endif
-
-
 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
   // ----------- S t a t e -------------
   //  -- rsp[0] : return address
@@ -327,7 +316,7 @@
   __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rdx);
   __ j(above_equal, &slow);
   // Is the string an array index, with cached numeric value?
-  __ movl(rbx, FieldOperand(rax, String::kLengthOffset));
+  __ movl(rbx, FieldOperand(rax, String::kHashFieldOffset));
   __ testl(rbx, Immediate(String::kIsArrayIndexMask));
 
   // If the string is a symbol, do a quick inline probe of the receiver's
@@ -342,20 +331,16 @@
   __ movq(rax, rcx);
   __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1);
   __ ret(0);
-  // Array index string: If short enough use cache in length/hash field (rbx).
-  // We assert that there are enough bits in an int32_t after the hash shift
-  // bits have been subtracted to allow space for the length and the cached
-  // array index.
+  // If the hash field contains an array index pick it out. The assert checks
+  // that the constants for the maximum number of digits for an array index
+  // cached in the hash field and the number of bits reserved for it does not
+  // conflict.
   ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
-         (1 << (String::kShortLengthShift - String::kHashShift)));
+         (1 << String::kArrayIndexValueBits));
   __ bind(&index_string);
-  const int kLengthFieldLimit =
-      (String::kMaxCachedArrayIndexLength + 1) << String::kShortLengthShift;
-  __ cmpl(rbx, Immediate(kLengthFieldLimit));
-  __ j(above_equal, &slow);
   __ movl(rax, rbx);
-  __ and_(rax, Immediate((1 << String::kShortLengthShift) - 1));
-  __ shrl(rax, Immediate(String::kLongLengthShift));
+  __ and_(rax, Immediate(String::kArrayIndexHashMask));
+  __ shrl(rax, Immediate(String::kHashShift));
   __ jmp(&index_int);
 }
 
@@ -393,7 +378,7 @@
   // ExternalArray.
   // rax: index (as a smi)
   // rcx: JSObject
-  __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset));
+  __ movq(rcx, FieldOperand(rcx, JSObject::kElementsOffset));
   __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset),
                  Heap::RootIndexForExternalArrayType(array_type));
   __ j(not_equal, &slow);
@@ -413,7 +398,7 @@
       __ movsxbq(rax, Operand(rcx, rax, times_1, 0));
       break;
     case kExternalUnsignedByteArray:
-      __ movb(rax, Operand(rcx, rax, times_1, 0));
+      __ movzxbq(rax, Operand(rcx, rax, times_1, 0));
       break;
     case kExternalShortArray:
       __ movsxwq(rax, Operand(rcx, rax, times_2, 0));
diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc
index 9dea616..7115791 100644
--- a/src/x64/macro-assembler-x64.cc
+++ b/src/x64/macro-assembler-x64.cc
@@ -67,6 +67,12 @@
 }
 
 
+void MacroAssembler::StackLimitCheck(Label* on_stack_overflow) {
+  CompareRoot(rsp, Heap::kStackLimitRootIndex);
+  j(below, on_stack_overflow);
+}
+
+
 static void RecordWriteHelper(MacroAssembler* masm,
                               Register object,
                               Register addr,
@@ -282,6 +288,9 @@
     RecordComment(msg);
   }
 #endif
+  // Disable stub call restrictions to always allow calls to abort.
+  set_allow_stub_calls(true);
+
   push(rax);
   movq(kScratchRegister, p0, RelocInfo::NONE);
   push(kScratchRegister);
@@ -291,6 +300,7 @@
   push(kScratchRegister);
   CallRuntime(Runtime::kAbort, 2);
   // will not return here
+  int3();
 }
 
 
@@ -2088,6 +2098,11 @@
 
 void MacroAssembler::UpdateAllocationTopHelper(Register result_end,
                                                Register scratch) {
+  if (FLAG_debug_code) {
+    testq(result_end, Immediate(kObjectAlignmentMask));
+    Check(zero, "Unaligned allocation in new space");
+  }
+
   ExternalReference new_space_allocation_top =
       ExternalReference::new_space_allocation_top_address();
 
@@ -2229,6 +2244,25 @@
 }
 
 
+void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
+  if (context_chain_length > 0) {
+    // Move up the chain of contexts to the context containing the slot.
+    movq(dst, Operand(rsi, Context::SlotOffset(Context::CLOSURE_INDEX)));
+    // Load the function context (which is the incoming, outer context).
+    movq(rax, FieldOperand(rax, JSFunction::kContextOffset));
+    for (int i = 1; i < context_chain_length; i++) {
+      movq(dst, Operand(dst, Context::SlotOffset(Context::CLOSURE_INDEX)));
+      movq(dst, FieldOperand(dst, JSFunction::kContextOffset));
+    }
+    // The context may be an intermediate context, not a function context.
+    movq(dst, Operand(dst, Context::SlotOffset(Context::FCONTEXT_INDEX)));
+  } else {  // context is the current function context.
+    // The context may be an intermediate context, not a function context.
+    movq(dst, Operand(rsi, Context::SlotOffset(Context::FCONTEXT_INDEX)));
+  }
+}
+
+
 CodePatcher::CodePatcher(byte* address, int size)
     : address_(address), size_(size), masm_(address, size + Assembler::kGap) {
   // Create a new macro assembler pointing to the address of the code to patch.
diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h
index 11cdfc3..9e7c25c 100644
--- a/src/x64/macro-assembler-x64.h
+++ b/src/x64/macro-assembler-x64.h
@@ -98,6 +98,12 @@
 #endif
 
   // ---------------------------------------------------------------------------
+  // Stack limit support
+
+  // Do simple test for stack overflow. This doesn't handle an overflow.
+  void StackLimitCheck(Label* on_stack_limit_hit);
+
+  // ---------------------------------------------------------------------------
   // Activation frames
 
   void EnterInternalFrame() { EnterFrame(StackFrame::INTERNAL); }
@@ -542,6 +548,9 @@
   // occurred.
   void IllegalOperation(int num_arguments);
 
+  // Find the function context up the context chain.
+  void LoadContext(Register dst, int context_chain_length);
+
   // ---------------------------------------------------------------------------
   // Runtime calls
 
diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc
index 584fd2b..55b0b87 100644
--- a/src/x64/stub-cache-x64.cc
+++ b/src/x64/stub-cache-x64.cc
@@ -173,7 +173,7 @@
   __ JumpIfSmi(receiver, &miss);
 
   // Get the map of the receiver and compute the hash.
-  __ movl(scratch, FieldOperand(name, String::kLengthOffset));
+  __ movl(scratch, FieldOperand(name, String::kHashFieldOffset));
   // Use only the low 32 bits of the map pointer.
   __ addl(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
   __ xor_(scratch, Immediate(flags));
@@ -183,7 +183,7 @@
   ProbeTable(masm, flags, kPrimary, name, scratch);
 
   // Primary miss: Compute hash for secondary probe.
-  __ movl(scratch, FieldOperand(name, String::kLengthOffset));
+  __ movl(scratch, FieldOperand(name, String::kHashFieldOffset));
   __ addl(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
   __ xor_(scratch, Immediate(flags));
   __ and_(scratch, Immediate((kPrimaryTableSize - 1) << kHeapObjectTagSize));
@@ -323,11 +323,7 @@
 
   // Load length directly from the string.
   __ bind(&load_length);
-  __ and_(scratch, Immediate(kStringSizeMask));
   __ movl(rax, FieldOperand(receiver, String::kLengthOffset));
-  // rcx is also the receiver.
-  __ lea(rcx, Operand(scratch, String::kLongLengthShift));
-  __ shr_cl(rax);
   __ Integer32ToSmi(rax, rax);
   __ ret(0);