Improved frame merge code generated by the code generator.

Optimized String.prototype.replace.

Implemented __defineGetter__ and __defineSetter__ for properties with integer keys on non-array objects.

Improved debugger and profiler support.

Fixed a number of portability issues to allow compilation for smaller ARM devices.

Exposed object cloning through the API.

Implemented hidden properties.  This is used to expose an identity hash for objects through the API.

Implemented restarting of regular expressions if their input string changes representation during preemption.

Fixed a code generator bug that could cause assignments in loops to be ignored if using continue to break out of the loop (issue 284).


git-svn-id: http://v8.googlecode.com/svn/trunk@1598 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/ChangeLog b/ChangeLog
index d6e36d7..2bd1413 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,30 @@
+2009-03-24: Version 1.1.2
+
+        Improved frame merge code generated by the code generator.
+
+        Optimized String.prototype.replace.
+
+        Implemented __defineGetter__ and __defineSetter__ for properties
+        with integer keys on non-array objects.
+
+        Improved debugger and profiler support.
+
+        Fixed a number of portability issues to allow compilation for
+        smaller ARM devices.
+
+        Exposed object cloning through the API.
+
+        Implemented hidden properties.  This is used to expose an identity
+        hash for objects through the API.
+
+        Implemented restarting of regular expressions if their input
+        string changes representation during preemption.
+
+        Fixed a code generator bug that could cause assignments in loops
+        to be ignored if using continue to break out of the loop (issue
+        284).
+
+
 2009-03-12: Version 1.1.1
 
         Fixed an assertion in the new compiler to take stack overflow
diff --git a/SConstruct b/SConstruct
index 64e6963..4268841 100644
--- a/SConstruct
+++ b/SConstruct
@@ -35,6 +35,40 @@
 sys.path.append(join(root_dir, 'tools'))
 import js2c, utils
 
+# ANDROID_TOP is the top of the Android checkout, fetched from the environment
+# variable 'TOP'.   You will also need to set the CXX, CC, AR and RANLIB
+# environment variables to the cross-compiling tools.
+ANDROID_TOP = os.environ.get('TOP')
+if ANDROID_TOP is None:
+  ANDROID_TOP=""
+
+ANDROID_FLAGS = ['-march=armv5te',
+                 '-mtune=xscale',
+                 '-msoft-float',
+                 '-fpic',
+                 '-mthumb-interwork',
+                 '-funwind-tables',
+                 '-fstack-protector',
+                 '-fno-short-enums',
+                 '-fmessage-length=0',
+                 '-finline-functions',
+                 '-fno-inline-functions-called-once',
+                 '-fgcse-after-reload',
+                 '-frerun-cse-after-loop',
+                 '-frename-registers',
+                 '-fomit-frame-pointer',
+                 '-fno-strict-aliasing',
+                 '-finline-limit=64',
+                 '-MD']
+
+ANDROID_INCLUDES = [ANDROID_TOP + '/bionic/libc/arch-arm/include',
+                    ANDROID_TOP + '/bionic/libc/include',
+                    ANDROID_TOP + '/bionic/libstdc++/include',
+                    ANDROID_TOP + '/bionic/libc/kernel/common',
+                    ANDROID_TOP + '/bionic/libc/kernel/arch-arm',
+                    ANDROID_TOP + '/bionic/libm/include',
+                    ANDROID_TOP + '/bionic/libm/include/arch/arm',
+                    ANDROID_TOP + '/bionic/libthread_db/include']
 
 LIBRARY_FLAGS = {
   'all': {
@@ -50,7 +84,11 @@
       'CPPDEFINES':   ['ENABLE_DISASSEMBLER', 'DEBUG']
     },
     'mode:release': {
-      'CCFLAGS':      ['-O3', '-fomit-frame-pointer', '-fdata-sections', '-ffunction-sections']
+      'CCFLAGS':      ['-O3', '-fomit-frame-pointer', '-fdata-sections',
+                       '-ffunction-sections'],
+      'os:android': {
+        'CPPDEFINES': ['SK_RELEASE', 'NDEBUG']
+      }
     },
     'os:linux': {
       'CCFLAGS':      ['-ansi'],
@@ -65,6 +103,14 @@
       'CCFLAGS':      ['-DWIN32'],
       'CXXFLAGS':     ['-DWIN32'],
     },
+    'os:android': {
+      'CPPDEFINES':   ['ANDROID', '__ARM_ARCH_5__', '__ARM_ARCH_5T__',
+                       '__ARM_ARCH_5E__', '__ARM_ARCH_5TE__'],
+      'CCFLAGS':      ANDROID_FLAGS,
+      'WARNINGFLAGS': ['-Wall', '-Wno-unused', '-Werror=return-type',
+                       '-Wstrict-aliasing=2'],
+      'CPPPATH':      ANDROID_INCLUDES,
+    },
     'wordsize:64': {
       'CCFLAGS':      ['-m32'],
       'LINKFLAGS':    ['-m32']
@@ -114,14 +160,23 @@
   'gcc': {
     'all': {
       'CXXFLAGS':     [], #['-fvisibility=hidden'],
-      'WARNINGFLAGS': ['-pedantic', '-Wall', '-Werror', '-W',
+      'WARNINGFLAGS': ['-Wall', '-Werror', '-W',
           '-Wno-unused-parameter']
     },
     'arch:arm': {
       'CPPDEFINES':   ['ARM']
     },
+    'arch:android': {
+      'CPPDEFINES':   ['ARM']
+    },
     'os:win32': {
-      'WARNINGFLAGS': ['-Wno-long-long']
+      'WARNINGFLAGS': ['-pedantic', '-Wno-long-long']
+    },
+    'os:linux': {
+      'WARNINGFLAGS': ['-pedantic']
+    },
+    'os:macos': {
+      'WARNINGFLAGS': ['-pedantic']
     },
     'disassembler:on': {
       'CPPDEFINES':   ['ENABLE_DISASSEMBLER']
@@ -151,7 +206,7 @@
 MKSNAPSHOT_EXTRA_FLAGS = {
   'gcc': {
     'os:linux': {
-      'LIBS': ['pthread'],
+      'LIBS': ['pthread', 'rt'],
     },
     'os:macos': {
       'LIBS': ['pthread'],
@@ -174,7 +229,7 @@
 DTOA_EXTRA_FLAGS = {
   'gcc': {
     'all': {
-      'WARNINGFLAGS': ['-Werror']
+      'WARNINGFLAGS': ['-Werror', '-Wno-uninitialized']
     }
   },
   'msvc': {
@@ -195,7 +250,7 @@
       'LIBPATH': [abspath('.')]
     },
     'os:linux': {
-      'LIBS':         ['pthread'],
+      'LIBS':         ['pthread', 'rt'],
     },
     'os:macos': {
       'LIBS':         ['pthread'],
@@ -230,10 +285,11 @@
   },
   'gcc': {
     'all': {
-      'LIBPATH': ['.']
+      'LIBPATH': ['.'],
+      'CCFLAGS': ['-fno-rtti', '-fno-exceptions']
     },
     'os:linux': {
-      'LIBS':         ['pthread'],
+      'LIBS':         ['pthread', 'rt'],
     },
     'os:macos': {
       'LIBS':         ['pthread'],
@@ -244,6 +300,27 @@
     'os:win32': {
       'LIBS':         ['winmm', 'ws2_32']
     },
+    'os:android': {
+      'CPPDEFINES':   ['ANDROID', '__ARM_ARCH_5__', '__ARM_ARCH_5T__',
+                       '__ARM_ARCH_5E__', '__ARM_ARCH_5TE__'],
+      'CCFLAGS':      ANDROID_FLAGS,
+      'CPPPATH':      ANDROID_INCLUDES,
+      'LIBPATH':     [ANDROID_TOP + '/out/target/product/generic/obj/lib'],
+      'LINKFLAGS':    ['-nostdlib',
+                       '-Bdynamic',
+                       '-Wl,-T,' + ANDROID_TOP + '/build/core/armelf.x',
+                       '-Wl,-dynamic-linker,/system/bin/linker',
+                       '-Wl,--gc-sections',
+                       '-Wl,-z,nocopyreloc',
+                       '-Wl,-rpath-link=' + ANDROID_TOP + '/out/target/product/generic/obj/lib',
+                       ANDROID_TOP + '/out/target/product/generic/obj/lib/crtbegin_dynamic.o',
+                       ANDROID_TOP + '/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/lib/gcc/arm-eabi/4.2.1/interwork/libgcc.a',
+                       ANDROID_TOP + '/out/target/product/generic/obj/lib/crtend_android.o'],
+      'LIBS':         ['c', 'stdc++', 'm'],
+      'mode:release': {
+        'CPPDEFINES': ['SK_RELEASE', 'NDEBUG']
+      }
+    },
     'wordsize:64': {
       'CCFLAGS':      ['-m32'],
       'LINKFLAGS':    ['-m32']
@@ -301,7 +378,7 @@
       'LIBS': ['readline']
     },
     'os:linux': {
-      'LIBS': ['pthread'],
+      'LIBS': ['pthread', 'rt'],
     },
     'os:macos': {
       'LIBS': ['pthread'],
@@ -355,7 +432,7 @@
     'help': 'the toolchain to use'
   },
   'os': {
-    'values': ['freebsd', 'linux', 'macos', 'win32'],
+    'values': ['freebsd', 'linux', 'macos', 'win32', 'android'],
     'default': OS_GUESS,
     'help': 'the os to build for'
   },
@@ -510,6 +587,8 @@
           options[key] = prefix + value
 
   def ConfigureObject(self, env, input, **kw):
+    if (kw.has_key('CPPPATH') and env.has_key('CPPPATH')):
+      kw['CPPPATH'] += env['CPPPATH']
     if self.options['library'] == 'static':
       return env.StaticObject(input, **kw)
     else:
@@ -574,7 +653,7 @@
   library_name = 'v8' + suffix
   env['LIBRARY'] = library_name
 
-  # Build the object files by invoking SCons recursively.  
+  # Build the object files by invoking SCons recursively.
   (object_files, shell_files, mksnapshot) = env.SConscript(
     join('src', 'SConscript'),
     build_dir=join('obj', target_id),
@@ -596,7 +675,7 @@
     pdb_name = library_name + '.dll.pdb'
     library = env.SharedLibrary(library_name, object_files, PDB=pdb_name)
   context.library_targets.append(library)
-  
+
   d8_env = Environment()
   d8_env.Replace(**context.flags['d8'])
   shell = d8_env.Program('d8' + suffix, object_files + shell_files)
@@ -616,7 +695,7 @@
     sample_program = sample_env.Program(sample_name, sample_object)
     sample_env.Depends(sample_program, library)
     context.sample_targets.append(sample_program)
-  
+
   cctest_program = env.SConscript(
     join('test', 'cctest', 'SConscript'),
     build_dir=join('obj', 'test', target_id),
@@ -624,7 +703,7 @@
     duplicate=False
   )
   context.cctest_targets.append(cctest_program)
-  
+
   return context
 
 
diff --git a/include/v8-debug.h b/include/v8-debug.h
index 42bb24f..74750d1 100644
--- a/include/v8-debug.h
+++ b/include/v8-debug.h
@@ -162,9 +162,10 @@
  /**
   * Enable the V8 builtin debug agent. The debugger agent will listen on the
   * supplied TCP/IP port for remote debugger connection.
+  * \param name the name of the embedding application
   * \param port the TCP/IP port to listen on
   */
-  static bool EnableAgent(int port);
+  static bool EnableAgent(const char* name, int port);
 };
 
 
diff --git a/include/v8.h b/include/v8.h
index ac772cf..a6851c9 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -51,8 +51,8 @@
 // the V8 DLL USING_V8_SHARED needs to be defined. When either building the V8
 // static library or building a program which uses the V8 static library neither
 // BUILDING_V8_SHARED nor USING_V8_SHARED should be defined.
-// The reason for having both EXPORT and EXPORT_INLINE is that classes which
-// have their code inside this header file needs to have __declspec(dllexport)
+// The reason for having both V8EXPORT and V8EXPORT_INLINE is that classes which
+// have their code inside this header file need to have __declspec(dllexport)
 // when building the DLL but cannot have __declspec(dllimport) when building
 // a program which uses the DLL.
 #if defined(BUILDING_V8_SHARED) && defined(USING_V8_SHARED)
@@ -61,14 +61,14 @@
 #endif
 
 #ifdef BUILDING_V8_SHARED
-#define EXPORT __declspec(dllexport)
-#define EXPORT_INLINE __declspec(dllexport)
+#define V8EXPORT __declspec(dllexport)
+#define V8EXPORT_INLINE __declspec(dllexport)
 #elif USING_V8_SHARED
-#define EXPORT __declspec(dllimport)
-#define EXPORT_INLINE
+#define V8EXPORT __declspec(dllimport)
+#define V8EXPORT_INLINE
 #else
-#define EXPORT
-#define EXPORT_INLINE
+#define V8EXPORT
+#define V8EXPORT_INLINE
 #endif  // BUILDING_V8_SHARED
 
 #else  // _WIN32
@@ -80,11 +80,11 @@
 // the shared or static V8 library as there is on Windows. Therefore there is
 // no checking of BUILDING_V8_SHARED and USING_V8_SHARED.
 #if defined(__GNUC__) && (__GNUC__ >= 4)
-#define EXPORT __attribute__ ((visibility("default")))
-#define EXPORT_INLINE __attribute__ ((visibility("default")))
+#define V8EXPORT __attribute__ ((visibility("default")))
+#define V8EXPORT_INLINE __attribute__ ((visibility("default")))
 #else  // defined(__GNUC__) && (__GNUC__ >= 4)
-#define EXPORT
-#define EXPORT_INLINE
+#define V8EXPORT
+#define V8EXPORT_INLINE
 #endif  // defined(__GNUC__) && (__GNUC__ >= 4)
 
 #endif  // _WIN32
@@ -164,7 +164,7 @@
  * behind the scenes and the same rules apply to these values as to
  * their handles.
  */
-template <class T> class EXPORT_INLINE Handle {
+template <class T> class V8EXPORT_INLINE Handle {
  public:
 
   /**
@@ -252,7 +252,7 @@
  * handle scope are destroyed when the handle scope is destroyed.  Hence it
  * is not necessary to explicitly deallocate local handles.
  */
-template <class T> class EXPORT_INLINE Local : public Handle<T> {
+template <class T> class V8EXPORT_INLINE Local : public Handle<T> {
  public:
   Local();
   template <class S> inline Local(Local<S> that)
@@ -295,7 +295,7 @@
  * different storage cells but rather two references to the same
  * storage cell.
  */
-template <class T> class EXPORT_INLINE Persistent : public Handle<T> {
+template <class T> class V8EXPORT_INLINE Persistent : public Handle<T> {
  public:
 
   /**
@@ -394,7 +394,7 @@
  * handle and may deallocate it.  The behavior of accessing a handle
  * for which the handle scope has been deleted is undefined.
  */
-class EXPORT HandleScope {
+class V8EXPORT HandleScope {
  public:
   HandleScope();
 
@@ -426,7 +426,7 @@
 
   // This Data class is accessible internally through a typedef in the
   // ImplementationUtilities class.
-  class EXPORT Data {
+  class V8EXPORT Data {
    public:
     int extensions;
     void** next;
@@ -454,7 +454,7 @@
 /**
  * The superclass of values and API object templates.
  */
-class EXPORT Data {
+class V8EXPORT Data {
  private:
   Data();
 };
@@ -466,7 +466,7 @@
  * compiling it, and can be stored between compilations.  When script
  * data is given to the compile method compilation will be faster.
  */
-class EXPORT ScriptData {  // NOLINT
+class V8EXPORT ScriptData {  // NOLINT
  public:
   virtual ~ScriptData() { }
   static ScriptData* PreCompile(const char* input, int length);
@@ -480,7 +480,7 @@
 /**
  * The origin, within a file, of a script.
  */
-class EXPORT ScriptOrigin {
+class V8EXPORT ScriptOrigin {
  public:
   ScriptOrigin(Handle<Value> resource_name,
                Handle<Integer> resource_line_offset = Handle<Integer>(),
@@ -501,7 +501,7 @@
 /**
  * A compiled JavaScript script.
  */
-class EXPORT Script {
+class V8EXPORT Script {
  public:
 
   /**
@@ -535,7 +535,7 @@
 /**
  * An error message.
  */
-class EXPORT Message {
+class V8EXPORT Message {
  public:
   Local<String> Get() const;
   Local<String> GetSourceLine() const;
@@ -582,7 +582,7 @@
 /**
  * The superclass of all JavaScript values and objects.
  */
-class EXPORT Value : public Data {
+class V8EXPORT Value : public Data {
  public:
 
   /**
@@ -683,14 +683,14 @@
 /**
  * The superclass of primitive values.  See ECMA-262 4.3.2.
  */
-class EXPORT Primitive : public Value { };
+class V8EXPORT Primitive : public Value { };
 
 
 /**
  * A primitive boolean value (ECMA-262, 4.3.14).  Either the true
  * or false value.
  */
-class EXPORT Boolean : public Primitive {
+class V8EXPORT Boolean : public Primitive {
  public:
   bool Value() const;
   static inline Handle<Boolean> New(bool value);
@@ -700,7 +700,7 @@
 /**
  * A JavaScript string value (ECMA-262, 4.3.17).
  */
-class EXPORT String : public Primitive {
+class V8EXPORT String : public Primitive {
  public:
 
   /**
@@ -755,7 +755,7 @@
    * ExternalStringResource to manage the life cycle of the underlying
    * buffer.  Note that the string data must be immutable.
    */
-  class EXPORT ExternalStringResource {  // NOLINT
+  class V8EXPORT ExternalStringResource {  // NOLINT
    public:
     /**
      * Override the destructor to manage the life cycle of the underlying
@@ -785,7 +785,7 @@
    * Use String::New or convert to 16 bit data for non-ASCII.
    */
 
-  class EXPORT ExternalAsciiStringResource {  // NOLINT
+  class V8EXPORT ExternalAsciiStringResource {  // NOLINT
    public:
     /**
      * Override the destructor to manage the life cycle of the underlying
@@ -844,7 +844,7 @@
    * external string resource.
    */
   static Local<String> NewExternal(ExternalStringResource* resource);
-  
+
   /**
    * Associate an external string resource with this string by transforming it
    * in place so that existing references to this string in the JavaScript heap
@@ -864,7 +864,7 @@
    * external string resource.
    */
   static Local<String> NewExternal(ExternalAsciiStringResource* resource);
-  
+
   /**
    * Associate an external string resource with this string by transforming it
    * in place so that existing references to this string in the JavaScript heap
@@ -885,7 +885,7 @@
    * Converts an object to a utf8-encoded character array.  Useful if
    * you want to print the object.
    */
-  class EXPORT Utf8Value {
+  class V8EXPORT Utf8Value {
    public:
     explicit Utf8Value(Handle<v8::Value> obj);
     ~Utf8Value();
@@ -904,7 +904,7 @@
    * Converts an object to an ascii string.
    * Useful if you want to print the object.
    */
-  class EXPORT AsciiValue {
+  class V8EXPORT AsciiValue {
    public:
     explicit AsciiValue(Handle<v8::Value> obj);
     ~AsciiValue();
@@ -922,7 +922,7 @@
   /**
    * Converts an object to a two-byte string.
    */
-  class EXPORT Value {
+  class V8EXPORT Value {
    public:
     explicit Value(Handle<v8::Value> obj);
     ~Value();
@@ -942,7 +942,7 @@
 /**
  * A JavaScript number value (ECMA-262, 4.3.20)
  */
-class EXPORT Number : public Primitive {
+class V8EXPORT Number : public Primitive {
  public:
   double Value() const;
   static Local<Number> New(double value);
@@ -955,7 +955,7 @@
 /**
  * A JavaScript value representing a signed integer.
  */
-class EXPORT Integer : public Number {
+class V8EXPORT Integer : public Number {
  public:
   static Local<Integer> New(int32_t value);
   int64_t Value() const;
@@ -968,7 +968,7 @@
 /**
  * A JavaScript value representing a 32-bit signed integer.
  */
-class EXPORT Int32 : public Integer {
+class V8EXPORT Int32 : public Integer {
  public:
   int32_t Value() const;
  private:
@@ -979,7 +979,7 @@
 /**
  * A JavaScript value representing a 32-bit unsigned integer.
  */
-class EXPORT Uint32 : public Integer {
+class V8EXPORT Uint32 : public Integer {
  public:
   uint32_t Value() const;
  private:
@@ -990,7 +990,7 @@
 /**
  * An instance of the built-in Date constructor (ECMA-262, 15.9).
  */
-class EXPORT Date : public Value {
+class V8EXPORT Date : public Value {
  public:
   static Local<Value> New(double time);
 
@@ -1014,7 +1014,7 @@
 /**
  * A JavaScript object (ECMA-262, 4.3.3)
  */
-class EXPORT Object : public Value {
+class V8EXPORT Object : public Value {
  public:
   bool Set(Handle<Value> key,
            Handle<Value> value,
@@ -1113,7 +1113,7 @@
 /**
  * An instance of the built-in array constructor (ECMA-262, 15.4.2).
  */
-class EXPORT Array : public Object {
+class V8EXPORT Array : public Object {
  public:
   uint32_t Length() const;
 
@@ -1127,7 +1127,7 @@
 /**
  * A JavaScript function object (ECMA-262, 15.3).
  */
-class EXPORT Function : public Object {
+class V8EXPORT Function : public Object {
  public:
   Local<Object> NewInstance() const;
   Local<Object> NewInstance(int argc, Handle<Value> argv[]) const;
@@ -1141,12 +1141,21 @@
 
 
 /**
- * A JavaScript value that wraps a c++ void*.  This type of value is
- * mainly used to associate c++ data structures with JavaScript
+ * A JavaScript value that wraps a C++ void*.  This type of value is
+ * mainly used to associate C++ data structures with JavaScript
  * objects.
+ *
+ * The Wrap function V8 will return the most optimal Value object wrapping the
+ * C++ void*. The type of the value is not guaranteed to be an External object
+ * and no assumptions about its type should be made. To access the wrapped
+ * value Unwrap should be used, all other operations on that object will lead
+ * to unpredictable results.
  */
-class EXPORT External : public Value {
+class V8EXPORT External : public Value {
  public:
+  static Local<Value> Wrap(void* data);
+  static void* Unwrap(Handle<Value> obj);
+
   static Local<External> New(void* value);
   static External* Cast(Value* obj);
   void* Value() const;
@@ -1161,7 +1170,7 @@
 /**
  * The superclass of object and function templates.
  */
-class EXPORT Template : public Data {
+class V8EXPORT Template : public Data {
  public:
   /** Adds a property to each instance created by this template.*/
   void Set(Handle<String> name, Handle<Data> value,
@@ -1181,7 +1190,7 @@
  * including the receiver, the number and values of arguments, and
  * the holder of the function.
  */
-class EXPORT Arguments {
+class V8EXPORT Arguments {
  public:
   inline int Length() const;
   inline Local<Value> operator[](int i) const;
@@ -1211,7 +1220,7 @@
  * The information passed to an accessor callback about the context
  * of the property access.
  */
-class EXPORT AccessorInfo {
+class V8EXPORT AccessorInfo {
  public:
   inline AccessorInfo(Local<Object> self,
                       Local<Value> data,
@@ -1465,7 +1474,7 @@
  *   child_instance.instance_property == 3;
  * \endcode
  */
-class EXPORT FunctionTemplate : public Template {
+class V8EXPORT FunctionTemplate : public Template {
  public:
   /** Creates a function template.*/
   static Local<FunctionTemplate> New(
@@ -1557,7 +1566,7 @@
  * Properties added to an ObjectTemplate are added to each object
  * created from the ObjectTemplate.
  */
-class EXPORT ObjectTemplate : public Template {
+class V8EXPORT ObjectTemplate : public Template {
  public:
   /** Creates an ObjectTemplate. */
   static Local<ObjectTemplate> New();
@@ -1699,7 +1708,7 @@
  * A Signature specifies which receivers and arguments a function can
  * legally be called with.
  */
-class EXPORT Signature : public Data {
+class V8EXPORT Signature : public Data {
  public:
   static Local<Signature> New(Handle<FunctionTemplate> receiver =
                                   Handle<FunctionTemplate>(),
@@ -1714,7 +1723,7 @@
  * A utility for determining the type of objects based on the template
  * they were constructed from.
  */
-class EXPORT TypeSwitch : public Data {
+class V8EXPORT TypeSwitch : public Data {
  public:
   static Local<TypeSwitch> New(Handle<FunctionTemplate> type);
   static Local<TypeSwitch> New(int argc, Handle<FunctionTemplate> types[]);
@@ -1730,7 +1739,7 @@
 /**
  * Ignore
  */
-class EXPORT Extension {  // NOLINT
+class V8EXPORT Extension {  // NOLINT
  public:
   Extension(const char* name,
             const char* source = 0,
@@ -1762,13 +1771,13 @@
 };
 
 
-void EXPORT RegisterExtension(Extension* extension);
+void V8EXPORT RegisterExtension(Extension* extension);
 
 
 /**
  * Ignore
  */
-class EXPORT DeclareExtension {
+class V8EXPORT DeclareExtension {
  public:
   inline DeclareExtension(Extension* extension) {
     RegisterExtension(extension);
@@ -1779,17 +1788,17 @@
 // --- S t a t i c s ---
 
 
-Handle<Primitive> EXPORT Undefined();
-Handle<Primitive> EXPORT Null();
-Handle<Boolean> EXPORT True();
-Handle<Boolean> EXPORT False();
+Handle<Primitive> V8EXPORT Undefined();
+Handle<Primitive> V8EXPORT Null();
+Handle<Boolean> V8EXPORT True();
+Handle<Boolean> V8EXPORT False();
 
 
 /**
  * A set of constraints that specifies the limits of the runtime's
  * memory use.
  */
-class EXPORT ResourceConstraints {
+class V8EXPORT ResourceConstraints {
  public:
   ResourceConstraints();
   int max_young_space_size() const { return max_young_space_size_; }
@@ -1823,13 +1832,13 @@
  * operation; the caller must return immediately and only after the exception
  * has been handled does it become legal to invoke JavaScript operations.
  */
-Handle<Value> EXPORT ThrowException(Handle<Value> exception);
+Handle<Value> V8EXPORT ThrowException(Handle<Value> exception);
 
 /**
  * Create new error objects by calling the corresponding error object
  * constructor with the message.
  */
-class EXPORT Exception {
+class V8EXPORT Exception {
  public:
   static Local<Value> RangeError(Handle<String> message);
   static Local<Value> ReferenceError(Handle<String> message);
@@ -1843,6 +1852,13 @@
 
 typedef int* (*CounterLookupCallback)(const char* name);
 
+typedef void* (*CreateHistogramCallback)(const char* name,
+                                         int min,
+                                         int max,
+                                         size_t buckets);
+
+typedef void (*AddHistogramSampleCallback)(void* histogram, int sample);
+
 // --- F a i l e d A c c e s s C h e c k C a l l b a c k ---
 typedef void (*FailedAccessCheckCallback)(Local<Object> target,
                                           AccessType type,
@@ -1872,7 +1888,7 @@
 /**
  * Container class for static utility functions.
  */
-class EXPORT V8 {
+class V8EXPORT V8 {
  public:
   /** Set the callback to invoke in case of fatal errors. */
   static void SetFatalErrorHandler(FatalErrorCallback that);
@@ -1933,6 +1949,15 @@
   static void SetCounterFunction(CounterLookupCallback);
 
   /**
+   * Enables the host application to provide a mechanism for recording
+   * histograms. The CreateHistogram function returns a
+   * histogram which will later be passed to the AddHistogramSample
+   * function.
+   */
+  static void SetCreateHistogramFunction(CreateHistogramCallback);
+  static void SetAddHistogramSampleFunction(AddHistogramSampleCallback);
+
+  /**
    * Enables the computation of a sliding window of states. The sliding
    * window information is recorded in statistics counters.
    */
@@ -2028,7 +2053,7 @@
 /**
  * An external exception handler.
  */
-class EXPORT TryCatch {
+class V8EXPORT TryCatch {
  public:
 
   /**
@@ -2107,7 +2132,7 @@
 /**
  * Ignore
  */
-class EXPORT ExtensionConfiguration {
+class V8EXPORT ExtensionConfiguration {
  public:
   ExtensionConfiguration(int name_count, const char* names[])
       : name_count_(name_count), names_(names) { }
@@ -2122,7 +2147,7 @@
  * A sandboxed execution context with its own set of built-in objects
  * and functions.
  */
-class EXPORT Context {
+class V8EXPORT Context {
  public:
   /** Returns the global object of the context. */
   Local<Object> Global();
@@ -2181,7 +2206,7 @@
    * Stack-allocated class which sets the execution context for all
    * operations executed within a local scope.
    */
-  class EXPORT Scope {
+  class V8EXPORT Scope {
    public:
     inline Scope(Handle<Context> context) : context_(context) {
       context_->Enter();
@@ -2267,14 +2292,14 @@
  * // V8 Now no longer locked.
  * \endcode
  */
-class EXPORT Unlocker {
+class V8EXPORT Unlocker {
  public:
   Unlocker();
   ~Unlocker();
 };
 
 
-class EXPORT Locker {
+class V8EXPORT Locker {
  public:
   Locker();
   ~Locker();
@@ -2485,8 +2510,8 @@
 }  // namespace v8
 
 
-#undef EXPORT
-#undef EXPORT_INLINE
+#undef V8EXPORT
+#undef V8EXPORT_INLINE
 #undef TYPE_CHECK
 
 
diff --git a/samples/shell.cc b/samples/shell.cc
index 63e2944..d85e6ea 100644
--- a/samples/shell.cc
+++ b/samples/shell.cc
@@ -26,9 +26,10 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <v8.h>
-#include <cstring>
-#include <cstdio>
-#include <cstdlib>
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
 
 
 void RunShell(v8::Handle<v8::Context> context);
diff --git a/src/SConscript b/src/SConscript
index 67f7889..5ea7441 100644
--- a/src/SConscript
+++ b/src/SConscript
@@ -66,9 +66,10 @@
     'stub-cache-ia32.cc', 'virtual-frame-ia32.cc'
   ],
   'simulator:arm': ['simulator-arm.cc'],
-  'os:freebsd': ['platform-freebsd.cc'],
-  'os:linux':   ['platform-linux.cc'],
-  'os:macos':   ['platform-macos.cc'],
+  'os:freebsd': ['platform-freebsd.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'],
   'os:nullos':  ['platform-nullos.cc'],
   'os:win32':   ['platform-win32.cc'],
   'mode:release': [],
diff --git a/src/allocation.cc b/src/allocation.cc
index d7d21aa..3d26123 100644
--- a/src/allocation.cc
+++ b/src/allocation.cc
@@ -87,6 +87,16 @@
 }
 
 
+char* StrNDup(const char* str, size_t n) {
+  size_t length = strlen(str);
+  if (n < length) length = n;
+  char* result = NewArray<char>(length + 1);
+  memcpy(result, str, length * kCharSize);
+  result[length] = '\0';
+  return result;
+}
+
+
 int NativeAllocationChecker::allocation_disallowed_ = 0;
 
 
diff --git a/src/allocation.h b/src/allocation.h
index 35e68bd..a690f08 100644
--- a/src/allocation.h
+++ b/src/allocation.h
@@ -119,10 +119,11 @@
 }
 
 
-// The normal strdup function uses malloc.  This version of StrDup
-// uses new and calls the FatalProcessOutOfMemory handler if
-// allocation fails.
+// The normal strdup functions use malloc.  These versions of StrDup
+// and StrNDup uses new and calls the FatalProcessOutOfMemory handler
+// if allocation fails.
 char* StrDup(const char* str);
+char* StrNDup(const char* str, size_t n);
 
 
 // Allocation policy for allocating in the C free store using malloc
diff --git a/src/api.cc b/src/api.cc
index c4049a8..00fefc0 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -2116,7 +2116,7 @@
   i::Handle<i::String> str = Utils::OpenHandle(this);
   // Flatten the string for efficiency.  This applies whether we are
   // using StringInputBuffer or Get(i) to access the characters.
-  str->TryFlattenIfNotFlat(i::StringShape(*str));
+  str->TryFlattenIfNotFlat();
   int end = length;
   if ( (length == -1) || (length > str->length() - start) )
     end = str->length() - start;
@@ -2141,7 +2141,7 @@
   i::Handle<i::String> str = Utils::OpenHandle(this);
   // Flatten the string for efficiency.  This applies whether we are
   // using StringInputBuffer or Get(i) to access the characters.
-  str->TryFlattenIfNotFlat(i::StringShape(*str));
+  str->TryFlattenIfNotFlat();
   int end = length;
   if ( (length == -1) || (length > str->length() - start) )
     end = str->length() - start;
@@ -2159,16 +2159,14 @@
 bool v8::String::IsExternal() const {
   EnsureInitialized("v8::String::IsExternal()");
   i::Handle<i::String> str = Utils::OpenHandle(this);
-  i::StringShape shape(*str);
-  return shape.IsExternalTwoByte();
+  return i::StringShape(*str).IsExternalTwoByte();
 }
 
 
 bool v8::String::IsExternalAscii() const {
   EnsureInitialized("v8::String::IsExternalAscii()");
   i::Handle<i::String> str = Utils::OpenHandle(this);
-  i::StringShape shape(*str);
-  return shape.IsExternalAscii();
+  return i::StringShape(*str).IsExternalAscii();
 }
 
 
@@ -2228,13 +2226,6 @@
 }
 
 
-void* External::Value() const {
-  if (IsDeadCheck("v8::External::Value()")) return 0;
-  i::Handle<i::Object> obj = Utils::OpenHandle(this);
-  return reinterpret_cast<void*>(i::Proxy::cast(*obj)->proxy());
-}
-
-
 int v8::Object::InternalFieldCount() {
   if (IsDeadCheck("v8::Object::InternalFieldCount()")) return 0;
   i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
@@ -2282,7 +2273,7 @@
 
 
 const char* v8::V8::GetVersion() {
-  return "1.1.1.4";
+  return "1.1.2";
 }
 
 
@@ -2465,12 +2456,58 @@
 }
 
 
+static Local<External> ExternalNewImpl(void* data) {
+  return Utils::ToLocal(i::Factory::NewProxy(static_cast<i::Address>(data)));
+}
+
+static void* ExternalValueImpl(i::Handle<i::Object> obj) {
+  return reinterpret_cast<void*>(i::Proxy::cast(*obj)->proxy());
+}
+
+
+static const intptr_t kAlignedPointerMask = 3;
+static const int kAlignedPointerShift = 2;
+
+
+Local<Value> v8::External::Wrap(void* data) {
+  STATIC_ASSERT(sizeof(data) == sizeof(i::Address));
+  LOG_API("External::Wrap");
+  EnsureInitialized("v8::External::Wrap()");
+  if ((reinterpret_cast<intptr_t>(data) & kAlignedPointerMask) == 0) {
+    uintptr_t data_ptr = reinterpret_cast<uintptr_t>(data);
+    int data_value = static_cast<int>(data_ptr >> kAlignedPointerShift);
+    STATIC_ASSERT(sizeof(data_ptr) == sizeof(data_value));
+    i::Handle<i::Object> obj(i::Smi::FromInt(data_value));
+    return Utils::ToLocal(obj);
+  }
+  return ExternalNewImpl(data);
+}
+
+
+void* v8::External::Unwrap(v8::Handle<v8::Value> value) {
+  if (IsDeadCheck("v8::External::Unwrap()")) return 0;
+  i::Handle<i::Object> obj = Utils::OpenHandle(*value);
+  if (obj->IsSmi()) {
+    // The external value was an aligned pointer.
+    uintptr_t result = i::Smi::cast(*obj)->value() << kAlignedPointerShift;
+    return reinterpret_cast<void*>(result);
+  }
+  return ExternalValueImpl(obj);
+}
+
+
 Local<External> v8::External::New(void* data) {
   STATIC_ASSERT(sizeof(data) == sizeof(i::Address));
   LOG_API("External::New");
   EnsureInitialized("v8::External::New()");
-  i::Handle<i::Proxy> obj = i::Factory::NewProxy(static_cast<i::Address>(data));
-  return Utils::ToLocal(obj);
+  return ExternalNewImpl(data);
+}
+
+
+void* External::Value() const {
+  if (IsDeadCheck("v8::External::Value()")) return 0;
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  return ExternalValueImpl(obj);
 }
 
 
@@ -2791,6 +2828,15 @@
   i::StatsTable::SetCounterFunction(callback);
 }
 
+void V8::SetCreateHistogramFunction(CreateHistogramCallback callback) {
+  if (IsDeadCheck("v8::V8::SetCreateHistogramFunction()")) return;
+  i::StatsTable::SetCreateHistogramFunction(callback);
+}
+
+void V8::SetAddHistogramSampleFunction(AddHistogramSampleCallback callback) {
+  if (IsDeadCheck("v8::V8::SetAddHistogramSampleFunction()")) return;
+  i::StatsTable::SetAddHistogramSampleFunction(callback);
+}
 
 void V8::EnableSlidingStateWindow() {
   if (IsDeadCheck("v8::V8::EnableSlidingStateWindow()")) return;
@@ -3067,8 +3113,8 @@
 }
 
 
-bool Debug::EnableAgent(int port) {
-  return i::Debugger::StartAgent(port);
+bool Debug::EnableAgent(const char* name, int port) {
+  return i::Debugger::StartAgent(name, port);
 }
 
 
diff --git a/src/ast.cc b/src/ast.cc
index 25a2cd4..1a6010a 100644
--- a/src/ast.cc
+++ b/src/ast.cc
@@ -135,8 +135,12 @@
   Object* k = *key->handle();
   if (k->IsSymbol() && Heap::Proto_symbol()->Equals(String::cast(k))) {
     kind_ = PROTOTYPE;
+  } else if (value_->AsMaterializedLiteral() != NULL) {
+    kind_ = MATERIALIZED_LITERAL;
+  } else if (value_->AsLiteral() != NULL) {
+    kind_ = CONSTANT;
   } else {
-    kind_ = value_->AsLiteral() == NULL ? COMPUTED : CONSTANT;
+    kind_ = COMPUTED;
   }
 }
 
diff --git a/src/ast.h b/src/ast.h
index 2aeb148..1574479 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -95,6 +95,7 @@
 
 // Forward declarations
 class TargetCollector;
+class MaterializedLiteral;
 
 #define DEF_FORWARD_DECLARATION(type) class type;
 NODE_LIST(DEF_FORWARD_DECLARATION)
@@ -129,6 +130,9 @@
   virtual BinaryOperation* AsBinaryOperation() { return NULL; }
   virtual Assignment* AsAssignment() { return NULL; }
   virtual FunctionLiteral* AsFunctionLiteral() { return NULL; }
+  virtual MaterializedLiteral* AsMaterializedLiteral() { return NULL; }
+  virtual ObjectLiteral* AsObjectLiteral() { return NULL; }
+  virtual ArrayLiteral* AsArrayLiteral() { return NULL; }
 
   void set_statement_pos(int statement_pos) { statement_pos_ = statement_pos; }
   int statement_pos() const { return statement_pos_; }
@@ -287,8 +291,13 @@
   enum Type { DO_LOOP, FOR_LOOP, WHILE_LOOP };
 
   LoopStatement(ZoneStringList* labels, Type type)
-      : IterationStatement(labels), type_(type), init_(NULL),
-        cond_(NULL), next_(NULL) { }
+      : IterationStatement(labels),
+        type_(type),
+        init_(NULL),
+        cond_(NULL),
+        next_(NULL),
+        has_function_literal_(false) {
+  }
 
   void Initialize(Statement* init,
                   Expression* cond,
@@ -308,6 +317,7 @@
   Statement* init() const  { return init_; }
   Expression* cond() const  { return cond_; }
   Statement* next() const  { return next_; }
+  bool has_function_literal() const { return has_function_literal_; }
 
 #ifdef DEBUG
   const char* OperatorString() const;
@@ -318,6 +328,10 @@
   Statement* init_;
   Expression* cond_;
   Statement* next_;
+  // True if there is a function literal subexpression in the condition.
+  bool has_function_literal_;
+
+  friend class AstOptimizer;
 };
 
 
@@ -626,11 +640,23 @@
 // Base class for literals that needs space in the corresponding JSFunction.
 class MaterializedLiteral: public Expression {
  public:
-  explicit MaterializedLiteral(int literal_index)
-      : literal_index_(literal_index) {}
+  explicit MaterializedLiteral(int literal_index, bool is_simple, int depth)
+      : literal_index_(literal_index), is_simple_(is_simple), depth_(depth) {}
+
+  virtual MaterializedLiteral* AsMaterializedLiteral() { return this; }
+
   int literal_index() { return literal_index_; }
+
+  // A materialized literal is simple if the values consist of only
+  // constants and simple object and array literals.
+  bool is_simple() const { return is_simple_; }
+
+  int depth() const { return depth_; }
+
  private:
   int literal_index_;
+  bool is_simple_;
+  int depth_;
 };
 
 
@@ -645,10 +671,11 @@
    public:
 
     enum Kind {
-      CONSTANT,       // Property with constant value (at compile time).
-      COMPUTED,       // Property with computed value (at execution time).
-      GETTER, SETTER,  // Property is an accessor function.
-      PROTOTYPE       // Property is __proto__.
+      CONSTANT,              // Property with constant value (compile time).
+      COMPUTED,              // Property with computed value (execution time).
+      MATERIALIZED_LITERAL,  // Property value is a materialized literal.
+      GETTER, SETTER,        // Property is an accessor function.
+      PROTOTYPE              // Property is __proto__.
     };
 
     Property(Literal* key, Expression* value);
@@ -666,12 +693,14 @@
 
   ObjectLiteral(Handle<FixedArray> constant_properties,
                 ZoneList<Property*>* properties,
-                int literal_index)
-      : MaterializedLiteral(literal_index),
+                int literal_index,
+                bool is_simple,
+                int depth)
+      : MaterializedLiteral(literal_index, is_simple, depth),
         constant_properties_(constant_properties),
-        properties_(properties) {
-  }
+        properties_(properties) {}
 
+  virtual ObjectLiteral* AsObjectLiteral() { return this; }
   virtual void Accept(AstVisitor* v);
 
   Handle<FixedArray> constant_properties() const {
@@ -691,7 +720,7 @@
   RegExpLiteral(Handle<String> pattern,
                 Handle<String> flags,
                 int literal_index)
-      : MaterializedLiteral(literal_index),
+      : MaterializedLiteral(literal_index, false, 1),
         pattern_(pattern),
         flags_(flags) {}
 
@@ -707,14 +736,19 @@
 
 // An array literal has a literals object that is used
 // for minimizing the work when constructing it at runtime.
-class ArrayLiteral: public Expression {
+class ArrayLiteral: public MaterializedLiteral {
  public:
   ArrayLiteral(Handle<FixedArray> literals,
-               ZoneList<Expression*>* values)
-      : literals_(literals), values_(values) {
-  }
+               ZoneList<Expression*>* values,
+               int literal_index,
+               bool is_simple,
+               int depth)
+      : MaterializedLiteral(literal_index, is_simple, depth),
+        literals_(literals),
+        values_(values) {}
 
   virtual void Accept(AstVisitor* v);
+  virtual ArrayLiteral* AsArrayLiteral() { return this; }
 
   Handle<FixedArray> literals() const { return literals_; }
   ZoneList<Expression*>* values() const { return values_; }
diff --git a/src/char-predicates-inl.h b/src/char-predicates-inl.h
index 3ef2f91..217db9c 100644
--- a/src/char-predicates-inl.h
+++ b/src/char-predicates-inl.h
@@ -43,26 +43,28 @@
 }
 
 
+static inline bool IsInRange(int value, int lower_limit, int higher_limit) {
+  ASSERT(lower_limit <= higher_limit);
+  return static_cast<unsigned int>(value - lower_limit) <=
+      static_cast<unsigned int>(higher_limit - lower_limit);
+}
+
+
 inline bool IsDecimalDigit(uc32 c) {
   // ECMA-262, 3rd, 7.8.3 (p 16)
-  return
-    '0' <= c && c <= '9';
+  return IsInRange(c, '0', '9');
 }
 
 
 inline bool IsHexDigit(uc32 c) {
   // ECMA-262, 3rd, 7.6 (p 15)
-  return
-    ('0' <= c && c <= '9') ||
-    ('A' <= c && c <= 'F') ||
-    ('a' <= c && c <= 'f');
+  return IsDecimalDigit(c) || IsInRange(c | 0x20, 'a', 'f');
 }
 
 
 inline bool IsRegExpWord(uc16 c) {
-  return ('a' <= c && c <= 'z')
-      || ('A' <= c && c <= 'Z')
-      || ('0' <= c && c <= '9')
+  return IsInRange(c | 0x20, 'a', 'z')
+      || IsDecimalDigit(c)
       || (c == '_');
 }
 
diff --git a/src/codegen-arm.cc b/src/codegen-arm.cc
index 3236859..52009d9 100644
--- a/src/codegen-arm.cc
+++ b/src/codegen-arm.cc
@@ -1,4 +1,4 @@
-// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// 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:
@@ -30,8 +30,11 @@
 #include "bootstrapper.h"
 #include "codegen-inl.h"
 #include "debug.h"
-#include "scopes.h"
+#include "parser.h"
+#include "register-allocator-inl.h"
 #include "runtime.h"
+#include "scopes.h"
+
 
 namespace v8 { namespace internal {
 
@@ -376,6 +379,22 @@
 }
 
 
+void CodeGenerator::LoadConditionAndSpill(Expression* expression,
+                                          TypeofState typeof_state,
+                                          JumpTarget* true_target,
+                                          JumpTarget* false_target,
+                                          bool force_control) {
+  ASSERT(in_spilled_code());
+  set_in_spilled_code(false);
+  LoadCondition(expression, typeof_state, true_target, false_target,
+                force_control);
+  if (frame_ != NULL) {
+    frame_->SpillAll();
+  }
+  set_in_spilled_code(true);
+}
+
+
 // Loads a value on TOS. If it is a boolean value, the result may have been
 // (partially) translated into branches, or it may have set the condition
 // code register. If force_cc is set, the value is forced to set the
@@ -421,6 +440,16 @@
 }
 
 
+void CodeGenerator::LoadAndSpill(Expression* expression,
+                                 TypeofState typeof_state) {
+  ASSERT(in_spilled_code());
+  set_in_spilled_code(false);
+  Load(expression, typeof_state);
+  frame_->SpillAll();
+  set_in_spilled_code(true);
+}
+
+
 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) {
 #ifdef DEBUG
   int original_height = frame_->height();
@@ -1113,6 +1142,28 @@
 }
 
 
+void CodeGenerator::VisitAndSpill(Statement* statement) {
+  ASSERT(in_spilled_code());
+  set_in_spilled_code(false);
+  Visit(statement);
+  if (frame_ != NULL) {
+    frame_->SpillAll();
+    }
+  set_in_spilled_code(true);
+}
+
+
+void CodeGenerator::VisitStatementsAndSpill(ZoneList<Statement*>* statements) {
+  ASSERT(in_spilled_code());
+  set_in_spilled_code(false);
+  VisitStatements(statements);
+  if (frame_ != NULL) {
+    frame_->SpillAll();
+  }
+  set_in_spilled_code(true);
+}
+
+
 void CodeGenerator::VisitStatements(ZoneList<Statement*>* statements) {
 #ifdef DEBUG
   int original_height = frame_->height();
@@ -1966,14 +2017,17 @@
   CheckStack();  // TODO(1222600): ignore if body contains calls.
   VisitAndSpill(node->body());
 
-  // Next.
+  // Next.  Reestablish a spilled frame in case we are coming here via
+  // a continue in the body.
   node->continue_target()->Bind();
+  frame_->SpillAll();
   frame_->EmitPop(r0);
   __ add(r0, r0, Operand(Smi::FromInt(1)));
   frame_->EmitPush(r0);
   entry.Jump();
 
-  // Cleanup.
+  // Cleanup.  No need to spill because VirtualFrame::Drop is safe for
+  // any frame.
   node->break_target()->Bind();
   frame_->Drop(5);
 
@@ -2612,7 +2666,7 @@
 
 
 // This deferred code stub will be used for creating the boilerplate
-// by calling Runtime_CreateObjectLiteral.
+// by calling Runtime_CreateObjectLiteralBoilerplate.
 // Each created boilerplate is stored in the JSFunction and they are
 // therefore context dependent.
 class DeferredObjectLiteral: public DeferredCode {
@@ -2634,7 +2688,7 @@
   enter()->Bind();
   VirtualFrame::SpilledScope spilled_scope(generator());
 
-  // If the entry is undefined we call the runtime system to computed
+  // If the entry is undefined we call the runtime system to compute
   // the literal.
 
   VirtualFrame* frame = generator()->frame();
@@ -2686,7 +2740,11 @@
   frame_->EmitPush(r2);
 
   // Clone the boilerplate object.
-  frame_->CallRuntime(Runtime::kCloneObjectLiteralBoilerplate, 1);
+  Runtime::FunctionId clone_function_id = Runtime::kCloneLiteralBoilerplate;
+  if (node->depth() == 1) {
+    clone_function_id = Runtime::kCloneShallowLiteralBoilerplate;
+  }
+  frame_->CallRuntime(clone_function_id, 1);
   frame_->EmitPush(r0);  // save the result
   // r0: cloned object literal
 
@@ -2695,7 +2753,11 @@
     Literal* key = property->key();
     Expression* value = property->value();
     switch (property->kind()) {
-      case ObjectLiteral::Property::CONSTANT: break;
+      case ObjectLiteral::Property::CONSTANT:
+        break;
+      case ObjectLiteral::Property::MATERIALIZED_LITERAL:
+        if (CompileTimeValue::IsCompileTimeValue(property->value())) break;
+        // else fall through
       case ObjectLiteral::Property::COMPUTED:  // fall through
       case ObjectLiteral::Property::PROTOTYPE: {
         frame_->EmitPush(r0);  // dup the result
@@ -2732,6 +2794,49 @@
 }
 
 
+// This deferred code stub will be used for creating the boilerplate
+// by calling Runtime_CreateArrayLiteralBoilerplate.
+// Each created boilerplate is stored in the JSFunction and they are
+// therefore context dependent.
+class DeferredArrayLiteral: public DeferredCode {
+ public:
+  DeferredArrayLiteral(CodeGenerator* generator, ArrayLiteral* node)
+      : DeferredCode(generator), node_(node) {
+    set_comment("[ DeferredArrayLiteral");
+  }
+
+  virtual void Generate();
+
+ private:
+  ArrayLiteral* node_;
+};
+
+
+void DeferredArrayLiteral::Generate() {
+  // Argument is passed in r1.
+  enter()->Bind();
+  VirtualFrame::SpilledScope spilled_scope(generator());
+
+  // If the entry is undefined we call the runtime system to computed
+  // the literal.
+
+  VirtualFrame* frame = generator()->frame();
+  // Literal array (0).
+  frame->EmitPush(r1);
+  // Literal index (1).
+  __ mov(r0, Operand(Smi::FromInt(node_->literal_index())));
+  frame->EmitPush(r0);
+  // Constant properties (2).
+  __ mov(r0, Operand(node_->literals()));
+  frame->EmitPush(r0);
+  Result boilerplate =
+      frame->CallRuntime(Runtime::kCreateArrayLiteralBoilerplate, 3);
+  __ mov(r2, Operand(boilerplate.reg()));
+  // Result is returned in r2.
+  exit_.Jump();
+}
+
+
 void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) {
 #ifdef DEBUG
   int original_height = frame_->height();
@@ -2739,43 +2844,67 @@
   VirtualFrame::SpilledScope spilled_scope(this);
   Comment cmnt(masm_, "[ ArrayLiteral");
 
-  // Call runtime to create the array literal.
-  __ mov(r0, Operand(node->literals()));
-  frame_->EmitPush(r0);
-  // Load the function of this frame.
-  __ ldr(r0, frame_->Function());
-  __ ldr(r0, FieldMemOperand(r0, JSFunction::kLiteralsOffset));
-  frame_->EmitPush(r0);
-  frame_->CallRuntime(Runtime::kCreateArrayLiteral, 2);
+  DeferredArrayLiteral* deferred = new DeferredArrayLiteral(this, node);
 
-  // Push the resulting array literal on the stack.
-  frame_->EmitPush(r0);
+  // Retrieve the literal array and check the allocated entry.
+
+  // Load the function of this activation.
+  __ ldr(r1, frame_->Function());
+
+  // Load the literals array of the function.
+  __ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset));
+
+  // Load the literal at the ast saved index.
+  int literal_offset =
+      FixedArray::kHeaderSize + node->literal_index() * kPointerSize;
+  __ ldr(r2, FieldMemOperand(r1, literal_offset));
+
+  // Check whether we need to materialize the object literal boilerplate.
+  // If so, jump to the deferred code.
+  __ cmp(r2, Operand(Factory::undefined_value()));
+  deferred->enter()->Branch(eq);
+  deferred->BindExit();
+
+  // Push the object literal boilerplate.
+  frame_->EmitPush(r2);
+
+  // Clone the boilerplate object.
+  Runtime::FunctionId clone_function_id = Runtime::kCloneLiteralBoilerplate;
+  if (node->depth() == 1) {
+    clone_function_id = Runtime::kCloneShallowLiteralBoilerplate;
+  }
+  frame_->CallRuntime(clone_function_id, 1);
+  frame_->EmitPush(r0);  // save the result
+  // r0: cloned object literal
 
   // Generate code to set the elements in the array that are not
   // literals.
   for (int i = 0; i < node->values()->length(); i++) {
     Expression* value = node->values()->at(i);
 
-    // If value is literal the property value is already
-    // set in the boilerplate object.
-    if (value->AsLiteral() == NULL) {
-      // The property must be set by generated code.
-      LoadAndSpill(value);
-      frame_->EmitPop(r0);
+    // If value is a literal the property value is already set in the
+    // boilerplate object.
+    if (value->AsLiteral() != NULL) continue;
+    // If value is a materialized literal the property value is already set
+    // in the boilerplate object if it is simple.
+    if (CompileTimeValue::IsCompileTimeValue(value)) continue;
 
-      // Fetch the object literal
-      __ ldr(r1, frame_->Top());
-        // Get the elements array.
-      __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset));
+    // The property must be set by generated code.
+    LoadAndSpill(value);
+    frame_->EmitPop(r0);
 
-      // Write to the indexed properties array.
-      int offset = i * kPointerSize + Array::kHeaderSize;
-      __ str(r0, FieldMemOperand(r1, offset));
+    // Fetch the object literal.
+    __ ldr(r1, frame_->Top());
+    // Get the elements array.
+    __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset));
 
-      // Update the write barrier for the array address.
-      __ mov(r3, Operand(offset));
-      __ RecordWrite(r1, r3, r2);
-    }
+    // Write to the indexed properties array.
+    int offset = i * kPointerSize + Array::kHeaderSize;
+    __ str(r0, FieldMemOperand(r1, offset));
+
+    // Update the write barrier for the array address.
+    __ mov(r3, Operand(offset));
+    __ RecordWrite(r1, r3, r2);
   }
   ASSERT(frame_->height() == original_height + 1);
 }
@@ -3974,6 +4103,15 @@
 }
 
 
+void Reference::GetValueAndSpill(TypeofState typeof_state) {
+  ASSERT(cgen_->in_spilled_code());
+  cgen_->set_in_spilled_code(false);
+  GetValue(typeof_state);
+  cgen_->frame()->SpillAll();
+  cgen_->set_in_spilled_code(true);
+}
+
+
 void Reference::GetValue(TypeofState typeof_state) {
   ASSERT(!cgen_->in_spilled_code());
   ASSERT(cgen_->HasValidEntryRegisters());
diff --git a/src/codegen-arm.h b/src/codegen-arm.h
index 29fe2d4..7c4b069 100644
--- a/src/codegen-arm.h
+++ b/src/codegen-arm.h
@@ -28,12 +28,12 @@
 #ifndef V8_CODEGEN_ARM_H_
 #define V8_CODEGEN_ARM_H_
 
-#include "scopes.h"
-
 namespace v8 { namespace internal {
 
 // Forward declarations
 class DeferredCode;
+class RegisterAllocator;
+class RegisterFile;
 
 // Mode to overwrite BinaryExpression values.
 enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
@@ -220,27 +220,11 @@
   // reach the end of the statement (ie, it does not exit via break,
   // continue, return, or throw).  This function is used temporarily while
   // the code generator is being transformed.
-  void VisitAndSpill(Statement* statement) {
-    ASSERT(in_spilled_code());
-    set_in_spilled_code(false);
-    Visit(statement);
-    if (frame_ != NULL) {
-      frame_->SpillAll();
-    }
-    set_in_spilled_code(true);
-  }
+  void VisitAndSpill(Statement* statement);
 
   // Visit a list of statements and then spill the virtual frame if control
   // flow can reach the end of the list.
-  void VisitStatementsAndSpill(ZoneList<Statement*>* statements) {
-    ASSERT(in_spilled_code());
-    set_in_spilled_code(false);
-    VisitStatements(statements);
-    if (frame_ != NULL) {
-      frame_->SpillAll();
-    }
-    set_in_spilled_code(true);
-  }
+  void VisitStatementsAndSpill(ZoneList<Statement*>* statements);
 
   // Main code generation function
   void GenCode(FunctionLiteral* fun);
@@ -278,13 +262,7 @@
   // and then spill the frame fully to memory.  This function is used
   // temporarily while the code generator is being transformed.
   void LoadAndSpill(Expression* expression,
-                    TypeofState typeof_state = NOT_INSIDE_TYPEOF) {
-    ASSERT(in_spilled_code());
-    set_in_spilled_code(false);
-    Load(expression, typeof_state);
-    frame_->SpillAll();
-    set_in_spilled_code(true);
-  }
+                    TypeofState typeof_state = NOT_INSIDE_TYPEOF);
 
   // Call LoadCondition and then spill the virtual frame unless control flow
   // cannot reach the end of the expression (ie, by emitting only
@@ -293,16 +271,7 @@
                              TypeofState typeof_state,
                              JumpTarget* true_target,
                              JumpTarget* false_target,
-                             bool force_control) {
-    ASSERT(in_spilled_code());
-    set_in_spilled_code(false);
-    LoadCondition(expression, typeof_state, true_target, false_target,
-                  force_control);
-    if (frame_ != NULL) {
-      frame_->SpillAll();
-    }
-    set_in_spilled_code(true);
-  }
+                             bool force_control);
 
   // Read a value from a slot and leave it on top of the expression stack.
   void LoadFromSlot(Slot* slot, TypeofState typeof_state);
@@ -470,15 +439,6 @@
 };
 
 
-void Reference::GetValueAndSpill(TypeofState typeof_state) {
-  ASSERT(cgen_->in_spilled_code());
-  cgen_->set_in_spilled_code(false);
-  GetValue(typeof_state);
-  cgen_->frame()->SpillAll();
-  cgen_->set_in_spilled_code(true);
-}
-
-
 } }  // namespace v8::internal
 
 #endif  // V8_CODEGEN_ARM_H_
diff --git a/src/codegen-ia32.cc b/src/codegen-ia32.cc
index d12ab59..68b98df 100644
--- a/src/codegen-ia32.cc
+++ b/src/codegen-ia32.cc
@@ -1,4 +1,4 @@
-// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// 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:
@@ -30,8 +30,10 @@
 #include "bootstrapper.h"
 #include "codegen-inl.h"
 #include "debug.h"
-#include "scopes.h"
+#include "parser.h"
+#include "register-allocator-inl.h"
 #include "runtime.h"
+#include "scopes.h"
 
 namespace v8 { namespace internal {
 
@@ -439,6 +441,16 @@
 }
 
 
+void CodeGenerator::LoadAndSpill(Expression* expression,
+                                 TypeofState typeof_state) {
+  ASSERT(in_spilled_code());
+  set_in_spilled_code(false);
+  Load(expression, typeof_state);
+  frame_->SpillAll();
+  set_in_spilled_code(true);
+}
+
+
 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) {
 #ifdef DEBUG
   int original_height = frame_->height();
@@ -1553,6 +1565,28 @@
 }
 
 
+void CodeGenerator::VisitAndSpill(Statement* statement) {
+  ASSERT(in_spilled_code());
+  set_in_spilled_code(false);
+  Visit(statement);
+  if (frame_ != NULL) {
+    frame_->SpillAll();
+  }
+  set_in_spilled_code(true);
+}
+
+
+void CodeGenerator::VisitStatementsAndSpill(ZoneList<Statement*>* statements) {
+  ASSERT(in_spilled_code());
+  set_in_spilled_code(false);
+  VisitStatements(statements);
+  if (frame_ != NULL) {
+    frame_->SpillAll();
+  }
+  set_in_spilled_code(true);
+}
+
+
 void CodeGenerator::VisitStatements(ZoneList<Statement*>* statements) {
   ASSERT(!in_spilled_code());
   for (int i = 0; has_valid_frame() && i < statements->length(); i++) {
@@ -2227,18 +2261,25 @@
     }
 
     case LoopStatement::WHILE_LOOP: {
-      // TODO(260): This flag controls whether to duplicate the test
-      // at the bottom of the loop.  Replace it with a better
-      // indication of when it is safe to do so.
-      static const bool test_at_bottom = false;
+      // Do not duplicate conditions with function literal
+      // subexpressions.  This can cause us to compile the function
+      // literal twice.
+      bool test_at_bottom =
+          !scope_->is_global_scope() && !node->has_function_literal();
 
-      JumpTarget body(this);  // Initialized as forward-only.
       IncrementLoopNesting();
 
       // If the condition is always false and has no side effects, we
       // do not need to compile anything.
       if (info == ALWAYS_FALSE) break;
 
+      JumpTarget body;
+      if (test_at_bottom) {
+        body.Initialize(this, JumpTarget::BIDIRECTIONAL);
+      } else {
+        body.Initialize(this);
+      }
+
       // Based on the condition analysis, compile the test as necessary.
       if (info == ALWAYS_TRUE) {
         // We will not compile the test expression.  Label the top of
@@ -2251,7 +2292,6 @@
           // Continue is the test at the bottom, no need to label the
           // test at the top.  The body is a backward target.
           node->continue_target()->Initialize(this);
-          body.make_bidirectional();
         } else {
           // Label the test at the top as the continue target.  The
           // body is a forward-only target.
@@ -2320,13 +2360,11 @@
     }
 
     case LoopStatement::FOR_LOOP: {
-      // TODO(260): This flag controls whether to duplicate the test
-      // at the bottom of the loop.  Replace it with a better
-      // indication of when it is safe to do so.
-      static const bool test_at_bottom = false;
-
-      JumpTarget loop(this, JumpTarget::BIDIRECTIONAL);
-      JumpTarget body(this);
+      // Do not duplicate conditions with function literal
+      // subexpressions.  This can cause us to compile the function
+      // literal twice.
+      bool test_at_bottom =
+          !scope_->is_global_scope() && !node->has_function_literal();
 
       // Compile the init expression if present.
       if (node->init() != NULL) {
@@ -2339,6 +2377,19 @@
       // do not need to compile anything else.
       if (info == ALWAYS_FALSE) break;
 
+      // Target for backward edge if no test at the bottom, otherwise
+      // unused.
+      JumpTarget loop(this, JumpTarget::BIDIRECTIONAL);
+
+      // Target for backward edge if there is a test at the bottom,
+      // otherwise used as target for test at the top.
+      JumpTarget body;
+      if (test_at_bottom) {
+        body.Initialize(this, JumpTarget::BIDIRECTIONAL);
+      } else {
+        body.Initialize(this);
+      }
+
       // Based on the condition analysis, compile the test as necessary.
       if (info == ALWAYS_TRUE) {
         // We will not compile the test expression.  Label the top of
@@ -2632,14 +2683,17 @@
   CheckStack();  // TODO(1222600): ignore if body contains calls.
   VisitAndSpill(node->body());
 
-  // Next.
+  // Next.  Reestablish a spilled frame in case we are coming here via
+  // a continue in the body.
   node->continue_target()->Bind();
+  frame_->SpillAll();
   frame_->EmitPop(eax);
   __ add(Operand(eax), Immediate(Smi::FromInt(1)));
   frame_->EmitPush(eax);
   entry.Jump();
 
-  // Cleanup.
+  // Cleanup.  No need to spill because VirtualFrame::Drop is safe for
+  // any frame.
   node->break_target()->Bind();
   frame_->Drop(5);
 
@@ -3482,15 +3536,22 @@
   // Push the boilerplate object.
   frame_->Push(&boilerplate);
   // Clone the boilerplate object.
-  Result clone =
-      frame_->CallRuntime(Runtime::kCloneObjectLiteralBoilerplate, 1);
+  Runtime::FunctionId clone_function_id = Runtime::kCloneLiteralBoilerplate;
+  if (node->depth() == 1) {
+    clone_function_id = Runtime::kCloneShallowLiteralBoilerplate;
+  }
+  Result clone = frame_->CallRuntime(clone_function_id, 1);
   // Push the newly cloned literal object as the result.
   frame_->Push(&clone);
 
   for (int i = 0; i < node->properties()->length(); i++) {
     ObjectLiteral::Property* property = node->properties()->at(i);
     switch (property->kind()) {
-      case ObjectLiteral::Property::CONSTANT: break;
+      case ObjectLiteral::Property::CONSTANT:
+        break;
+      case ObjectLiteral::Property::MATERIALIZED_LITERAL:
+        if (CompileTimeValue::IsCompileTimeValue(property->value())) break;
+        // else fall through.
       case ObjectLiteral::Property::COMPUTED: {
         Handle<Object> key(property->key()->handle());
         Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
@@ -3548,59 +3609,126 @@
 }
 
 
+// This deferred code stub will be used for creating the boilerplate
+// by calling Runtime_CreateArrayLiteralBoilerplate.
+// Each created boilerplate is stored in the JSFunction and they are
+// therefore context dependent.
+class DeferredArrayLiteral: public DeferredCode {
+ public:
+  DeferredArrayLiteral(CodeGenerator* generator,
+                       ArrayLiteral* node)
+      : DeferredCode(generator), node_(node) {
+    set_comment("[ DeferredArrayLiteral");
+  }
+
+  virtual void Generate();
+
+ private:
+  ArrayLiteral* node_;
+};
+
+
+void DeferredArrayLiteral::Generate() {
+  Result literals(generator());
+  enter()->Bind(&literals);
+  // Since the entry is undefined we call the runtime system to
+  // compute the literal.
+
+  VirtualFrame* frame = generator()->frame();
+  // Literal array (0).
+  frame->Push(&literals);
+  // Literal index (1).
+  frame->Push(Smi::FromInt(node_->literal_index()));
+  // Constant properties (2).
+  frame->Push(node_->literals());
+  Result boilerplate =
+      frame->CallRuntime(Runtime::kCreateArrayLiteralBoilerplate, 3);
+  exit_.Jump(&boilerplate);
+}
+
+
 void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) {
   Comment cmnt(masm_, "[ ArrayLiteral");
+  DeferredArrayLiteral* deferred = new DeferredArrayLiteral(this, node);
 
-  // Call the runtime to create the array literal.
-  frame_->Push(node->literals());
-  // Load the literals array of the current function.
+  // Retrieve the literals array and check the allocated entry.  Begin
+  // with a writable copy of the function of this activation in a
+  // register.
   frame_->PushFunction();
   Result literals = frame_->Pop();
   literals.ToRegister();
-  frame_->Spill(literals.reg());  // Make it writable.
+  frame_->Spill(literals.reg());
+
+  // Load the literals array of the function.
   __ mov(literals.reg(),
          FieldOperand(literals.reg(), JSFunction::kLiteralsOffset));
-  frame_->Push(&literals);
-  Result array = frame_->CallRuntime(Runtime::kCreateArrayLiteral, 2);
+
+  // Load the literal at the ast saved index.
+  int literal_offset =
+      FixedArray::kHeaderSize + node->literal_index() * kPointerSize;
+  Result boilerplate = allocator_->Allocate();
+  ASSERT(boilerplate.is_valid());
+  __ mov(boilerplate.reg(), FieldOperand(literals.reg(), literal_offset));
+
+  // Check whether we need to materialize the object literal boilerplate.
+  // If so, jump to the deferred code passing the literals array.
+  __ cmp(boilerplate.reg(), Factory::undefined_value());
+  deferred->enter()->Branch(equal, &literals, not_taken);
+
+  literals.Unuse();
+  // The deferred code returns the boilerplate object.
+  deferred->BindExit(&boilerplate);
 
   // Push the resulting array literal on the stack.
-  frame_->Push(&array);
+  frame_->Push(&boilerplate);
+
+  // Clone the boilerplate object.
+  Runtime::FunctionId clone_function_id = Runtime::kCloneLiteralBoilerplate;
+  if (node->depth() == 1) {
+    clone_function_id = Runtime::kCloneShallowLiteralBoilerplate;
+  }
+  Result clone = frame_->CallRuntime(clone_function_id, 1);
+  // Push the newly cloned literal object as the result.
+  frame_->Push(&clone);
 
   // Generate code to set the elements in the array that are not
   // literals.
   for (int i = 0; i < node->values()->length(); i++) {
     Expression* value = node->values()->at(i);
 
-    // If value is literal the property value is already set in the
+    // If value is a literal the property value is already set in the
     // boilerplate object.
-    if (value->AsLiteral() == NULL) {
-      // The property must be set by generated code.
-      Load(value);
+    if (value->AsLiteral() != NULL) continue;
+    // If value is a materialized literal the property value is already set
+    // in the boilerplate object if it is simple.
+    if (CompileTimeValue::IsCompileTimeValue(value)) continue;
 
-      // Get the property value off the stack.
-      Result prop_value = frame_->Pop();
-      prop_value.ToRegister();
+    // The property must be set by generated code.
+    Load(value);
 
-      // Fetch the array literal while leaving a copy on the stack and
-      // use it to get the elements array.
-      frame_->Dup();
-      Result elements = frame_->Pop();
-      elements.ToRegister();
-      frame_->Spill(elements.reg());
-      // Get the elements array.
-      __ mov(elements.reg(),
-             FieldOperand(elements.reg(), JSObject::kElementsOffset));
+    // Get the property value off the stack.
+    Result prop_value = frame_->Pop();
+    prop_value.ToRegister();
 
-      // Write to the indexed properties array.
-      int offset = i * kPointerSize + Array::kHeaderSize;
-      __ mov(FieldOperand(elements.reg(), offset), prop_value.reg());
+    // Fetch the array literal while leaving a copy on the stack and
+    // use it to get the elements array.
+    frame_->Dup();
+    Result elements = frame_->Pop();
+    elements.ToRegister();
+    frame_->Spill(elements.reg());
+    // Get the elements array.
+    __ mov(elements.reg(),
+           FieldOperand(elements.reg(), JSObject::kElementsOffset));
 
-      // Update the write barrier for the array address.
-      frame_->Spill(prop_value.reg());  // Overwritten by the write barrier.
-      Result scratch = allocator_->Allocate();
-      ASSERT(scratch.is_valid());
-      __ RecordWrite(elements.reg(), offset, prop_value.reg(), scratch.reg());
-    }
+    // Write to the indexed properties array.
+    int offset = i * kPointerSize + Array::kHeaderSize;
+    __ mov(FieldOperand(elements.reg(), offset), prop_value.reg());
+
+    // Update the write barrier for the array address.
+    frame_->Spill(prop_value.reg());  // Overwritten by the write barrier.
+    Result scratch = allocator_->Allocate();
+    ASSERT(scratch.is_valid());
+    __ RecordWrite(elements.reg(), offset, prop_value.reg(), scratch.reg());
   }
 }
 
diff --git a/src/codegen-ia32.h b/src/codegen-ia32.h
index dfa5978..a7e9b5e 100644
--- a/src/codegen-ia32.h
+++ b/src/codegen-ia32.h
@@ -28,13 +28,12 @@
 #ifndef V8_CODEGEN_IA32_H_
 #define V8_CODEGEN_IA32_H_
 
-#include "scopes.h"
-#include "register-allocator.h"
-
 namespace v8 { namespace internal {
 
 // Forward declarations
 class DeferredCode;
+class RegisterAllocator;
+class RegisterFile;
 
 // Mode to overwrite BinaryExpression values.
 enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
@@ -82,11 +81,6 @@
   // the expression stack, and it is left in place with its value above it.
   void GetValue(TypeofState typeof_state);
 
-  // Generate code to push the value of a reference on top of the expression
-  // stack and then spill the stack frame.  This function is used temporarily
-  // while the code generator is being transformed.
-  inline void GetValueAndSpill(TypeofState typeof_state);
-
   // Like GetValue except that the slot is expected to be written to before
   // being read from again.  Thae value of the reference may be invalidated,
   // causing subsequent attempts to read it to fail.
@@ -368,27 +362,11 @@
   // reach the end of the statement (ie, it does not exit via break,
   // continue, return, or throw).  This function is used temporarily while
   // the code generator is being transformed.
-  void VisitAndSpill(Statement* statement) {
-    ASSERT(in_spilled_code());
-    set_in_spilled_code(false);
-    Visit(statement);
-    if (frame_ != NULL) {
-      frame_->SpillAll();
-    }
-    set_in_spilled_code(true);
-  }
+  void VisitAndSpill(Statement* statement);
 
   // Visit a list of statements and then spill the virtual frame if control
   // flow can reach the end of the list.
-  void VisitStatementsAndSpill(ZoneList<Statement*>* statements) {
-    ASSERT(in_spilled_code());
-    set_in_spilled_code(false);
-    VisitStatements(statements);
-    if (frame_ != NULL) {
-      frame_->SpillAll();
-    }
-    set_in_spilled_code(true);
-  }
+  void VisitStatementsAndSpill(ZoneList<Statement*>* statements);
 
   // Main code generation function
   void GenCode(FunctionLiteral* fun);
@@ -430,29 +408,7 @@
   // and then spill the frame fully to memory.  This function is used
   // temporarily while the code generator is being transformed.
   void LoadAndSpill(Expression* expression,
-                    TypeofState typeof_state = NOT_INSIDE_TYPEOF) {
-    ASSERT(in_spilled_code());
-    set_in_spilled_code(false);
-    Load(expression, typeof_state);
-    frame_->SpillAll();
-    set_in_spilled_code(true);
-  }
-
-  // Call LoadCondition and then spill the virtual frame unless control flow
-  // cannot reach the end of the expression (ie, by emitting only
-  // unconditional jumps to the control targets).
-  void LoadConditionAndSpill(Expression* expression,
-                             TypeofState typeof_state,
-                             ControlDestination* destination,
-                             bool force_control) {
-    ASSERT(in_spilled_code());
-    set_in_spilled_code(false);
-    LoadCondition(expression, typeof_state, destination, force_control);
-    if (frame_ != NULL) {
-      frame_->SpillAll();
-    }
-    set_in_spilled_code(true);
-  }
+                    TypeofState typeof_state = NOT_INSIDE_TYPEOF);
 
   // Read a value from a slot and leave it on top of the expression stack.
   void LoadFromSlot(Slot* slot, TypeofState typeof_state);
@@ -644,15 +600,6 @@
 };
 
 
-void Reference::GetValueAndSpill(TypeofState typeof_state) {
-  ASSERT(cgen_->in_spilled_code());
-  cgen_->set_in_spilled_code(false);
-  GetValue(typeof_state);
-  cgen_->frame()->SpillAll();
-  cgen_->set_in_spilled_code(true);
-}
-
-
 } }  // namespace v8::internal
 
 #endif  // V8_CODEGEN_IA32_H_
diff --git a/src/codegen-inl.h b/src/codegen-inl.h
index c6abbec..c42f5ac 100644
--- a/src/codegen-inl.h
+++ b/src/codegen-inl.h
@@ -31,7 +31,6 @@
 
 #include "codegen.h"
 
-
 namespace v8 { namespace internal {
 
 
diff --git a/src/codegen.cc b/src/codegen.cc
index 558e854..9d48ebf 100644
--- a/src/codegen.cc
+++ b/src/codegen.cc
@@ -31,8 +31,9 @@
 #include "codegen-inl.h"
 #include "debug.h"
 #include "prettyprinter.h"
-#include "scopeinfo.h"
+#include "register-allocator-inl.h"
 #include "runtime.h"
+#include "scopeinfo.h"
 #include "stub-cache.h"
 
 namespace v8 { namespace internal {
@@ -402,8 +403,7 @@
      "_Log"}
   };
   Handle<String> name = node->name();
-  StringShape shape(*name);
-  if (name->length(shape) > 0 && name->Get(shape, 0) == '_') {
+  if (name->length() > 0 && name->Get(0) == '_') {
     for (unsigned i = 0;
          i < sizeof(kInlineRuntimeLUT) / sizeof(InlineRuntimeLUT);
          i++) {
diff --git a/src/compiler.cc b/src/compiler.cc
index 6450885..3fd74ac 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -110,10 +110,10 @@
   // Measure how long it takes to do the compilation; only take the
   // rest of the function into account to avoid overlap with the
   // parsing statistics.
-  StatsRate* rate = is_eval
+  HistogramTimer* rate = is_eval
       ? &Counters::compile_eval
       : &Counters::compile;
-  StatsRateScope timer(rate);
+  HistogramTimerScope timer(rate);
 
   // Compile the code.
   Handle<Code> code = MakeCode(lit, script, context, is_eval);
@@ -300,7 +300,7 @@
   // Measure how long it takes to do the lazy compilation; only take
   // the rest of the function into account to avoid overlap with the
   // lazy parsing statistics.
-  StatsRateScope timer(&Counters::compile_lazy);
+  HistogramTimerScope timer(&Counters::compile_lazy);
 
   // Compile the code.
   Handle<Code> code = MakeCode(lit, script, Handle<Context>::null(), false);
diff --git a/src/conversions-inl.h b/src/conversions-inl.h
index e3db4e9..64e4a79 100644
--- a/src/conversions-inl.h
+++ b/src/conversions-inl.h
@@ -30,6 +30,7 @@
 
 #include <math.h>
 #include <float.h>         // required for DBL_MAX and on Win32 for finite()
+#include <stdarg.h>
 
 // ----------------------------------------------------------------------------
 // Extra POSIX/ANSI functions for Win32/MSVC.
diff --git a/src/conversions.cc b/src/conversions.cc
index 4b4faa5..57a4568 100644
--- a/src/conversions.cc
+++ b/src/conversions.cc
@@ -55,8 +55,7 @@
 
 
 static inline int GetChar(String* str, int index) {
-  StringShape shape(str);
-  return str->Get(shape, index);
+  return str->Get(index);
 }
 
 
@@ -76,11 +75,10 @@
 
 
 static inline const char* GetCString(String* str, int index) {
-  StringShape shape(str);
-  int length = str->length(shape);
+  int length = str->length();
   char* result = NewArray<char>(length + 1);
   for (int i = index; i < length; i++) {
-    uc16 c = str->Get(shape, i);
+    uc16 c = str->Get(i);
     if (c <= 127) {
       result[i - index] = static_cast<char>(c);
     } else {
@@ -108,8 +106,7 @@
 
 
 static inline bool IsSpace(String* str, int index) {
-  StringShape shape(str);
-  return Scanner::kIsWhiteSpace.get(str->Get(shape, index));
+  return Scanner::kIsWhiteSpace.get(str->Get(index));
 }
 
 
diff --git a/src/counters.cc b/src/counters.cc
index 8878ec5..bf9b8d8 100644
--- a/src/counters.cc
+++ b/src/counters.cc
@@ -33,6 +33,8 @@
 namespace v8 { namespace internal {
 
 CounterLookupCallback StatsTable::lookup_function_ = NULL;
+CreateHistogramCallback StatsTable::create_histogram_function_ = NULL;
+AddHistogramSampleCallback StatsTable::add_histogram_sample_function_ = NULL;
 
 // Start the timer.
 void StatsCounterTimer::Start() {
@@ -53,4 +55,23 @@
   counter_.Increment(milliseconds);
 }
 
+// Start the timer.
+void HistogramTimer::Start() {
+  if (GetHistogram() != NULL) {
+    stop_time_ = 0;
+    start_time_ = OS::Ticks();
+  }
+}
+
+// Stop the timer and record the results.
+void HistogramTimer::Stop() {
+  if (histogram_ != NULL) {
+    stop_time_ = OS::Ticks();
+
+    // Compute the delta between start and stop, in milliseconds.
+    int milliseconds = static_cast<int>(stop_time_ - start_time_) / 1000;
+    StatsTable::AddHistogramSample(histogram_, milliseconds);
+  }
+}
+
 } }  // namespace v8::internal
diff --git a/src/counters.h b/src/counters.h
index 0e239c8..df1c70a 100644
--- a/src/counters.h
+++ b/src/counters.h
@@ -42,6 +42,18 @@
     lookup_function_ = f;
   }
 
+  // Register an application-defined function to create
+  // a histogram for passing to the AddHistogramSample function
+  static void SetCreateHistogramFunction(CreateHistogramCallback f) {
+    create_histogram_function_ = f;
+  }
+
+  // Register an application-defined function to add a sample
+  // to a histogram created with CreateHistogram function
+  static void SetAddHistogramSampleFunction(AddHistogramSampleCallback f) {
+    add_histogram_sample_function_ = f;
+  }
+
   static bool HasCounterFunction() {
     return lookup_function_ != NULL;
   }
@@ -57,8 +69,30 @@
     return lookup_function_(name);
   }
 
+  // Create a histogram by name. If the create is successful,
+  // returns a non-NULL pointer for use with AddHistogramSample
+  // function. min and max define the expected minimum and maximum
+  // sample values. buckets is the maximum number of buckets
+  // that the samples will be grouped into.
+  static void *CreateHistogram(const char* name,
+                               int min,
+                               int max,
+                               size_t buckets) {
+    if (!create_histogram_function_) return NULL;
+    return create_histogram_function_(name, min, max, buckets);
+  }
+
+  // Add a sample to a histogram created with the CreateHistogram
+  // function.
+  static void AddHistogramSample(void* histogram, int sample) {
+    if (!add_histogram_sample_function_) return;
+    return add_histogram_sample_function_(histogram, sample);
+  }
+
  private:
   static CounterLookupCallback lookup_function_;
+  static CreateHistogramCallback create_histogram_function_;
+  static AddHistogramSampleCallback add_histogram_sample_function_;
 };
 
 // StatsCounters are dynamically created values which can be tracked in
@@ -152,44 +186,50 @@
   }
 };
 
-// A StatsRate is a combination of both a timer and a counter so that
-// several statistics can be produced:
-//    min, max, avg, count, total
-//
-// For example:
-//   StatsCounter c = { { { L"t:myrate", NULL, false }, 0, 0 },
-//                      { L"c:myrate", NULL, false } };
-struct StatsRate {
-  StatsCounterTimer timer_;
-  StatsCounter counter_;
+// A HistogramTimer allows distributions of results to be created
+// HistogramTimer t = { L"foo", NULL, false, 0, 0 };
+struct HistogramTimer {
+  const char* name_;
+  void* histogram_;
+  bool lookup_done_;
 
-  // Starts the rate timer.
-  void Start() {
-    timer_.Start();
+  int64_t start_time_;
+  int64_t stop_time_;
+
+  // Start the timer.
+  void Start();
+
+  // Stop the timer and record the results.
+  void Stop();
+
+  // Returns true if the timer is running.
+  bool Running() {
+    return (histogram_ != NULL) && (start_time_ != 0) && (stop_time_ == 0);
   }
 
-  // Stops the rate and records the time.
-  void Stop() {
-    if (timer_.Running()) {
-      timer_.Stop();
-      counter_.Increment();
+ protected:
+  // Returns the handle to the histogram.
+  void* GetHistogram() {
+    if (!lookup_done_) {
+      lookup_done_ = true;
+      histogram_ = StatsTable::CreateHistogram(name_, 0, 10000, 50);
     }
+    return histogram_;
   }
 };
 
-
-// Helper class for scoping a rate.
-class StatsRateScope BASE_EMBEDDED {
+// Helper class for scoping a HistogramTimer.
+class HistogramTimerScope BASE_EMBEDDED {
  public:
-  explicit StatsRateScope(StatsRate* rate) :
-      rate_(rate) {
-    rate_->Start();
+  explicit HistogramTimerScope(HistogramTimer* timer) :
+  timer_(timer) {
+    timer_->Start();
   }
-  ~StatsRateScope() {
-    rate_->Stop();
+  ~HistogramTimerScope() {
+    timer_->Stop();
   }
  private:
-  StatsRate* rate_;
+  HistogramTimer* timer_;
 };
 
 
diff --git a/src/d8-debug.cc b/src/d8-debug.cc
index 5b21816..4e0243a 100644
--- a/src/d8-debug.cc
+++ b/src/d8-debug.cc
@@ -305,6 +305,11 @@
 
 
 void ReceiverThread::Run() {
+  // Receive the connect message (with empty body).
+  i::SmartPointer<char> message =
+    i::DebuggerAgentUtil::ReceiveMessage(remote_debugger_->conn());
+  ASSERT(*message == NULL);
+
   while (true) {
     // Receive a message.
     i::SmartPointer<char> message =
@@ -332,7 +337,7 @@
 
     // Pass the keyboard command to the main thread.
     remote_debugger_->KeyboardCommand(
-        i::SmartPointer<char>(i::OS::StrDup(command)));
+        i::SmartPointer<char>(i::StrDup(command)));
   }
 }
 
diff --git a/src/d8-readline.cc b/src/d8-readline.cc
index b86648d..34b7b60 100644
--- a/src/d8-readline.cc
+++ b/src/d8-readline.cc
@@ -103,7 +103,7 @@
   static unsigned current_index;
   static Persistent<Array> current_completions;
   if (state == 0) {
-    i::SmartPointer<char> full_text(i::OS::StrNDup(rl_line_buffer, rl_point));
+    i::SmartPointer<char> full_text(i::StrNDup(rl_line_buffer, rl_point));
     HandleScope scope;
     Handle<Array> completions =
       Shell::GetCompletions(String::New(text), String::New(*full_text));
diff --git a/src/d8.cc b/src/d8.cc
index 5f5e81c..3e4f2f2 100644
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -27,6 +27,7 @@
 
 
 #include <stdlib.h>
+#include <errno.h>
 
 #include "d8.h"
 #include "d8-debug.h"
@@ -174,6 +175,12 @@
 }
 
 
+Handle<Value> Shell::Yield(const Arguments& args) {
+  v8::Unlocker unlocker;
+  return Undefined();
+}
+
+
 Handle<Value> Shell::Quit(const Arguments& args) {
   int exit_code = args[0]->Int32Value();
   OnExit();
@@ -481,6 +488,8 @@
                        FunctionTemplate::New(Shell::Print));
   global_template->Set(String::New("load"),
                        FunctionTemplate::New(Shell::Load));
+  global_template->Set(String::New("yield"),
+                       FunctionTemplate::New(Shell::Yield));
   global_template->Set(String::New("version"),
                        FunctionTemplate::New(Shell::Version));
 
@@ -530,6 +539,14 @@
   }
   Initialize();
   bool run_shell = (argc == 1);
+
+  // Default use preemption if threads are created.
+  bool use_preemption = true;
+
+  // Default to use lowest possible thread preemption interval to test as many
+  // edgecases as possible.
+  int preemption_interval = 1;
+
   i::List<i::Thread*> threads(1);
 
   {
@@ -542,6 +559,22 @@
       char* str = argv[i];
       if (strcmp(str, "--shell") == 0) {
         run_shell = true;
+      } else if (strcmp(str, "--preemption") == 0) {
+        use_preemption = true;
+      } else if (strcmp(str, "--no-preemption") == 0) {
+        use_preemption = false;
+      } else if (strcmp(str, "--preemption-interval") == 0) {
+        if (i + 1 < argc) {
+          char *end = NULL;
+          preemption_interval = strtol(argv[++i], &end, 10);  // NOLINT
+          if (preemption_interval <= 0 || *end != '\0' || errno == ERANGE) {
+            printf("Invalid value for --preemption-interval '%s'\n", argv[i]);
+            return 1;
+          }
+        } else {
+          printf("Missing value for --preemption-interval\n");
+          return 1;
+       }
       } else if (strcmp(str, "-f") == 0) {
         // Ignore any -f flags for compatibility with other stand-alone
         // JavaScript engines.
@@ -553,13 +586,12 @@
         v8::HandleScope handle_scope;
         v8::Handle<v8::String> file_name = v8::String::New("unnamed");
         v8::Handle<v8::String> source = v8::String::New(argv[i + 1]);
-        if (!ExecuteString(source, file_name, false, true))
+        if (!ExecuteString(source, file_name, false, true)) {
+          OnExit();
           return 1;
+        }
         i++;
       } else if (strcmp(str, "-p") == 0 && i + 1 < argc) {
-        // Use the lowest possible thread preemption interval to test as many
-        // edgecases as possible.
-        Locker::StartPreemption(1);
         int size = 0;
         const char *files = ReadChars(argv[++i], &size);
         if (files == NULL) return 1;
@@ -577,11 +609,18 @@
           printf("Error reading '%s'\n", str);
           return 1;
         }
-        if (!ExecuteString(source, file_name, false, true))
+        if (!ExecuteString(source, file_name, false, true)) {
+          OnExit();
           return 1;
+        }
       }
     }
 
+    // Start preemption if threads have been created and preemption is enabled.
+    if (threads.length() > 0 && use_preemption) {
+      Locker::StartPreemption(preemption_interval);
+    }
+
     // Run the remote debugger if requested.
     if (i::FLAG_remote_debugger) {
       RunRemoteDebugger(i::FLAG_debugger_port);
@@ -590,7 +629,7 @@
 
     // Start the debugger agent if requested.
     if (i::FLAG_debugger_agent) {
-      v8::Debug::EnableAgent(i::FLAG_debugger_port);
+      v8::Debug::EnableAgent("d8 shell", i::FLAG_debugger_port);
     }
 
     // Start the in-process debugger if requested.
diff --git a/src/d8.h b/src/d8.h
index 45bab92..ceb6c19 100644
--- a/src/d8.h
+++ b/src/d8.h
@@ -92,6 +92,7 @@
   static Handle<Value> DebugCommandToJSONRequest(Handle<String> command);
 
   static Handle<Value> Print(const Arguments& args);
+  static Handle<Value> Yield(const Arguments& args);
   static Handle<Value> Quit(const Arguments& args);
   static Handle<Value> Version(const Arguments& args);
   static Handle<Value> Load(const Arguments& args);
diff --git a/src/d8.js b/src/d8.js
index 04b90fe..e2766d0 100644
--- a/src/d8.js
+++ b/src/d8.js
@@ -324,6 +324,10 @@
       this.request_ = this.clearCommandToJSONRequest_(args);
       break;
 
+    case 'threads':
+      this.request_ = this.threadsCommandToJSONRequest_(args);
+      break;
+
     case 'trace':
       // Return undefined to indicate command handled internally (no JSON).
       this.request_ = void 0;
@@ -686,6 +690,14 @@
 };
 
 
+// Create a JSON request for the threads command.
+DebugRequest.prototype.threadsCommandToJSONRequest_ = function(args) {
+  // Build a threads request from the text command.
+  var request = this.createRequest('threads');
+  return request.toJSONProtocol();
+};
+
+
 // Handle the trace command.
 DebugRequest.prototype.traceCommand_ = function(args) {
   // Process arguments.
@@ -919,6 +931,18 @@
         details.text = result;
         break;
 
+      case 'threads':
+        var result = 'Active V8 threads: ' + body.totalThreads + '\n';
+        body.threads.sort(function(a, b) { return a.id - b.id; });
+        for (i = 0; i < body.threads.length; i++) {
+          result += body.threads[i].current ? '*' : ' ';
+          result += ' ';
+          result += body.threads[i].id;
+          result += '\n';
+        }
+        details.text = result;
+        break;
+
       case 'continue':
         details.text = "(running)";
         break;
diff --git a/src/date-delay.js b/src/date-delay.js
index d9b2421..2421e5b 100644
--- a/src/date-delay.js
+++ b/src/date-delay.js
@@ -228,7 +228,6 @@
 
 
 // Compute modified Julian day from year, month, date.
-// The missing days in 1582 are ignored for JavaScript compatibility.
 function ToJulianDay(year, month, date) {
   var jy = (month > 1) ? year : year - 1;
   var jm = (month > 1) ? month + 2 : month + 14;
@@ -568,10 +567,12 @@
 
 // -------------------------------------------------------------------
 
+// Reused output buffer.
+var parse_buffer = $Array(7);
 
 // ECMA 262 - 15.9.4.2
 function DateParse(string) {
-  var arr = %DateParseString(ToString(string));
+  var arr = %DateParseString(ToString(string), parse_buffer);
   if (IS_NULL(arr)) return $NaN;
 
   var day = MakeDay(arr[0], arr[1], arr[2]);
diff --git a/src/dateparser-inl.h b/src/dateparser-inl.h
new file mode 100644
index 0000000..734c151
--- /dev/null
+++ b/src/dateparser-inl.h
@@ -0,0 +1,106 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+namespace v8 { namespace internal {
+
+template <typename Char>
+bool DateParser::Parse(Vector<Char> str, FixedArray* out) {
+  ASSERT(out->length() >= OUTPUT_SIZE);
+  InputReader<Char> in(str);
+  TimeZoneComposer tz;
+  TimeComposer time;
+  DayComposer day;
+
+  while (!in.IsEnd()) {
+    if (in.IsAsciiDigit()) {
+      // Parse a number (possibly with 1 or 2 trailing colons).
+      int n = in.ReadUnsignedNumber();
+      if (in.Skip(':')) {
+        if (in.Skip(':')) {
+          // n + "::"
+          if (!time.IsEmpty()) return false;
+          time.Add(n);
+          time.Add(0);
+        } else {
+          // n + ":"
+          if (!time.Add(n)) return false;
+        }
+      } else if (tz.IsExpecting(n)) {
+        tz.SetAbsoluteMinute(n);
+      } else if (time.IsExpecting(n)) {
+        time.AddFinal(n);
+        // Require end or white space immediately after finalizing time.
+        if (!in.IsEnd() && !in.SkipWhiteSpace()) return false;
+      } else {
+        if (!day.Add(n)) return false;
+        in.Skip('-');  // Ignore suffix '-' for year, month, or day.
+      }
+    } else if (in.IsAsciiAlphaOrAbove()) {
+      // Parse a "word" (sequence of chars. >= 'A').
+      uint32_t pre[KeywordTable::kPrefixLength];
+      int len = in.ReadWord(pre, KeywordTable::kPrefixLength);
+      int index = KeywordTable::Lookup(pre, len);
+      KeywordType type = KeywordTable::GetType(index);
+
+      if (type == AM_PM && !time.IsEmpty()) {
+        time.SetHourOffset(KeywordTable::GetValue(index));
+      } else if (type == MONTH_NAME) {
+        day.SetNamedMonth(KeywordTable::GetValue(index));
+        in.Skip('-');  // Ignore suffix '-' for month names
+      } else if (type == TIME_ZONE_NAME && in.HasReadNumber()) {
+        tz.Set(KeywordTable::GetValue(index));
+      } else {
+        // Garbage words are illegal if a number has been read.
+        if (in.HasReadNumber()) return false;
+      }
+    } else if (in.IsAsciiSign() && (tz.IsUTC() || !time.IsEmpty())) {
+      // Parse UTC offset (only after UTC or time).
+      tz.SetSign(in.GetAsciiSignValue());
+      in.Next();
+      int n = in.ReadUnsignedNumber();
+      if (in.Skip(':')) {
+        tz.SetAbsoluteHour(n);
+        tz.SetAbsoluteMinute(kNone);
+      } else {
+        tz.SetAbsoluteHour(n / 100);
+        tz.SetAbsoluteMinute(n % 100);
+      }
+    } else if (in.Is('(')) {
+      // Ignore anything from '(' to a matching ')' or end of string.
+      in.SkipParentheses();
+    } else if ((in.IsAsciiSign() || in.Is(')')) && in.HasReadNumber()) {
+      // Extra sign or ')' is illegal if a number has been read.
+      return false;
+    } else {
+      // Ignore other characters.
+      in.Next();
+    }
+  }
+  return day.Write(out) && time.Write(out) && tz.Write(out);
+}
+
+} }  // namespace v8::internal
diff --git a/src/dateparser.cc b/src/dateparser.cc
index 4b64785..a1ae55d 100644
--- a/src/dateparser.cc
+++ b/src/dateparser.cc
@@ -31,84 +31,6 @@
 
 namespace v8 { namespace internal {
 
-
-bool DateParser::Parse(String* str, FixedArray* out) {
-  ASSERT(out->length() == OUTPUT_SIZE);
-
-  InputReader in(str);
-  TimeZoneComposer tz;
-  TimeComposer time;
-  DayComposer day;
-
-  while (!in.IsEnd()) {
-    if (in.IsAsciiDigit()) {
-      // Parse a number (possibly with 1 or 2 trailing colons).
-      int n = in.ReadUnsignedNumber();
-      if (in.Skip(':')) {
-        if (in.Skip(':')) {
-          // n + "::"
-          if (!time.IsEmpty()) return false;
-          time.Add(n);
-          time.Add(0);
-        } else {
-          // n + ":"
-          if (!time.Add(n)) return false;
-        }
-      } else if (tz.IsExpecting(n)) {
-        tz.SetAbsoluteMinute(n);
-      } else if (time.IsExpecting(n)) {
-        time.AddFinal(n);
-        // Require end or white space immediately after finalizing time.
-        if (!in.IsEnd() && !in.SkipWhiteSpace()) return false;
-      } else {
-        if (!day.Add(n)) return false;
-        in.Skip('-');  // Ignore suffix '-' for year, month, or day.
-      }
-    } else if (in.IsAsciiAlphaOrAbove()) {
-      // Parse a "word" (sequence of chars. >= 'A').
-      uint32_t pre[KeywordTable::kPrefixLength];
-      int len = in.ReadWord(pre, KeywordTable::kPrefixLength);
-      int index = KeywordTable::Lookup(pre, len);
-      KeywordType type = KeywordTable::GetType(index);
-
-      if (type == AM_PM && !time.IsEmpty()) {
-        time.SetHourOffset(KeywordTable::GetValue(index));
-      } else if (type == MONTH_NAME) {
-        day.SetNamedMonth(KeywordTable::GetValue(index));
-        in.Skip('-');  // Ignore suffix '-' for month names
-      } else if (type == TIME_ZONE_NAME && in.HasReadNumber()) {
-        tz.Set(KeywordTable::GetValue(index));
-      } else {
-        // Garbage words are illegal if no number read yet.
-        if (in.HasReadNumber()) return false;
-      }
-    } else if (in.IsAsciiSign() && (tz.IsUTC() || !time.IsEmpty())) {
-      // Parse UTC offset (only after UTC or time).
-      tz.SetSign(in.GetAsciiSignValue());
-      in.Next();
-      int n = in.ReadUnsignedNumber();
-      if (in.Skip(':')) {
-        tz.SetAbsoluteHour(n);
-        tz.SetAbsoluteMinute(kNone);
-      } else {
-        tz.SetAbsoluteHour(n / 100);
-        tz.SetAbsoluteMinute(n % 100);
-      }
-    } else if (in.Is('(')) {
-      // Ignore anything from '(' to a matching ')' or end of string.
-      in.SkipParentheses();
-    } else if ((in.IsAsciiSign() || in.Is(')')) && in.HasReadNumber()) {
-      // Extra sign or ')' is illegal if no number read yet.
-      return false;
-    } else {
-      // Ignore other characters.
-      in.Next();
-    }
-  }
-  return day.Write(out) && time.Write(out) && tz.Write(out);
-}
-
-
 bool DateParser::DayComposer::Write(FixedArray* output) {
   int year = 0;  // Default year is 0 (=> 2000) for KJS compatibility.
   int month = kNone;
@@ -192,7 +114,6 @@
   return true;
 }
 
-
 bool DateParser::TimeZoneComposer::Write(FixedArray* output) {
   if (sign_ != kNone) {
     if (hour_ == kNone) hour_ = 0;
@@ -210,9 +131,8 @@
   return true;
 }
 
-
-const int8_t
-DateParser::KeywordTable::array[][DateParser::KeywordTable::kEntrySize] = {
+const int8_t DateParser::KeywordTable::
+    array[][DateParser::KeywordTable::kEntrySize] = {
   {'j', 'a', 'n', DateParser::MONTH_NAME, 1},
   {'f', 'e', 'b', DateParser::MONTH_NAME, 2},
   {'m', 'a', 'r', DateParser::MONTH_NAME, 3},
diff --git a/src/dateparser.h b/src/dateparser.h
index bf96852..04d7e8b 100644
--- a/src/dateparser.h
+++ b/src/dateparser.h
@@ -32,7 +32,6 @@
 
 namespace v8 { namespace internal {
 
-
 class DateParser : public AllStatic {
  public:
 
@@ -46,25 +45,34 @@
   // [5]: second
   // [6]: UTC offset in seconds, or null value if no timezone specified
   // If parsing fails, return false (content of output array is not defined).
-  static bool Parse(String* str, FixedArray* output);
+  template <typename Char>
+  static bool Parse(Vector<Char> str, FixedArray* output);
 
-  enum {YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, UTC_OFFSET, OUTPUT_SIZE};
+  enum {
+    YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, UTC_OFFSET, OUTPUT_SIZE
+  };
 
  private:
   // Range testing
-  static bool Between(int x, int lo, int hi) { return x >= lo && x <= hi; }
+  static inline bool Between(int x, int lo, int hi) {
+    return static_cast<unsigned>(x - lo) <= static_cast<unsigned>(hi - lo);
+  }
   // Indicates a missing value.
   static const int kNone = kMaxInt;
 
   // InputReader provides basic string parsing and character classification.
+  template <typename Char>
   class InputReader BASE_EMBEDDED {
    public:
-    explicit InputReader(String* s) : buffer_(s), has_read_number_(false) {
+    explicit InputReader(Vector<Char> s)
+        : index_(0),
+          buffer_(s),
+          has_read_number_(false) {
       Next();
     }
 
     // Advance to the next character of the string.
-    void Next() { ch_ = buffer_.has_more() ? buffer_.GetNext() : 0; }
+    void Next() { ch_ = (index_ < buffer_.length()) ? buffer_[index_++] : 0; }
 
     // Read a string of digits as an unsigned number (cap just below kMaxInt).
     int ReadUnsignedNumber() {
@@ -124,7 +132,8 @@
     // Else, return something outside of 'A'-'Z' and 'a'-'z'.
     uint32_t GetAsciiAlphaLower() const { return ch_ | 32; }
 
-    StringInputBuffer buffer_;
+    int index_;
+    Vector<Char> buffer_;
     bool has_read_number_;
     uint32_t ch_;
   };
diff --git a/src/debug-agent.cc b/src/debug-agent.cc
index 1ab5aac..e865e0e 100644
--- a/src/debug-agent.cc
+++ b/src/debug-agent.cc
@@ -42,25 +42,52 @@
 
 // Debugger agent main thread.
 void DebuggerAgent::Run() {
-  // Create a server socket and bind it to the requested port.
-  server_ = OS::CreateSocket();
-  server_->Bind(port_);
+  const int kOneSecondInMicros = 1000000;
 
+  // Allow this socket to reuse port even if still in TIME_WAIT.
+  server_->SetReuseAddress(true);
+
+  // First bind the socket to the requested port.
+  bool bound = false;
+  while (!bound && !terminate_) {
+    bound = server_->Bind(port_);
+
+    // If an error occoured wait a bit before retrying. The most common error
+    // would be that the port is already in use so this avoids a busy loop and
+    // make the agent take over the port when it becomes free.
+    if (!bound) {
+      terminate_now_->Wait(kOneSecondInMicros);
+    }
+  }
+
+  // Accept connections on the bound port.
   while (!terminate_) {
-    // Listen for new connections.
-    server_->Listen(1);
-
-    // Accept the new connection.
-    Socket* client = server_->Accept();
-
-    // Create and start a new session.
-    CreateSession(client);
+    bool ok = server_->Listen(1);
+    if (ok) {
+      // Accept the new connection.
+      Socket* client = server_->Accept();
+      ok = client != NULL;
+      if (ok) {
+        // Create and start a new session.
+        CreateSession(client);
+      }
+    }
   }
 }
 
 
 void DebuggerAgent::Shutdown() {
-  delete server_;
+  // Set the termination flag.
+  terminate_ = true;
+
+  // Signal termination and make the server exit either its listen call or its
+  // binding loop. This makes sure that no new sessions can be established.
+  terminate_now_->Signal();
+  server_->Shutdown();
+  Join();
+
+  // Close existing session if any.
+  CloseSession();
 }
 
 
@@ -69,7 +96,7 @@
 
   // If another session is already established terminate this one.
   if (session_ != NULL) {
-    static const char* message = "Remote debugging session already active\n";
+    static const char* message = "Remote debugging session already active\r\n";
 
     client->Send(message, strlen(message));
     delete client;
@@ -83,6 +110,19 @@
 }
 
 
+void DebuggerAgent::CloseSession() {
+  ScopedLock with(session_access_);
+
+  // Terminate the session.
+  if (session_ != NULL) {
+    session_->Shutdown();
+    session_->Join();
+    delete session_;
+    session_ = NULL;
+  }
+}
+
+
 void DebuggerAgent::DebuggerMessage(const uint16_t* message, int length) {
   ScopedLock with(session_access_);
 
@@ -94,26 +134,32 @@
 }
 
 
-void DebuggerAgent::SessionClosed(DebuggerAgentSession* session) {
-  ScopedLock with(session_access_);
+void DebuggerAgent::OnSessionClosed(DebuggerAgentSession* session) {
+  // Don't do anything during termination.
+  if (terminate_) {
+    return;
+  }
 
   // Terminate the session.
+  ScopedLock with(session_access_);
   ASSERT(session == session_);
   if (session == session_) {
-    session->Join();
-    delete session;
-    session_ = NULL;
+    CloseSession();
   }
 }
 
 
 void DebuggerAgentSession::Run() {
+  // Send the hello message.
+  bool ok = DebuggerAgentUtil::SendConnectMessage(client_, *agent_->name_);
+  if (!ok) return;
+
   while (true) {
     // Read data from the debugger front end.
     SmartPointer<char> message = DebuggerAgentUtil::ReceiveMessage(client_);
     if (*message == NULL) {
       // Session is closed.
-      agent_->SessionClosed(this);
+      agent_->OnSessionClosed(this);
       return;
     }
 
@@ -142,6 +188,12 @@
 }
 
 
+void DebuggerAgentSession::Shutdown() {
+  // Shutdown the socket to end the blocking receive.
+  client_->Shutdown();
+}
+
+
 const char* DebuggerAgentUtil::kContentLength = "Content-Length";
 int DebuggerAgentUtil::kContentLengthSize = strlen(kContentLength);
 
@@ -150,70 +202,75 @@
   int received;
 
   // Read header.
-  const int kHeaderBufferSize = 80;
-  char header_buffer[kHeaderBufferSize];
-  int header_buffer_position = 0;
-  char c = '\0';  // One character receive buffer.
-  char last_c = '\0';  // Previous character.
   int content_length = 0;
-  while (!(c == '\n' && last_c == '\n')) {
-    last_c = c;
-    received = conn->Receive(&c, 1);
-    if (received <= 0) {
-      PrintF("Error %d\n", Socket::LastError());
-      return SmartPointer<char>();
-    }
+  while (true) {
+    const int kHeaderBufferSize = 80;
+    char header_buffer[kHeaderBufferSize];
+    int header_buffer_position = 0;
+    char c = '\0';  // One character receive buffer.
+    char prev_c = '\0';  // Previous character.
 
-    // Check for end of header line.
-    if (c == '\n') {
-      // Empty header line.
-      if (header_buffer_position == 0) {
-        continue;
+    // Read until CRLF.
+    while (!(c == '\n' && prev_c == '\r')) {
+      prev_c = c;
+      received = conn->Receive(&c, 1);
+      if (received <= 0) {
+        PrintF("Error %d\n", Socket::LastError());
+        return SmartPointer<char>();
       }
 
-      // Terminate header.
-      ASSERT(header_buffer_position < kHeaderBufferSize);
+      // Add character to header buffer.
       if (header_buffer_position < kHeaderBufferSize) {
-        header_buffer[header_buffer_position] = '\0';
-      }
-
-      // Split header.
-      char* key = header_buffer;
-      char* value = NULL;
-      for (int i = 0; i < header_buffer_position; i++) {
-        if (header_buffer[i] == ':') {
-          header_buffer[i] = '\0';
-          value = header_buffer + i + 1;
-          while (*value == ' ') {
-            value++;
-          }
-          break;
-        }
-      }
-
-      // Check that key is Content-Length.
-      if (strcmp(key, kContentLength) == 0) {
-        // Get the content length value if within a sensible range.
-        if (strlen(value) > 7) {
-          return SmartPointer<char>();
-        }
-        for (int i = 0; value[i] != '\0'; i++) {
-          // Bail out if illegal data.
-          if (value[i] < '0' || value[i] > '9') {
-            return SmartPointer<char>();
-          }
-          content_length = 10 * content_length + (value[i] - '0');
-        }
-      }
-
-      // Start collecting new header.
-      header_buffer_position = 0;
-    } else {
-      // Add character to header buffer (reserve room for terminating '\0').
-      if (header_buffer_position < kHeaderBufferSize - 1) {
         header_buffer[header_buffer_position++] = c;
       }
     }
+
+    // Check for end of header (empty header line).
+    if (header_buffer_position == 2) {  // Receive buffer contains CRLF.
+      break;
+    }
+
+    // Terminate header.
+    ASSERT(header_buffer_position > 1);  // At least CRLF is received.
+    ASSERT(header_buffer_position <= kHeaderBufferSize);
+    header_buffer[header_buffer_position - 2] = '\0';
+
+    // Split header.
+    char* key = header_buffer;
+    char* value = NULL;
+    for (int i = 0; header_buffer[i] != '\0'; i++) {
+      if (header_buffer[i] == ':') {
+        header_buffer[i] = '\0';
+        value = header_buffer + i + 1;
+        while (*value == ' ') {
+          value++;
+        }
+        break;
+      }
+    }
+
+    // Check that key is Content-Length.
+    if (strcmp(key, kContentLength) == 0) {
+      // Get the content length value if within a sensible range.
+      if (strlen(value) > 7) {
+        return SmartPointer<char>();
+      }
+      for (int i = 0; value[i] != '\0'; i++) {
+        // Bail out if illegal data.
+        if (value[i] < '0' || value[i] > '9') {
+          return SmartPointer<char>();
+        }
+        content_length = 10 * content_length + (value[i] - '0');
+      }
+    } else {
+      // For now just print all other headers than Content-Length.
+      PrintF("%s: %s\n", key, value != NULL ? value : "(no value)");
+    }
+  }
+
+  // Return now if no body.
+  if (content_length == 0) {
+    return SmartPointer<char>();
   }
 
   // Read body.
@@ -229,6 +286,52 @@
 }
 
 
+bool DebuggerAgentUtil::SendConnectMessage(const Socket* conn,
+                                           const char* embedding_host) {
+  static const int kBufferSize = 80;
+  char buffer[kBufferSize];  // Sending buffer.
+  bool ok;
+  int len;
+
+  // Send the header.
+  len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
+                     "Type: connect\r\n");
+  ok = conn->Send(buffer, len);
+  if (!ok) return false;
+
+  len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
+                     "V8-Version: %s\r\n", v8::V8::GetVersion());
+  ok = conn->Send(buffer, len);
+  if (!ok) return false;
+
+  len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
+                     "Protocol-Version: 1\r\n");
+  ok = conn->Send(buffer, len);
+  if (!ok) return false;
+
+  if (embedding_host != NULL) {
+    len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
+                       "Embedding-Host: %s\r\n", embedding_host);
+    ok = conn->Send(buffer, len);
+    if (!ok) return false;
+  }
+
+  len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
+                     "%s: 0\r\n", kContentLength);
+  ok = conn->Send(buffer, len);
+  if (!ok) return false;
+
+  // Terminate header with empty line.
+  len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "\r\n");
+  ok = conn->Send(buffer, len);
+  if (!ok) return false;
+
+  // No body for connect message.
+
+  return true;
+}
+
+
 bool DebuggerAgentUtil::SendMessage(const Socket* conn,
                                     const Vector<uint16_t> message) {
   static const int kBufferSize = 80;
@@ -243,11 +346,11 @@
   // Send the header.
   int len;
   len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
-                     "Content-Length: %d\n", utf8_len);
+                     "%s: %d\r\n", kContentLength, utf8_len);
   conn->Send(buffer, len);
 
   // Terminate header with empty line.
-  len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "\n");
+  len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "\r\n");
   conn->Send(buffer, len);
 
   // Send message body as UTF-8.
@@ -280,11 +383,11 @@
   // Send the header.
   int len;
   len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
-                     "Content-Length: %d\n", utf8_request.length());
+                     "Content-Length: %d\r\n", utf8_request.length());
   conn->Send(buffer, len);
 
   // Terminate header with empty line.
-  len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "\n");
+  len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "\r\n");
   conn->Send(buffer, len);
 
   // Send message body as UTF-8.
diff --git a/src/debug-agent.h b/src/debug-agent.h
index 7ca7ec4..177af0c 100644
--- a/src/debug-agent.h
+++ b/src/debug-agent.h
@@ -42,10 +42,12 @@
 // handles connection from a remote debugger.
 class DebuggerAgent: public Thread {
  public:
-  explicit DebuggerAgent(int port)
-      : port_(port), server_(OS::CreateSocket()), terminate_(false),
-        session_access_(OS::CreateMutex()), session_(NULL) {}
-  ~DebuggerAgent() {}
+  explicit DebuggerAgent(const char* name, int port)
+      : name_(StrDup(name)), port_(port),
+        server_(OS::CreateSocket()), terminate_(false),
+        session_access_(OS::CreateMutex()), session_(NULL),
+        terminate_now_(OS::CreateSemaphore(0)) {}
+  ~DebuggerAgent() { delete server_; }
 
   void Shutdown();
 
@@ -53,13 +55,16 @@
   void Run();
   void CreateSession(Socket* socket);
   void DebuggerMessage(const uint16_t* message, int length);
-  void SessionClosed(DebuggerAgentSession* session);
+  void CloseSession();
+  void OnSessionClosed(DebuggerAgentSession* session);
 
+  SmartPointer<const char> name_;  // Name of the embedding application.
   int port_;  // Port to use for the agent.
   Socket* server_;  // Server socket for listen/accept.
   bool terminate_;  // Termination flag.
   Mutex* session_access_;  // Mutex guarging access to session_.
   DebuggerAgentSession* session_;  // Current active session if any.
+  Semaphore* terminate_now_;  // Semaphore to signal termination.
 
   friend class DebuggerAgentSession;
   friend void DebuggerAgentMessageHandler(const uint16_t* message, int length,
@@ -77,6 +82,7 @@
       : agent_(agent), client_(client) {}
 
   void DebuggerMessage(Vector<uint16_t> message);
+  void Shutdown();
 
  private:
   void Run();
@@ -84,7 +90,7 @@
   void DebuggerMessage(Vector<char> message);
 
   DebuggerAgent* agent_;
-  const Socket* client_;
+  Socket* client_;
 
   DISALLOW_COPY_AND_ASSIGN(DebuggerAgentSession);
 };
@@ -97,6 +103,8 @@
   static int kContentLengthSize;
 
   static SmartPointer<char> ReceiveMessage(const Socket* conn);
+  static bool SendConnectMessage(const Socket* conn,
+                                 const char* embedding_host);
   static bool SendMessage(const Socket* conn, const Vector<uint16_t> message);
   static bool SendMessage(const Socket* conn,
                           const v8::Handle<v8::String> message);
diff --git a/src/debug-delay.js b/src/debug-delay.js
index 3b7a4de..31437cd 100644
--- a/src/debug-delay.js
+++ b/src/debug-delay.js
@@ -752,6 +752,10 @@
   return %GetFrameCount(this.break_id);
 };
 
+ExecutionState.prototype.threadCount = function() {
+  return %GetThreadCount(this.break_id);
+};
+
 ExecutionState.prototype.frame = function(opt_index) {
   // If no index supplied return the selected frame.
   if (opt_index == null) opt_index = this.selected_frame;
@@ -1167,6 +1171,8 @@
         this.sourceRequest_(request, response);
       } else if (request.command == 'scripts') {
         this.scriptsRequest_(request, response);
+      } else if (request.command == 'threads') {
+        this.threadsRequest_(request, response);
       } else {
         throw new Error('Unknown command "' + request.command + '" in request');
       }
@@ -1673,6 +1679,28 @@
 };
 
 
+DebugCommandProcessor.prototype.threadsRequest_ = function(request, response) {
+  // Get the number of threads.
+  var total_threads = this.exec_state_.threadCount();
+
+  // Get information for all threads.
+  var threads = [];
+  for (var i = 0; i < total_threads; i++) {
+    var details = %GetThreadDetails(this.exec_state_.break_id, i);
+    var thread_info = { current: details[0],
+                        id: details[1]
+                      }
+    threads.push(thread_info);
+  }
+
+  // Create the response body.
+  response.body = {
+    totalThreads: total_threads,
+    threads: threads
+  }
+};
+
+
 // Check whether the previously processed command caused the VM to become
 // running.
 DebugCommandProcessor.prototype.isRunning = function() {
diff --git a/src/debug.cc b/src/debug.cc
index b704eed..7e0b298 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -688,7 +688,7 @@
     ClearStepping();
 
     // Notify the debug event listeners.
-    Debugger::OnDebugBreak(break_points_hit);
+    Debugger::OnDebugBreak(break_points_hit, false);
   } else if (thread_local_.last_step_action_ != StepNone) {
     // Hold on to last step action as it is cleared by the call to
     // ClearStepping.
@@ -1508,12 +1508,13 @@
   }
 
   // Process debug event
-  ProcessDebugEvent(v8::Exception, event_data);
+  ProcessDebugEvent(v8::Exception, event_data, false);
   // Return to continue execution from where the exception was thrown.
 }
 
 
-void Debugger::OnDebugBreak(Handle<Object> break_points_hit) {
+void Debugger::OnDebugBreak(Handle<Object> break_points_hit,
+                            bool auto_continue) {
   HandleScope scope;
 
   // Debugger has already been entered by caller.
@@ -1539,7 +1540,7 @@
   }
 
   // Process debug event
-  ProcessDebugEvent(v8::Break, event_data);
+  ProcessDebugEvent(v8::Break, event_data, auto_continue);
 }
 
 
@@ -1564,7 +1565,7 @@
   }
 
   // Process debug event
-  ProcessDebugEvent(v8::BeforeCompile, event_data);
+  ProcessDebugEvent(v8::BeforeCompile, event_data, false);
 }
 
 
@@ -1625,7 +1626,7 @@
     return;
   }
   // Process debug event
-  ProcessDebugEvent(v8::AfterCompile, event_data);
+  ProcessDebugEvent(v8::AfterCompile, event_data, false);
 }
 
 
@@ -1650,12 +1651,13 @@
     return;
   }
   // Process debug event.
-  ProcessDebugEvent(v8::NewFunction, event_data);
+  ProcessDebugEvent(v8::NewFunction, event_data, false);
 }
 
 
 void Debugger::ProcessDebugEvent(v8::DebugEvent event,
-                                 Handle<Object> event_data) {
+                                 Handle<Object> event_data,
+                                 bool auto_continue) {
   HandleScope scope;
 
   // Create the execution state.
@@ -1666,7 +1668,7 @@
   }
   // First notify the builtin debugger.
   if (message_thread_ != NULL) {
-    message_thread_->DebugEvent(event, exec_state, event_data);
+    message_thread_->DebugEvent(event, exec_state, event_data, auto_continue);
   }
   // Notify registered debug event listener. This can be either a C or a
   // JavaScript function.
@@ -1773,6 +1775,15 @@
 }
 
 
+bool Debugger::HasCommands() {
+  if (message_thread_ != NULL) {
+    return message_thread_->HasCommands();
+  } else {
+    return false;
+  }
+}
+
+
 void Debugger::ProcessHostDispatch(void* dispatch) {
   if (message_thread_ != NULL) {
     message_thread_->ProcessHostDispatch(dispatch);
@@ -1817,9 +1828,9 @@
 }
 
 
-bool Debugger::StartAgent(int port) {
+bool Debugger::StartAgent(const char* name, int port) {
   if (Socket::Setup()) {
-    agent_ = new DebuggerAgent(port);
+    agent_ = new DebuggerAgent(name, port);
     agent_->Start();
     return true;
   }
@@ -1828,6 +1839,16 @@
 }
 
 
+void Debugger::StopAgent() {
+  if (agent_ != NULL) {
+    agent_->Shutdown();
+    agent_->Join();
+    delete agent_;
+    agent_ = NULL;
+  }
+}
+
+
 DebugMessageThread::DebugMessageThread()
     : host_running_(true),
       command_queue_(kQueueInitialSize),
@@ -1904,7 +1925,8 @@
 // the VM.
 void DebugMessageThread::DebugEvent(v8::DebugEvent event,
                                     Handle<Object> exec_state,
-                                    Handle<Object> event_data) {
+                                    Handle<Object> event_data,
+                                    bool auto_continue) {
   HandleScope scope;
 
   if (!Debug::Load()) return;
@@ -1946,19 +1968,29 @@
     return;
   }
 
-  // Notify the debugger that a debug event has occurred.
-  bool success = SetEventJSONFromEvent(event_data);
-  if (!success) {
-    // If failed to notify debugger just continue running.
-    return;
+  // Notify the debugger that a debug event has occurred unless auto continue is
+  // active in which case no event is send.
+  if (!auto_continue) {
+    bool success = SetEventJSONFromEvent(event_data);
+    if (!success) {
+      // If failed to notify debugger just continue running.
+      return;
+    }
   }
 
-  // Wait for requests from the debugger.
+  // Process requests from the debugger.
   host_running_ = false;
   while (true) {
+    // Wait for new command in the queue.
     command_received_->Wait();
-    Logger::DebugTag("Got request from command queue, in interactive loop.");
+
+    // The debug command interrupt flag might have been set when the command was
+    // added.
+    StackGuard::Continue(DEBUGCOMMAND);
+
+    // Get the command from the queue.
     Vector<uint16_t> command = command_queue_.Get();
+    Logger::DebugTag("Got request from command queue, in interactive loop.");
     ASSERT(!host_running_);
     if (!Debugger::debugger_active()) {
       host_running_ = true;
@@ -2030,8 +2062,10 @@
     // Return the result.
     SendMessage(str);
 
-    // Return from debug event processing is VM should be running.
-    if (running) {
+    // Return from debug event processing if either the VM is put into the
+    // runnning state (through a continue command) or auto continue is active
+    // and there are no more commands queued.
+    if (running || (auto_continue && !HasCommands())) {
       return;
     }
   }
@@ -2049,6 +2083,10 @@
   Logger::DebugTag("Put command on command_queue.");
   command_queue_.Put(command_copy);
   command_received_->Signal();
+
+  if (!Debug::InDebugger()) {
+    StackGuard::DebugCommand();
+  }
 }
 
 
diff --git a/src/debug.h b/src/debug.h
index 9f4e047..c29b49b 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -418,20 +418,22 @@
   static Handle<Object> MakeCompileEvent(Handle<Script> script,
                                          bool before,
                                          bool* caught_exception);
-  static void OnDebugBreak(Handle<Object> break_points_hit);
+  static void OnDebugBreak(Handle<Object> break_points_hit, bool auto_continue);
   static void OnException(Handle<Object> exception, bool uncaught);
   static void OnBeforeCompile(Handle<Script> script);
   static void OnAfterCompile(Handle<Script> script,
                            Handle<JSFunction> fun);
   static void OnNewFunction(Handle<JSFunction> fun);
   static void ProcessDebugEvent(v8::DebugEvent event,
-                                Handle<Object> event_data);
+                                Handle<Object> event_data,
+                                bool auto_continue);
   static void SetEventListener(Handle<Object> callback, Handle<Object> data);
   static void SetMessageHandler(v8::DebugMessageHandler handler, void* data);
   static void SetHostDispatchHandler(v8::DebugHostDispatchHandler handler,
                                      void* data);
   static void SendMessage(Vector<uint16_t> message);
   static void ProcessCommand(Vector<const uint16_t> command);
+  static bool HasCommands();
   static void ProcessHostDispatch(void* dispatch);
   static void UpdateActiveDebugger();
   static Handle<Object> Call(Handle<JSFunction> fun,
@@ -439,7 +441,10 @@
                              bool* pending_exception);
 
   // Start the debugger agent listening on the provided port.
-  static bool StartAgent(int port);
+  static bool StartAgent(const char* name, int port);
+
+  // Stop the debugger agent.
+  static void StopAgent();
 
   inline static bool EventActive(v8::DebugEvent event) {
     // Currently argument event is not used.
@@ -528,7 +533,8 @@
   // when host_running_ is false.
   void DebugEvent(v8::DebugEvent,
                   Handle<Object> exec_state,
-                  Handle<Object> event_data);
+                  Handle<Object> event_data,
+                  bool auto_continue);
   // Puts event on the output queue.  Called by V8.
   // This is where V8 hands off
   // processing of the event to the DebugMessageThread thread,
@@ -546,6 +552,9 @@
   // Main function of DebugMessageThread thread.
   void Run();
 
+  // Check whether there are commands in the queue.
+  bool HasCommands() { return !command_queue_.IsEmpty(); }
+
   bool host_running_;  // Is the debugging host running or stopped?
   Semaphore* command_received_;  // Non-zero when command queue is non-empty.
   Semaphore* message_received_;  // Exactly equal to message queue length.
@@ -568,21 +577,11 @@
   EnterDebugger()
       : prev_(Debug::debugger_entry()),
         has_js_frames_(!it_.done()) {
-    ASSERT(!Debug::preemption_pending());
+    ASSERT(prev_ == NULL ? !Debug::preemption_pending() : true);
 
     // Link recursive debugger entry.
     Debug::set_debugger_entry(this);
 
-    // If a preemption is pending when first entering the debugger clear it as
-    // we don't want preemption happening while executing JavaScript in the
-    // debugger. When recursively entering the debugger the preemption flag
-    // cannot be set as this is disabled while in the debugger (see
-    // RuntimePreempt).
-    if (prev_ == NULL && StackGuard::IsPreempted()) {
-      StackGuard::Continue(PREEMPT);
-    }
-    ASSERT(!StackGuard::IsPreempted());
-
     // Store the previous break id and frame id.
     break_id_ = Debug::break_id();
     break_frame_id_ = Debug::break_frame_id();
@@ -616,6 +615,12 @@
       Debug::set_preemption_pending(false);
     }
 
+    // If there are commands in the queue when leaving the debugger request that
+    // these commands are processed.
+    if (prev_ == NULL && Debugger::HasCommands()) {
+      StackGuard::DebugCommand();
+    }
+
     // Leaving this debugger entry.
     Debug::set_debugger_entry(prev_);
   }
diff --git a/src/disassembler.cc b/src/disassembler.cc
index 9178aed..a838a08 100644
--- a/src/disassembler.cc
+++ b/src/disassembler.cc
@@ -28,7 +28,7 @@
 #include "v8.h"
 
 #include "code-stubs.h"
-#include "codegen.h"
+#include "codegen-inl.h"
 #include "debug.h"
 #include "disasm.h"
 #include "disassembler.h"
@@ -99,7 +99,7 @@
   }
 }
 
-static const int kOutBufferSize = 1024 + String::kMaxShortPrintLength;
+static const int kOutBufferSize = 2048 + String::kMaxShortPrintLength;
 static const int kRelocInfoPosition = 57;
 
 static int DecodeIt(FILE* f,
diff --git a/src/execution.cc b/src/execution.cc
index 419cc92..03017d0 100644
--- a/src/execution.cc
+++ b/src/execution.cc
@@ -318,6 +318,21 @@
 }
 
 
+bool StackGuard::IsDebugCommand() {
+  ExecutionAccess access;
+  return thread_local_.interrupt_flags_ & DEBUGCOMMAND;
+}
+
+
+void StackGuard::DebugCommand() {
+  if (FLAG_debugger_auto_break) {
+    ExecutionAccess access;
+    thread_local_.interrupt_flags_ |= DEBUGCOMMAND;
+    set_limits(kInterruptLimit, access);
+  }
+}
+
+
 void StackGuard::Continue(InterruptFlag after_what) {
   ExecutionAccess access;
   thread_local_.interrupt_flags_ &= ~static_cast<int>(after_what);
@@ -467,7 +482,8 @@
                                               bool* exc) {
   if (data->property_list()->IsUndefined() &&
       !data->constructor()->IsUndefined()) {
-    Object* result;
+    // Initialization to make gcc happy.
+    Object* result = NULL;
     {
       HandleScope scope;
       Handle<FunctionTemplateInfo> cons_template =
@@ -556,8 +572,18 @@
     }
   }
 
-  // Clear the debug request flag.
+  // Check for debug command break only.
+  bool debug_command_only =
+      StackGuard::IsDebugCommand() && !StackGuard::IsDebugBreak();
+
+  // Clear the debug request flags.
   StackGuard::Continue(DEBUGBREAK);
+  StackGuard::Continue(DEBUGCOMMAND);
+
+  // If debug command only and already in debugger ignore it.
+  if (debug_command_only && Debug::InDebugger()) {
+    return Heap::undefined_value();
+  }
 
   HandleScope scope;
   // Enter the debugger. Just continue if we fail to enter the debugger.
@@ -567,7 +593,7 @@
   }
 
   // Notify the debug event listeners.
-  Debugger::OnDebugBreak(Factory::undefined_value());
+  Debugger::OnDebugBreak(Factory::undefined_value(), debug_command_only);
 
   // Return to continue execution.
   return Heap::undefined_value();
@@ -575,7 +601,9 @@
 
 
 Object* Execution::HandleStackGuardInterrupt() {
-  if (StackGuard::IsDebugBreak()) DebugBreakHelper();
+  if (StackGuard::IsDebugBreak() || StackGuard::IsDebugCommand()) {
+    DebugBreakHelper();
+  }
   if (StackGuard::IsPreempted()) RuntimePreempt();
   if (StackGuard::IsInterrupted()) {
     // interrupt
diff --git a/src/execution.h b/src/execution.h
index d5f2fb6..6531572 100644
--- a/src/execution.h
+++ b/src/execution.h
@@ -35,7 +35,8 @@
 enum InterruptFlag {
   INTERRUPT = 1 << 0,
   DEBUGBREAK = 1 << 1,
-  PREEMPT = 1 << 2
+  DEBUGCOMMAND = 1 << 2,
+  PREEMPT = 1 << 3
 };
 
 class Execution : public AllStatic {
@@ -159,6 +160,8 @@
   static void Interrupt();
   static bool IsDebugBreak();
   static void DebugBreak();
+  static bool IsDebugCommand();
+  static void DebugCommand();
   static void Continue(InterruptFlag after_what);
 
  private:
diff --git a/src/factory.cc b/src/factory.cc
index ead40b4..e29c84d 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -90,11 +90,9 @@
 
 
 Handle<String> Factory::NewConsString(Handle<String> first,
-                                      StringShape first_shape,
-                                      Handle<String> second,
-                                      StringShape second_shape) {
-  if (first->length(first_shape) == 0) return second;
-  if (second->length(second_shape) == 0) return first;
+                                      Handle<String> second) {
+  if (first->length() == 0) return second;
+  if (second->length() == 0) return first;
   CALL_HEAP_FUNCTION(Heap::AllocateConsString(*first, *second), String);
 }
 
diff --git a/src/factory.h b/src/factory.h
index 1388de1..2564c3c 100644
--- a/src/factory.h
+++ b/src/factory.h
@@ -98,9 +98,7 @@
 
   // Create a new cons string object which consists of a pair of strings.
   static Handle<String> NewConsString(Handle<String> first,
-                                      StringShape first_shape,
-                                      Handle<String> second,
-                                      StringShape second_shape);
+                                      Handle<String> second);
 
   // Create a new sliced string object which represents a substring of a
   // backing string.
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index 67ad3f2..911ab8c 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -136,6 +136,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,
+            "automatically set the debug break flag when debugger commands are "
+            "in the queue (experimental)")
 
 // execution.cc
 DEFINE_bool(call_regexp, false, "allow calls to RegExp objects")
diff --git a/src/flags.cc b/src/flags.cc
index c71b08e..31e35f0 100644
--- a/src/flags.cc
+++ b/src/flags.cc
@@ -248,7 +248,7 @@
     args->Add(buffer.ToCString().Detach());
     JSArguments jsargs = *args_flag->args_variable();
     for (int j = 0; j < jsargs.argc(); j++) {
-      args->Add(OS::StrDup(jsargs[j]));
+      args->Add(StrDup(jsargs[j]));
     }
   }
   return args;
diff --git a/src/frames-arm.h b/src/frames-arm.h
index 0d1a27c..930f6e0 100644
--- a/src/frames-arm.h
+++ b/src/frames-arm.h
@@ -154,11 +154,9 @@
 };
 
 
-inline Object* JavaScriptFrame::function() const {
+inline Object* JavaScriptFrame::function_slot_object() const {
   const int offset = JavaScriptFrameConstants::kFunctionOffset;
-  Object* result = Memory::Object_at(fp() + offset);
-  ASSERT(result->IsJSFunction());
-  return result;
+  return Memory::Object_at(fp() + offset);
 }
 
 
diff --git a/src/frames-ia32.h b/src/frames-ia32.h
index e31906d..518b1ca 100644
--- a/src/frames-ia32.h
+++ b/src/frames-ia32.h
@@ -129,11 +129,9 @@
 };
 
 
-inline Object* JavaScriptFrame::function() const {
+inline Object* JavaScriptFrame::function_slot_object() const {
   const int offset = JavaScriptFrameConstants::kFunctionOffset;
-  Object* result = Memory::Object_at(fp() + offset);
-  ASSERT(result->IsJSFunction());
-  return result;
+  return Memory::Object_at(fp() + offset);
 }
 
 
diff --git a/src/frames-inl.h b/src/frames-inl.h
index c9d3ab6..32820a5 100644
--- a/src/frames-inl.h
+++ b/src/frames-inl.h
@@ -169,6 +169,20 @@
 }
 
 
+inline bool JavaScriptFrame::is_at_function() const {
+  Object* result = function_slot_object();
+  return Heap::Contains(reinterpret_cast<Address>(result)) &&
+      result->IsJSFunction();
+}
+
+
+inline Object* JavaScriptFrame::function() const {
+  Object* result = function_slot_object();
+  ASSERT(result->IsJSFunction());
+  return result;
+}
+
+
 template<typename Iterator>
 inline JavaScriptFrame* JavaScriptFrameIteratorTemp<Iterator>::frame() const {
   // TODO(1233797): The frame hierarchy needs to change. It's
diff --git a/src/frames.cc b/src/frames.cc
index 3270797..763ff48 100644
--- a/src/frames.cc
+++ b/src/frames.cc
@@ -66,23 +66,32 @@
 #define INITIALIZE_SINGLETON(type, field) field##_(this),
 StackFrameIterator::StackFrameIterator()
     : STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
-      frame_(NULL), handler_(NULL), thread_(Top::GetCurrentThread()) {
+      frame_(NULL), handler_(NULL), thread_(Top::GetCurrentThread()),
+      fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) {
   Reset();
 }
 StackFrameIterator::StackFrameIterator(ThreadLocalTop* t)
     : STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
-      frame_(NULL), handler_(NULL), thread_(t) {
+      frame_(NULL), handler_(NULL), thread_(t),
+      fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) {
   Reset();
 }
-StackFrameIterator::StackFrameIterator(bool reset)
+StackFrameIterator::StackFrameIterator(bool use_top, Address fp, Address sp)
     : STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
-      frame_(NULL), handler_(NULL), thread_(Top::GetCurrentThread()) {
-  if (reset) Reset();
+      frame_(NULL), handler_(NULL),
+      thread_(use_top ? Top::GetCurrentThread() : NULL),
+      fp_(use_top ? NULL : fp), sp_(sp),
+      advance_(use_top ? &StackFrameIterator::AdvanceWithHandler :
+               &StackFrameIterator::AdvanceWithoutHandler) {
+  if (use_top || fp != NULL) {
+    Reset();
+  }
 }
+
 #undef INITIALIZE_SINGLETON
 
 
-void StackFrameIterator::Advance() {
+void StackFrameIterator::AdvanceWithHandler() {
   ASSERT(!done());
   // Compute the state of the calling frame before restoring
   // callee-saved registers and unwinding handlers. This allows the
@@ -105,17 +114,45 @@
 }
 
 
-void StackFrameIterator::Reset() {
-  Address fp = Top::c_entry_fp(thread_);
+void StackFrameIterator::AdvanceWithoutHandler() {
+  // A simpler version of Advance which doesn't care about handler.
+  ASSERT(!done());
   StackFrame::State state;
-  StackFrame::Type type = ExitFrame::GetStateForFramePointer(fp, &state);
+  StackFrame::Type type = frame_->GetCallerState(&state);
   frame_ = SingletonFor(type, &state);
-  handler_ = StackHandler::FromAddress(Top::handler(thread_));
+}
+
+
+void StackFrameIterator::Reset() {
+  StackFrame::State state;
+  StackFrame::Type type;
+  if (thread_ != NULL) {
+    type = ExitFrame::GetStateForFramePointer(Top::c_entry_fp(thread_), &state);
+    handler_ = StackHandler::FromAddress(Top::handler(thread_));
+  } else {
+    ASSERT(fp_ != NULL);
+    state.fp = fp_;
+    state.sp = sp_;
+    state.pc_address =
+        reinterpret_cast<Address*>(StandardFrame::ComputePCAddress(fp_));
+    type = StackFrame::ComputeType(&state);
+    if (SingletonFor(type) == NULL) return;
+  }
+  frame_ = SingletonFor(type, &state);
 }
 
 
 StackFrame* StackFrameIterator::SingletonFor(StackFrame::Type type,
                                              StackFrame::State* state) {
+  if (type == StackFrame::NONE) return NULL;
+  StackFrame* result = SingletonFor(type);
+  ASSERT(result != NULL);
+  result->state_ = *state;
+  return result;
+}
+
+
+StackFrame* StackFrameIterator::SingletonFor(StackFrame::Type type) {
 #define FRAME_TYPE_CASE(type, field) \
   case StackFrame::type: result = &field##_; break;
 
@@ -125,8 +162,6 @@
     STACK_FRAME_TYPE_LIST(FRAME_TYPE_CASE)
     default: break;
   }
-  ASSERT(result != NULL);
-  result->state_ = *state;
   return result;
 
 #undef FRAME_TYPE_CASE
@@ -154,29 +189,50 @@
 
 
 SafeStackFrameIterator::SafeStackFrameIterator(
-    Address low_bound, Address high_bound) :
+    Address fp, Address sp, Address low_bound, Address high_bound) :
     low_bound_(low_bound), high_bound_(high_bound),
-    is_working_iterator_(IsInBounds(low_bound, high_bound,
-                                    Top::c_entry_fp(Top::GetCurrentThread()))),
-    iteration_done_(!is_working_iterator_), iterator_(is_working_iterator_) {
+    is_valid_top_(
+        IsWithinBounds(low_bound, high_bound,
+                       Top::c_entry_fp(Top::GetCurrentThread())) &&
+        Top::handler(Top::GetCurrentThread()) != NULL),
+    is_valid_fp_(IsWithinBounds(low_bound, high_bound, fp)),
+    is_working_iterator_(is_valid_top_ || is_valid_fp_),
+    iteration_done_(!is_working_iterator_),
+    iterator_(is_valid_top_, is_valid_fp_ ? fp : NULL, sp) {
 }
 
 
 void SafeStackFrameIterator::Advance() {
   ASSERT(is_working_iterator_);
   ASSERT(!done());
-  StackFrame* frame = iterator_.frame();
-  iteration_done_ =
-      !IsGoodStackAddress(frame->sp()) || !IsGoodStackAddress(frame->fp());
-  if (!iteration_done_) {
-    iterator_.Advance();
-    if (!iterator_.done()) {
-      // Check that we have actually moved to the previous frame in the stack
-      StackFrame* prev_frame = iterator_.frame();
-      iteration_done_ =
-          prev_frame->sp() < frame->sp() || prev_frame->fp() < frame->fp();
-    }
-  }
+  StackFrame* last_frame = iterator_.frame();
+  Address last_sp = last_frame->sp(), last_fp = last_frame->fp();
+  // Before advancing to the next stack frame, perform pointer validity tests
+  iteration_done_ = !IsValidFrame(last_frame) || !IsValidCaller(last_frame);
+  if (iteration_done_) return;
+
+  iterator_.Advance();
+  if (iterator_.done()) return;
+  // Check that we have actually moved to the previous frame in the stack
+  StackFrame* prev_frame = iterator_.frame();
+  iteration_done_ = prev_frame->sp() < last_sp || prev_frame->fp() < last_fp;
+}
+
+
+bool SafeStackFrameIterator::IsValidFrame(StackFrame* frame) const {
+  return IsValidStackAddress(frame->sp()) && IsValidStackAddress(frame->fp()) &&
+      // JavaScriptFrame uses function shared info to advance, hence it must
+      // point to a valid function object.
+      (!frame->is_java_script() ||
+       reinterpret_cast<JavaScriptFrame*>(frame)->is_at_function());
+}
+
+
+bool SafeStackFrameIterator::IsValidCaller(StackFrame* frame) {
+  StackFrame::State state;
+  frame->ComputeCallerState(&state);
+  return IsValidStackAddress(state.sp) && IsValidStackAddress(state.fp) &&
+      iterator_.SingletonFor(frame->GetCallerState(&state)) != NULL;
 }
 
 
@@ -193,9 +249,9 @@
 
 #ifdef ENABLE_LOGGING_AND_PROFILING
 SafeStackTraceFrameIterator::SafeStackTraceFrameIterator(
-    Address low_bound, Address high_bound) :
-    SafeJavaScriptFrameIterator(low_bound, high_bound) {
-  if (!done() && !frame()->function()->IsJSFunction()) Advance();
+    Address fp, Address sp, Address low_bound, Address high_bound) :
+    SafeJavaScriptFrameIterator(fp, sp, low_bound, high_bound) {
+  if (!done() && !frame()->is_at_function()) Advance();
 }
 
 
@@ -203,7 +259,7 @@
   while (true) {
     SafeJavaScriptFrameIterator::Advance();
     if (done()) return;
-    if (frame()->function()->IsJSFunction()) return;
+    if (frame()->is_at_function()) return;
   }
 }
 #endif
@@ -279,11 +335,22 @@
 }
 
 
+StackFrame::Type StackFrame::GetCallerState(State* state) const {
+  ComputeCallerState(state);
+  return ComputeType(state);
+}
+
+
 Code* EntryFrame::code() const {
   return Heap::js_entry_code();
 }
 
 
+void EntryFrame::ComputeCallerState(State* state) const {
+  GetCallerState(state);
+}
+
+
 StackFrame::Type EntryFrame::GetCallerState(State* state) const {
   const int offset = EntryFrameConstants::kCallerFPOffset;
   Address fp = Memory::Address_at(this->fp() + offset);
@@ -301,13 +368,12 @@
 }
 
 
-StackFrame::Type ExitFrame::GetCallerState(State* state) const {
+void ExitFrame::ComputeCallerState(State* state) const {
   // Setup the caller state.
   state->sp = pp();
   state->fp = Memory::Address_at(fp() + ExitFrameConstants::kCallerFPOffset);
   state->pc_address
       = reinterpret_cast<Address*>(fp() + ExitFrameConstants::kCallerPCOffset);
-  return ComputeType(state);
 }
 
 
@@ -338,11 +404,10 @@
 }
 
 
-StackFrame::Type StandardFrame::GetCallerState(State* state) const {
+void StandardFrame::ComputeCallerState(State* state) const {
   state->sp = caller_sp();
   state->fp = caller_fp();
   state->pc_address = reinterpret_cast<Address*>(ComputePCAddress(fp()));
-  return ComputeType(state);
 }
 
 
diff --git a/src/frames.h b/src/frames.h
index e6dbd24..78d8e72 100644
--- a/src/frames.h
+++ b/src/frames.h
@@ -190,8 +190,11 @@
   const StackFrameIterator* iterator_;
   State state_;
 
+  // Fill in the state of the calling frame.
+  virtual void ComputeCallerState(State* state) const = 0;
+
   // Get the type and the state of the calling frame.
-  virtual Type GetCallerState(State* state) const = 0;
+  virtual Type GetCallerState(State* state) const;
 
   // Cooking/uncooking support.
   void Cook();
@@ -199,6 +202,7 @@
 
   friend class StackFrameIterator;
   friend class StackHandlerIterator;
+  friend class SafeStackFrameIterator;
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(StackFrame);
 };
@@ -228,6 +232,7 @@
   virtual Address GetCallerStackPointer() const { return 0; }
 
  private:
+  virtual void ComputeCallerState(State* state) const;
   virtual Type GetCallerState(State* state) const;
 
   friend class StackFrameIterator;
@@ -280,7 +285,7 @@
   virtual Address GetCallerStackPointer() const;
 
  private:
-  virtual Type GetCallerState(State* state) const;
+  virtual void ComputeCallerState(State* state) const;
 
   friend class StackFrameIterator;
 };
@@ -328,7 +333,7 @@
   explicit StandardFrame(StackFrameIterator* iterator)
       : StackFrame(iterator) { }
 
-  virtual Type GetCallerState(State* state) const;
+  virtual void ComputeCallerState(State* state) const;
 
   // Accessors.
   inline Address caller_sp() const;
@@ -368,6 +373,7 @@
   virtual Type type() const { return JAVA_SCRIPT; }
 
   // Accessors.
+  inline bool is_at_function() const;
   inline Object* function() const;
   inline Object* receiver() const;
   inline void set_receiver(Object* value);
@@ -413,6 +419,8 @@
   virtual Address GetCallerStackPointer() const;
 
  private:
+  inline Object* function_slot_object() const;
+
   friend class StackFrameIterator;
 };
 
@@ -509,8 +517,10 @@
   // An iterator that iterates over a given thread's stack.
   explicit StackFrameIterator(ThreadLocalTop* thread);
 
-  // An iterator that conditionally resets itself on init.
-  explicit StackFrameIterator(bool reset);
+  // An iterator that can start from a given FP address.
+  // If use_top, then work as usual, if fp isn't NULL, use it,
+  // otherwise, do nothing.
+  StackFrameIterator(bool use_top, Address fp, Address sp);
 
   StackFrame* frame() const {
     ASSERT(!done());
@@ -518,7 +528,7 @@
   }
 
   bool done() const { return frame_ == NULL; }
-  void Advance();
+  void Advance() { (this->*advance_)(); }
 
   // Go back to the first frame.
   void Reset();
@@ -530,6 +540,9 @@
   StackFrame* frame_;
   StackHandler* handler_;
   ThreadLocalTop* thread_;
+  Address fp_;
+  Address sp_;
+  void (StackFrameIterator::*advance_)();
 
   StackHandler* handler() const {
     ASSERT(!done());
@@ -538,8 +551,14 @@
 
   // Get the type-specific frame singleton in a given state.
   StackFrame* SingletonFor(StackFrame::Type type, StackFrame::State* state);
+  // A helper function, can return a NULL pointer.
+  StackFrame* SingletonFor(StackFrame::Type type);
+
+  void AdvanceWithHandler();
+  void AdvanceWithoutHandler();
 
   friend class StackFrame;
+  friend class SafeStackFrameIterator;
   DISALLOW_COPY_AND_ASSIGN(StackFrameIterator);
 };
 
@@ -558,8 +577,11 @@
   // Skip frames until the frame with the given id is reached.
   explicit JavaScriptFrameIteratorTemp(StackFrame::Id id);
 
-  explicit JavaScriptFrameIteratorTemp(Address low_bound, Address high_bound) :
-      iterator_(low_bound, high_bound) { if (!done()) Advance(); }
+  JavaScriptFrameIteratorTemp(Address fp, Address sp,
+                              Address low_bound, Address high_bound) :
+      iterator_(fp, sp, low_bound, high_bound) {
+    if (!done()) Advance();
+  }
 
   inline JavaScriptFrame* frame() const;
 
@@ -595,7 +617,8 @@
 
 class SafeStackFrameIterator BASE_EMBEDDED {
  public:
-  explicit SafeStackFrameIterator(Address low_bound, Address high_bound);
+  SafeStackFrameIterator(Address fp, Address sp,
+                         Address low_bound, Address high_bound);
 
   StackFrame* frame() const {
     ASSERT(is_working_iterator_);
@@ -608,16 +631,20 @@
   void Reset();
 
  private:
-  static bool IsInBounds(
+  static bool IsWithinBounds(
       Address low_bound, Address high_bound, Address addr) {
     return low_bound <= addr && addr <= high_bound;
   }
-  bool IsGoodStackAddress(Address addr) const {
-    return IsInBounds(low_bound_, high_bound_, addr);
+  bool IsValidStackAddress(Address addr) const {
+    return IsWithinBounds(low_bound_, high_bound_, addr);
   }
+  bool IsValidFrame(StackFrame* frame) const;
+  bool IsValidCaller(StackFrame* frame);
 
   Address low_bound_;
   Address high_bound_;
+  const bool is_valid_top_;
+  const bool is_valid_fp_;
   const bool is_working_iterator_;
   bool iteration_done_;
   StackFrameIterator iterator_;
@@ -631,7 +658,8 @@
 
 class SafeStackTraceFrameIterator: public SafeJavaScriptFrameIterator {
  public:
-  explicit SafeStackTraceFrameIterator(Address low_bound, Address high_bound);
+  explicit SafeStackTraceFrameIterator(Address fp, Address sp,
+                                       Address low_bound, Address high_bound);
   void Advance();
 };
 #endif
diff --git a/src/handles.cc b/src/handles.cc
index b6c59b0..2382706 100644
--- a/src/handles.cc
+++ b/src/handles.cc
@@ -181,8 +181,8 @@
 
 
 void FlattenString(Handle<String> string) {
-  CALL_HEAP_FUNCTION_VOID(string->TryFlattenIfNotFlat(StringShape(*string)));
-  ASSERT(string->IsFlat(StringShape(*string)));
+  CALL_HEAP_FUNCTION_VOID(string->TryFlattenIfNotFlat());
+  ASSERT(string->IsFlat());
 }
 
 
diff --git a/src/heap.cc b/src/heap.cc
index f384297..8bab00e 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -34,7 +34,6 @@
 #include "compilation-cache.h"
 #include "debug.h"
 #include "global-handles.h"
-#include "jsregexp.h"
 #include "mark-compact.h"
 #include "natives.h"
 #include "scanner.h"
@@ -230,7 +229,6 @@
 
 
 void Heap::GarbageCollectionPrologue() {
-  RegExpImpl::NewSpaceCollectionPrologue();
   gc_count_++;
 #ifdef DEBUG
   ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC);
@@ -302,7 +300,7 @@
   // contexts are disposed and leave it to the embedder to make
   // informed decisions about when to force a collection.
   if (!FLAG_expose_gc && context_disposed_pending_) {
-    StatsRateScope scope(&Counters::gc_context);
+    HistogramTimerScope scope(&Counters::gc_context);
     CollectAllGarbage();
   }
   context_disposed_pending_ = false;
@@ -337,7 +335,7 @@
     // Tell the tracer which collector we've selected.
     tracer.set_collector(collector);
 
-    StatsRate* rate = (collector == SCAVENGER)
+    HistogramTimer* rate = (collector == SCAVENGER)
         ? &Counters::gc_scavenger
         : &Counters::gc_compactor;
     rate->Start();
@@ -467,7 +465,6 @@
   ClearKeyedLookupCache();
 
   CompilationCache::MarkCompactPrologue();
-  RegExpImpl::OldSpaceCollectionPrologue();
 
   Top::MarkCompactPrologue(is_compacting);
   ThreadManager::MarkCompactPrologue(is_compacting);
@@ -1393,41 +1390,31 @@
 
 Object* Heap::AllocateConsString(String* first,
                                  String* second) {
-  StringShape first_shape(first);
-  StringShape second_shape(second);
-  int first_length = first->length(first_shape);
-  int second_length = second->length(second_shape);
+  int first_length = first->length();
+  int second_length = second->length();
   int length = first_length + second_length;
-  bool is_ascii = first_shape.IsAsciiRepresentation()
-      && second_shape.IsAsciiRepresentation();
+  bool is_ascii = StringShape(first).IsAsciiRepresentation()
+      && StringShape(second).IsAsciiRepresentation();
 
   // If the resulting string is small make a flat string.
   if (length < String::kMinNonFlatLength) {
-    ASSERT(first->IsFlat(first_shape));
-    ASSERT(second->IsFlat(second_shape));
+    ASSERT(first->IsFlat());
+    ASSERT(second->IsFlat());
     if (is_ascii) {
       Object* result = AllocateRawAsciiString(length);
       if (result->IsFailure()) return result;
       // Copy the characters into the new object.
       char* dest = SeqAsciiString::cast(result)->GetChars();
-      String::WriteToFlat(first, first_shape, dest, 0, first_length);
-      String::WriteToFlat(second,
-                          second_shape,
-                          dest + first_length,
-                          0,
-                          second_length);
+      String::WriteToFlat(first, dest, 0, first_length);
+      String::WriteToFlat(second, dest + first_length, 0, second_length);
       return result;
     } else {
       Object* result = AllocateRawTwoByteString(length);
       if (result->IsFailure()) return result;
       // Copy the characters into the new object.
       uc16* dest = SeqTwoByteString::cast(result)->GetChars();
-      String::WriteToFlat(first, first_shape, dest, 0, first_length);
-      String::WriteToFlat(second,
-                          second_shape,
-                          dest + first_length,
-                          0,
-                          second_length);
+      String::WriteToFlat(first, dest, 0, first_length);
+      String::WriteToFlat(second, dest + first_length, 0, second_length);
       return result;
     }
   }
@@ -1458,25 +1445,24 @@
 Object* Heap::AllocateSlicedString(String* buffer,
                                    int start,
                                    int end) {
-  StringShape buffer_shape(buffer);
   int length = end - start;
 
   // If the resulting string is small make a sub string.
   if (end - start <= String::kMinNonFlatLength) {
-    return Heap::AllocateSubString(buffer, buffer_shape, start, end);
+    return Heap::AllocateSubString(buffer, start, end);
   }
 
   Map* map;
   if (length <= String::kMaxShortStringSize) {
-    map = buffer_shape.IsAsciiRepresentation() ?
+    map = StringShape(buffer).IsAsciiRepresentation() ?
       short_sliced_ascii_string_map() :
       short_sliced_string_map();
   } else if (length <= String::kMaxMediumStringSize) {
-    map = buffer_shape.IsAsciiRepresentation() ?
+    map = StringShape(buffer).IsAsciiRepresentation() ?
       medium_sliced_ascii_string_map() :
       medium_sliced_string_map();
   } else {
-    map = buffer_shape.IsAsciiRepresentation() ?
+    map = StringShape(buffer).IsAsciiRepresentation() ?
       long_sliced_ascii_string_map() :
       long_sliced_string_map();
   }
@@ -1494,41 +1480,38 @@
 
 
 Object* Heap::AllocateSubString(String* buffer,
-                                StringShape buffer_shape,
                                 int start,
                                 int end) {
   int length = end - start;
 
   if (length == 1) {
     return Heap::LookupSingleCharacterStringFromCode(
-        buffer->Get(buffer_shape, start));
+        buffer->Get(start));
   }
 
   // Make an attempt to flatten the buffer to reduce access time.
-  if (!buffer->IsFlat(buffer_shape)) {
-    buffer->TryFlatten(buffer_shape);
-    buffer_shape = StringShape(buffer);
+  if (!buffer->IsFlat()) {
+    buffer->TryFlatten();
   }
 
-  Object* result = buffer_shape.IsAsciiRepresentation()
+  Object* result = StringShape(buffer).IsAsciiRepresentation()
       ? AllocateRawAsciiString(length)
       : AllocateRawTwoByteString(length);
   if (result->IsFailure()) return result;
 
   // Copy the characters into the new object.
   String* string_result = String::cast(result);
-  StringShape result_shape(string_result);
   StringHasher hasher(length);
   int i = 0;
   for (; i < length && hasher.is_array_index(); i++) {
-    uc32 c = buffer->Get(buffer_shape, start + i);
+    uc32 c = buffer->Get(start + i);
     hasher.AddCharacter(c);
-    string_result->Set(result_shape, i, c);
+    string_result->Set(i, c);
   }
   for (; i < length; i++) {
-    uc32 c = buffer->Get(buffer_shape, start + i);
+    uc32 c = buffer->Get(start + i);
     hasher.AddCharacterNoIndex(c);
-    string_result->Set(result_shape, i, c);
+    string_result->Set(i, c);
   }
   string_result->set_length_field(hasher.GetHashField());
   return result;
@@ -1591,7 +1574,7 @@
   Object* result = Heap::AllocateRawTwoByteString(1);
   if (result->IsFailure()) return result;
   String* answer = String::cast(result);
-  answer->Set(StringShape(answer), 0, code);
+  answer->Set(0, code);
   return answer;
 }
 
@@ -2017,10 +2000,9 @@
   // Convert and copy the characters into the new object.
   String* string_result = String::cast(result);
   decoder->Reset(string.start(), string.length());
-  StringShape result_shape(string_result);
   for (int i = 0; i < chars; i++) {
     uc32 r = decoder->GetNext();
-    string_result->Set(result_shape, i, r);
+    string_result->Set(i, r);
   }
   return result;
 }
@@ -2043,9 +2025,8 @@
   // Copy the characters into the new object, which may be either ASCII or
   // UTF-16.
   String* string_result = String::cast(result);
-  StringShape result_shape(string_result);
   for (int i = 0; i < string.length(); i++) {
-    string_result->Set(result_shape, i, string[i]);
+    string_result->Set(i, string[i]);
   }
   return result;
 }
@@ -2164,14 +2145,13 @@
   reinterpret_cast<HeapObject*>(result)->set_map(map);
   // The hash value contains the length of the string.
   String* answer = String::cast(result);
-  StringShape answer_shape(answer);
   answer->set_length_field(length_field);
 
   ASSERT_EQ(size, answer->Size());
 
   // Fill in the characters.
   for (int i = 0; i < chars; i++) {
-    answer->Set(answer_shape, i, buffer->GetNext());
+    answer->Set(i, buffer->GetNext());
   }
   return answer;
 }
diff --git a/src/heap.h b/src/heap.h
index a1dd81e..c83c2e8 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -167,8 +167,6 @@
   V(char_at_symbol, "CharAt")                                            \
   V(undefined_symbol, "undefined")                                       \
   V(value_of_symbol, "valueOf")                                          \
-  V(CreateObjectLiteralBoilerplate_symbol, "CreateObjectLiteralBoilerplate") \
-  V(CreateArrayLiteral_symbol, "CreateArrayLiteral")                     \
   V(InitializeVarGlobal_symbol, "InitializeVarGlobal")                   \
   V(InitializeConstGlobal_symbol, "InitializeConstGlobal")               \
   V(stack_overflow_symbol, "kStackOverflowBoilerplate")                  \
@@ -533,7 +531,6 @@
   // failed.
   // Please note this does not perform a garbage collection.
   static Object* AllocateSubString(String* buffer,
-                                   StringShape buffer_shape,
                                    int start,
                                    int end);
 
diff --git a/src/interpreter-irregexp.cc b/src/interpreter-irregexp.cc
index 33f6ec6..1cc5c5a 100644
--- a/src/interpreter-irregexp.cc
+++ b/src/interpreter-irregexp.cc
@@ -569,13 +569,12 @@
                                 Handle<String> subject,
                                 int* registers,
                                 int start_position) {
-  ASSERT(subject->IsFlat(StringShape(*subject)));
+  ASSERT(subject->IsFlat());
 
   AssertNoAllocation a;
   const byte* code_base = code_array->GetDataStartAddress();
-  StringShape subject_shape(*subject);
   uc16 previous_char = '\n';
-  if (subject_shape.IsAsciiRepresentation()) {
+  if (StringShape(*subject).IsAsciiRepresentation()) {
     Vector<const char> subject_vector = subject->ToAsciiVector();
     if (start_position != 0) previous_char = subject_vector[start_position - 1];
     return RawMatch(code_base,
diff --git a/src/jsregexp.cc b/src/jsregexp.cc
index 7644cea..e117189 100644
--- a/src/jsregexp.cc
+++ b/src/jsregexp.cc
@@ -55,27 +55,6 @@
 namespace v8 { namespace internal {
 
 
-String* RegExpImpl::last_ascii_string_ = NULL;
-String* RegExpImpl::two_byte_cached_string_ = NULL;
-
-
-void RegExpImpl::NewSpaceCollectionPrologue() {
-  // The two byte string is always in the old space.  The Ascii string may be
-  // in either place.  If it is in the old space we don't need to do anything.
-  if (Heap::InNewSpace(last_ascii_string_)) {
-    // Invalidate the cache.
-    last_ascii_string_ = NULL;
-    two_byte_cached_string_ = NULL;
-  }
-}
-
-
-void RegExpImpl::OldSpaceCollectionPrologue() {
-  last_ascii_string_ = NULL;
-  two_byte_cached_string_ = NULL;
-}
-
-
 Handle<Object> RegExpImpl::CreateRegExpLiteral(Handle<JSFunction> constructor,
                                                Handle<String> pattern,
                                                Handle<String> flags,
@@ -92,55 +71,10 @@
 }
 
 
-// Converts a source string to a 16 bit flat string or a SlicedString containing
-// a 16 bit flat string).
-Handle<String> RegExpImpl::CachedStringToTwoByte(Handle<String> subject) {
-  if (*subject == last_ascii_string_) {
-    ASSERT(two_byte_cached_string_ != NULL);
-    return Handle<String>(String::cast(two_byte_cached_string_));
-  }
-  Handle<String> two_byte_string = StringToTwoByte(subject);
-  last_ascii_string_ = *subject;
-  two_byte_cached_string_ = *two_byte_string;
-  return two_byte_string;
-}
-
-
-// Converts a source string to a 16 bit flat string or a SlicedString containing
-// a 16 bit flat string).
-Handle<String> RegExpImpl::StringToTwoByte(Handle<String> pattern) {
-  StringShape shape(*pattern);
-  if (!pattern->IsFlat(shape)) {
-    FlattenString(pattern);
-    shape = StringShape(*pattern);
-  }
-  Handle<String> flat_string(shape.IsCons() ?
-    String::cast(ConsString::cast(*pattern)->first()) :
-    *pattern);
-  ASSERT(flat_string->IsString());
-  StringShape flat_shape(*flat_string);
-  ASSERT(!flat_shape.IsCons());
-  ASSERT(flat_shape.IsSequential() ||
-         flat_shape.IsSliced() ||
-         flat_shape.IsExternal());
-  if (!flat_shape.IsAsciiRepresentation()) {
-    return flat_string;
-  }
-
-  int len = flat_string->length(flat_shape);
-  Handle<String> two_byte_string =
-    Factory::NewRawTwoByteString(len, TENURED);
-  uc16* dest = SeqTwoByteString::cast(*two_byte_string)->GetChars();
-  String::WriteToFlat(*flat_string, flat_shape, dest, 0, len);
-  return two_byte_string;
-}
-
-
 static JSRegExp::Flags RegExpFlagsFromString(Handle<String> str) {
   int flags = JSRegExp::NONE;
-  StringShape shape(*str);
-  for (int i = 0; i < str->length(shape); i++) {
-    switch (str->Get(shape, i)) {
+  for (int i = 0; i < str->length(); i++) {
+    switch (str->Get(i)) {
       case 'i':
         flags |= JSRegExp::IGNORE_CASE;
         break;
@@ -373,9 +307,10 @@
     // that is attached to the global RegExp object.  We will be returning
     // an array of these.
     Handle<FixedArray> array = Factory::NewFixedArray(kFirstCapture + 2);
+    SetLastCaptureCount(*array, 2);
+    // Ignore subject and input fields.
     SetCapture(*array, 0, value);
     SetCapture(*array, 1, end);
-    SetLastCaptureCount(*array, 2);
     Handle<JSArray> pair = Factory::NewJSArrayWithElements(array);
     SetElement(result, match_count, pair);
     match_count++;
@@ -421,7 +356,7 @@
   JSRegExp::Flags flags = re->GetFlags();
 
   Handle<String> pattern(re->Pattern());
-  if (!pattern->IsFlat(StringShape(*pattern))) {
+  if (!pattern->IsFlat()) {
     FlattenString(pattern);
   }
 
@@ -531,15 +466,9 @@
                                         Handle<JSArray> last_match_info) {
   ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
 
-  bool is_ascii = StringShape(*subject).IsAsciiRepresentation();
-  if (!EnsureCompiledIrregexp(regexp, is_ascii)) {
-    return Handle<Object>::null();
-  }
-
   // Prepare space for the return values.
-  Handle<FixedArray> re_data(FixedArray::cast(regexp->data()));
   int number_of_capture_registers =
-      (IrregexpNumberOfCaptures(*re_data) + 1) * 2;
+      (IrregexpNumberOfCaptures(FixedArray::cast(regexp->data())) + 1) * 2;
   OffsetsVector offsets(number_of_capture_registers);
 
   int previous_index = index;
@@ -552,13 +481,13 @@
   }
 #endif
 
-  if (!subject->IsFlat(StringShape(*subject))) {
+  if (!subject->IsFlat()) {
     FlattenString(subject);
   }
 
   last_match_info->EnsureSize(number_of_capture_registers + kLastMatchOverhead);
 
-  return IrregexpExecOnce(re_data,
+  return IrregexpExecOnce(regexp,
                           number_of_capture_registers,
                           last_match_info,
                           subject,
@@ -572,16 +501,10 @@
                                               Handle<String> subject,
                                               Handle<JSArray> last_match_info) {
   ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
-  Handle<FixedArray> irregexp(FixedArray::cast(regexp->data()));
-
-  bool is_ascii = StringShape(*subject).IsAsciiRepresentation();
-  if (!EnsureCompiledIrregexp(regexp, is_ascii)) {
-    return Handle<Object>::null();
-  }
 
   // Prepare space for the return values.
   int number_of_capture_registers =
-      (IrregexpNumberOfCaptures(*irregexp) + 1) * 2;
+      (IrregexpNumberOfCaptures(FixedArray::cast(regexp->data())) + 1) * 2;
   OffsetsVector offsets(number_of_capture_registers);
 
   int previous_index = 0;
@@ -590,7 +513,7 @@
   int result_length = 0;
   Handle<Object> matches;
 
-  if (!subject->IsFlat(StringShape(*subject))) {
+  if (!subject->IsFlat()) {
     FlattenString(subject);
   }
 
@@ -600,7 +523,6 @@
     if (previous_index > subject->length() || previous_index < 0) {
       // Per ECMA-262 15.10.6.2, if the previous index is greater than the
       // string length, there is no match.
-      matches = Factory::null_value();
       return result;
     } else {
 #ifdef DEBUG
@@ -611,7 +533,7 @@
       }
 #endif
       HandleScope scope;
-      matches = IrregexpExecOnce(irregexp,
+      matches = IrregexpExecOnce(regexp,
                                  number_of_capture_registers,
                                  last_match_info,
                                  subject,
@@ -628,22 +550,22 @@
         // Create an array that looks like the static last_match_info array
         // that is attached to the global RegExp object.  We will be returning
         // an array of these.
-        Handle<FixedArray> matches_array(JSArray::cast(*matches)->elements());
+        int match_length = kFirstCapture + number_of_capture_registers;
         Handle<JSArray> latest_match =
-            Factory::NewJSArray(kFirstCapture + number_of_capture_registers);
-        Handle<FixedArray> latest_match_array(latest_match->elements());
+            Factory::NewJSArray(match_length);
 
-        for (int i = 0; i < number_of_capture_registers; i++) {
-          SetCapture(*latest_match_array, i, GetCapture(*matches_array, i));
-        }
-        SetLastCaptureCount(*latest_match_array, number_of_capture_registers);
-
+        AssertNoAllocation no_allocation;
+        FixedArray* match_array = JSArray::cast(*matches)->elements();
+        match_array->CopyTo(0,
+                            latest_match->elements(),
+                            0,
+                            match_length);
         SetElement(result, result_length, latest_match);
         result_length++;
-        previous_index = GetCapture(*matches_array, 1);
-        if (GetCapture(*matches_array, 0) == previous_index)
+        previous_index = GetCapture(match_array, 1);
+        if (GetCapture(match_array, 0) == previous_index) {
           previous_index++;
-
+        }
       } else {
         ASSERT(matches->IsNull());
         return result;
@@ -653,94 +575,51 @@
 }
 
 
-Handle<Object> RegExpImpl::IrregexpExecOnce(Handle<FixedArray> regexp,
+Handle<Object> RegExpImpl::IrregexpExecOnce(Handle<JSRegExp> jsregexp,
                                             int number_of_capture_registers,
                                             Handle<JSArray> last_match_info,
                                             Handle<String> subject,
                                             int previous_index,
                                             int* offsets_vector,
                                             int offsets_vector_length) {
-  StringShape shape(*subject);
-  ASSERT(subject->IsFlat(shape));
-  bool is_ascii = shape.IsAsciiRepresentation();
+  ASSERT(subject->IsFlat());
   bool rc;
 
   Handle<String> original_subject = subject;
-  if (FLAG_regexp_native) {
-#ifndef ARM
-    Handle<Code> code(IrregexpNativeCode(*regexp, is_ascii));
-
-    // Character offsets into string.
-    int start_offset = previous_index;
-    int end_offset = subject->length(shape);
-
-    if (shape.IsCons()) {
-      subject = Handle<String>(ConsString::cast(*subject)->first());
-    } else if (shape.IsSliced()) {
-      SlicedString* slice = SlicedString::cast(*subject);
-      start_offset += slice->start();
-      end_offset += slice->start();
-      subject = Handle<String>(slice->buffer());
-    }
-
-    // String is now either Sequential or External
-    StringShape flatshape(*subject);
-    bool is_ascii = flatshape.IsAsciiRepresentation();
-    int char_size_shift = is_ascii ? 0 : 1;
-
+  Handle<FixedArray> regexp(FixedArray::cast(jsregexp->data()));
+  if (UseNativeRegexp()) {
+#ifdef ARM
+    UNREACHABLE();
+#else
     RegExpMacroAssemblerIA32::Result res;
-
-    if (flatshape.IsExternal()) {
-      const byte* address;
-      if (is_ascii) {
-        ExternalAsciiString* ext = ExternalAsciiString::cast(*subject);
-        address = reinterpret_cast<const byte*>(ext->resource()->data());
-      } else {
-        ExternalTwoByteString* ext = ExternalTwoByteString::cast(*subject);
-        address = reinterpret_cast<const byte*>(ext->resource()->data());
+    do {
+      bool is_ascii = StringShape(*subject).IsAsciiRepresentation();
+      if (!EnsureCompiledIrregexp(jsregexp, is_ascii)) {
+        return Handle<Object>::null();
       }
-      res = RegExpMacroAssemblerIA32::Execute(
-          *code,
-          const_cast<Address*>(&address),
-          start_offset << char_size_shift,
-          end_offset << char_size_shift,
-          offsets_vector,
-          previous_index == 0);
-    } else {  // Sequential string
-      ASSERT(StringShape(*subject).IsSequential());
-      Address char_address =
-          is_ascii ? SeqAsciiString::cast(*subject)->GetCharsAddress()
-                   : SeqTwoByteString::cast(*subject)->GetCharsAddress();
-      int byte_offset = char_address - reinterpret_cast<Address>(*subject);
-      res = RegExpMacroAssemblerIA32::Execute(
-          *code,
-          reinterpret_cast<Address*>(subject.location()),
-          byte_offset + (start_offset << char_size_shift),
-          byte_offset + (end_offset << char_size_shift),
-          offsets_vector,
-          previous_index == 0);
-    }
-
+      Handle<Code> code(RegExpImpl::IrregexpNativeCode(*regexp, is_ascii));
+      res = RegExpMacroAssemblerIA32::Match(code,
+                                            subject,
+                                            offsets_vector,
+                                            offsets_vector_length,
+                                            previous_index);
+      // If result is RETRY, the string have changed representation, and we
+      // must restart from scratch.
+    } while (res == RegExpMacroAssemblerIA32::RETRY);
     if (res == RegExpMacroAssemblerIA32::EXCEPTION) {
       ASSERT(Top::has_pending_exception());
       return Handle<Object>::null();
     }
-    rc = (res == RegExpMacroAssemblerIA32::SUCCESS);
+    ASSERT(res == RegExpMacroAssemblerIA32::SUCCESS
+        || res == RegExpMacroAssemblerIA32::FAILURE);
 
-    if (rc) {
-      // Capture values are relative to start_offset only.
-      for (int i = 0; i < offsets_vector_length; i++) {
-        if (offsets_vector[i] >= 0) {
-          offsets_vector[i] += previous_index;
-        }
-      }
-    }
-  } else {
-#else
-  // Unimplemented on ARM, fall through to bytecode.
-  }
-  {
+    rc = (res == RegExpMacroAssemblerIA32::SUCCESS);
 #endif
+  } else {
+    bool is_ascii = StringShape(*subject).IsAsciiRepresentation();
+    if (!EnsureCompiledIrregexp(jsregexp, is_ascii)) {
+      return Handle<Object>::null();
+    }
     for (int i = number_of_capture_registers - 1; i >= 0; i--) {
       offsets_vector[i] = -1;
     }
@@ -759,13 +638,13 @@
   FixedArray* array = last_match_info->elements();
   ASSERT(array->length() >= number_of_capture_registers + kLastMatchOverhead);
   // The captures come in (start, end+1) pairs.
-  for (int i = 0; i < number_of_capture_registers; i += 2) {
-    SetCapture(array, i, offsets_vector[i]);
-    SetCapture(array, i + 1, offsets_vector[i + 1]);
-  }
   SetLastCaptureCount(array, number_of_capture_registers);
   SetLastSubject(array, *original_subject);
   SetLastInput(array, *original_subject);
+  for (int i = 0; i < number_of_capture_registers; i+=2) {
+    SetCapture(array, i, offsets_vector[i]);
+    SetCapture(array, i + 1, offsets_vector[i + 1]);
+  }
   return last_match_info;
 }
 
@@ -4716,9 +4595,9 @@
 
   NodeInfo info = *node->info();
 
-  if (FLAG_regexp_native) {
+  if (RegExpImpl::UseNativeRegexp()) {
 #ifdef ARM
-    // Unimplemented, fall-through to bytecode implementation.
+    UNREACHABLE();
 #else  // IA32
     RegExpMacroAssemblerIA32::Mode mode;
     if (is_ascii) {
diff --git a/src/jsregexp.h b/src/jsregexp.h
index bb28f06..c03879e 100644
--- a/src/jsregexp.h
+++ b/src/jsregexp.h
@@ -36,6 +36,13 @@
 
 class RegExpImpl {
  public:
+  static inline bool UseNativeRegexp() {
+#ifdef ARM
+    return false;
+#else
+    return FLAG_regexp_native;
+#endif
+  }
   // Creates a regular expression literal in the old space.
   // This function calls the garbage collector if necessary.
   static Handle<Object> CreateRegExpLiteral(Handle<JSFunction> constructor,
@@ -101,22 +108,14 @@
                                            Handle<String> subject,
                                            Handle<JSArray> lastMatchInfo);
 
-  static void NewSpaceCollectionPrologue();
-  static void OldSpaceCollectionPrologue();
-
-  // Converts a source string to a 16 bit flat string.  The string
-  // will be either sequential or it will be a SlicedString backed
-  // by a flat string.
-  static Handle<String> StringToTwoByte(Handle<String> pattern);
-  static Handle<String> CachedStringToTwoByte(Handle<String> pattern);
-
   // Offsets in the lastMatchInfo array.
   static const int kLastCaptureCount = 0;
   static const int kLastSubject = 1;
   static const int kLastInput = 2;
-  static const int kFirstCapture = 1;
+  static const int kFirstCapture = 3;
   static const int kLastMatchOverhead = 3;
 
+  // Used to access the lastMatchInfo array.
   static int GetCapture(FixedArray* array, int index) {
     return Smi::cast(array->get(index + kFirstCapture))->value();
   }
@@ -126,25 +125,22 @@
   }
 
   static void SetLastSubject(FixedArray* array, String* to) {
-    int capture_count = GetLastCaptureCount(array);
-    array->set(capture_count + kLastSubject, to);
+    array->set(kLastSubject, to);
   }
 
   static void SetLastInput(FixedArray* array, String* to) {
-    int capture_count = GetLastCaptureCount(array);
-    array->set(capture_count + kLastInput, to);
+    array->set(kLastInput, to);
   }
 
   static void SetCapture(FixedArray* array, int index, int to) {
     array->set(index + kFirstCapture, Smi::FromInt(to));
   }
 
- private:
-  static String* last_ascii_string_;
-  static String* two_byte_cached_string_;
+  static int GetLastCaptureCount(FixedArray* array) {
+    return Smi::cast(array->get(kLastCaptureCount))->value();
+  }
 
-  static bool EnsureCompiledIrregexp(Handle<JSRegExp> re, bool is_ascii);
-
+  // For acting on the JSRegExp data FixedArray.
   static int IrregexpMaxRegisterCount(FixedArray* re);
   static void SetIrregexpMaxRegisterCount(FixedArray* re, int value);
   static int IrregexpNumberOfCaptures(FixedArray* re);
@@ -152,10 +148,17 @@
   static ByteArray* IrregexpByteCode(FixedArray* re, bool is_ascii);
   static Code* IrregexpNativeCode(FixedArray* re, bool is_ascii);
 
+ private:
+  static String* last_ascii_string_;
+  static String* two_byte_cached_string_;
+
+  static bool EnsureCompiledIrregexp(Handle<JSRegExp> re, bool is_ascii);
+
+
   // On a successful match, the result is a JSArray containing
   // captured positions. On a failure, the result is the null value.
   // Returns an empty handle in case of an exception.
-  static Handle<Object> IrregexpExecOnce(Handle<FixedArray> regexp,
+  static Handle<Object> IrregexpExecOnce(Handle<JSRegExp> jsregexp,
                                          int num_captures,
                                          Handle<JSArray> lastMatchInfo,
                                          Handle<String> subject16,
@@ -171,10 +174,6 @@
                               int character_position,
                               int utf8_position);
 
-  // Used to access the lastMatchInfo array.
-  static int GetLastCaptureCount(FixedArray* array) {
-    return Smi::cast(array->get(kLastCaptureCount))->value();
-  }
   // A one element cache of the last utf8_subject string and its length.  The
   // subject JS String object is cached in the heap.  We also cache a
   // translation between position and utf8 position.
diff --git a/src/jump-target-arm.cc b/src/jump-target-arm.cc
index b7aad93..41b80e2 100644
--- a/src/jump-target-arm.cc
+++ b/src/jump-target-arm.cc
@@ -27,8 +27,8 @@
 
 #include "v8.h"
 
-#include "codegen.h"
-#include "jump-target.h"
+#include "codegen-inl.h"
+#include "register-allocator-inl.h"
 
 namespace v8 { namespace internal {
 
@@ -70,40 +70,58 @@
   ASSERT(cgen_->has_valid_frame());
 
   if (is_bound()) {
-    // Backward branch.  We have an expected frame to merge to on the
-    // backward edge.  We negate the condition and emit the merge code
-    // here.
-    //
-    // TODO(210): we should try to avoid negating the condition in the
-    // case where there is no merge code to emit.  Otherwise, we emit
-    // a branch around an unconditional jump.
     ASSERT(direction_ == BIDIRECTIONAL);
+    // Backward branch.  We have an expected frame to merge to on the
+    // backward edge.
+
+    // Swap the current frame for a copy (we do the swapping to get
+    // the off-frame registers off the fall through) to use for the
+    // branch.
+    VirtualFrame* fall_through_frame = cgen_->frame();
+    VirtualFrame* branch_frame = new VirtualFrame(fall_through_frame);
+    RegisterFile non_frame_registers = RegisterAllocator::Reserved();
+    cgen_->SetFrame(branch_frame, &non_frame_registers);
+
+    // Check if we can avoid merge code.
+    cgen_->frame()->PrepareMergeTo(entry_frame_);
+    if (cgen_->frame()->Equals(entry_frame_)) {
+      // Branch right in to the block.
+      cgen_->DeleteFrame();
+      __ b(cc, &entry_label_);
+      cgen_->SetFrame(fall_through_frame, &non_frame_registers);
+      return;
+    }
+
+    // Check if we can reuse existing merge code.
+    for (int i = 0; i < reaching_frames_.length(); i++) {
+      if (reaching_frames_[i] != NULL &&
+          cgen_->frame()->Equals(reaching_frames_[i])) {
+        // Branch to the merge code.
+        cgen_->DeleteFrame();
+        __ b(cc, &merge_labels_[i]);
+        cgen_->SetFrame(fall_through_frame, &non_frame_registers);
+        return;
+      }
+    }
+
+    // To emit the merge code here, we negate the condition and branch
+    // around the merge code on the fall through path.
     Label original_fall_through;
     __ b(NegateCondition(cc), &original_fall_through);
-    // Swap the current frame for a copy of it, saving non-frame
-    // register reference counts and invalidating all non-frame register
-    // references except the reserved ones on the backward edge.
-    VirtualFrame* original_frame = cgen_->frame();
-    VirtualFrame* working_frame = new VirtualFrame(original_frame);
-    RegisterFile non_frame_registers = RegisterAllocator::Reserved();
-    cgen_->SetFrame(working_frame, &non_frame_registers);
-
-    working_frame->MergeTo(entry_frame_);
+    cgen_->frame()->MergeTo(entry_frame_);
     cgen_->DeleteFrame();
-    __ jmp(&entry_label_);
-
-    // Restore the frame and its associated non-frame registers.
-    cgen_->SetFrame(original_frame, &non_frame_registers);
+    __ b(&entry_label_);
+    cgen_->SetFrame(fall_through_frame, &non_frame_registers);
     __ bind(&original_fall_through);
+
   } else {
     // Forward branch.  A copy of the current frame is added to the end
     // of the list of frames reaching the target block and a branch to
     // the merge code is emitted.
     AddReachingFrame(new VirtualFrame(cgen_->frame()));
     __ b(cc, &merge_labels_.last());
+    is_linked_ = true;
   }
-
-  is_linked_ = !is_bound_;
 }
 
 
@@ -138,79 +156,130 @@
   // block.
   ASSERT(!cgen_->has_valid_frame() || cgen_->HasValidEntryRegisters());
 
+  if (direction_ == FORWARD_ONLY) {
+    // A simple case: no forward jumps and no possible backward jumps.
+    if (!is_linked()) {
+      // The stack pointer can be floating above the top of the
+      // virtual frame before the bind.  Afterward, it should not.
+      ASSERT(cgen_->has_valid_frame());
+      VirtualFrame* frame = cgen_->frame();
+      int difference =
+          frame->stack_pointer_ - (frame->elements_.length() - 1);
+      if (difference > 0) {
+        frame->stack_pointer_ -= difference;
+        __ add(sp, sp, Operand(difference * kPointerSize));
+      }
+
+      is_bound_ = true;
+      return;
+    }
+
+    // Another simple case: no fall through, a single forward jump,
+    // and no possible backward jumps.
+    if (!cgen_->has_valid_frame() && reaching_frames_.length() == 1) {
+      // Pick up the only reaching frame, take ownership of it, and
+      // use it for the block about to be emitted.
+      VirtualFrame* frame = reaching_frames_[0];
+      RegisterFile reserved = RegisterAllocator::Reserved();
+      cgen_->SetFrame(frame, &reserved);
+      reaching_frames_[0] = NULL;
+      __ bind(&merge_labels_[0]);
+
+      // The stack pointer can be floating above the top of the
+      // virtual frame before the bind.  Afterward, it should not.
+      int difference =
+          frame->stack_pointer_ - (frame->elements_.length() - 1);
+      if (difference > 0) {
+        frame->stack_pointer_ -= difference;
+        __ add(sp, sp, Operand(difference * kPointerSize));
+      }
+
+      is_linked_ = false;
+      is_bound_ = true;
+      return;
+    }
+  }
+
+  // If there is a current frame, record it as the fall-through.  It
+  // is owned by the reaching frames for now.
+  bool had_fall_through = false;
+  if (cgen_->has_valid_frame()) {
+    had_fall_through = true;
+    AddReachingFrame(cgen_->frame());
+    RegisterFile empty;
+    cgen_->SetFrame(NULL, &empty);
+  }
+
   // Compute the frame to use for entry to the block.
   ComputeEntryFrame(mergable_elements);
 
+  // Some moves required to merge to an expected frame require purely
+  // frame state changes, and do not require any code generation.
+  // Perform those first to increase the possibility of finding equal
+  // frames below.
+  for (int i = 0; i < reaching_frames_.length(); i++) {
+    if (reaching_frames_[i] != NULL) {
+      reaching_frames_[i]->PrepareMergeTo(entry_frame_);
+    }
+  }
+
   if (is_linked()) {
     // There were forward jumps.  Handle merging the reaching frames
     // and possible fall through to the entry frame.
 
-    // Some moves required to merge to an expected frame require
-    // purely frame state changes, and do not require any code
-    // generation.  Perform those first to increase the possibility of
-    // finding equal frames below.
-    if (cgen_->has_valid_frame()) {
-      cgen_->frame()->PrepareMergeTo(entry_frame_);
-    }
-    for (int i = 0; i < reaching_frames_.length(); i++) {
-      reaching_frames_[i]->PrepareMergeTo(entry_frame_);
-    }
-
-    // If there is a fall through to the jump target and it needs
-    // merge code, process it first.
-    if (cgen_->has_valid_frame() && !cgen_->frame()->Equals(entry_frame_)) {
-      // Loop over all the reaching frames, looking for any that can
-      // share merge code with this one.
-      for (int i = 0; i < reaching_frames_.length(); i++) {
-        if (cgen_->frame()->Equals(reaching_frames_[i])) {
-          // Set the reaching frames element to null to avoid
-          // processing it later, and then bind its entry label.
-          delete reaching_frames_[i];
-          reaching_frames_[i] = NULL;
-          __ bind(&merge_labels_[i]);
-        }
-      }
-
-      // Emit the merge code.
-      cgen_->frame()->MergeTo(entry_frame_);
-    }
-
     // Loop over the (non-null) reaching frames and process any that
-    // need merge code.
-    for (int i = 0; i < reaching_frames_.length(); i++) {
+    // need merge code.  Iterate backwards through the list to handle
+    // the fall-through frame first.  Set frames that will be
+    // processed after 'i' to NULL if we want to avoid processing
+    // them.
+    for (int i = reaching_frames_.length() - 1; i >= 0; i--) {
       VirtualFrame* frame = reaching_frames_[i];
-      if (frame != NULL && !frame->Equals(entry_frame_)) {
-        // Set the reaching frames element to null to avoid processing
-        // it later.  Do not delete it as it is needed for merging.
-        reaching_frames_[i] = NULL;
 
-        // If the code generator has a current frame (a fall-through
-        // or a previously merged frame), insert a jump around the
-        // merge code we are about to generate.
-        if (cgen_->has_valid_frame()) {
-          cgen_->DeleteFrame();
-          __ jmp(&entry_label_);
-        }
-
-        // Set the frame to merge as the code generator's current
-        // frame and bind its merge label.
-        RegisterFile reserved_registers = RegisterAllocator::Reserved();
-        cgen_->SetFrame(frame, &reserved_registers);
-        __ bind(&merge_labels_[i]);
-
-        // Loop over the remaining (non-null) reaching frames, looking
-        // for any that can share merge code with this one.
-        for (int j = i + 1; j < reaching_frames_.length(); j++) {
-          VirtualFrame* other = reaching_frames_[j];
-          if (other != NULL && frame->Equals(other)) {
-            delete other;
-            reaching_frames_[j] = NULL;
-            __ bind(&merge_labels_[j]);
+      if (frame != NULL) {
+        // Does the frame (probably) need merge code?
+        if (!frame->Equals(entry_frame_)) {
+          // We could have a valid frame as the fall through to the
+          // binding site or as the fall through from a previous merge
+          // code block.  Jump around the code we are about to
+          // generate.
+          if (cgen_->has_valid_frame()) {
+            cgen_->DeleteFrame();
+            __ b(&entry_label_);
           }
-        }
+          // Pick up the frame for this block.  Assume ownership if
+          // there cannot be backward jumps.
+          RegisterFile reserved = RegisterAllocator::Reserved();
+          if (direction_ == BIDIRECTIONAL) {
+            cgen_->SetFrame(new VirtualFrame(frame), &reserved);
+          } else {
+            cgen_->SetFrame(frame, &reserved);
+            reaching_frames_[i] = NULL;
+          }
+          __ bind(&merge_labels_[i]);
 
-        // Emit the merge code.
-        cgen_->frame()->MergeTo(entry_frame_);
+          // Loop over the remaining (non-null) reaching frames,
+          // looking for any that can share merge code with this one.
+          for (int j = 0; j < i; j++) {
+            VirtualFrame* other = reaching_frames_[j];
+            if (other != NULL && other->Equals(cgen_->frame())) {
+              // Set the reaching frame element to null to avoid
+              // processing it later, and then bind its entry label.
+              delete other;
+              reaching_frames_[j] = NULL;
+              __ bind(&merge_labels_[j]);
+            }
+          }
+
+          // Emit the merge code.
+          cgen_->frame()->MergeTo(entry_frame_);
+        } else if (i == reaching_frames_.length() - 1 && had_fall_through) {
+          // If this is the fall through, and it didn't need merge
+          // code, we need to pick up the frame so we can jump around
+          // subsequent merge blocks if necessary.
+          RegisterFile reserved = RegisterAllocator::Reserved();
+          cgen_->SetFrame(frame, &reserved);
+          reaching_frames_[i] = NULL;
+        }
       }
     }
 
@@ -227,23 +296,31 @@
     __ bind(&entry_label_);
 
     // There may be unprocessed reaching frames that did not need
-    // merge code.  Bind their merge labels to be the same as the
-    // entry label.
+    // merge code.  They will have unbound merge labels.  Bind their
+    // merge labels to be the same as the entry label and deallocate
+    // them.
     for (int i = 0; i < reaching_frames_.length(); i++) {
-      if (reaching_frames_[i] != NULL) {
+      if (!merge_labels_[i].is_bound()) {
         delete reaching_frames_[i];
+        reaching_frames_[i] = NULL;
         __ bind(&merge_labels_[i]);
       }
     }
 
-    // All the reaching frames except the one that is the current
-    // frame (if it is one of the reaching frames) have been deleted.
-    reaching_frames_.Clear();
-    merge_labels_.Clear();
-
+    // There are non-NULL reaching frames with bound labels for each
+    // merge block, but only on backward targets.
   } else {
-    // There were no forward jumps.  The current frame is merged to
-    // the entry frame.
+    // There were no forward jumps.  There must be a current frame and
+    // this must be a bidirectional target.
+    ASSERT(reaching_frames_.length() == 1);
+    ASSERT(reaching_frames_[0] != NULL);
+    ASSERT(direction_ == BIDIRECTIONAL);
+
+    // Use a copy of the reaching frame so the original can be saved
+    // for possible reuse as a backward merge block.
+    RegisterFile reserved = RegisterAllocator::Reserved();
+    cgen_->SetFrame(new VirtualFrame(reaching_frames_[0]), &reserved);
+    __ bind(&merge_labels_[0]);
     cgen_->frame()->MergeTo(entry_frame_);
     __ bind(&entry_label_);
   }
diff --git a/src/jump-target-ia32.cc b/src/jump-target-ia32.cc
index 12eb26f..d2d35ca 100644
--- a/src/jump-target-ia32.cc
+++ b/src/jump-target-ia32.cc
@@ -27,8 +27,8 @@
 
 #include "v8.h"
 
-#include "codegen.h"
-#include "jump-target.h"
+#include "codegen-inl.h"
+#include "register-allocator-inl.h"
 
 namespace v8 { namespace internal {
 
@@ -70,40 +70,58 @@
   ASSERT(cgen_->has_valid_frame());
 
   if (is_bound()) {
-    // Backward branch.  We have an expected frame to merge to on the
-    // backward edge.  We negate the condition and emit the merge code
-    // here.
-    //
-    // TODO(210): we should try to avoid negating the condition in the
-    // case where there is no merge code to emit.  Otherwise, we emit
-    // a branch around an unconditional jump.
     ASSERT(direction_ == BIDIRECTIONAL);
+    // Backward branch.  We have an expected frame to merge to on the
+    // backward edge.
+
+    // Swap the current frame for a copy (we do the swapping to get
+    // the off-frame registers off the fall through) to use for the
+    // branch.
+    VirtualFrame* fall_through_frame = cgen_->frame();
+    VirtualFrame* branch_frame = new VirtualFrame(fall_through_frame);
+    RegisterFile non_frame_registers = RegisterAllocator::Reserved();
+    cgen_->SetFrame(branch_frame, &non_frame_registers);
+
+    // Check if we can avoid merge code.
+    cgen_->frame()->PrepareMergeTo(entry_frame_);
+    if (cgen_->frame()->Equals(entry_frame_)) {
+      // Branch right in to the block.
+      cgen_->DeleteFrame();
+      __ j(cc, &entry_label_, hint);
+      cgen_->SetFrame(fall_through_frame, &non_frame_registers);
+      return;
+    }
+
+    // Check if we can reuse existing merge code.
+    for (int i = 0; i < reaching_frames_.length(); i++) {
+      if (reaching_frames_[i] != NULL &&
+          cgen_->frame()->Equals(reaching_frames_[i])) {
+        // Branch to the merge code.
+        cgen_->DeleteFrame();
+        __ j(cc, &merge_labels_[i], hint);
+        cgen_->SetFrame(fall_through_frame, &non_frame_registers);
+        return;
+      }
+    }
+
+    // To emit the merge code here, we negate the condition and branch
+    // around the merge code on the fall through path.
     Label original_fall_through;
     __ j(NegateCondition(cc), &original_fall_through, NegateHint(hint));
-    // Swap the current frame for a copy of it, saving non-frame
-    // register reference counts and invalidating all non-frame register
-    // references except the reserved ones on the backward edge.
-    VirtualFrame* original_frame = cgen_->frame();
-    VirtualFrame* working_frame = new VirtualFrame(original_frame);
-    RegisterFile non_frame_registers = RegisterAllocator::Reserved();
-    cgen_->SetFrame(working_frame, &non_frame_registers);
-
-    working_frame->MergeTo(entry_frame_);
+    cgen_->frame()->MergeTo(entry_frame_);
     cgen_->DeleteFrame();
     __ jmp(&entry_label_);
-
-    // Restore the frame and its associated non-frame registers.
-    cgen_->SetFrame(original_frame, &non_frame_registers);
+    cgen_->SetFrame(fall_through_frame, &non_frame_registers);
     __ bind(&original_fall_through);
+
   } else {
     // Forward branch.  A copy of the current frame is added to the end
     // of the list of frames reaching the target block and a branch to
     // the merge code is emitted.
     AddReachingFrame(new VirtualFrame(cgen_->frame()));
     __ j(cc, &merge_labels_.last(), hint);
+    is_linked_ = true;
   }
-
-  is_linked_ = !is_bound_;
 }
 
 
@@ -138,79 +156,130 @@
   // block.
   ASSERT(!cgen_->has_valid_frame() || cgen_->HasValidEntryRegisters());
 
+  if (direction_ == FORWARD_ONLY) {
+    // A simple case: no forward jumps and no possible backward jumps.
+    if (!is_linked()) {
+      // The stack pointer can be floating above the top of the
+      // virtual frame before the bind.  Afterward, it should not.
+      ASSERT(cgen_->has_valid_frame());
+      VirtualFrame* frame = cgen_->frame();
+      int difference =
+          frame->stack_pointer_ - (frame->elements_.length() - 1);
+      if (difference > 0) {
+        frame->stack_pointer_ -= difference;
+        __ add(Operand(esp), Immediate(difference * kPointerSize));
+      }
+
+      is_bound_ = true;
+      return;
+    }
+
+    // Another simple case: no fall through, a single forward jump,
+    // and no possible backward jumps.
+    if (!cgen_->has_valid_frame() && reaching_frames_.length() == 1) {
+      // Pick up the only reaching frame, take ownership of it, and
+      // use it for the block about to be emitted.
+      VirtualFrame* frame = reaching_frames_[0];
+      RegisterFile reserved = RegisterAllocator::Reserved();
+      cgen_->SetFrame(frame, &reserved);
+      reaching_frames_[0] = NULL;
+      __ bind(&merge_labels_[0]);
+
+      // The stack pointer can be floating above the top of the
+      // virtual frame before the bind.  Afterward, it should not.
+      int difference =
+          frame->stack_pointer_ - (frame->elements_.length() - 1);
+      if (difference > 0) {
+        frame->stack_pointer_ -= difference;
+        __ add(Operand(esp), Immediate(difference * kPointerSize));
+      }
+
+      is_linked_ = false;
+      is_bound_ = true;
+      return;
+    }
+  }
+
+  // If there is a current frame, record it as the fall-through.  It
+  // is owned by the reaching frames for now.
+  bool had_fall_through = false;
+  if (cgen_->has_valid_frame()) {
+    had_fall_through = true;
+    AddReachingFrame(cgen_->frame());
+    RegisterFile empty;
+    cgen_->SetFrame(NULL, &empty);
+  }
+
   // Compute the frame to use for entry to the block.
   ComputeEntryFrame(mergable_elements);
 
-  if (is_linked()) {
-    // There were forward jumps.  Handle merging the reaching frames
-    // and possible fall through to the entry frame.
-
-    // Some moves required to merge to an expected frame require
-    // purely frame state changes, and do not require any code
-    // generation.  Perform those first to increase the possibility of
-    // finding equal frames below.
-    if (cgen_->has_valid_frame()) {
-      cgen_->frame()->PrepareMergeTo(entry_frame_);
-    }
-    for (int i = 0; i < reaching_frames_.length(); i++) {
+  // Some moves required to merge to an expected frame require purely
+  // frame state changes, and do not require any code generation.
+  // Perform those first to increase the possibility of finding equal
+  // frames below.
+  for (int i = 0; i < reaching_frames_.length(); i++) {
+    if (reaching_frames_[i] != NULL) {
       reaching_frames_[i]->PrepareMergeTo(entry_frame_);
     }
+  }
 
-    // If there is a fall through to the jump target and it needs
-    // merge code, process it first.
-    if (cgen_->has_valid_frame() && !cgen_->frame()->Equals(entry_frame_)) {
-      // Loop over all the reaching frames, looking for any that can
-      // share merge code with this one.
-      for (int i = 0; i < reaching_frames_.length(); i++) {
-        if (cgen_->frame()->Equals(reaching_frames_[i])) {
-          // Set the reaching frames element to null to avoid
-          // processing it later, and then bind its entry label.
-          delete reaching_frames_[i];
-          reaching_frames_[i] = NULL;
-          __ bind(&merge_labels_[i]);
-        }
-      }
-
-      // Emit the merge code.
-      cgen_->frame()->MergeTo(entry_frame_);
-    }
+  if (is_linked()) {
+    // There were forward jumps.  Handle merging the reaching frames
+    // to the entry frame.
 
     // Loop over the (non-null) reaching frames and process any that
-    // need merge code.
-    for (int i = 0; i < reaching_frames_.length(); i++) {
+    // need merge code.  Iterate backwards through the list to handle
+    // the fall-through frame first.  Set frames that will be
+    // processed after 'i' to NULL if we want to avoid processing
+    // them.
+    for (int i = reaching_frames_.length() - 1; i >= 0; i--) {
       VirtualFrame* frame = reaching_frames_[i];
-      if (frame != NULL && !frame->Equals(entry_frame_)) {
-        // Set the reaching frames element to null to avoid processing
-        // it later.  Do not delete it as it is needed for merging.
-        reaching_frames_[i] = NULL;
 
-        // If the code generator has a current frame (a fall-through
-        // or a previously merged frame), insert a jump around the
-        // merge code we are about to generate.
-        if (cgen_->has_valid_frame()) {
-          cgen_->DeleteFrame();
-          __ jmp(&entry_label_);
-        }
-
-        // Set the frame to merge as the code generator's current
-        // frame and bind its merge label.
-        RegisterFile reserved_registers = RegisterAllocator::Reserved();
-        cgen_->SetFrame(frame, &reserved_registers);
-        __ bind(&merge_labels_[i]);
-
-        // Loop over the remaining (non-null) reaching frames, looking
-        // for any that can share merge code with this one.
-        for (int j = i + 1; j < reaching_frames_.length(); j++) {
-          VirtualFrame* other = reaching_frames_[j];
-          if (other != NULL && frame->Equals(other)) {
-            delete other;
-            reaching_frames_[j] = NULL;
-            __ bind(&merge_labels_[j]);
+      if (frame != NULL) {
+        // Does the frame (probably) need merge code?
+        if (!frame->Equals(entry_frame_)) {
+          // We could have a valid frame as the fall through to the
+          // binding site or as the fall through from a previous merge
+          // code block.  Jump around the code we are about to
+          // generate.
+          if (cgen_->has_valid_frame()) {
+            cgen_->DeleteFrame();
+            __ jmp(&entry_label_);
           }
-        }
+          // Pick up the frame for this block.  Assume ownership if
+          // there cannot be backward jumps.
+          RegisterFile reserved = RegisterAllocator::Reserved();
+          if (direction_ == BIDIRECTIONAL) {
+            cgen_->SetFrame(new VirtualFrame(frame), &reserved);
+          } else {
+            cgen_->SetFrame(frame, &reserved);
+            reaching_frames_[i] = NULL;
+          }
+          __ bind(&merge_labels_[i]);
 
-        // Emit the merge code.
-        cgen_->frame()->MergeTo(entry_frame_);
+          // Loop over the remaining (non-null) reaching frames,
+          // looking for any that can share merge code with this one.
+          for (int j = 0; j < i; j++) {
+            VirtualFrame* other = reaching_frames_[j];
+            if (other != NULL && other->Equals(cgen_->frame())) {
+              // Set the reaching frame element to null to avoid
+              // processing it later, and then bind its entry label.
+              delete other;
+              reaching_frames_[j] = NULL;
+              __ bind(&merge_labels_[j]);
+            }
+          }
+
+          // Emit the merge code.
+          cgen_->frame()->MergeTo(entry_frame_);
+        } else if (i == reaching_frames_.length() - 1 && had_fall_through) {
+          // If this is the fall through frame, and it didn't need
+          // merge code, we need to pick up the frame so we can jump
+          // around subsequent merge blocks if necessary.
+          RegisterFile reserved = RegisterAllocator::Reserved();
+          cgen_->SetFrame(frame, &reserved);
+          reaching_frames_[i] = NULL;
+        }
       }
     }
 
@@ -227,23 +296,31 @@
     __ bind(&entry_label_);
 
     // There may be unprocessed reaching frames that did not need
-    // merge code.  Bind their merge labels to be the same as the
-    // entry label.
+    // merge code.  They will have unbound merge labels.  Bind their
+    // merge labels to be the same as the entry label and deallocate
+    // them.
     for (int i = 0; i < reaching_frames_.length(); i++) {
-      if (reaching_frames_[i] != NULL) {
+      if (!merge_labels_[i].is_bound()) {
         delete reaching_frames_[i];
+        reaching_frames_[i] = NULL;
         __ bind(&merge_labels_[i]);
       }
     }
 
-    // All the reaching frames except the one that is the current
-    // frame (if it is one of the reaching frames) have been deleted.
-    reaching_frames_.Clear();
-    merge_labels_.Clear();
-
+    // There are non-NULL reaching frames with bound labels for each
+    // merge block, but only on backward targets.
   } else {
-    // There were no forward jumps.  The current frame is merged to
-    // the entry frame.
+    // There were no forward jumps.  There must be a current frame and
+    // this must be a bidirectional target.
+    ASSERT(reaching_frames_.length() == 1);
+    ASSERT(reaching_frames_[0] != NULL);
+    ASSERT(direction_ == BIDIRECTIONAL);
+
+    // Use a copy of the reaching frame so the original can be saved
+    // for possible reuse as a backward merge block.
+    RegisterFile reserved = RegisterAllocator::Reserved();
+    cgen_->SetFrame(new VirtualFrame(reaching_frames_[0]), &reserved);
+    __ bind(&merge_labels_[0]);
     cgen_->frame()->MergeTo(entry_frame_);
     __ bind(&entry_label_);
   }
diff --git a/src/jump-target.cc b/src/jump-target.cc
index cdfdee9..24f3965 100644
--- a/src/jump-target.cc
+++ b/src/jump-target.cc
@@ -27,8 +27,8 @@
 
 #include "v8.h"
 
-#include "codegen.h"
-#include "jump-target.h"
+#include "codegen-inl.h"
+#include "register-allocator-inl.h"
 
 namespace v8 { namespace internal {
 
@@ -78,7 +78,6 @@
     delete reaching_frames_[i];
   }
   delete entry_frame_;
-
   Reset();
 }
 
@@ -144,19 +143,12 @@
 
 
 void JumpTarget::ComputeEntryFrame(int mergable_elements) {
-  // Given: a collection of frames reaching by forward CFG edges
-  // (including the code generator's current frame) and the
-  // directionality of the block.  Compute: an entry frame for the
+  // Given: a collection of frames reaching by forward CFG edges and
+  // the directionality of the block.  Compute: an entry frame for the
   // block.
 
-  // Choose an initial frame, either the code generator's current
-  // frame if there is one, or the first reaching frame if not.
-  VirtualFrame* initial_frame = cgen_->frame();
-  int start_index = 0;  // Begin iteration with the 1st reaching frame.
-  if (initial_frame == NULL) {
-    initial_frame = reaching_frames_[0];
-    start_index = 1;  // Begin iteration with the 2nd reaching frame.
-  }
+  // Choose an initial frame.
+  VirtualFrame* initial_frame = reaching_frames_[0];
 
   // A list of pointers to frame elements in the entry frame.  NULL
   // indicates that the element has not yet been determined.
@@ -186,9 +178,9 @@
   }
 
   // Compute elements based on the other reaching frames.
-  if (start_index < reaching_frames_.length()) {
+  if (reaching_frames_.length() > 1) {
     for (int i = 0; i < length; i++) {
-      for (int j = start_index; j < reaching_frames_.length(); j++) {
+      for (int j = 1; j < reaching_frames_.length(); j++) {
         FrameElement* element = elements[i];
 
         // Element computation is monotonic: new information will not
@@ -227,12 +219,11 @@
       // If the value is synced on all frames, put it in memory.  This
       // costs nothing at the merge code but will incur a
       // memory-to-register move when the value is needed later.
-      bool is_synced = initial_frame->elements_[i].is_synced();
-      int j = start_index;
-      while (is_synced && j < reaching_frames_.length()) {
+      bool is_synced = true;
+      for (int j = 0; is_synced && j < reaching_frames_.length(); j++) {
         is_synced = reaching_frames_[j]->elements_[i].is_synced();
-        j++;
       }
+
       // There is nothing to be done if the elements are all synced.
       // It is already recorded as a memory element.
       if (is_synced) continue;
@@ -243,17 +234,8 @@
       int max_count = kMinInt;
       int best_reg_code = no_reg.code_;
 
-      // Consider the initial frame.
-      FrameElement element = initial_frame->elements_[i];
-      if (element.is_register() &&
-          !frame_registers.is_used(element.reg())) {
-        candidate_registers.Use(element.reg());
-        max_count = 1;
-        best_reg_code = element.reg().code();
-      }
-      // Consider the other frames.
-      for (int j = start_index; j < reaching_frames_.length(); j++) {
-        element = reaching_frames_[j]->elements_[i];
+      for (int j = 0; j < reaching_frames_.length(); j++) {
+        FrameElement element = reaching_frames_[j]->elements_[i];
         if (element.is_register() &&
             !frame_registers.is_used(element.reg())) {
           candidate_registers.Use(element.reg());
@@ -288,6 +270,16 @@
     }
   }
 
+  // Set the copied flags in the frame to be exact.  This assumes that
+  // the backing store of copies is always lower in the frame.
+  for (int i = 0; i < length; i++) {
+    entry_frame_->elements_[i].clear_copied();
+    if (entry_frame_->elements_[i].is_copy()) {
+      int index = entry_frame_->elements_[i].index();
+      entry_frame_->elements_[index].set_copied();
+    }
+  }
+
   // Fill in the other fields of the entry frame.
   entry_frame_->local_count_ = initial_frame->local_count_;
   entry_frame_->frame_pointer_ = initial_frame->frame_pointer_;
@@ -590,16 +582,18 @@
 #ifdef DEBUG
   ASSERT(mergable_elements == kAllElements);
   ASSERT(cgen_ != NULL);
+  // All the forward-reaching frames should have been adjusted at the
+  // jumps to this target.
   for (int i = 0; i < reaching_frames_.length(); i++) {
-    ASSERT(reaching_frames_[i]->height() == expected_height_);
+    ASSERT(reaching_frames_[i] == NULL ||
+           reaching_frames_[i]->height() == expected_height_);
   }
 #endif
-
-  // This is a break target so drop leftover statement state from the
-  // frame before merging.
+  // This is a break target so we drop leftover statement state from
+  // the frame before merging, even on the fall through.  This is
+  // because we can bind the return target with state on the frame.
   if (cgen_->has_valid_frame()) {
-    int count = cgen_->frame()->height() - expected_height_;
-    cgen_->frame()->ForgetElements(count);
+    cgen_->frame()->ForgetElements(cgen_->frame()->height() - expected_height_);
   }
   JumpTarget::Bind(mergable_elements);
 }
diff --git a/src/jump-target.h b/src/jump-target.h
index bf4fc99..3a57302 100644
--- a/src/jump-target.h
+++ b/src/jump-target.h
@@ -28,10 +28,14 @@
 #ifndef V8_JUMP_TARGET_H_
 #define V8_JUMP_TARGET_H_
 
-#include "virtual-frame.h"
-
 namespace v8 { namespace internal {
 
+// Forward declarations.
+class FrameElement;
+class Result;
+class VirtualFrame;
+
+
 // -------------------------------------------------------------------------
 // Jump targets
 //
@@ -93,8 +97,6 @@
     entry_frame_ = frame;
   }
 
-  void make_bidirectional() { direction_ = BIDIRECTIONAL; }
-
   // Predicates testing the state of the encapsulated label.
   bool is_bound() const { return is_bound_; }
   bool is_linked() const { return is_linked_; }
diff --git a/src/log.cc b/src/log.cc
index 805bb51..5919827 100644
--- a/src/log.cc
+++ b/src/log.cc
@@ -142,28 +142,17 @@
     return;
   }
 
-  // If c_entry_fp is available, this means that we are inside a C++
-  // function and sample->fp value isn't reliable due to FPO.
-  if (Top::c_entry_fp(Top::GetCurrentThread()) != NULL) {
-    SafeStackTraceFrameIterator it(
-        reinterpret_cast<Address>(sample->sp),
-        reinterpret_cast<Address>(low_stack_bound_));
-    int i = 0;
-    while (!it.done() && i < TickSample::kMaxFramesCount) {
-      sample->stack[i++] = it.frame()->pc();
-      it.Advance();
-    }
-    sample->frames_count = i;
-  } else if (sample->sp < sample->fp && sample->fp < low_stack_bound_) {
-    // The check assumes that stack grows from lower addresses.
-    sample->stack[0] = Memory::Address_at(
-        (Address)(sample->fp + StandardFrameConstants::kCallerPCOffset));
-    sample->frames_count = 1;
-  } else {
-    // FP seems to be in some intermediate state,
-    // better discard this sample
-    sample->frames_count = 0;
+  SafeStackTraceFrameIterator it(
+      reinterpret_cast<Address>(sample->fp),
+      reinterpret_cast<Address>(sample->sp),
+      reinterpret_cast<Address>(sample->sp),
+      reinterpret_cast<Address>(low_stack_bound_));
+  int i = 0;
+  while (!it.done() && i < TickSample::kMaxFramesCount) {
+    sample->stack[i++] = it.frame()->pc();
+    it.Advance();
   }
+  sample->frames_count = i;
 }
 
 
@@ -362,29 +351,27 @@
 // Append a heap string.
 void LogMessageBuilder::Append(String* str) {
   AssertNoAllocation no_heap_allocation;  // Ensure string stay valid.
-  StringShape shape(str);
-  int length = str->length(shape);
+  int length = str->length();
   for (int i = 0; i < length; i++) {
-    Append(static_cast<char>(str->Get(shape, i)));
+    Append(static_cast<char>(str->Get(i)));
   }
 }
 
 void LogMessageBuilder::AppendDetailed(String* str, bool show_impl_info) {
   AssertNoAllocation no_heap_allocation;  // Ensure string stay valid.
-  StringShape shape(str);
-  int len = str->length(shape);
+  int len = str->length();
   if (len > 0x1000)
     len = 0x1000;
   if (show_impl_info) {
-    Append(shape.IsAsciiRepresentation() ? 'a' : '2');
-    if (shape.IsExternal())
+    Append(StringShape(str).IsAsciiRepresentation() ? 'a' : '2');
+    if (StringShape(str).IsExternal())
       Append('e');
-    if (shape.IsSymbol())
+    if (StringShape(str).IsSymbol())
       Append('#');
     Append(":%i:", str->length());
   }
   for (int i = 0; i < len; i++) {
-    uc32 c = str->Get(shape, i);
+    uc32 c = str->Get(i);
     if (c > 0xff) {
       Append("\\u%04x", c);
     } else if (c < 32 || c > 126) {
@@ -938,7 +925,7 @@
     msg.Append(",overflow");
   }
   for (int i = 0; i < sample->frames_count; ++i) {
-    msg.Append(",%p", sample->stack[i]);
+    msg.Append(",0x%x", reinterpret_cast<uint32_t>(sample->stack[i]));
   }
   msg.Append('\n');
   msg.WriteToLogFile();
@@ -1033,7 +1020,7 @@
   // as log is initialized early with V8, we can assume that JS execution
   // frames can never reach this point on stack
   int stack_var;
-  ticker_ = new Ticker(10, reinterpret_cast<unsigned int>(&stack_var));
+  ticker_ = new Ticker(1, reinterpret_cast<unsigned int>(&stack_var));
 
   if (FLAG_sliding_state_window && sliding_state_window_ == NULL) {
     sliding_state_window_ = new SlidingStateWindow();
diff --git a/src/log.h b/src/log.h
index 1066e34..d238f9b 100644
--- a/src/log.h
+++ b/src/log.h
@@ -270,7 +270,7 @@
 };
 
 
-// Class that extracts stack trace, used for profiling
+// Class that extracts stack trace, used for profiling.
 class StackTracer BASE_EMBEDDED {
  public:
   explicit StackTracer(unsigned int low_stack_bound)
diff --git a/src/macros.py b/src/macros.py
index a3db5f9..d78ecd9 100644
--- a/src/macros.py
+++ b/src/macros.py
@@ -102,7 +102,7 @@
 
 # Constants used on an array to implement the properties of the RegExp object.
 const REGEXP_NUMBER_OF_CAPTURES = 0;
-const REGEXP_FIRST_CAPTURE = 1;
+const REGEXP_FIRST_CAPTURE = 3;
 
 # We can't put macros in macros so we use constants here.
 # REGEXP_NUMBER_OF_CAPTURES
@@ -111,10 +111,10 @@
 # Last input and last subject are after the captures so we can omit them on
 # results returned from global searches.  Beware - these evaluate their
 # arguments twice.
-macro LAST_SUBJECT(array) = ((array)[(array)[0] + 1]);
-macro LAST_INPUT(array) = ((array)[(array)[0] + 2]);
+macro LAST_SUBJECT(array) = ((array)[1]);
+macro LAST_INPUT(array) = ((array)[2]);
 
 # REGEXP_FIRST_CAPTURE
-macro CAPTURE(index) = (1 + (index));
-const CAPTURE0 = 1;
-const CAPTURE1 = 2;
+macro CAPTURE(index) = (3 + (index));
+const CAPTURE0 = 3;
+const CAPTURE1 = 4;
diff --git a/src/mark-compact.cc b/src/mark-compact.cc
index a747ca3..b369cac 100644
--- a/src/mark-compact.cc
+++ b/src/mark-compact.cc
@@ -228,13 +228,13 @@
       static_cast<StringRepresentationTag>(type & kStringRepresentationMask);
   if (rep != kConsStringTag) return object;
 
-  Object* second = reinterpret_cast<ConsString*>(object)->second();
+  Object* second = reinterpret_cast<ConsString*>(object)->unchecked_second();
   if (reinterpret_cast<String*>(second) != Heap::empty_string()) return object;
 
   // Since we don't have the object's start, it is impossible to update the
   // remembered set.  Therefore, we only replace the string with its left
   // substring when the remembered set does not change.
-  Object* first = reinterpret_cast<ConsString*>(object)->first();
+  Object* first = reinterpret_cast<ConsString*>(object)->unchecked_first();
   if (!Heap::InNewSpace(object) && Heap::InNewSpace(first)) return object;
 
   *p = first;
diff --git a/src/objects-debug.cc b/src/objects-debug.cc
index 5b1e0b3..f40fd3e 100644
--- a/src/objects-debug.cc
+++ b/src/objects-debug.cc
@@ -30,6 +30,7 @@
 #include "disassembler.h"
 #include "disasm.h"
 #include "macro-assembler.h"
+#include "jsregexp.h"
 
 namespace v8 { namespace internal {
 
@@ -490,20 +491,19 @@
 
 
 void String::StringPrint() {
-  StringShape shape(this);
-  if (shape.IsSymbol()) {
+  if (StringShape(this).IsSymbol()) {
     PrintF("#");
-  } else if (shape.IsCons()) {
+  } else if (StringShape(this).IsCons()) {
     PrintF("c\"");
   } else {
     PrintF("\"");
   }
 
   for (int i = 0; i < length(); i++) {
-    PrintF("%c", Get(shape, i));
+    PrintF("%c", Get(i));
   }
 
-  if (!shape.IsSymbol()) PrintF("\"");
+  if (!StringShape(this).IsSymbol()) PrintF("\"");
 }
 
 
@@ -696,11 +696,8 @@
       break;
     }
     case JSRegExp::IRREGEXP: {
-      bool is_native = FLAG_regexp_native;
-#ifdef ARM
-      // No native regexp on arm yet.
-      is_native = false;
-#endif
+      bool is_native = RegExpImpl::UseNativeRegexp();
+
       FixedArray* arr = FixedArray::cast(data());
       Object* ascii_data = arr->get(JSRegExp::kIrregexpASCIICodeIndex);
       ASSERT(ascii_data->IsTheHole()
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 941b84c..762bb63 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -143,15 +143,15 @@
 
 bool Object::IsSeqAsciiString() {
   if (!IsString()) return false;
-  StringShape shape(String::cast(this));
-  return shape.IsSequential() && shape.IsAsciiRepresentation();
+  return StringShape(String::cast(this)).IsSequential() &&
+         StringShape(String::cast(this)).IsAsciiRepresentation();
 }
 
 
 bool Object::IsSeqTwoByteString() {
   if (!IsString()) return false;
-  StringShape shape(String::cast(this));
-  return shape.IsSequential() && shape.IsTwoByteRepresentation();
+  return StringShape(String::cast(this)).IsSequential() &&
+         StringShape(String::cast(this)).IsTwoByteRepresentation();
 }
 
 
@@ -163,15 +163,15 @@
 
 bool Object::IsExternalAsciiString() {
   if (!IsString()) return false;
-  StringShape shape(String::cast(this));
-  return shape.IsExternal() && shape.IsAsciiRepresentation();
+  return StringShape(String::cast(this)).IsExternal() &&
+         StringShape(String::cast(this)).IsAsciiRepresentation();
 }
 
 
 bool Object::IsExternalTwoByteString() {
   if (!IsString()) return false;
-  StringShape shape(String::cast(this));
-  return shape.IsExternal() && shape.IsTwoByteRepresentation();
+  return StringShape(String::cast(this)).IsExternal() &&
+         StringShape(String::cast(this)).IsTwoByteRepresentation();
 }
 
 
@@ -1094,6 +1094,15 @@
 }
 
 
+Object* JSObject::InObjectPropertyAt(int index) {
+  // Adjust for the number of properties stored in the object.
+  index -= map()->inobject_properties();
+  ASSERT(index < 0);
+  int offset = map()->instance_size() + (index * kPointerSize);
+  return READ_FIELD(this, offset);
+}
+
+
 Object* JSObject::InObjectPropertyAtPut(int index,
                                         Object* value,
                                         WriteBarrierMode mode) {
@@ -1243,15 +1252,13 @@
 int DescriptorArray::Search(String* name) {
   SLOW_ASSERT(IsSortedNoDuplicates());
 
-  StringShape shape(name);
-
   // Check for empty descriptor array.
   int nof = number_of_descriptors();
   if (nof == 0) return kNotFound;
 
   // Fast case: do linear search for small arrays.
   const int kMaxElementsForLinearSearch = 8;
-  if (shape.IsSymbol() && nof < kMaxElementsForLinearSearch) {
+  if (StringShape(name).IsSymbol() && nof < kMaxElementsForLinearSearch) {
     return LinearSearch(name, nof);
   }
 
@@ -1327,6 +1334,13 @@
 }
 
 
+void Dictionary::set_requires_slow_elements() {
+  set(kMaxNumberKeyIndex,
+      Smi::FromInt(kRequiresSlowElementsMask),
+      SKIP_WRITE_BARRIER);
+}
+
+
 // ------------------------------------
 // Cast operations
 
@@ -1385,27 +1399,21 @@
 
 bool String::Equals(String* other) {
   if (other == this) return true;
-  StringShape this_shape(this);
-  StringShape other_shape(other);
-  if (this_shape.IsSymbol() && other_shape.IsSymbol()) return false;
-  return SlowEquals(this_shape, other, other_shape);
+  if (StringShape(this).IsSymbol() && StringShape(other).IsSymbol()) {
+    return false;
+  }
+  return SlowEquals(other);
 }
 
 
-int String::length(StringShape shape) {
-  ASSERT(shape.type() == StringShape(this).type());
+int String::length() {
   uint32_t len = READ_INT_FIELD(this, kLengthOffset);
 
   ASSERT(kShortStringTag + kLongLengthShift == kShortLengthShift);
   ASSERT(kMediumStringTag + kLongLengthShift == kMediumLengthShift);
   ASSERT(kLongStringTag == 0);
 
-  return len >> (shape.size_tag() + kLongLengthShift);
-}
-
-
-int String::length() {
-  return length(StringShape(this));
+  return len >> (StringShape(this).size_tag() + kLongLengthShift);
 }
 
 
@@ -1414,10 +1422,9 @@
   ASSERT(kMediumStringTag + kLongLengthShift == kMediumLengthShift);
   ASSERT(kLongStringTag == 0);
 
-  StringShape shape(this);
   WRITE_INT_FIELD(this,
                   kLengthOffset,
-                  value << (shape.size_tag() + kLongLengthShift));
+                  value << (StringShape(this).size_tag() + kLongLengthShift));
 }
 
 
@@ -1431,21 +1438,19 @@
 }
 
 
-Object* String::TryFlattenIfNotFlat(StringShape shape) {
-  ASSERT(shape.type() == StringShape(this).type());
+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.
-  if (!IsFlat(shape)) {
-    return TryFlatten(shape);
+  if (!IsFlat()) {
+    return TryFlatten();
   }
   return this;
 }
 
 
-uint16_t String::Get(StringShape shape, int index) {
-  ASSERT(shape.type() == StringShape(this).type());
-  ASSERT(index >= 0 && index < length(shape));
-  switch (shape.full_representation_tag()) {
+uint16_t String::Get(int index) {
+  ASSERT(index >= 0 && index < length());
+  switch (StringShape(this).full_representation_tag()) {
     case kSeqStringTag | kAsciiStringTag:
       return SeqAsciiString::cast(this)->SeqAsciiStringGet(index);
     case kSeqStringTag | kTwoByteStringTag:
@@ -1469,29 +1474,26 @@
 }
 
 
-void String::Set(StringShape shape, int index, uint16_t value) {
-  ASSERT(shape.type() == StringShape(this).type());
-  ASSERT(shape.type() == StringShape(this).type());
-  ASSERT(index >= 0 && index < length(shape));
-  ASSERT(shape.IsSequential());
+void String::Set(int index, uint16_t value) {
+  ASSERT(index >= 0 && index < length());
+  ASSERT(StringShape(this).IsSequential());
 
-  return shape.IsAsciiRepresentation()
+  return StringShape(this).IsAsciiRepresentation()
       ? SeqAsciiString::cast(this)->SeqAsciiStringSet(index, value)
       : SeqTwoByteString::cast(this)->SeqTwoByteStringSet(index, value);
 }
 
 
-bool String::IsFlat(StringShape shape) {
-  ASSERT(shape.type() == StringShape(this).type());
-  switch (shape.representation_tag()) {
+bool String::IsFlat() {
+  switch (StringShape(this).representation_tag()) {
     case kConsStringTag: {
       String* second = ConsString::cast(this)->second();
       // Only flattened strings have second part empty.
       return second->length() == 0;
     }
     case kSlicedStringTag: {
-      StringShape slice_shape = StringShape(SlicedString::cast(this)->buffer());
-      StringRepresentationTag tag = slice_shape.representation_tag();
+      StringRepresentationTag tag =
+          StringShape(SlicedString::cast(this)->buffer()).representation_tag();
       return tag == kSeqStringTag || tag == kExternalStringTag;
     }
     default:
@@ -1545,7 +1547,7 @@
 }
 
 
-int SeqTwoByteString::SeqTwoByteStringSize(StringShape shape) {
+int SeqTwoByteString::SeqTwoByteStringSize(InstanceType instance_type) {
   uint32_t length = READ_INT_FIELD(this, kLengthOffset);
 
   ASSERT(kShortStringTag + kLongLengthShift == kShortLengthShift);
@@ -1554,13 +1556,13 @@
 
   // Use the map (and not 'this') to compute the size tag, since
   // TwoByteStringSize is called during GC when maps are encoded.
-  length >>= shape.size_tag() + kLongLengthShift;
+  length >>= StringShape(instance_type).size_tag() + kLongLengthShift;
 
   return SizeFor(length);
 }
 
 
-int SeqAsciiString::SeqAsciiStringSize(StringShape shape) {
+int SeqAsciiString::SeqAsciiStringSize(InstanceType instance_type) {
   uint32_t length = READ_INT_FIELD(this, kLengthOffset);
 
   ASSERT(kShortStringTag + kLongLengthShift == kShortLengthShift);
@@ -1569,13 +1571,18 @@
 
   // Use the map (and not 'this') to compute the size tag, since
   // AsciiStringSize is called during GC when maps are encoded.
-  length >>= shape.size_tag() + kLongLengthShift;
+  length >>= StringShape(instance_type).size_tag() + kLongLengthShift;
 
   return SizeFor(length);
 }
 
 
 String* ConsString::first() {
+  ASSERT(String::cast(READ_FIELD(this, kSecondOffset))->length() != 0 ||
+      StringShape(
+          String::cast(
+              READ_FIELD(this, kFirstOffset))).IsAsciiRepresentation()
+          == StringShape(this).IsAsciiRepresentation());
   return String::cast(READ_FIELD(this, kFirstOffset));
 }
 
@@ -1608,6 +1615,10 @@
 
 
 String* SlicedString::buffer() {
+  ASSERT(
+      StringShape(
+          String::cast(READ_FIELD(this, kBufferOffset))).IsAsciiRepresentation()
+      == StringShape(this).IsAsciiRepresentation());
   return String::cast(READ_FIELD(this, kBufferOffset));
 }
 
@@ -2316,6 +2327,19 @@
 }
 
 
+int JSRegExp::CaptureCount() {
+  switch (TypeTag()) {
+    case ATOM:
+      return 0;
+    case IRREGEXP:
+      return Smi::cast(DataAt(kIrregexpCaptureCountIndex))->value();
+    default:
+      UNREACHABLE();
+      return -1;
+  }
+}
+
+
 JSRegExp::Flags JSRegExp::GetFlags() {
   ASSERT(this->data()->IsFixedArray());
   Object* data = this->data();
diff --git a/src/objects.cc b/src/objects.cc
index 44ebb3f..9f50d62 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -213,15 +213,8 @@
   if (structure->IsFixedArray()) {
     Object* getter = FixedArray::cast(structure)->get(kGetterIndex);
     if (getter->IsJSFunction()) {
-      HandleScope scope;
-      Handle<JSFunction> fun(JSFunction::cast(getter));
-      Handle<Object> self(receiver);
-      bool has_pending_exception;
-      Handle<Object> result =
-          Execution::Call(fun, self, 0, NULL, &has_pending_exception);
-      // Check for pending exception and return the result.
-      if (has_pending_exception) return Failure::Exception();
-      return *result;
+      return Object::GetPropertyWithDefinedGetter(receiver,
+                                                  JSFunction::cast(getter));
     }
     // Getter is not a function.
     return Heap::undefined_value();
@@ -232,6 +225,20 @@
 }
 
 
+Object* Object::GetPropertyWithDefinedGetter(Object* receiver,
+                                             JSFunction* getter) {
+  HandleScope scope;
+  Handle<JSFunction> fun(JSFunction::cast(getter));
+  Handle<Object> self(receiver);
+  bool has_pending_exception;
+  Handle<Object> result =
+      Execution::Call(fun, self, 0, NULL, &has_pending_exception);
+  // Check for pending exception and return the result.
+  if (has_pending_exception) return Failure::Exception();
+  return *result;
+}
+
+
 // Only deal with CALLBACKS and INTERCEPTOR
 Object* JSObject::GetPropertyWithFailedAccessCheck(
     Object* receiver,
@@ -568,10 +575,9 @@
 // We don't use the BBC's overcorrect "an historic occasion" though if
 // you speak a dialect you may well say "an 'istoric occasion".
 static bool AnWord(String* str) {
-  StringShape shape(str);
-  if (str->length(shape) == 0) return false;  // A nothing.
-  int c0 = str->Get(shape, 0);
-  int c1 = str->length(shape) > 1 ? str->Get(shape, 1) : 0;
+  if (str->length() == 0) return false;  // A nothing.
+  int c0 = str->Get(0);
+  int c1 = str->length() > 1 ? str->Get(1) : 0;
   if (c0 == 'U') {
     if (c1 > 'Z') {
       return true;  // An Umpire, but a UTF8String, a U.
@@ -587,7 +593,7 @@
 }
 
 
-Object* String::TryFlatten(StringShape shape) {
+Object* String::TryFlatten() {
 #ifdef DEBUG
   // Do not attempt to flatten in debug mode when allocation is not
   // allowed.  This is to avoid an assertion failure when allocating.
@@ -596,7 +602,7 @@
   if (!Heap::IsAllocationAllowed()) return this;
 #endif
 
-  switch (shape.representation_tag()) {
+  switch (StringShape(this).representation_tag()) {
     case kSlicedStringTag: {
       SlicedString* ss = SlicedString::cast(this);
       // The SlicedString constructor should ensure that there are no
@@ -604,7 +610,7 @@
       // SlicedStrings.
       String* buf = ss->buffer();
       ASSERT(!buf->IsSlicedString());
-      Object* ok = buf->TryFlatten(StringShape(buf));
+      Object* ok = buf->TryFlatten();
       if (ok->IsFailure()) return ok;
       // Under certain circumstances (TryFlattenIfNotFlat fails in
       // String::Slice) we can have a cons string under a slice.
@@ -612,6 +618,8 @@
       if (StringShape(String::cast(ok)).IsCons()) {
         ss->set_buffer(ConsString::cast(ok)->first());
       }
+      ASSERT(StringShape(this).IsAsciiRepresentation() ==
+          StringShape(ss->buffer()).IsAsciiRepresentation());
       return this;
     }
     case kConsStringTag: {
@@ -623,21 +631,19 @@
       // cons string is in old space.  It can never get GCed until there is
       // an old space GC.
       PretenureFlag tenure = Heap::InNewSpace(this) ? NOT_TENURED : TENURED;
-      int len = length(shape);
+      int len = length();
       Object* object;
       String* result;
-      if (shape.IsAsciiRepresentation()) {
+      if (StringShape(this).IsAsciiRepresentation()) {
         object = Heap::AllocateRawAsciiString(len, tenure);
         if (object->IsFailure()) return object;
         result = String::cast(object);
         String* first = cs->first();
-        StringShape first_shape(first);
-        int first_length = first->length(first_shape);
+        int first_length = first->length();
         char* dest = SeqAsciiString::cast(result)->GetChars();
-        WriteToFlat(first, first_shape, dest, 0, first_length);
+        WriteToFlat(first, dest, 0, first_length);
         String* second = cs->second();
         WriteToFlat(second,
-                    StringShape(second),
                     dest + first_length,
                     0,
                     len - first_length);
@@ -647,12 +653,10 @@
         result = String::cast(object);
         uc16* dest = SeqTwoByteString::cast(result)->GetChars();
         String* first = cs->first();
-        StringShape first_shape(first);
-        int first_length = first->length(first_shape);
-        WriteToFlat(first, first_shape, dest, 0, first_length);
+        int first_length = first->length();
+        WriteToFlat(first, dest, 0, first_length);
         String* second = cs->second();
         WriteToFlat(second,
-                    StringShape(second),
                     dest + first_length,
                     0,
                     len - first_length);
@@ -754,8 +758,7 @@
 
 
 void String::StringShortPrint(StringStream* accumulator) {
-  StringShape shape(this);
-  int len = length(shape);
+  int len = length();
   if (len > kMaxMediumStringSize) {
     accumulator->Add("<Very long string[%u]>", len);
     return;
@@ -783,7 +786,7 @@
   }
   buf.Reset(this);
   if (ascii) {
-    accumulator->Add("<String[%u]: ", length(shape));
+    accumulator->Add("<String[%u]: ", length());
     for (int i = 0; i < len; i++) {
       accumulator->Put(buf.GetNext());
     }
@@ -791,7 +794,7 @@
   } else {
     // Backslash indicates that the string contains control
     // characters and that backslashes are therefore escaped.
-    accumulator->Add("<String[%u]\\: ", length(shape));
+    accumulator->Add("<String[%u]\\: ", length());
     for (int i = 0; i < len; i++) {
       int c = buf.GetNext();
       if (c == '\n') {
@@ -972,12 +975,12 @@
 
   if (instance_type < FIRST_NONSTRING_TYPE
       && (StringShape(instance_type).IsSequential())) {
-    StringShape shape(instance_type);
-    if (shape.IsAsciiRepresentation()) {
-      return reinterpret_cast<SeqAsciiString*>(this)->SeqAsciiStringSize(shape);
+    if (StringShape(instance_type).IsAsciiRepresentation()) {
+      SeqAsciiString* seq_ascii_this = reinterpret_cast<SeqAsciiString*>(this);
+      return seq_ascii_this->SeqAsciiStringSize(instance_type);
     } else {
       SeqTwoByteString* self = reinterpret_cast<SeqTwoByteString*>(this);
-      return self->SeqTwoByteStringSize(shape);
+      return self->SeqTwoByteStringSize(instance_type);
     }
   }
 
@@ -1499,13 +1502,7 @@
   if (structure->IsFixedArray()) {
     Object* setter = FixedArray::cast(structure)->get(kSetterIndex);
     if (setter->IsJSFunction()) {
-      Handle<JSFunction> fun(JSFunction::cast(setter));
-      Handle<JSObject> self(this);
-      bool has_pending_exception;
-      Object** argv[] = { value_handle.location() };
-      Execution::Call(fun, self, 1, argv, &has_pending_exception);
-      // Check for pending exception and return the result.
-      if (has_pending_exception) return Failure::Exception();
+     return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value);
     } else {
       Handle<String> key(name);
       Handle<Object> holder_handle(holder);
@@ -1513,7 +1510,6 @@
       return Top::Throw(*Factory::NewTypeError("no_setter_in_callback",
                                                HandleVector(args, 2)));
     }
-    return *value_handle;
   }
 
   UNREACHABLE();
@@ -1521,6 +1517,19 @@
 }
 
 
+Object* JSObject::SetPropertyWithDefinedSetter(JSFunction* setter,
+                                               Object* value) {
+  Handle<Object> value_handle(value);
+  Handle<JSFunction> fun(JSFunction::cast(setter));
+  Handle<JSObject> self(this);
+  bool has_pending_exception;
+  Object** argv[] = { value_handle.location() };
+  Execution::Call(fun, self, 1, argv, &has_pending_exception);
+  // Check for pending exception and return the result.
+  if (has_pending_exception) return Failure::Exception();
+  return *value_handle;
+}
+
 void JSObject::LookupCallbackSetterInPrototypes(String* name,
                                                 LookupResult* result) {
   for (Object* pt = GetPrototype();
@@ -1541,6 +1550,26 @@
 }
 
 
+Object* JSObject::LookupCallbackSetterInPrototypes(uint32_t index) {
+  for (Object* pt = GetPrototype();
+       pt != Heap::null_value();
+       pt = pt->GetPrototype()) {
+    if (JSObject::cast(pt)->HasFastElements()) continue;
+    Dictionary* dictionary = JSObject::cast(pt)->element_dictionary();
+    int entry = dictionary->FindNumberEntry(index);
+    if (entry != -1) {
+      Object* element = dictionary->ValueAt(entry);
+      PropertyDetails details = dictionary->DetailsAt(entry);
+      if (details.type() == CALLBACKS) {
+        // Only accessors allowed as elements.
+        return FixedArray::cast(element)->get(kSetterIndex);
+      }
+    }
+  }
+  return Heap::undefined_value();
+}
+
+
 void JSObject::LookupInDescriptor(String* name, LookupResult* result) {
   DescriptorArray* descriptors = map()->instance_descriptors();
   int number = descriptors->Search(name);
@@ -2494,11 +2523,7 @@
   }
 
   // Try to flatten before operating on the string.
-  name->TryFlattenIfNotFlat(StringShape(name));
-
-  // Make sure name is not an index.
-  uint32_t index;
-  if (name->AsArrayIndex(&index)) return Heap::undefined_value();
+  name->TryFlattenIfNotFlat();
 
   // Check if there is an API defined callback object which prohibits
   // callback overwriting in this object or it's prototype chain.
@@ -2516,34 +2541,74 @@
     }
   }
 
-  // Lookup the name.
-  LookupResult result;
-  LocalLookup(name, &result);
-  if (result.IsValid()) {
-    if (result.IsReadOnly()) return Heap::undefined_value();
-    if (result.type() == CALLBACKS) {
-      Object* obj = result.GetCallbackObject();
-      if (obj->IsFixedArray()) return obj;
+  uint32_t index;
+  bool is_element = name->AsArrayIndex(&index);
+  if (is_element && IsJSArray()) return Heap::undefined_value();
+
+  if (is_element) {
+    // Lookup the index.
+    if (!HasFastElements()) {
+      Dictionary* dictionary = element_dictionary();
+      int entry = dictionary->FindNumberEntry(index);
+      if (entry != -1) {
+        Object* result = dictionary->ValueAt(entry);
+        PropertyDetails details = dictionary->DetailsAt(entry);
+        if (details.IsReadOnly()) return Heap::undefined_value();
+        if (details.type() == CALLBACKS) {
+          // Only accessors allowed as elements.
+          ASSERT(result->IsFixedArray());
+          return result;
+        }
+      }
+    }
+  } else {
+    // Lookup the name.
+    LookupResult result;
+    LocalLookup(name, &result);
+    if (result.IsValid()) {
+      if (result.IsReadOnly()) return Heap::undefined_value();
+      if (result.type() == CALLBACKS) {
+        Object* obj = result.GetCallbackObject();
+        if (obj->IsFixedArray()) return obj;
+      }
     }
   }
 
-  // Normalize object to make this operation simple.
-  Object* ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES);
-  if (ok->IsFailure()) return ok;
-
   // Allocate the fixed array to hold getter and setter.
-  Object* array = Heap::AllocateFixedArray(2, TENURED);
-  if (array->IsFailure()) return array;
-
-  // Update the dictionary with the new CALLBACKS property.
+  Object* structure = Heap::AllocateFixedArray(2, TENURED);
+  if (structure->IsFailure()) return structure;
   PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
-  Object* dict =
-      property_dictionary()->SetOrAddStringEntry(name, array, details);
-  if (dict->IsFailure()) return dict;
 
-  // Set the potential new dictionary on the object.
-  set_properties(Dictionary::cast(dict));
-  return array;
+  if (is_element) {
+    // Normalize object to make this operation simple.
+    Object* ok = NormalizeElements();
+    if (ok->IsFailure()) return ok;
+
+    // Update the dictionary with the new CALLBACKS property.
+    Object* dict =
+        element_dictionary()->SetOrAddNumberEntry(index, structure, details);
+    if (dict->IsFailure()) return dict;
+
+    // If name is an index we need to stay in slow case.
+    Dictionary* elements = Dictionary::cast(dict);
+    elements->set_requires_slow_elements();
+    // Set the potential new dictionary on the object.
+    set_elements(Dictionary::cast(dict));
+  } else {
+    // Normalize object to make this operation simple.
+    Object* ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES);
+    if (ok->IsFailure()) return ok;
+
+    // Update the dictionary with the new CALLBACKS property.
+    Object* dict =
+        property_dictionary()->SetOrAddStringEntry(name, structure, details);
+    if (dict->IsFailure()) return dict;
+
+    // Set the potential new dictionary on the object.
+    set_properties(Dictionary::cast(dict));
+  }
+
+  return structure;
 }
 
 
@@ -2583,24 +2648,40 @@
     return Heap::undefined_value();
   }
 
-  // Make sure name is not an index.
-  uint32_t index;
-  if (name->AsArrayIndex(&index)) return Heap::undefined_value();
-
   // Make the lookup and include prototypes.
-  for (Object* obj = this;
-       obj != Heap::null_value();
-       obj = JSObject::cast(obj)->GetPrototype()) {
-    LookupResult result;
-    JSObject::cast(obj)->LocalLookup(name, &result);
-    if (result.IsValid()) {
-      if (result.IsReadOnly()) return Heap::undefined_value();
-      if (result.type() == CALLBACKS) {
-        Object* obj = result.GetCallbackObject();
-        if (obj->IsFixedArray()) {
-          return FixedArray::cast(obj)->get(is_getter
-                                            ? kGetterIndex
-                                            : kSetterIndex);
+  int accessor_index = is_getter ? kGetterIndex : kSetterIndex;
+  uint32_t index;
+  if (name->AsArrayIndex(&index)) {
+    for (Object* obj = this;
+         obj != Heap::null_value();
+         obj = JSObject::cast(obj)->GetPrototype()) {
+      JSObject* jsObject = JSObject::cast(obj);
+      if (!jsObject->HasFastElements()) {
+        Dictionary* dictionary = jsObject->element_dictionary();
+        int entry = dictionary->FindNumberEntry(index);
+        if (entry != -1) {
+          Object* element = dictionary->ValueAt(entry);
+          PropertyDetails details = dictionary->DetailsAt(entry);
+          if (details.type() == CALLBACKS) {
+            // Only accessors allowed as elements.
+            return FixedArray::cast(element)->get(accessor_index);
+          }
+        }
+      }
+    }
+  } else {
+    for (Object* obj = this;
+         obj != Heap::null_value();
+         obj = JSObject::cast(obj)->GetPrototype()) {
+      LookupResult result;
+      JSObject::cast(obj)->LocalLookup(name, &result);
+      if (result.IsValid()) {
+        if (result.IsReadOnly()) return Heap::undefined_value();
+        if (result.type() == CALLBACKS) {
+          Object* obj = result.GetCallbackObject();
+          if (obj->IsFixedArray()) {
+            return FixedArray::cast(obj)->get(accessor_index);
+          }
         }
       }
     }
@@ -3149,13 +3230,12 @@
 
 
 int String::Utf8Length() {
-  StringShape shape(this);
-  if (shape.IsAsciiRepresentation()) return length(shape);
+  if (StringShape(this).IsAsciiRepresentation()) return length();
   // Attempt to flatten before accessing the string.  It probably
   // doesn't make Utf8Length faster, but it is very likely that
   // the string will be accessed later (for example by WriteUtf8)
   // so it's still a good idea.
-  TryFlattenIfNotFlat(shape);  // shape is now no longer valid.
+  TryFlattenIfNotFlat();
   Access<StringInputBuffer> buffer(&string_input_buffer);
   buffer->Reset(0, this);
   int result = 0;
@@ -3166,26 +3246,23 @@
 
 
 Vector<const char> String::ToAsciiVector() {
-  StringShape shape(this);
-  ASSERT(shape.IsAsciiRepresentation());
-  ASSERT(IsFlat(shape));
+  ASSERT(StringShape(this).IsAsciiRepresentation());
+  ASSERT(IsFlat());
 
   int offset = 0;
-  int length = this->length(shape);
-  StringRepresentationTag string_tag = shape.representation_tag();
+  int length = this->length();
+  StringRepresentationTag string_tag = StringShape(this).representation_tag();
   String* string = this;
   if (string_tag == kSlicedStringTag) {
     SlicedString* sliced = SlicedString::cast(string);
     offset += sliced->start();
     string = sliced->buffer();
-    shape = StringShape(string);
-    string_tag = shape.representation_tag();
+    string_tag = StringShape(string).representation_tag();
   } else if (string_tag == kConsStringTag) {
     ConsString* cons = ConsString::cast(string);
-    ASSERT(cons->second()->length(StringShape(cons->second())) == 0);
+    ASSERT(cons->second()->length() == 0);
     string = cons->first();
-    shape = StringShape(string);
-    string_tag = shape.representation_tag();
+    string_tag = StringShape(string).representation_tag();
   }
   if (string_tag == kSeqStringTag) {
     SeqAsciiString* seq = SeqAsciiString::cast(string);
@@ -3200,26 +3277,23 @@
 
 
 Vector<const uc16> String::ToUC16Vector() {
-  StringShape shape(this);
-  ASSERT(shape.IsTwoByteRepresentation());
-  ASSERT(IsFlat(shape));
+  ASSERT(StringShape(this).IsTwoByteRepresentation());
+  ASSERT(IsFlat());
 
   int offset = 0;
-  int length = this->length(shape);
-  StringRepresentationTag string_tag = shape.representation_tag();
+  int length = this->length();
+  StringRepresentationTag string_tag = StringShape(this).representation_tag();
   String* string = this;
   if (string_tag == kSlicedStringTag) {
     SlicedString* sliced = SlicedString::cast(string);
     offset += sliced->start();
     string = String::cast(sliced->buffer());
-    shape = StringShape(string);
-    string_tag = shape.representation_tag();
+    string_tag = StringShape(string).representation_tag();
   } else if (string_tag == kConsStringTag) {
     ConsString* cons = ConsString::cast(string);
-    ASSERT(cons->second()->length(StringShape(cons->second())) == 0);
+    ASSERT(cons->second()->length() == 0);
     string = cons->first();
-    shape = StringShape(string);
-    string_tag = shape.representation_tag();
+    string_tag = StringShape(string).representation_tag();
   }
   if (string_tag == kSeqStringTag) {
     SeqTwoByteString* seq = SeqTwoByteString::cast(string);
@@ -3299,9 +3373,8 @@
 
 
 const uc16* String::GetTwoByteData(unsigned start) {
-  StringShape shape(this);
-  ASSERT(!shape.IsAsciiRepresentation());
-  switch (shape.representation_tag()) {
+  ASSERT(!StringShape(this).IsAsciiRepresentation());
+  switch (StringShape(this).representation_tag()) {
     case kSeqStringTag:
       return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
     case kExternalStringTag:
@@ -3313,7 +3386,7 @@
       if (StringShape(buffer).IsCons()) {
         ConsString* cs = ConsString::cast(buffer);
         // Flattened string.
-        ASSERT(cs->second()->length(StringShape(cs->second())) == 0);
+        ASSERT(cs->second()->length() == 0);
         buffer = cs->first();
       }
       return buffer->GetTwoByteData(start + sliced_string->start());
@@ -3416,8 +3489,7 @@
 
   while (true) {
     String* left = current->first();
-    StringShape left_shape(left);
-    unsigned left_length = (unsigned)left->length(left_shape);
+    unsigned left_length = (unsigned)left->length();
     if (left_length > offset &&
         (max_chars <= left_length - offset ||
          (rbb->capacity <= left_length - offset &&
@@ -3429,7 +3501,7 @@
       // the point where we switch to the -IntoBuffer routines (below) in order
       // to maximize the chances of delegating a big chunk of work to the
       // efficient *AsciiStringReadBlock routines.
-      if (left_shape.IsCons()) {
+      if (StringShape(left).IsCons()) {
         current = ConsString::cast(left);
         continue;
       } else {
@@ -3594,10 +3666,9 @@
     rbb->remaining = 0;
     return NULL;
   }
-  StringShape shape(input);
-  switch (shape.representation_tag()) {
+  switch (StringShape(input).representation_tag()) {
     case kSeqStringTag:
-      if (shape.IsAsciiRepresentation()) {
+      if (StringShape(input).IsAsciiRepresentation()) {
         SeqAsciiString* str = SeqAsciiString::cast(input);
         return str->SeqAsciiStringReadBlock(&rbb->remaining,
                                             offset_ptr,
@@ -3618,7 +3689,7 @@
                                                               offset_ptr,
                                                               max_chars);
     case kExternalStringTag:
-      if (shape.IsAsciiRepresentation()) {
+      if (StringShape(input).IsAsciiRepresentation()) {
         return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock(
             &rbb->remaining,
             offset_ptr,
@@ -3670,9 +3741,8 @@
 void FlatStringReader::RefreshState() {
   if (str_ == NULL) return;
   Handle<String> str(str_);
-  StringShape shape(*str);
-  ASSERT(str->IsFlat(shape));
-  is_ascii_ = shape.IsAsciiRepresentation();
+  ASSERT(str->IsFlat());
+  is_ascii_ = StringShape(*str).IsAsciiRepresentation();
   if (is_ascii_) {
     start_ = str->ToAsciiVector().start();
   } else {
@@ -3708,13 +3778,12 @@
                                  ReadBlockBuffer* rbb,
                                  unsigned* offset_ptr,
                                  unsigned max_chars) {
-  StringShape shape(input);
-  ASSERT(*offset_ptr <= (unsigned)input->length(shape));
+  ASSERT(*offset_ptr <= (unsigned)input->length());
   if (max_chars == 0) return;
 
-  switch (shape.representation_tag()) {
+  switch (StringShape(input).representation_tag()) {
     case kSeqStringTag:
-      if (shape.IsAsciiRepresentation()) {
+      if (StringShape(input).IsAsciiRepresentation()) {
         SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb,
                                                                  offset_ptr,
                                                                  max_chars);
@@ -3736,7 +3805,7 @@
                                                                  max_chars);
       return;
     case kExternalStringTag:
-      if (shape.IsAsciiRepresentation()) {
+      if (StringShape(input).IsAsciiRepresentation()) {
          ExternalAsciiString::cast(input)->
              ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars);
        } else {
@@ -3760,12 +3829,11 @@
                                        unsigned capacity,
                                        unsigned* remaining,
                                        unsigned* offset_ptr) {
-  StringShape shape(input);
-  ASSERT(*offset_ptr <= (unsigned)input->length(shape));
-  unsigned chars = input->length(shape) - *offset_ptr;
+  ASSERT(*offset_ptr <= (unsigned)input->length());
+  unsigned chars = input->length() - *offset_ptr;
   ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
   const unibrow::byte* answer = ReadBlock(input, &rbb, offset_ptr, chars);
-  ASSERT(rbb.remaining <= static_cast<unsigned>(input->length(shape)));
+  ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
   *remaining = rbb.remaining;
   return answer;
 }
@@ -3776,14 +3844,13 @@
                                        unsigned capacity,
                                        unsigned* remaining,
                                        unsigned* offset_ptr) {
-  StringShape shape(*raw_input);
   Handle<String> input(raw_input);
-  ASSERT(*offset_ptr <= (unsigned)input->length(shape));
-  unsigned chars = input->length(shape) - *offset_ptr;
+  ASSERT(*offset_ptr <= (unsigned)input->length());
+  unsigned chars = input->length() - *offset_ptr;
   if (chars > capacity) chars = capacity;
   ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
   ReadBlockIntoBuffer(*input, &rbb, offset_ptr, chars);
-  ASSERT(rbb.remaining <= static_cast<unsigned>(input->length(shape)));
+  ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
   *remaining = rbb.remaining;
   return rbb.util_buffer;
 }
@@ -3803,13 +3870,12 @@
 
   while (true) {
     String* left = current->first();
-    StringShape left_shape(left);
-    unsigned left_length = (unsigned)left->length(left_shape);
+    unsigned left_length = (unsigned)left->length();
     if (left_length > offset &&
       max_chars <= left_length - offset) {
       // Left hand side only - iterate unless we have reached the bottom of
       // the cons tree.
-      if (left_shape.IsCons()) {
+      if (StringShape(left).IsCons()) {
         current = ConsString::cast(left);
         continue;
       } else {
@@ -3877,27 +3943,23 @@
   // Check for a flattened cons string
   if (second()->length() == 0) {
     String* left = first();
-    return left->Get(StringShape(left), index);
+    return left->Get(index);
   }
 
   String* string = String::cast(this);
-  StringShape shape(string);
 
   while (true) {
-    if (shape.IsCons()) {
+    if (StringShape(string).IsCons()) {
       ConsString* cons_string = ConsString::cast(string);
       String* left = cons_string->first();
-      StringShape left_shape(left);
-      if (left->length(left_shape) > index) {
+      if (left->length() > index) {
         string = left;
-        shape = left_shape;
       } else {
-        index -= left->length(left_shape);
+        index -= left->length();
         string = cons_string->second();
-        shape = StringShape(string);
       }
     } else {
-      return string->Get(shape, index);
+      return string->Get(index);
     }
   }
 
@@ -3908,17 +3970,15 @@
 
 template <typename sinkchar>
 void String::WriteToFlat(String* src,
-                         StringShape src_shape,
                          sinkchar* sink,
                          int f,
                          int t) {
   String* source = src;
-  StringShape shape = src_shape;
   int from = f;
   int to = t;
   while (true) {
-    ASSERT(0 <= from && from <= to && to <= source->length(shape));
-    switch (shape.full_representation_tag()) {
+    ASSERT(0 <= from && from <= to && to <= source->length());
+    switch (StringShape(source).full_representation_tag()) {
       case kAsciiStringTag | kExternalStringTag: {
         CopyChars(sink,
                   ExternalAsciiString::cast(source)->resource()->data() + from,
@@ -3952,19 +4012,17 @@
         from += start;
         to += start;
         source = String::cast(sliced_string->buffer());
-        shape = StringShape(source);
         break;
       }
       case kAsciiStringTag | kConsStringTag:
       case kTwoByteStringTag | kConsStringTag: {
         ConsString* cons_string = ConsString::cast(source);
         String* first = cons_string->first();
-        StringShape first_shape(first);
-        int boundary = first->length(first_shape);
+        int boundary = first->length();
         if (to - boundary >= boundary - from) {
           // Right hand side is longer.  Recurse over left.
           if (from < boundary) {
-            WriteToFlat(first, first_shape, sink, from, boundary);
+            WriteToFlat(first, sink, from, boundary);
             sink += boundary - from;
             from = 0;
           } else {
@@ -3972,20 +4030,17 @@
           }
           to -= boundary;
           source = cons_string->second();
-          shape = StringShape(source);
         } else {
           // Left hand side is longer.  Recurse over right.
           if (to > boundary) {
             String* second = cons_string->second();
             WriteToFlat(second,
-                        StringShape(second),
                         sink + boundary - from,
                         0,
                         to - boundary);
             to = boundary;
           }
           source = first;
-          shape = first_shape;
         }
         break;
       }
@@ -4003,7 +4058,7 @@
   ASSERT(index >= 0 && index < this->length());
   // Delegate to the buffer string.
   String* underlying = buffer();
-  return underlying->Get(StringShape(underlying), start() + index);
+  return underlying->Get(start() + index);
 }
 
 
@@ -4067,9 +4122,8 @@
 
 template <typename IteratorA>
 static inline bool CompareStringContentsPartial(IteratorA* ia, String* b) {
-  StringShape b_shape(b);
-  if (b->IsFlat(b_shape)) {
-    if (b_shape.IsAsciiRepresentation()) {
+  if (b->IsFlat()) {
+    if (StringShape(b).IsAsciiRepresentation()) {
       VectorIterator<char> ib(b->ToAsciiVector());
       return CompareStringContents(ia, &ib);
     } else {
@@ -4086,12 +4140,10 @@
 static StringInputBuffer string_compare_buffer_a;
 
 
-bool String::SlowEquals(StringShape this_shape,
-                        String* other,
-                        StringShape other_shape) {
+bool String::SlowEquals(String* other) {
   // Fast check: negative check with lengths.
-  int len = length(this_shape);
-  if (len != other->length(other_shape)) return false;
+  int len = length();
+  if (len != other->length()) return false;
   if (len == 0) return true;
 
   // Fast check: if hash code is computed for both strings
@@ -4100,18 +4152,19 @@
     if (Hash() != other->Hash()) return false;
   }
 
-  if (this_shape.IsSequentialAscii() && other_shape.IsSequentialAscii()) {
+  if (StringShape(this).IsSequentialAscii() &&
+      StringShape(other).IsSequentialAscii()) {
     const char* str1 = SeqAsciiString::cast(this)->GetChars();
     const char* str2 = SeqAsciiString::cast(other)->GetChars();
     return CompareRawStringContents(Vector<const char>(str1, len),
                                     Vector<const char>(str2, len));
   }
 
-  if (this->IsFlat(this_shape)) {
-    if (this_shape.IsAsciiRepresentation()) {
+  if (this->IsFlat()) {
+    if (StringShape(this).IsAsciiRepresentation()) {
       Vector<const char> vec1 = this->ToAsciiVector();
-      if (other->IsFlat(other_shape)) {
-        if (other_shape.IsAsciiRepresentation()) {
+      if (other->IsFlat()) {
+        if (StringShape(other).IsAsciiRepresentation()) {
           Vector<const char> vec2 = other->ToAsciiVector();
           return CompareRawStringContents(vec1, vec2);
         } else {
@@ -4126,8 +4179,8 @@
       }
     } else {
       Vector<const uc16> vec1 = this->ToUC16Vector();
-      if (other->IsFlat(other_shape)) {
-        if (other_shape.IsAsciiRepresentation()) {
+      if (other->IsFlat()) {
+        if (StringShape(other).IsAsciiRepresentation()) {
           VectorIterator<uc16> buf1(vec1);
           VectorIterator<char> ib(other->ToAsciiVector());
           return CompareStringContents(&buf1, &ib);
@@ -4177,14 +4230,13 @@
 
 
 bool String::IsEqualTo(Vector<const char> str) {
-  StringShape this_shape(this);
-  int slen = length(this_shape);
+  int slen = length();
   Access<Scanner::Utf8Decoder> decoder(Scanner::utf8_decoder());
   decoder->Reset(str.start(), str.length());
   int i;
   for (i = 0; i < slen && decoder->has_more(); i++) {
     uc32 r = decoder->GetNext();
-    if (Get(this_shape, i) != r) return false;
+    if (Get(i) != r) return false;
   }
   return i == slen && !decoder->has_more();
 }
@@ -4240,8 +4292,7 @@
 
 
 bool String::SlowAsArrayIndex(uint32_t* index) {
-  StringShape shape(this);
-  if (length(shape) <= kMaxCachedArrayIndexLength) {
+  if (length() <= kMaxCachedArrayIndexLength) {
     Hash();  // force computation of hash code
     uint32_t field = length_field();
     if ((field & kIsArrayIndexMask) == 0) return false;
@@ -4249,7 +4300,7 @@
     return true;
   } else {
     StringInputBuffer buffer(this);
-    return ComputeArrayIndex(&buffer, index, length(shape));
+    return ComputeArrayIndex(&buffer, index, length());
   }
 }
 
@@ -4310,9 +4361,8 @@
 
 
 Object* String::Slice(int start, int end) {
-  StringShape shape(this);
-  if (start == 0 && end == length(shape)) return this;
-  if (shape.representation_tag() == kSlicedStringTag) {
+  if (start == 0 && end == length()) return this;
+  if (StringShape(this).representation_tag() == kSlicedStringTag) {
     // Translate slices of a SlicedString into slices of the
     // underlying string buffer.
     SlicedString* str = SlicedString::cast(this);
@@ -4336,14 +4386,13 @@
   // if Heap::AllocateSlicedString actually returned a SlicedString.  It will
   // return flat strings for small slices for efficiency reasons.
   String* answer = String::cast(result);
-  StringShape answer_shape(answer);
-  if (answer_shape.IsSliced() &&
-      shape.representation_tag() == kConsStringTag) {
-    TryFlatten(shape);
+  if (StringShape(answer).IsSliced() &&
+      StringShape(this).representation_tag() == kConsStringTag) {
+    TryFlatten();
     // If the flatten succeeded we might as well make the sliced string point
     // to the flat string rather than the cons string.
     String* second = ConsString::cast(this)->second();
-    if (second->length(StringShape(second)) == 0) {
+    if (second->length() == 0) {
       SlicedString::cast(answer)->set_buffer(ConsString::cast(this)->first());
     }
   }
@@ -4352,10 +4401,9 @@
 
 
 void String::PrintOn(FILE* file) {
-  StringShape shape(this);
-  int length = this->length(shape);
+  int length = this->length();
   for (int i = 0; i < length; i++) {
-    fprintf(file, "%c", Get(shape, i));
+    fprintf(file, "%c", Get(i));
   }
 }
 
@@ -5221,6 +5269,13 @@
   FixedArray* elms = FixedArray::cast(elements());
   uint32_t elms_length = static_cast<uint32_t>(elms->length());
 
+  if (!IsJSArray() && (index >= elms_length || elms->get(index)->IsTheHole())) {
+    Object* setter = LookupCallbackSetterInPrototypes(index);
+    if (setter->IsJSFunction()) {
+      return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value);
+    }
+  }
+
   // Check whether there is extra space in fixed array..
   if (index < elms_length) {
     elms->set(index, value);
@@ -5290,10 +5345,41 @@
   // Insert element in the dictionary.
   FixedArray* elms = FixedArray::cast(elements());
   Dictionary* dictionary = Dictionary::cast(elms);
-  Object* result = dictionary->AtNumberPut(index, value);
-  if (result->IsFailure()) return result;
-  if (elms != FixedArray::cast(result)) {
-    set_elements(FixedArray::cast(result));
+
+  int entry = dictionary->FindNumberEntry(index);
+  if (entry != -1) {
+    Object* element = dictionary->ValueAt(entry);
+    PropertyDetails details = dictionary->DetailsAt(entry);
+    if (details.type() == CALLBACKS) {
+      // Only accessors allowed as elements.
+      FixedArray* structure = FixedArray::cast(element);
+      if (structure->get(kSetterIndex)->IsJSFunction()) {
+        JSFunction* setter = JSFunction::cast(structure->get(kSetterIndex));
+        return SetPropertyWithDefinedSetter(setter, value);
+      } else {
+        Handle<Object> self(this);
+        Handle<Object> key(Factory::NewNumberFromUint(index));
+        Handle<Object> args[2] = { key, self };
+        return Top::Throw(*Factory::NewTypeError("no_setter_in_callback",
+                                                 HandleVector(args, 2)));
+      }
+    } else {
+      dictionary->UpdateMaxNumberKey(index);
+      dictionary->ValueAtPut(entry, value);
+    }
+  } else {
+    // Index not already used. Look for an accessor in the prototype chain.
+    if (!IsJSArray()) {
+      Object* setter = LookupCallbackSetterInPrototypes(index);
+      if (setter->IsJSFunction()) {
+        return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value);
+      }
+    }
+    Object* result = dictionary->AtNumberPut(index, value);
+    if (result->IsFailure()) return result;
+    if (elms != FixedArray::cast(result)) {
+      set_elements(FixedArray::cast(result));
+    }
   }
 
   // Update the array length if this JSObject is an array.
@@ -5426,7 +5512,18 @@
     Dictionary* dictionary = element_dictionary();
     int entry = dictionary->FindNumberEntry(index);
     if (entry != -1) {
-      return dictionary->ValueAt(entry);
+      Object* element = dictionary->ValueAt(entry);
+      PropertyDetails details = dictionary->DetailsAt(entry);
+      if (details.type() == CALLBACKS) {
+        // Only accessors allowed as elements.
+        FixedArray* structure = FixedArray::cast(element);
+        Object* getter = structure->get(kGetterIndex);
+        if (getter->IsJSFunction()) {
+          return GetPropertyWithDefinedGetter(receiver,
+                                              JSFunction::cast(getter));
+        }
+      }
+      return element;
     }
   }
 
@@ -5901,13 +5998,12 @@
     Object* val = JSValue::cast(this)->value();
     if (val->IsString()) {
       String* str = String::cast(val);
-      StringShape shape(str);
       if (storage) {
-        for (int i = 0; i < str->length(shape); i++) {
+        for (int i = 0; i < str->length(); i++) {
           storage->set(counter + i, Smi::FromInt(i), SKIP_WRITE_BARRIER);
         }
       }
-      counter += str->length(shape);
+      counter += str->length();
     }
   }
   ASSERT(!storage || storage->length() == counter);
@@ -5941,7 +6037,6 @@
  public:
   explicit NumberKey(uint32_t number) : number_(number) { }
 
- private:
   bool IsMatch(Object* number) {
     return number_ == ToUint32(number);
   }
@@ -5954,6 +6049,9 @@
     return Heap::NumberFromDouble(number_);
   }
 
+  bool IsStringKey() { return false; }
+
+ private:
   static uint32_t NumberHash(Object* obj) {
     return ComputeIntegerHash(ToUint32(obj));
   }
@@ -5963,8 +6061,6 @@
     return static_cast<uint32_t>(obj->Number());
   }
 
-  bool IsStringKey() { return false; }
-
   uint32_t number_;
 };
 
@@ -6165,10 +6261,9 @@
   Object* GetObject() {
     // If the string is a cons string, attempt to flatten it so that
     // symbols will most often be flat strings.
-    StringShape shape(string_);
-    if (shape.IsCons()) {
+    if (StringShape(string_).IsCons()) {
       ConsString* cons_string = ConsString::cast(string_);
-      cons_string->TryFlatten(shape);
+      cons_string->TryFlatten();
       if (cons_string->second() == Heap::empty_string()) {
         string_ = cons_string->first();
       }
@@ -6771,9 +6866,7 @@
   // Check if this index is high enough that we should require slow
   // elements.
   if (key > kRequiresSlowElementsLimit) {
-    set(kMaxNumberKeyIndex,
-        Smi::FromInt(kRequiresSlowElementsMask),
-        SKIP_WRITE_BARRIER);
+    set_requires_slow_elements();
     return;
   }
   // Update max key value.
@@ -6833,6 +6926,21 @@
 }
 
 
+Object* Dictionary::SetOrAddNumberEntry(uint32_t key,
+                                        Object* value,
+                                        PropertyDetails details) {
+  NumberKey k(key);
+  int entry = FindEntry(&k);
+  if (entry == -1) return AddNumberEntry(key, value, details);
+  // Preserve enumeration index.
+  details = PropertyDetails(details.attributes(),
+                            details.type(),
+                            DetailsAt(entry).index());
+  SetEntry(entry, k.GetObject(), value, details);
+  return this;
+}
+
+
 int Dictionary::NumberOfElementsFilterAttributes(PropertyAttributes filter) {
   int capacity = Capacity();
   int result = 0;
diff --git a/src/objects.h b/src/objects.h
index c38aa38..63480eb 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -707,6 +707,8 @@
                                   Object* structure,
                                   String* name,
                                   Object* holder);
+  Object* GetPropertyWithDefinedGetter(Object* receiver,
+                                       JSFunction* getter);
 
   inline Object* GetElement(uint32_t index);
   Object* GetElementWithReceiver(Object* receiver, uint32_t index);
@@ -1168,6 +1170,8 @@
                                   String* name,
                                   Object* value,
                                   JSObject* holder);
+  Object* SetPropertyWithDefinedSetter(JSFunction* setter,
+                                       Object* value);
   Object* SetPropertyWithInterceptor(String* name,
                                      Object* value,
                                      PropertyAttributes attributes);
@@ -1300,6 +1304,7 @@
   void LookupRealNamedProperty(String* name, LookupResult* result);
   void LookupRealNamedPropertyInPrototypes(String* name, LookupResult* result);
   void LookupCallbackSetterInPrototypes(String* name, LookupResult* result);
+  Object* LookupCallbackSetterInPrototypes(uint32_t index);
   void LookupCallback(String* name, LookupResult* result);
 
   // Returns the number of properties on this object filtering out properties
@@ -1391,7 +1396,8 @@
   inline Object* FastPropertyAt(int index);
   inline Object* FastPropertyAtPut(int index, Object* value);
 
-  // Access to set in object properties.
+  // Access to in object properties.
+  inline Object* InObjectPropertyAt(int index);
   inline Object* InObjectPropertyAtPut(int index,
                                        Object* value,
                                        WriteBarrierMode mode
@@ -1995,11 +2001,15 @@
   Object* AddStringEntry(String* key, Object* value, PropertyDetails details);
   Object* AddNumberEntry(uint32_t key, Object* value, PropertyDetails details);
 
-  // Set and existing string entry or add a new one if needed.
+  // Set an existing entry or add a new one if needed.
   Object* SetOrAddStringEntry(String* key,
                               Object* value,
                               PropertyDetails details);
 
+  Object* SetOrAddNumberEntry(uint32_t key,
+                              Object* value,
+                              PropertyDetails details);
+
   // Returns the number of elements in the dictionary filtering out properties
   // with the specified attributes.
   int NumberOfElementsFilterAttributes(PropertyAttributes filter);
@@ -2021,8 +2031,10 @@
   // If slow elements are required we will never go back to fast-case
   // for the elements kept in this dictionary.  We require slow
   // elements if an element has been added at an index larger than
-  // kRequiresSlowElementsLimit.
+  // kRequiresSlowElementsLimit or set_requires_slow_elements() has been called
+  // when defining a getter or setter with a number key.
   inline bool requires_slow_elements();
+  inline void set_requires_slow_elements();
 
   // Get the value of the max number key that has been added to this
   // dictionary.  max_number_key can only be called if
@@ -2055,6 +2067,8 @@
   static const int kRequiresSlowElementsTagSize = 1;
   static const uint32_t kRequiresSlowElementsLimit = (1 << 29) - 1;
 
+  void UpdateMaxNumberKey(uint32_t key);
+
  private:
   // Generic at put operation.
   Object* AtPut(HashTableKey* key, Object* value);
@@ -2073,8 +2087,6 @@
                        Object* value,
                        PropertyDetails details);
 
-  void UpdateMaxNumberKey(uint32_t key);
-
   // Generate new enumeration indices to avoid enumeration index overflow.
   Object* GenerateNewEnumerationIndices();
 
@@ -3008,6 +3020,7 @@
   DECL_ACCESSORS(data, Object)
 
   inline Type TypeTag();
+  inline int CaptureCount();
   inline Flags GetFlags();
   inline String* Pattern();
   inline Object* DataAt(int index);
@@ -3125,13 +3138,9 @@
 // to be passed by value and is immutable, but be aware that flattening a
 // string can potentially alter its shape.  Also be aware that a GC caused by
 // something else can alter the shape of a string due to ConsString
-// shortcutting.
-//
-// Most of the methods designed to interrogate a string as to its exact nature
-// have been made into methods on StringShape in order to encourage the use of
-// StringShape.  The String class has both a length() and a length(StringShape)
-// operation.  The former is simpler to type, but the latter is faster if you
-// need the StringShape for some other operation immediately before or after.
+// shortcutting.  Keeping these restrictions in mind has proven to be error-
+// prone and so we no longer put StringShapes in variables unless there is a
+// concrete performance benefit at that particular point in the code.
 class StringShape BASE_EMBEDDED {
  public:
   inline explicit StringShape(String* s);
@@ -3180,9 +3189,6 @@
 class String: public HeapObject {
  public:
   // Get and set the length of the string.
-  // Fast version.
-  inline int length(StringShape shape);
-  // Easy version.
   inline int length();
   inline void set_length(int value);
 
@@ -3194,22 +3200,22 @@
   inline void set_length_field(uint32_t value);
 
   // Get and set individual two byte chars in the string.
-  inline void Set(StringShape shape, int index, uint16_t value);
+  inline void Set(int index, uint16_t value);
   // Get individual two byte char in the string.  Repeated calls
   // to this method are not efficient unless the string is flat.
-  inline uint16_t Get(StringShape shape, int index);
+  inline uint16_t Get(int index);
 
   // Try to flatten the top level ConsString that is hiding behind this
   // string.  This is a no-op unless the string is a ConsString or a
   // SlicedString.  Flatten mutates the ConsString and might return a
   // failure.
-  Object* TryFlatten(StringShape shape);
+  Object* TryFlatten();
 
   // Try to flatten the string.  Checks first inline to see if it is necessary.
   // Do not handle allocation failures.  After calling TryFlattenIfNotFlat, the
   // string could still be a ConsString, in which case a failure is returned.
   // Use FlattenString from Handles.cc to be sure to flatten.
-  inline Object* TryFlattenIfNotFlat(StringShape shape);
+  inline Object* TryFlattenIfNotFlat();
 
   Vector<const char> ToAsciiVector();
   Vector<const uc16> ToUC16Vector();
@@ -3288,7 +3294,7 @@
   void StringPrint();
   void StringVerify();
 #endif
-  inline bool IsFlat(StringShape shape);
+  inline bool IsFlat();
 
   // Layout description.
   static const int kLengthOffset = HeapObject::kHeaderSize;
@@ -3350,7 +3356,6 @@
   // Helper function for flattening strings.
   template <typename sinkchar>
   static void WriteToFlat(String* source,
-                          StringShape shape,
                           sinkchar* sink,
                           int from,
                           int to);
@@ -3391,9 +3396,7 @@
  private:
   // Slow case of String::Equals.  This implementation works on any strings
   // but it is most efficient on strings that are almost flat.
-  bool SlowEquals(StringShape this_shape,
-                  String* other,
-                  StringShape other_shape);
+  bool SlowEquals(String* other);
 
   // Slow case of AsArrayIndex.
   bool SlowAsArrayIndex(uint32_t* index);
@@ -3440,7 +3443,7 @@
   // Garbage collection support.  This method is called by the
   // garbage collector to compute the actual size of an AsciiString
   // instance.
-  inline int SeqAsciiStringSize(StringShape shape);
+  inline int SeqAsciiStringSize(InstanceType instance_type);
 
   // Computes the size for an AsciiString instance of a given length.
   static int SizeFor(int length) {
@@ -3485,7 +3488,7 @@
   // Garbage collection support.  This method is called by the
   // garbage collector to compute the actual size of a TwoByteString
   // instance.
-  inline int SeqTwoByteStringSize(StringShape shape);
+  inline int SeqTwoByteStringSize(InstanceType instance_type);
 
   // Computes the size for a TwoByteString instance of a given length.
   static int SizeFor(int length) {
diff --git a/src/parser.cc b/src/parser.cc
index 509675c..fc0ca4d 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -158,10 +158,12 @@
 
   // Decide if a property should be the object boilerplate.
   bool IsBoilerplateProperty(ObjectLiteral::Property* property);
-  // If the property is CONSTANT type, it returns the literal value,
-  // otherwise, it return undefined literal as the placeholder
+  // If the expression is a literal, return the literal value;
+  // if the expression is a materialized literal and is simple return a
+  // compile time value as encoded by CompileTimeValue::GetValue().
+  // Otherwise, return undefined literal as the placeholder
   // in the object literal boilerplate.
-  Literal* GetBoilerplateValue(ObjectLiteral::Property* property);
+  Handle<Object> GetBoilerplateValue(Expression* expression);
 
   enum FunctionLiteralType {
     EXPRESSION,
@@ -1073,7 +1075,7 @@
 
 
 bool Parser::PreParseProgram(unibrow::CharacterStream* stream) {
-  StatsRateScope timer(&Counters::pre_parse);
+  HistogramTimerScope timer(&Counters::pre_parse);
   StackGuard guard;
   AssertNoZoneAllocation assert_no_zone_allocation;
   AssertNoAllocation assert_no_allocation;
@@ -1096,12 +1098,11 @@
                                       bool in_global_context) {
   ZoneScope zone_scope(DONT_DELETE_ON_EXIT);
 
-  StatsRateScope timer(&Counters::parse);
-  StringShape shape(*source);
-  Counters::total_parse_size.Increment(source->length(shape));
+  HistogramTimerScope timer(&Counters::parse);
+  Counters::total_parse_size.Increment(source->length());
 
   // Initialize parser state.
-  source->TryFlattenIfNotFlat(shape);
+  source->TryFlattenIfNotFlat();
   scanner_.Init(source, stream, 0);
   ASSERT(target_stack_ == NULL);
 
@@ -1149,10 +1150,9 @@
                                    int start_position,
                                    bool is_expression) {
   ZoneScope zone_scope(DONT_DELETE_ON_EXIT);
-  StatsRateScope timer(&Counters::parse_lazy);
-  source->TryFlattenIfNotFlat(StringShape(*source));
-  StringShape shape(*source);
-  Counters::total_parse_size.Increment(source->length(shape));
+  HistogramTimerScope timer(&Counters::parse_lazy);
+  source->TryFlattenIfNotFlat();
+  Counters::total_parse_size.Increment(source->length());
   SafeStringInputBuffer buffer(source.location());
 
   // Initialize parser state.
@@ -3056,6 +3056,7 @@
 
   // Update the scope information before the pre-parsing bailout.
   temp_scope_->set_contains_array_literal();
+  int literal_index = temp_scope_->NextMaterializedLiteralIndex();
 
   if (is_pre_parsing_) return NULL;
 
@@ -3064,16 +3065,24 @@
       Factory::NewFixedArray(values.length(), TENURED);
 
   // Fill in the literals.
+  bool is_simple = true;
+  int depth = 1;
   for (int i = 0; i < values.length(); i++) {
-    Literal* literal = values.at(i)->AsLiteral();
-    if (literal == NULL) {
+    MaterializedLiteral* m_literal = values.at(i)->AsMaterializedLiteral();
+    if (m_literal != NULL && m_literal->depth() + 1 > depth) {
+      depth = m_literal->depth() + 1;
+    }
+    Handle<Object> boilerplate_value = GetBoilerplateValue(values.at(i));
+    if (boilerplate_value->IsUndefined()) {
       literals->set_the_hole(i);
+      is_simple = false;
     } else {
-      literals->set(i, *literal->handle());
+      literals->set(i, *boilerplate_value);
     }
   }
 
-  return NEW(ArrayLiteral(literals, values.elements()));
+  return NEW(ArrayLiteral(literals, values.elements(),
+                          literal_index, is_simple, depth));
 }
 
 
@@ -3083,10 +3092,48 @@
 }
 
 
-Literal* Parser::GetBoilerplateValue(ObjectLiteral::Property* property) {
-  if (property->kind() == ObjectLiteral::Property::CONSTANT)
-    return property->value()->AsLiteral();
-  return GetLiteralUndefined();
+bool CompileTimeValue::IsCompileTimeValue(Expression* expression) {
+  MaterializedLiteral* lit = expression->AsMaterializedLiteral();
+  return lit != NULL && lit->is_simple();
+}
+
+Handle<FixedArray> CompileTimeValue::GetValue(Expression* expression) {
+  ASSERT(IsCompileTimeValue(expression));
+  Handle<FixedArray> result = Factory::NewFixedArray(2, TENURED);
+  ObjectLiteral* object_literal = expression->AsObjectLiteral();
+  if (object_literal != NULL) {
+    ASSERT(object_literal->is_simple());
+    result->set(kTypeSlot, Smi::FromInt(OBJECT_LITERAL));
+    result->set(kElementsSlot, *object_literal->constant_properties());
+  } else {
+    ArrayLiteral* array_literal = expression->AsArrayLiteral();
+    ASSERT(array_literal != NULL && array_literal->is_simple());
+    result->set(kTypeSlot, Smi::FromInt(ARRAY_LITERAL));
+    result->set(kElementsSlot, *array_literal->literals());
+  }
+  return result;
+}
+
+
+CompileTimeValue::Type CompileTimeValue::GetType(Handle<FixedArray> value) {
+  Smi* type_value = Smi::cast(value->get(kTypeSlot));
+  return static_cast<Type>(type_value->value());
+}
+
+
+Handle<FixedArray> CompileTimeValue::GetElements(Handle<FixedArray> value) {
+  return Handle<FixedArray>(FixedArray::cast(value->get(kElementsSlot)));
+}
+
+
+Handle<Object> Parser::GetBoilerplateValue(Expression* expression) {
+  if (expression->AsLiteral() != NULL) {
+    return expression->AsLiteral()->handle();
+  }
+  if (CompileTimeValue::IsCompileTimeValue(expression)) {
+    return CompileTimeValue::GetValue(expression);
+  }
+  return Factory::undefined_value();
 }
 
 
@@ -3181,24 +3228,36 @@
   Handle<FixedArray> constant_properties =
       Factory::NewFixedArray(number_of_boilerplate_properties * 2, TENURED);
   int position = 0;
+  bool is_simple = true;
+  int depth = 1;
   for (int i = 0; i < properties.length(); i++) {
     ObjectLiteral::Property* property = properties.at(i);
-    if (!IsBoilerplateProperty(property)) continue;
+    if (!IsBoilerplateProperty(property)) {
+      is_simple = false;
+      continue;
+    }
+    MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral();
+    if (m_literal != NULL && m_literal->depth() + 1 > depth) {
+      depth = m_literal->depth() + 1;
+    }
 
     // Add CONSTANT and COMPUTED properties to boilerplate. Use undefined
     // value for COMPUTED properties, the real value is filled in at
     // runtime. The enumeration order is maintained.
     Handle<Object> key = property->key()->handle();
-    Literal* literal = GetBoilerplateValue(property);
+    Handle<Object> value = GetBoilerplateValue(property->value());
+    is_simple = is_simple && !value->IsUndefined();
 
     // Add name, value pair to the fixed array.
     constant_properties->set(position++, *key);
-    constant_properties->set(position++, *literal->handle());
+    constant_properties->set(position++, *value);
   }
 
   return new ObjectLiteral(constant_properties,
                            properties.elements(),
-                           literal_index);
+                           literal_index,
+                           is_simple,
+                           depth);
 }
 
 
diff --git a/src/parser.h b/src/parser.h
index ee303b4..4c1401c 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -29,6 +29,7 @@
 #define V8_PARSER_H_
 
 #include "scanner.h"
+#include "allocation.h"
 
 namespace v8 { namespace internal {
 
@@ -165,6 +166,35 @@
                              int end_position,
                              bool is_expression);
 
+
+// Support for handling complex values (array and object literals) that
+// can be fully handled at compile time.
+class CompileTimeValue: public AllStatic {
+ public:
+  enum Type {
+    OBJECT_LITERAL,
+    ARRAY_LITERAL
+  };
+
+  static bool IsCompileTimeValue(Expression* expression);
+
+  // Get the value as a compile time value.
+  static Handle<FixedArray> GetValue(Expression* expression);
+
+  // Get the type of a compile time value returned by GetValue().
+  static Type GetType(Handle<FixedArray> value);
+
+  // Get the elements array of a compile time value returned by GetValue().
+  static Handle<FixedArray> GetElements(Handle<FixedArray> value);
+
+ private:
+  static const int kTypeSlot = 0;
+  static const int kElementsSlot = 1;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(CompileTimeValue);
+};
+
+
 } }  // namespace v8::internal
 
 #endif  // V8_PARSER_H_
diff --git a/src/platform-freebsd.cc b/src/platform-freebsd.cc
index b1e0b73..9a15d85 100644
--- a/src/platform-freebsd.cc
+++ b/src/platform-freebsd.cc
@@ -25,14 +25,14 @@
 // (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 FreeBSD goes here
+// Platform specific code for FreeBSD 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/socket.h>
 #include <sys/types.h>
 #include <sys/ucontext.h>
 #include <stdlib.h>
@@ -44,9 +44,6 @@
 #include <unistd.h>     // getpagesize
 #include <execinfo.h>   // backtrace, backtrace_symbols
 #include <strings.h>    // index
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include <netdb.h>
 #include <errno.h>
 #include <stdarg.h>
 #include <limits.h>
@@ -199,28 +196,6 @@
 }
 
 
-char *OS::StrDup(const char* str) {
-  return strdup(str);
-}
-
-
-char* OS::StrNDup(const char* str, size_t n) {
-  // Stupid implementation of strndup since freebsd isn't born with
-  // one.
-  size_t len = strlen(str);
-  if (len <= n) {
-    return StrDup(str);
-  }
-  char* result = new char[n+1];
-  size_t i;
-  for (i = 0; i <= n; i++) {
-    result[i] = str[i];
-  }
-  result[i] = '\0';
-  return result;
-}
-
-
 double OS::nan_value() {
   return NAN;
 }
@@ -608,11 +583,13 @@
   virtual ~FreeBSDSemaphore() { sem_destroy(&sem_); }
 
   virtual void Wait();
+  virtual bool Wait(int timeout);
   virtual void Signal() { sem_post(&sem_); }
  private:
   sem_t sem_;
 };
 
+
 void FreeBSDSemaphore::Wait() {
   while (true) {
     int result = sem_wait(&sem_);
@@ -621,162 +598,44 @@
   }
 }
 
+
+bool FreeBSDSemaphore::Wait(int timeout) {
+  const long kOneSecondMicros = 1000000;  // NOLINT
+  const long kOneSecondNanos = 1000000000;  // NOLINT
+
+  // Split timeout into second and nanosecond parts.
+  long nanos = (timeout % kOneSecondMicros) * 1000;  // NOLINT
+  time_t secs = timeout / kOneSecondMicros;
+
+  // Get the current real time clock.
+  struct timespec ts;
+  if (clock_gettime(CLOCK_REALTIME, &ts) == -1) {
+    return false;
+  }
+
+  // Calculate realtime for end of timeout.
+  ts.tv_nsec += nanos;
+  if (ts.tv_nsec >= kOneSecondNanos) {
+    ts.tv_nsec -= kOneSecondNanos;
+    ts.tv_nsec++;
+  }
+  ts.tv_sec += secs;
+
+  // Wait for semaphore signalled or timeout.
+  while (true) {
+    int result = sem_timedwait(&sem_, &ts);
+    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 FreeBSDSemaphore(count);
 }
 
 
-// ----------------------------------------------------------------------------
-// FreeBSD socket support.
-//
-
-class FreeBSDSocket : public Socket {
- public:
-  explicit FreeBSDSocket() {
-    // Create the socket.
-    socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
-  }
-  explicit FreeBSDSocket(int socket): socket_(socket) { }
-
-
-  virtual ~FreeBSDSocket() {
-    if (IsValid()) {
-      // Close socket.
-      close(socket_);
-    }
-  }
-
-  // Server initialization.
-  bool Bind(const int port);
-  bool Listen(int backlog) const;
-  Socket* Accept() const;
-
-  // Client initialization.
-  bool Connect(const char* host, const char* port);
-
-  // Data Transimission
-  int Send(const char* data, int len) const;
-  int Receive(char* data, int len) const;
-
-  bool IsValid() const { return socket_ != -1; }
-
- private:
-  int socket_;
-};
-
-
-bool FreeBSDSocket::Bind(const int port) {
-  if (!IsValid())  {
-    return false;
-  }
-
-  sockaddr_in addr;
-  memset(&addr, 0, sizeof(addr));
-  addr.sin_family = AF_INET;
-  addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-  addr.sin_port = htons(port);
-  int status = bind(socket_,
-                    reinterpret_cast<struct sockaddr *>(&addr),
-                    sizeof(addr));
-  return status == 0;
-}
-
-
-bool FreeBSDSocket::Listen(int backlog) const {
-  if (!IsValid()) {
-    return false;
-  }
-
-  int status = listen(socket_, backlog);
-  return status == 0;
-}
-
-
-Socket* FreeBSDSocket::Accept() const {
-  if (!IsValid()) {
-    return NULL;
-  }
-
-  int socket = accept(socket_, NULL, NULL);
-  if (socket == -1) {
-    return NULL;
-  } else {
-    return new FreeBSDSocket(socket);
-  }
-}
-
-
-bool FreeBSDSocket::Connect(const char* host, const char* port) {
-  if (!IsValid()) {
-    return false;
-  }
-
-  // Lookup host and port.
-  struct addrinfo *result = NULL;
-  struct addrinfo hints;
-  memset(&hints, 0, sizeof(addrinfo));
-  hints.ai_family = AF_INET;
-  hints.ai_socktype = SOCK_STREAM;
-  hints.ai_protocol = IPPROTO_TCP;
-  int status = getaddrinfo(host, port, &hints, &result);
-  if (status != 0) {
-    return false;
-  }
-
-  // Connect.
-  status = connect(socket_, result->ai_addr, result->ai_addrlen);
-  return status == 0;
-}
-
-
-int FreeBSDSocket::Send(const char* data, int len) const {
-  int status = send(socket_, data, len, 0);
-  return status;
-}
-
-
-int FreeBSDSocket::Receive(char* data, int len) const {
-  int status = recv(socket_, data, len, 0);
-  return status;
-}
-
-
-bool Socket::Setup() {
-  // Nothing to do on FreeBSD.
-  return true;
-}
-
-
-int Socket::LastError() {
-  return errno;
-}
-
-
-uint16_t Socket::HToN(uint16_t value) {
-  return htons(value);
-}
-
-
-uint16_t Socket::NToH(uint16_t value) {
-  return ntohs(value);
-}
-
-
-uint32_t Socket::HToN(uint32_t value) {
-  return htonl(value);
-}
-
-
-uint32_t Socket::NToH(uint32_t value) {
-  return ntohl(value);
-}
-
-
-Socket* OS::CreateSocket() {
-  return new FreeBSDSocket();
-}
-
-
 #ifdef ENABLE_LOGGING_AND_PROFILING
 
 static Sampler* active_sampler_ = NULL;
diff --git a/src/platform-linux.cc b/src/platform-linux.cc
index 05013eb..f1cac09 100644
--- a/src/platform-linux.cc
+++ b/src/platform-linux.cc
@@ -25,14 +25,14 @@
 // (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 Linux goes here
+// Platform specific code for Linux 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/socket.h>
 #include <sys/types.h>
 #include <stdlib.h>
 
@@ -42,17 +42,15 @@
 #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 <fcntl.h>      // open
+#include <unistd.h>     // sysconf
+#ifdef __GLIBC__
 #include <execinfo.h>   // backtrace, backtrace_symbols
+#endif  // def __GLIBC__
 #include <strings.h>    // index
 #include <errno.h>
 #include <stdarg.h>
 
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include <netdb.h>
-
 #undef MAP_TYPE
 
 #include "v8.h"
@@ -196,16 +194,6 @@
 }
 
 
-char* OS::StrDup(const char* str) {
-  return strdup(str);
-}
-
-
-char* OS::StrNDup(const char* str, size_t n) {
-  return strndup(str, n);
-}
-
-
 double OS::nan_value() {
   return NAN;
 }
@@ -240,14 +228,14 @@
 
 
 size_t OS::AllocateAlignment() {
-  return getpagesize();
+  return sysconf(_SC_PAGESIZE);
 }
 
 
 void* OS::Allocate(const size_t requested,
                    size_t* allocated,
                    bool executable) {
-  const size_t msize = RoundUp(requested, getpagesize());
+  const size_t msize = RoundUp(requested, sysconf(_SC_PAGESIZE));
   int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
   void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
   if (mbase == MAP_FAILED) {
@@ -371,6 +359,8 @@
 
 
 int OS::StackWalk(OS::StackFrame* frames, int frames_size) {
+  // backtrace is a glibc extension.
+#ifdef __GLIBC__
   void** addresses = NewArray<void*>(frames_size);
 
   int frames_count = backtrace(addresses, frames_size);
@@ -397,6 +387,9 @@
   free(symbols);
 
   return frames_count;
+#else  // ndef __GLIBC__
+  return 0;
+#endif  // ndef __GLIBC__
 }
 
 
@@ -592,11 +585,13 @@
   virtual ~LinuxSemaphore() { sem_destroy(&sem_); }
 
   virtual void Wait();
+  virtual bool Wait(int timeout);
   virtual void Signal() { sem_post(&sem_); }
  private:
   sem_t sem_;
 };
 
+
 void LinuxSemaphore::Wait() {
   while (true) {
     int result = sem_wait(&sem_);
@@ -605,167 +600,56 @@
   }
 }
 
+
+bool LinuxSemaphore::Wait(int timeout) {
+  const long kOneSecondMicros = 1000000;  // NOLINT
+  const long kOneSecondNanos = 1000000000;  // NOLINT
+
+  // Split timeout into second and nanosecond parts.
+  long nanos = (timeout % kOneSecondMicros) * 1000;  // NOLINT
+  time_t secs = timeout / kOneSecondMicros;
+
+  // Get the current realtime clock.
+  struct timespec ts;
+  if (clock_gettime(CLOCK_REALTIME, &ts) == -1) {
+    return false;
+  }
+
+  // Calculate real time for end of timeout.
+  ts.tv_nsec += nanos;
+  if (ts.tv_nsec >= kOneSecondNanos) {
+    ts.tv_nsec -= kOneSecondNanos;
+    ts.tv_nsec++;
+  }
+  ts.tv_sec += secs;
+
+  // Wait for semaphore signalled or timeout.
+  while (true) {
+    int result = sem_timedwait(&sem_, &ts);
+    if (result == 0) return true;  // Successfully got semaphore.
+    if (result > 0) {
+      // For glibc prior to 2.3.4 sem_timedwait returns the error instead of -1.
+      errno = result;
+      result = -1;
+    }
+    if (result == -1 && errno == ETIMEDOUT) return false;  // Timeout.
+    CHECK(result == -1 && errno == EINTR);  // Signal caused spurious wakeup.
+  }
+}
+
+
 Semaphore* OS::CreateSemaphore(int count) {
   return new LinuxSemaphore(count);
 }
 
 
-// ----------------------------------------------------------------------------
-// Linux socket support.
-//
-
-class LinuxSocket : public Socket {
- public:
-  explicit LinuxSocket() {
-    // Create the socket.
-    socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
-  }
-  explicit LinuxSocket(int socket): socket_(socket) { }
-
-
-  virtual ~LinuxSocket() {
-    if (IsValid()) {
-      // Close socket.
-      close(socket_);
-    }
-  }
-
-  // Server initialization.
-  bool Bind(const int port);
-  bool Listen(int backlog) const;
-  Socket* Accept() const;
-
-  // Client initialization.
-  bool Connect(const char* host, const char* port);
-
-  // Data Transimission
-  int Send(const char* data, int len) const;
-  int Receive(char* data, int len) const;
-
-  bool IsValid() const { return socket_ != -1; }
-
- private:
-  int socket_;
-};
-
-
-bool LinuxSocket::Bind(const int port) {
-  if (!IsValid())  {
-    return false;
-  }
-
-  sockaddr_in addr;
-  memset(&addr, 0, sizeof(addr));
-  addr.sin_family = AF_INET;
-  addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-  addr.sin_port = htons(port);
-  int status = bind(socket_,
-                    reinterpret_cast<struct sockaddr *>(&addr),
-                    sizeof(addr));
-  return status == 0;
-}
-
-
-bool LinuxSocket::Listen(int backlog) const {
-  if (!IsValid()) {
-    return false;
-  }
-
-  int status = listen(socket_, backlog);
-  return status == 0;
-}
-
-
-Socket* LinuxSocket::Accept() const {
-  if (!IsValid()) {
-    return NULL;
-  }
-
-  int socket = accept(socket_, NULL, NULL);
-  if (socket == -1) {
-    return NULL;
-  } else {
-    return new LinuxSocket(socket);
-  }
-}
-
-
-bool LinuxSocket::Connect(const char* host, const char* port) {
-  if (!IsValid()) {
-    return false;
-  }
-
-  // Lookup host and port.
-  struct addrinfo *result = NULL;
-  struct addrinfo hints;
-  memset(&hints, 0, sizeof(addrinfo));
-  hints.ai_family = AF_INET;
-  hints.ai_socktype = SOCK_STREAM;
-  hints.ai_protocol = IPPROTO_TCP;
-  int status = getaddrinfo(host, port, &hints, &result);
-  if (status != 0) {
-    return false;
-  }
-
-  // Connect.
-  status = connect(socket_, result->ai_addr, result->ai_addrlen);
-  return status == 0;
-}
-
-
-int LinuxSocket::Send(const char* data, int len) const {
-  int status = send(socket_, data, len, 0);
-  return status;
-}
-
-
-int LinuxSocket::Receive(char* data, int len) const {
-  int status = recv(socket_, data, len, 0);
-  return status;
-}
-
-
-bool Socket::Setup() {
-  // Nothing to do on Linux.
-  return true;
-}
-
-
-int Socket::LastError() {
-  return errno;
-}
-
-
-uint16_t Socket::HToN(uint16_t value) {
-  return htons(value);
-}
-
-
-uint16_t Socket::NToH(uint16_t value) {
-  return ntohs(value);
-}
-
-
-uint32_t Socket::HToN(uint32_t value) {
-  return htonl(value);
-}
-
-
-uint32_t Socket::NToH(uint32_t value) {
-  return ntohl(value);
-}
-
-
-Socket* OS::CreateSocket() {
-  return new LinuxSocket();
-}
-
-
 #ifdef ENABLE_LOGGING_AND_PROFILING
 
 static Sampler* active_sampler_ = NULL;
 
 static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
+  // Ucontext is a glibc extension - no profiling on Android at the moment.
+#ifdef __GLIBC__
   USE(info);
   if (signal != SIGPROF) return;
   if (active_sampler_ == NULL) return;
@@ -792,6 +676,7 @@
   sample.state = Logger::state();
 
   active_sampler_->Tick(&sample);
+#endif
 }
 
 
diff --git a/src/platform-macos.cc b/src/platform-macos.cc
index 4892e2a..586880f 100644
--- a/src/platform-macos.cc
+++ b/src/platform-macos.cc
@@ -25,7 +25,8 @@
 // (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 MacOS goes here
+// Platform specific code for MacOS goes here. For the POSIX comaptible parts
+// the implementation is in platform-posix.cc.
 
 #include <ucontext.h>
 #include <unistd.h>
@@ -45,14 +46,10 @@
 #include <mach/task.h>
 #include <sys/time.h>
 #include <sys/resource.h>
-#include <sys/socket.h>
 #include <sys/types.h>
 #include <stdarg.h>
 #include <stdlib.h>
 
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include <netdb.h>
 #include <errno.h>
 
 #undef MAP_TYPE
@@ -202,28 +199,6 @@
 }
 
 
-char* OS::StrDup(const char* str) {
-  return strdup(str);
-}
-
-
-char* OS::StrNDup(const char* str, size_t n) {
-  // Stupid implementation of strndup since macos isn't born with
-  // one.
-  size_t len = strlen(str);
-  if (len <= n) {
-    return StrDup(str);
-  }
-  char* result = new char[n+1];
-  size_t i;
-  for (i = 0; i <= n; i++) {
-    result[i] = str[i];
-  }
-  result[i] = '\0';
-  return result;
-}
-
-
 // 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
@@ -565,6 +540,8 @@
   // platform is not needed here.
   void Wait() { semaphore_wait(semaphore_); }
 
+  bool Wait(int timeout);
+
   void Signal() { semaphore_signal(semaphore_); }
 
  private:
@@ -572,168 +549,19 @@
 };
 
 
+bool MacOSSemaphore::Wait(int timeout) {
+  mach_timespec_t ts;
+  ts.tv_sec = timeout / 1000000;
+  ts.tv_nsec = (timeout % 1000000) * 1000;
+  return semaphore_timedwait(semaphore_, ts) != KERN_OPERATION_TIMED_OUT;
+}
+
+
 Semaphore* OS::CreateSemaphore(int count) {
   return new MacOSSemaphore(count);
 }
 
 
-// ----------------------------------------------------------------------------
-// MacOS socket support.
-//
-
-class MacOSSocket : public Socket {
- public:
-  explicit MacOSSocket() {
-    // Create the socket.
-    socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
-  }
-  explicit MacOSSocket(int socket): socket_(socket) { }
-
-
-  virtual ~MacOSSocket() {
-    if (IsValid()) {
-      // Close socket.
-      close(socket_);
-    }
-  }
-
-  // Server initialization.
-  bool Bind(const int port);
-  bool Listen(int backlog) const;
-  Socket* Accept() const;
-
-  // Client initialization.
-  bool Connect(const char* host, const char* port);
-
-  // Data Transimission
-  int Send(const char* data, int len) const;
-  int Receive(char* data, int len) const;
-
-  bool IsValid() const { return socket_ != -1; }
-
- private:
-  int socket_;
-};
-
-
-bool MacOSSocket::Bind(const int port) {
-  if (!IsValid())  {
-    return false;
-  }
-
-  int on = 1;
-  int status = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
-  if (status != 0) {
-    return false;
-  }
-
-  sockaddr_in addr;
-  memset(&addr, 0, sizeof(addr));
-  addr.sin_family = AF_INET;
-  addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-  addr.sin_port = htons(port);
-  status = bind(socket_,
-                reinterpret_cast<struct sockaddr *>(&addr),
-                sizeof(addr));
-  return status == 0;
-}
-
-
-bool MacOSSocket::Listen(int backlog) const {
-  if (!IsValid()) {
-    return false;
-  }
-
-  int status = listen(socket_, backlog);
-  return status == 0;
-}
-
-
-Socket* MacOSSocket::Accept() const {
-  if (!IsValid()) {
-    return NULL;
-  }
-
-  int socket = accept(socket_, NULL, NULL);
-  if (socket == -1) {
-    return NULL;
-  } else {
-    return new MacOSSocket(socket);
-  }
-}
-
-
-bool MacOSSocket::Connect(const char* host, const char* port) {
-  if (!IsValid()) {
-    return false;
-  }
-
-  // Lookup host and port.
-  struct addrinfo *result = NULL;
-  struct addrinfo hints;
-  memset(&hints, 0, sizeof(addrinfo));
-  hints.ai_family = AF_INET;
-  hints.ai_socktype = SOCK_STREAM;
-  hints.ai_protocol = IPPROTO_TCP;
-  int status = getaddrinfo(host, port, &hints, &result);
-  if (status != 0) {
-    return false;
-  }
-
-  // Connect.
-  status = connect(socket_, result->ai_addr, result->ai_addrlen);
-  return status == 0;
-}
-
-
-int MacOSSocket::Send(const char* data, int len) const {
-  int status = send(socket_, data, len, 0);
-  return status;
-}
-
-
-int MacOSSocket::Receive(char* data, int len) const {
-  int status = recv(socket_, data, len, 0);
-  return status;
-}
-
-
-bool Socket::Setup() {
-  // Nothing to do on MacOS.
-  return true;
-}
-
-
-int Socket::LastError() {
-  return errno;
-}
-
-
-uint16_t Socket::HToN(uint16_t value) {
-  return htons(value);
-}
-
-
-uint16_t Socket::NToH(uint16_t value) {
-  return ntohs(value);
-}
-
-
-uint32_t Socket::HToN(uint32_t value) {
-  return htonl(value);
-}
-
-
-uint32_t Socket::NToH(uint32_t value) {
-  return ntohl(value);
-}
-
-
-Socket* OS::CreateSocket() {
-  return new MacOSSocket();
-}
-
-
 #ifdef ENABLE_LOGGING_AND_PROFILING
 
 static Sampler* active_sampler_ = NULL;
diff --git a/src/platform-posix.cc b/src/platform-posix.cc
new file mode 100644
index 0000000..6f71315
--- /dev/null
+++ b/src/platform-posix.cc
@@ -0,0 +1,219 @@
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// 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.
+
+#include <unistd.h>
+#include <errno.h>
+
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include "v8.h"
+
+#include "platform.h"
+
+
+namespace v8 { namespace internal {
+
+
+// ----------------------------------------------------------------------------
+// POSIX socket support.
+//
+
+class POSIXSocket : public Socket {
+ public:
+  explicit POSIXSocket() {
+    // Create the socket.
+    socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  }
+  explicit POSIXSocket(int socket): socket_(socket) { }
+  virtual ~POSIXSocket() { Shutdown(); }
+
+  // Server initialization.
+  bool Bind(const int port);
+  bool Listen(int backlog) const;
+  Socket* Accept() const;
+
+  // Client initialization.
+  bool Connect(const char* host, const char* port);
+
+  // Shutdown socket for both read and write.
+  bool Shutdown();
+
+  // Data Transimission
+  int Send(const char* data, int len) const;
+  int Receive(char* data, int len) const;
+
+  bool SetReuseAddress(bool reuse_address);
+
+  bool IsValid() const { return socket_ != -1; }
+
+ private:
+  int socket_;
+};
+
+
+bool POSIXSocket::Bind(const int port) {
+  if (!IsValid())  {
+    return false;
+  }
+
+  sockaddr_in addr;
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+  addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+  addr.sin_port = htons(port);
+  int status = bind(socket_,
+                    reinterpret_cast<struct sockaddr *>(&addr),
+                    sizeof(addr));
+  return status == 0;
+}
+
+
+bool POSIXSocket::Listen(int backlog) const {
+  if (!IsValid()) {
+    return false;
+  }
+
+  int status = listen(socket_, backlog);
+  return status == 0;
+}
+
+
+Socket* POSIXSocket::Accept() const {
+  if (!IsValid()) {
+    return NULL;
+  }
+
+  int socket = accept(socket_, NULL, NULL);
+  if (socket == -1) {
+    return NULL;
+  } else {
+    return new POSIXSocket(socket);
+  }
+}
+
+
+bool POSIXSocket::Connect(const char* host, const char* port) {
+  if (!IsValid()) {
+    return false;
+  }
+
+  // Lookup host and port.
+  struct addrinfo *result = NULL;
+  struct addrinfo hints;
+  memset(&hints, 0, sizeof(addrinfo));
+  hints.ai_family = AF_INET;
+  hints.ai_socktype = SOCK_STREAM;
+  hints.ai_protocol = IPPROTO_TCP;
+  int status = getaddrinfo(host, port, &hints, &result);
+  if (status != 0) {
+    return false;
+  }
+
+  // Connect.
+  status = connect(socket_, result->ai_addr, result->ai_addrlen);
+  freeaddrinfo(result);
+  return status == 0;
+}
+
+
+bool POSIXSocket::Shutdown() {
+  if (IsValid()) {
+    // Shutdown socket for both read and write.
+    int status = shutdown(socket_, SHUT_RDWR);
+    close(socket_);
+    socket_ = -1;
+    return status == 0;
+  }
+  return true;
+}
+
+
+int POSIXSocket::Send(const char* data, int len) const {
+  int status = send(socket_, data, len, 0);
+  return status;
+}
+
+
+int POSIXSocket::Receive(char* data, int len) const {
+  int status = recv(socket_, data, len, 0);
+  return status;
+}
+
+
+bool POSIXSocket::SetReuseAddress(bool reuse_address) {
+  int on = reuse_address ? 1 : 0;
+  int status = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+  return status == 0;
+}
+
+
+bool Socket::Setup() {
+  // Nothing to do on POSIX.
+  return true;
+}
+
+
+int Socket::LastError() {
+  return errno;
+}
+
+
+uint16_t Socket::HToN(uint16_t value) {
+  return htons(value);
+}
+
+
+uint16_t Socket::NToH(uint16_t value) {
+  return ntohs(value);
+}
+
+
+uint32_t Socket::HToN(uint32_t value) {
+  return htonl(value);
+}
+
+
+uint32_t Socket::NToH(uint32_t value) {
+  return ntohl(value);
+}
+
+
+Socket* OS::CreateSocket() {
+  return new POSIXSocket();
+}
+
+
+} }  // namespace v8::internal
diff --git a/src/platform-win32.cc b/src/platform-win32.cc
index 4e98964..04e7860 100644
--- a/src/platform-win32.cc
+++ b/src/platform-win32.cc
@@ -745,28 +745,6 @@
 }
 
 
-char* OS::StrDup(const char* str) {
-  return _strdup(str);
-}
-
-
-char* OS::StrNDup(const char* str, size_t n) {
-  // Stupid implementation of strndup since windows isn't born with
-  // one.
-  size_t len = strlen(str);
-  if (len <= n) {
-    return StrDup(str);
-  }
-  char* result = new char[n+1];
-  size_t i;
-  for (i = 0; i <= n; i++) {
-    result[i] = str[i];
-  }
-  result[i] = '\0';
-  return result;
-}
-
-
 // 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
@@ -1538,6 +1516,12 @@
     WaitForSingleObject(sem, INFINITE);
   }
 
+  bool Wait(int timeout) {
+    // Timeout in Windows API is in milliseconds.
+    DWORD millis_timeout = timeout / 1000;
+    return WaitForSingleObject(sem, millis_timeout) != WAIT_TIMEOUT;
+  }
+
   void Signal() {
     LONG dummy;
     ReleaseSemaphore(sem, 1, &dummy);
@@ -1564,14 +1548,7 @@
     socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
   }
   explicit Win32Socket(SOCKET socket): socket_(socket) { }
-
-
-  virtual ~Win32Socket() {
-    if (IsValid()) {
-      // Close socket.
-      closesocket(socket_);
-    }
-  }
+  virtual ~Win32Socket() { Shutdown(); }
 
   // Server initialization.
   bool Bind(const int port);
@@ -1581,10 +1558,15 @@
   // Client initialization.
   bool Connect(const char* host, const char* port);
 
+  // Shutdown socket for both read and write.
+  bool Shutdown();
+
   // Data Transimission
   int Send(const char* data, int len) const;
   int Receive(char* data, int len) const;
 
+  bool SetReuseAddress(bool reuse_address);
+
   bool IsValid() const { return socket_ != INVALID_SOCKET; }
 
  private:
@@ -1652,10 +1634,23 @@
 
   // Connect.
   status = connect(socket_, result->ai_addr, result->ai_addrlen);
+  freeaddrinfo(result);
   return status == 0;
 }
 
 
+bool Win32Socket::Shutdown() {
+  if (IsValid()) {
+    // Shutdown socket for both read and write.
+    int status = shutdown(socket_, SD_BOTH);
+    closesocket(socket_);
+    socket_ = INVALID_SOCKET;
+    return status == SOCKET_ERROR;
+  }
+  return true;
+}
+
+
 int Win32Socket::Send(const char* data, int len) const {
   int status = send(socket_, data, len, 0);
   return status;
@@ -1668,6 +1663,14 @@
 }
 
 
+bool Win32Socket::SetReuseAddress(bool reuse_address) {
+  BOOL on = reuse_address ? TRUE : FALSE;
+  int status = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR,
+                          reinterpret_cast<char*>(&on), sizeof(on));
+  return status == SOCKET_ERROR;
+}
+
+
 bool Socket::Setup() {
   // Initialize Winsock32
   int err;
@@ -1747,7 +1750,6 @@
         SuspendThread(profiled_thread_);
         context.ContextFlags = CONTEXT_FULL;
         GetThreadContext(profiled_thread_, &context);
-        ResumeThread(profiled_thread_);
         // Invoke tick handler with program counter and stack pointer.
         sample.pc = context.Eip;
         sample.sp = context.Esp;
@@ -1758,6 +1760,10 @@
       sample.state = Logger::state();
       sampler_->Tick(&sample);
 
+      if (sampler_->IsProfiling()) {
+        ResumeThread(profiled_thread_);
+      }
+
       // Wait until next sampling.
       Sleep(sampler_->interval_);
     }
diff --git a/src/platform.h b/src/platform.h
index 3293708..e910bd1 100644
--- a/src/platform.h
+++ b/src/platform.h
@@ -228,8 +228,6 @@
 
   static char* StrChr(char* str, int c);
   static void StrNCpy(Vector<char> dest, const char* src, size_t n);
-  static char* StrDup(const char* str);
-  static char* StrNDup(const char* str, size_t n);
 
   // Support for profiler.  Can do nothing, in which case ticks
   // occuring in shared libraries will not be properly accounted
@@ -410,10 +408,16 @@
  public:
   virtual ~Semaphore() {}
 
-  // Suspends the calling thread until the counter is non zero
+  // Suspends the calling thread until the semaphore counter is non zero
   // and then decrements the semaphore counter.
   virtual void Wait() = 0;
 
+  // Suspends the calling thread until the counter is non zero or the timeout
+  // time has passsed. If timeout happens the return value is false and the
+  // counter is unchanged. Otherwise the semaphore counter is decremented and
+  // true is returned. The timeout value is specified in microseconds.
+  virtual bool Wait(int timeout) = 0;
+
   // Increments the semaphore counter.
   virtual void Signal() = 0;
 };
@@ -435,10 +439,18 @@
   // Client initialization.
   virtual bool Connect(const char* host, const char* port) = 0;
 
+  // Shutdown socket for both read and write. This causes blocking Send and
+  // Receive calls to exit. After Shutdown the Socket object cannot be used for
+  // any communication.
+  virtual bool Shutdown() = 0;
+
   // Data Transimission
   virtual int Send(const char* data, int len) const = 0;
   virtual int Receive(char* data, int len) const = 0;
 
+  // Set the value of the SO_REUSEADDR socket option.
+  virtual bool SetReuseAddress(bool reuse_address) = 0;
+
   virtual bool IsValid() const = 0;
 
   static bool Setup();
diff --git a/src/prettyprinter.cc b/src/prettyprinter.cc
index c3bf531..0a1a169 100644
--- a/src/prettyprinter.cc
+++ b/src/prettyprinter.cc
@@ -517,10 +517,9 @@
   Object* object = *value;
   if (object->IsString()) {
     String* string = String::cast(object);
-    StringShape shape(string);
     if (quote) Print("\"");
-    for (int i = 0; i < string->length(shape); i++) {
-      Print("%c", string->Get(shape, i));
+    for (int i = 0; i < string->length(); i++) {
+      Print("%c", string->Get(i));
     }
     if (quote) Print("\"");
   } else if (object == Heap::null_value()) {
diff --git a/src/regexp-delay.js b/src/regexp-delay.js
index 7994875..8491863 100644
--- a/src/regexp-delay.js
+++ b/src/regexp-delay.js
@@ -200,9 +200,9 @@
 
 
 // Section 15.10.6.3 doesn't actually make sense, but the intention seems to be
-// that test is defined in terms of String.prototype.exec even if the method is
-// called on a non-RegExp object. However, it probably means the original
-// value of String.prototype.exec, which is what everybody else implements.
+// that test is defined in terms of String.prototype.exec. However, it probably
+// means the original value of String.prototype.exec, which is what everybody
+// else implements.
 function RegExpTest(string) {
   if (!IS_REGEXP(this)) {
     throw MakeTypeError('method_called_on_incompatible',
@@ -300,7 +300,7 @@
 
 // The properties $1..$9 are the first nine capturing substrings of the last
 // successful match, or ''.  The function RegExpMakeCaptureGetter will be
-// called with indeces from 1 to 9.
+// called with indices from 1 to 9.
 function RegExpMakeCaptureGetter(n) {
   return function() {
     var index = n * 2;
@@ -321,10 +321,10 @@
 // the subject string for the last successful match.
 var lastMatchInfo = [
     2,                 // REGEXP_NUMBER_OF_CAPTURES
-    0,                 // REGEXP_FIRST_CAPTURE + 0
-    0,                 // REGEXP_FIRST_CAPTURE + 1
     "",                // Last subject.
     void 0,            // Last input - settable with RegExpSetInput.
+    0,                 // REGEXP_FIRST_CAPTURE + 0
+    0,                 // REGEXP_FIRST_CAPTURE + 1
 ];
 
 // -------------------------------------------------------------------
@@ -353,8 +353,7 @@
     return IS_UNDEFINED(regExpInput) ? "" : regExpInput;
   }
   function RegExpSetInput(string) {
-    lastMatchInfo[lastMatchInfo[REGEXP_NUMBER_OF_CAPTURES] + 2] =
-        ToString(string);
+    LAST_INPUT(lastMatchInfo) = ToString(string);
   };
 
   %DefineAccessor($RegExp, 'input', GETTER, RegExpGetInput, DONT_DELETE);
diff --git a/src/regexp-macro-assembler-ia32.cc b/src/regexp-macro-assembler-ia32.cc
index 3483460..2a7bf3e 100644
--- a/src/regexp-macro-assembler-ia32.cc
+++ b/src/regexp-macro-assembler-ia32.cc
@@ -1,4 +1,4 @@
-// Copyright 2008 the V8 project authors. All rights reserved.
+// Copyright 2008-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:
@@ -25,7 +25,6 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#include <string.h>
 #include "v8.h"
 #include "unicode.h"
 #include "log.h"
@@ -45,8 +44,8 @@
  * - edi : current position in input, as negative offset from end of string.
  *         Please notice that this is the byte offset, not the character offset!
  * - esi : end of input (points to byte after last character in input).
- * - ebp : points to the location above the registers on the stack,
- *         as if by the "enter <register_count>" opcode.
+ * - ebp : frame pointer. Used to access arguments, local variables and
+ *         RegExp registers.
  * - esp : points to tip of C stack.
  * - ecx : points to tip of backtrack stack
  *
@@ -58,15 +57,17 @@
  *                             backtracking stack)
  *       - at_start           (if 1, start at start of string, if 0, don't)
  *       - int* capture_array (int[num_saved_registers_], for output).
- *       - end of input       (index of end of string, relative to *string_base)
- *       - start of input     (index of first character in string, relative
- *                            to *string_base)
- *       - void** string_base (location of a handle containing the string)
+ *       - end of input       (Address of end of string)
+ *       - start of input     (Address of first character in string)
+ *       - void* input_string (location of a handle containing the string)
+ *       --- frame alignment (if applicable) ---
  *       - return address
  * ebp-> - old ebp
  *       - backup of caller esi
  *       - backup of caller edi
  *       - backup of caller ebx
+ *       - Offset of location before start of input (effectively character
+ *         position -1). Used to initialize capture registers to a non-position.
  *       - register 0  ebp[-4]  (Only positions must be stored in the first
  *       - register 1  ebp[-8]   num_saved_registers_ registers)
  *       - ...
@@ -76,13 +77,13 @@
  * character of the string). The remaining registers starts out as garbage.
  *
  * The data up to the return address must be placed there by the calling
- * code, e.g., by calling the code as cast to:
- * bool (*match)(String** string_base,
- *               int start_offset,
- *               int end_offset,
- *               int* capture_output_array,
- *               bool at_start,
- *               byte* stack_area_top)
+ * code, e.g., by calling the code entry as cast to:
+ * int (*match)(String* input_string,
+ *              Address start,
+ *              Address end,
+ *              int* capture_output_array,
+ *              bool at_start,
+ *              byte* stack_area_top)
  */
 
 #define __ masm_->
@@ -174,16 +175,15 @@
 
 
 void RegExpMacroAssemblerIA32::CheckAtStart(Label* on_at_start) {
-  Label ok;
+  Label not_at_start;
   // Did we start the match at the start of the string at all?
   __ cmp(Operand(ebp, kAtStart), Immediate(0));
-  BranchOrBacktrack(equal, &ok);
+  BranchOrBacktrack(equal, &not_at_start);
   // If we did, are we still at the start of the input?
-  __ mov(eax, Operand(ebp, kInputEndOffset));
-  __ add(eax, Operand(edi));
-  __ cmp(eax, Operand(ebp, kInputStartOffset));
+  __ lea(eax, Operand(esi, edi, times_1, 0));
+  __ cmp(eax, Operand(ebp, kInputStart));
   BranchOrBacktrack(equal, on_at_start);
-  __ bind(&ok);
+  __ bind(&not_at_start);
 }
 
 
@@ -192,9 +192,8 @@
   __ cmp(Operand(ebp, kAtStart), Immediate(0));
   BranchOrBacktrack(equal, on_not_at_start);
   // If we did, are we still at the start of the input?
-  __ mov(eax, Operand(ebp, kInputEndOffset));
-  __ add(eax, Operand(edi));
-  __ cmp(eax, Operand(ebp, kInputStartOffset));
+  __ lea(eax, Operand(esi, edi, times_1, 0));
+  __ cmp(eax, Operand(ebp, kInputStart));
   BranchOrBacktrack(not_equal, on_not_at_start);
 }
 
@@ -329,33 +328,29 @@
     __ push(edi);
     __ push(backtrack_stackpointer());
     __ push(ebx);
-    const int four_arguments = 4;
-    FrameAlign(four_arguments, ecx);
+
+    const int argument_count = 3;
+    FrameAlign(argument_count, ecx);
     // Put arguments into allocated stack area, last argument highest on stack.
     // Parameters are
-    //   UC16** buffer - really the String** of the input string
-    //   int byte_offset1 - byte offset from *buffer of start of capture
-    //   int byte_offset2 - byte offset from *buffer of current position
+    //   Address byte_offset1 - Address captured substring's start.
+    //   Address byte_offset2 - Address of current character position.
     //   size_t byte_length - length of capture in bytes(!)
 
     // Set byte_length.
-    __ mov(Operand(esp, 3 * kPointerSize), ebx);
+    __ mov(Operand(esp, 2 * kPointerSize), ebx);
     // Set byte_offset2.
     // Found by adding negative string-end offset of current position (edi)
-    // to String** offset of end of string.
-    __ mov(ecx, Operand(ebp, kInputEndOffset));
-    __ add(edi, Operand(ecx));
-    __ mov(Operand(esp, 2 * kPointerSize), edi);
+    // to end of string.
+    __ add(edi, Operand(esi));
+    __ mov(Operand(esp, 1 * kPointerSize), edi);
     // Set byte_offset1.
     // Start of capture, where edx already holds string-end negative offset.
-    __ add(edx, Operand(ecx));
-    __ mov(Operand(esp, 1 * kPointerSize), edx);
-    // Set buffer. Original String** parameter to regexp code.
-    __ mov(eax, Operand(ebp, kInputBuffer));
-    __ mov(Operand(esp, 0 * kPointerSize), eax);
+    __ add(edx, Operand(esi));
+    __ mov(Operand(esp, 0 * kPointerSize), edx);
 
     Address function_address = FUNCTION_ADDR(&CaseInsensitiveCompareUC16);
-    CallCFunction(function_address, four_arguments);
+    CallCFunction(function_address, argument_count);
     // Pop original values before reacting on result value.
     __ pop(ebx);
     __ pop(backtrack_stackpointer());
@@ -630,7 +625,7 @@
   // Start new stack frame.
   __ push(ebp);
   __ mov(ebp, esp);
-  // Save callee-save registers.  Order here should correspond to order of
+  // Save callee-save registers. Order here should correspond to order of
   // kBackup_ebx etc.
   __ push(esi);
   __ push(edi);
@@ -653,24 +648,18 @@
   // the stack limit.
   __ cmp(ecx, num_registers_ * kPointerSize);
   __ j(above_equal, &stack_ok, taken);
-  // Exit with exception.
+  // Exit with OutOfMemory exception. There is not enough space on the stack
+  // for our working registers.
   __ mov(eax, EXCEPTION);
   __ jmp(&exit_label_);
 
   __ bind(&stack_limit_hit);
-  int num_arguments = 2;
-  FrameAlign(num_arguments, ebx);
-  __ mov(Operand(esp, 1 * kPointerSize), Immediate(masm_->CodeObject()));
-  __ lea(eax, Operand(esp, -kPointerSize));
-  __ mov(Operand(esp, 0 * kPointerSize), eax);
-  CallCFunction(FUNCTION_ADDR(&CheckStackGuardState), num_arguments);
+  CallCheckStackGuardState(ebx);
   __ or_(eax, Operand(eax));
-  // If returned value is non-zero, the stack guard reports the actual
-  // stack limit being hit and an exception has already been raised.
+  // If returned value is non-zero, we exit with the returned value as result.
   // Otherwise it was a preemption and we just check the limit again.
   __ j(equal, &retry_stack_check);
-  // Return value was non-zero. Exit with exception.
-  __ mov(eax, EXCEPTION);
+  // Return value was non-zero. Exit with exception or retry.
   __ jmp(&exit_label_);
 
   __ bind(&stack_ok);
@@ -678,17 +667,11 @@
   // Allocate space on stack for registers.
   __ sub(Operand(esp), Immediate(num_registers_ * kPointerSize));
   // Load string length.
-  __ mov(esi, Operand(ebp, kInputEndOffset));
+  __ mov(esi, Operand(ebp, kInputEnd));
   // Load input position.
-  __ mov(edi, Operand(ebp, kInputStartOffset));
+  __ mov(edi, Operand(ebp, kInputStart));
   // Set up edi to be negative offset from string end.
   __ sub(edi, Operand(esi));
-  // Set up esi to be end of string.  First get location.
-  __ mov(edx, Operand(ebp, kInputBuffer));
-  // Dereference location to get string start.
-  __ mov(edx, Operand(edx, 0));
-  // Add start to length to complete esi setup.
-  __ add(esi, Operand(edx));
   if (num_saved_registers_ > 0) {
     // Fill saved registers with initial value = start offset - 1
     // Fill in stack push order, to avoid accessing across an unwritten
@@ -738,8 +721,8 @@
     if (num_saved_registers_ > 0) {
       // copy captures to output
       __ mov(ebx, Operand(ebp, kRegisterOutput));
-      __ mov(ecx, Operand(ebp, kInputEndOffset));
-      __ sub(ecx, Operand(ebp, kInputStartOffset));
+      __ mov(ecx, Operand(ebp, kInputEnd));
+      __ sub(ecx, Operand(ebp, kInputStart));
       for (int i = 0; i < num_saved_registers_; i++) {
         __ mov(eax, register_location(i));
         __ add(eax, Operand(ecx));  // Convert to index from start, not end.
@@ -781,28 +764,21 @@
     Label retry;
 
     __ bind(&retry);
-    int num_arguments = 2;
-    FrameAlign(num_arguments, ebx);
-    __ mov(Operand(esp, 1 * kPointerSize), Immediate(masm_->CodeObject()));
-    __ lea(eax, Operand(esp, -kPointerSize));
-    __ mov(Operand(esp, 0 * kPointerSize), eax);
-    CallCFunction(FUNCTION_ADDR(&CheckStackGuardState), num_arguments);
-    // Return value must be zero. We cannot have a stack overflow at
-    // this point, since we checked the stack on entry and haven't
-    // pushed anything since, that we haven't also popped again.
-
+    CallCheckStackGuardState(ebx);
+    __ or_(eax, Operand(eax));
+    // If returning non-zero, we should end execution with the given
+    // result as return value.
+    __ j(not_zero, &exit_label_);
+    // Check if we are still preempted.
     ExternalReference stack_guard_limit =
         ExternalReference::address_of_stack_guard_limit();
-    // Check if we are still preempted.
     __ cmp(esp, Operand::StaticVariable(stack_guard_limit));
     __ j(below_equal, &retry);
 
     __ pop(edi);
     __ pop(backtrack_stackpointer());
-    // String might have moved: Recompute esi from scratch.
-    __ mov(esi, Operand(ebp, kInputBuffer));
-    __ mov(esi, Operand(esi, 0));
-    __ add(esi, Operand(ebp, kInputEndOffset));
+    // String might have moved: Reload esi from frame.
+    __ mov(esi, Operand(ebp, kInputEnd));
     SafeReturn();
   }
 
@@ -978,19 +954,80 @@
 }
 
 
-// Private methods:
+RegExpMacroAssemblerIA32::Result RegExpMacroAssemblerIA32::Match(
+    Handle<Code> regexp_code,
+    Handle<String> subject,
+    int* offsets_vector,
+    int offsets_vector_length,
+    int previous_index) {
 
+  ASSERT(subject->IsFlat());
+
+  // No allocations before calling the regexp, but we can't use
+  // AssertNoAllocation, since regexps might be preempted, and another thread
+  // might do allocation anyway.
+
+  String* subject_ptr = *subject;
+  // Character offsets into string.
+  int start_offset = previous_index;
+  int end_offset = subject_ptr->length();
+
+  bool is_ascii = StringShape(*subject).IsAsciiRepresentation();
+
+  if (StringShape(subject_ptr).IsCons()) {
+    subject_ptr = ConsString::cast(subject_ptr)->first();
+  } else if (StringShape(subject_ptr).IsSliced()) {
+    SlicedString* slice = SlicedString::cast(subject_ptr);
+    start_offset += slice->start();
+    end_offset += slice->start();
+    subject_ptr = slice->buffer();
+  }
+  // Ensure that an underlying string has the same ascii-ness.
+  ASSERT(StringShape(subject_ptr).IsAsciiRepresentation() == is_ascii);
+  ASSERT(subject_ptr->IsExternalString() || subject_ptr->IsSeqString());
+  // String is now either Sequential or External
+  int char_size_shift = is_ascii ? 0 : 1;
+  int char_length = end_offset - start_offset;
+
+  const byte* input_start =
+      StringCharacterPosition(subject_ptr, start_offset);
+  int byte_length = char_length << char_size_shift;
+  const byte* input_end = input_start + byte_length;
+  RegExpMacroAssemblerIA32::Result res = Execute(*regexp_code,
+                                                 subject_ptr,
+                                                 start_offset,
+                                                 input_start,
+                                                 input_end,
+                                                 offsets_vector,
+                                                 previous_index == 0);
+
+  if (res == SUCCESS) {
+    // Capture values are relative to start_offset only.
+    // Convert them to be relative to start of string.
+    for (int i = 0; i < offsets_vector_length; i++) {
+      if (offsets_vector[i] >= 0) {
+        offsets_vector[i] += previous_index;
+      }
+    }
+  }
+
+  return res;
+}
+
+// Private methods:
 
 static unibrow::Mapping<unibrow::Ecma262Canonicalize> canonicalize;
 
 RegExpMacroAssemblerIA32::Result RegExpMacroAssemblerIA32::Execute(
     Code* code,
-    Address* input,
+    String* input,
     int start_offset,
-    int end_offset,
+    const byte* input_start,
+    const byte* input_end,
     int* output,
     bool at_start) {
-  typedef int (*matcher)(Address*, int, int, int*, int, Address);
+  typedef int (*matcher)(String*, int, const byte*,
+                         const byte*, int*, int, Address);
   matcher matcher_func = FUNCTION_CAST<matcher>(code->entry());
 
   int at_start_val = at_start ? 1 : 0;
@@ -1001,31 +1038,32 @@
 
   int result = matcher_func(input,
                             start_offset,
-                            end_offset,
+                            input_start,
+                            input_end,
                             output,
                             at_start_val,
                             stack_top);
+  ASSERT(result <= SUCCESS);
+  ASSERT(result >= RETRY);
 
-  if (result < 0 && !Top::has_pending_exception()) {
+  if (result == EXCEPTION && !Top::has_pending_exception()) {
     // We detected a stack overflow (on the backtrack stack) in RegExp code,
     // but haven't created the exception yet.
     Top::StackOverflow();
   }
-  return (result < 0) ? EXCEPTION : (result ? SUCCESS : FAILURE);
+  return static_cast<Result>(result);
 }
 
 
-int RegExpMacroAssemblerIA32::CaseInsensitiveCompareUC16(uc16** buffer,
-                                                         int byte_offset1,
-                                                         int byte_offset2,
+int RegExpMacroAssemblerIA32::CaseInsensitiveCompareUC16(Address byte_offset1,
+                                                         Address byte_offset2,
                                                          size_t byte_length) {
   // This function is not allowed to cause a garbage collection.
   // A GC might move the calling generated code and invalidate the
   // return address on the stack.
   ASSERT(byte_length % 2 == 0);
-  Address buffer_address = reinterpret_cast<Address>(*buffer);
-  uc16* substring1 = reinterpret_cast<uc16*>(buffer_address + byte_offset1);
-  uc16* substring2 = reinterpret_cast<uc16*>(buffer_address + byte_offset2);
+  uc16* substring1 = reinterpret_cast<uc16*>(byte_offset1);
+  uc16* substring2 = reinterpret_cast<uc16*>(byte_offset2);
   size_t length = byte_length >> 1;
 
   for (size_t i = 0; i < length; i++) {
@@ -1045,19 +1083,75 @@
 }
 
 
+void RegExpMacroAssemblerIA32::CallCheckStackGuardState(Register scratch) {
+  int num_arguments = 3;
+  FrameAlign(num_arguments, scratch);
+  // RegExp code frame pointer.
+  __ mov(Operand(esp, 2 * kPointerSize), ebp);
+  // Code* of self.
+  __ mov(Operand(esp, 1 * kPointerSize), Immediate(masm_->CodeObject()));
+  // Next address on the stack (will be address of return address).
+  __ lea(eax, Operand(esp, -kPointerSize));
+  __ mov(Operand(esp, 0 * kPointerSize), eax);
+  CallCFunction(FUNCTION_ADDR(&CheckStackGuardState), num_arguments);
+}
+
+
+// Helper function for reading a value out of a stack frame.
+template <typename T>
+static T& frame_entry(Address re_frame, int frame_offset) {
+  return reinterpret_cast<T&>(Memory::int32_at(re_frame + frame_offset));
+}
+
+
+const byte* RegExpMacroAssemblerIA32::StringCharacterPosition(String* subject,
+                                                              int start_index) {
+  // Not just flat, but ultra flat.
+  ASSERT(subject->IsExternalString() || subject->IsSeqString());
+  ASSERT(start_index >= 0);
+  ASSERT(start_index <= subject->length());
+  if (StringShape(subject).IsAsciiRepresentation()) {
+    const byte* address;
+    if (StringShape(subject).IsExternal()) {
+      const char* data = ExternalAsciiString::cast(subject)->resource()->data();
+      address = reinterpret_cast<const byte*>(data);
+    } else {
+      ASSERT(subject->IsSeqAsciiString());
+      char* data = SeqAsciiString::cast(subject)->GetChars();
+      address = reinterpret_cast<const byte*>(data);
+    }
+    return address + start_index;
+  }
+  const uc16* data;
+  if (StringShape(subject).IsExternal()) {
+    data = ExternalTwoByteString::cast(subject)->resource()->data();
+  } else {
+    ASSERT(subject->IsSeqTwoByteString());
+    data = SeqTwoByteString::cast(subject)->GetChars();
+  }
+  return reinterpret_cast<const byte*>(data + start_index);
+}
+
+
 int RegExpMacroAssemblerIA32::CheckStackGuardState(Address* return_address,
-                                                   Code* re_code) {
+                                                   Code* re_code,
+                                                   Address re_frame) {
   if (StackGuard::IsStackOverflow()) {
     Top::StackOverflow();
-    return 1;
+    return EXCEPTION;
   }
 
   // If not real stack overflow the stack guard was used to interrupt
   // execution for another purpose.
 
   // Prepare for possible GC.
+  HandleScope handles;
   Handle<Code> code_handle(re_code);
 
+  Handle<String> subject(frame_entry<String*>(re_frame, kInputString));
+  // Current string.
+  bool is_ascii = StringShape(*subject).IsAsciiRepresentation();
+
   ASSERT(re_code->instruction_start() <= *return_address);
   ASSERT(*return_address <=
       re_code->instruction_start() + re_code->instruction_size());
@@ -1071,8 +1165,41 @@
   }
 
   if (result->IsException()) {
-    return 1;
+    return EXCEPTION;
   }
+
+  // String might have changed.
+  if (StringShape(*subject).IsAsciiRepresentation() != is_ascii) {
+    // If we changed between an ASCII and an UC16 string, the specialized
+    // code cannot be used, and we need to restart regexp matching from
+    // scratch (including, potentially, compiling a new version of the code).
+    return RETRY;
+  }
+
+  // Otherwise, the content of the string might have moved. It must still
+  // be a sequential or external string with the same content.
+  // Update the start and end pointers in the stack frame to the current
+  // location (whether it has actually moved or not).
+  ASSERT(StringShape(*subject).IsSequential() ||
+      StringShape(*subject).IsExternal());
+
+  // The original start address of the characters to match.
+  const byte* start_address = frame_entry<const byte*>(re_frame, kInputStart);
+
+  // Find the current start address of the same character at the current string
+  // position.
+  int start_index = frame_entry<int>(re_frame, kStartIndex);
+  const byte* new_address = StringCharacterPosition(*subject, start_index);
+
+  if (start_address != new_address) {
+    // If there is a difference, update start and end addresses in the
+    // RegExp stack frame to match the new value.
+    const byte* end_address = frame_entry<const byte* >(re_frame, kInputEnd);
+    int byte_length = end_address - start_address;
+    frame_entry<const byte*>(re_frame, kInputStart) = new_address;
+    frame_entry<const byte*>(re_frame, kInputEnd) = new_address + byte_length;
+  }
+
   return 0;
 }
 
@@ -1196,9 +1323,9 @@
 
 
 void RegExpMacroAssemblerIA32::FrameAlign(int num_arguments, Register scratch) {
-  // TODO(lrn): Since we no longer use the system stack arbitrarily, we
-  // know the current stack alignment - esp points to the last regexp register.
-  // We can do this simpler then.
+  // TODO(lrn): Since we no longer use the system stack arbitrarily (but we do
+  // use it, e.g., for SafeCall), we know the number of elements on the stack
+  // since the last frame alignment. We might be able to do this simpler then.
   int frameAlignment = OS::ActivationFrameAlignment();
   if (frameAlignment != 0) {
     // Make stack end at alignment and make room for num_arguments words
diff --git a/src/regexp-macro-assembler-ia32.h b/src/regexp-macro-assembler-ia32.h
index d6f11ad..0309f20 100644
--- a/src/regexp-macro-assembler-ia32.h
+++ b/src/regexp-macro-assembler-ia32.h
@@ -1,4 +1,4 @@
-// Copyright 2008 the V8 project authors. All rights reserved.
+// Copyright 2008-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:
@@ -34,7 +34,16 @@
  public:
   // Type of input string to generate code for.
   enum Mode { ASCII = 1, UC16 = 2 };
-  enum Result { EXCEPTION = -1, FAILURE = 0, SUCCESS = 1 };
+  // Result of calling the generated RegExp code:
+  // RETRY: Something significant changed during execution, and the matching
+  //        should be retried from scratch.
+  // EXCEPTION: Something failed during execution. If no exception has been
+  //        thrown, it's an internal out-of-memory, and the caller should
+  //        throw the exception.
+  // FAILURE: Matching failed.
+  // SUCCESS: Matching succeeded, and the output array has been filled with
+  //        capture positions.
+  enum Result { RETRY = -2, EXCEPTION = -1, FAILURE = 0, SUCCESS = 1 };
 
   RegExpMacroAssemblerIA32(Mode mode, int registers_to_save);
   virtual ~RegExpMacroAssemblerIA32();
@@ -113,10 +122,17 @@
   virtual void ClearRegisters(int reg_from, int reg_to);
   virtual void WriteStackPointerToRegister(int reg);
 
+  static Result Match(Handle<Code> regexp,
+                      Handle<String> subject,
+                      int* offsets_vector,
+                      int offsets_vector_length,
+                      int previous_index);
+
   static Result Execute(Code* code,
-                        Address* input,
+                        String* input,
                         int start_offset,
-                        int end_offset,
+                        const byte* input_start,
+                        const byte* input_end,
                         int* output,
                         bool at_start);
 
@@ -125,10 +141,13 @@
   static const int kFramePointer = 0;
   // Above the frame pointer - function parameters and return address.
   static const int kReturn_eip = kFramePointer + kPointerSize;
-  static const int kInputBuffer = kReturn_eip + kPointerSize;
-  static const int kInputStartOffset = kInputBuffer + kPointerSize;
-  static const int kInputEndOffset = kInputStartOffset + kPointerSize;
-  static const int kRegisterOutput = kInputEndOffset + kPointerSize;
+  static const int kFrameAlign = kReturn_eip + kPointerSize;
+  // Parameters.
+  static const int kInputString = kFrameAlign;
+  static const int kStartIndex = kInputString + kPointerSize;
+  static const int kInputStart = kStartIndex + kPointerSize;
+  static const int kInputEnd = kInputStart + kPointerSize;
+  static const int kRegisterOutput = kInputEnd + kPointerSize;
   static const int kAtStart = kRegisterOutput + kPointerSize;
   static const int kStackHighEnd = kAtStart + kPointerSize;
   // Below the frame pointer - local stack variables.
@@ -146,11 +165,12 @@
   // Initial size of constant buffers allocated during compilation.
   static const int kRegExpConstantsSize = 256;
 
+  static const byte* StringCharacterPosition(String* subject, int start_index);
+
   // Compares two-byte strings case insensitively.
   // Called from generated RegExp code.
-  static int CaseInsensitiveCompareUC16(uc16** buffer,
-                                        int byte_offset1,
-                                        int byte_offset2,
+  static int CaseInsensitiveCompareUC16(Address byte_offset1,
+                                        Address byte_offset2,
                                         size_t byte_length);
 
   // Load a number of characters at the given offset from the
@@ -166,7 +186,12 @@
   // Called from RegExp if the stack-guard is triggered.
   // If the code object is relocated, the return address is fixed before
   // returning.
-  static int CheckStackGuardState(Address* return_address, Code* re_code);
+  static int CheckStackGuardState(Address* return_address,
+                                  Code* re_code,
+                                  Address re_frame);
+
+  // Generate a call to CheckStackGuardState.
+  void CallCheckStackGuardState(Register scratch);
 
   // Called from RegExp if the backtrack stack limit is hit.
   // Tries to expand the stack. Returns the new stack-pointer if
diff --git a/src/register-allocator-arm.cc b/src/register-allocator-arm.cc
index b48710a..36a4d20 100644
--- a/src/register-allocator-arm.cc
+++ b/src/register-allocator-arm.cc
@@ -27,8 +27,8 @@
 
 #include "v8.h"
 
-#include "codegen.h"
-#include "register-allocator.h"
+#include "codegen-inl.h"
+#include "register-allocator-inl.h"
 
 namespace v8 { namespace internal {
 
diff --git a/src/register-allocator-ia32.cc b/src/register-allocator-ia32.cc
index 6149187..a898827 100644
--- a/src/register-allocator-ia32.cc
+++ b/src/register-allocator-ia32.cc
@@ -27,8 +27,8 @@
 
 #include "v8.h"
 
-#include "codegen.h"
-#include "register-allocator.h"
+#include "codegen-inl.h"
+#include "register-allocator-inl.h"
 
 namespace v8 { namespace internal {
 
diff --git a/src/register-allocator-inl.h b/src/register-allocator-inl.h
new file mode 100644
index 0000000..8611d6a
--- /dev/null
+++ b/src/register-allocator-inl.h
@@ -0,0 +1,48 @@
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_REGISTER_ALLOCATOR_INL_H_
+#define V8_REGISTER_ALLOCATOR_INL_H_
+
+#include "virtual-frame.h"
+
+namespace v8 { namespace internal {
+
+Result::~Result() {
+  if (is_register()) cgen_->allocator()->Unuse(reg());
+}
+
+
+void Result::Unuse() {
+  if (is_register()) cgen_->allocator()->Unuse(reg());
+  type_ = INVALID;
+}
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_REGISTER_ALLOCATOR_INL_H_
diff --git a/src/register-allocator.cc b/src/register-allocator.cc
index 7a96882..381aeb5 100644
--- a/src/register-allocator.cc
+++ b/src/register-allocator.cc
@@ -27,8 +27,8 @@
 
 #include "v8.h"
 
-#include "codegen.h"
-#include "register-allocator.h"
+#include "codegen-inl.h"
+#include "register-allocator-inl.h"
 
 namespace v8 { namespace internal {
 
@@ -59,14 +59,6 @@
 }
 
 
-void Result::Unuse() {
-  if (is_register()) {
-    cgen_->allocator()->Unuse(reg());
-  }
-  type_ = INVALID;
-}
-
-
 // -------------------------------------------------------------------------
 // RegisterFile implementation.
 
@@ -83,11 +75,10 @@
 
 Result RegisterAllocator::AllocateWithoutSpilling() {
   // Return the first free register, if any.
-  for (int i = 0; i < kNumRegisters; i++) {
-    if (!is_used(i)) {
-      Register free_reg = { i };
-      return Result(free_reg, cgen_);
-    }
+  int free_reg = registers_.ScanForFreeRegister();
+  if (free_reg < kNumRegisters) {
+    Register free_result = { free_reg };
+    return Result(free_result, cgen_);
   }
   return Result(cgen_);
 }
diff --git a/src/register-allocator.h b/src/register-allocator.h
index 759ab14..f6db62c 100644
--- a/src/register-allocator.h
+++ b/src/register-allocator.h
@@ -73,9 +73,9 @@
     return *this;
   }
 
-  ~Result() { Unuse(); }
+  inline ~Result();
 
-  void Unuse();
+  inline void Unuse();
 
   Type type() const { return type_; }
 
@@ -149,10 +149,9 @@
   // Record that a register will no longer be used by decrementing its
   // reference count.
   void Unuse(Register reg) {
+    ASSERT(!reg.is(no_reg));
     ASSERT(is_used(reg.code()));
-    if (is_used(reg.code())) {
-      ref_counts_[reg.code()]--;
-    }
+    ref_counts_[reg.code()]--;
   }
 
   // Copy the reference counts from this register file to the other.
@@ -161,6 +160,17 @@
  private:
   int ref_counts_[kNumRegisters];
 
+  // Very fast inlined loop to find a free register.
+  // Used in RegisterAllocator::AllocateWithoutSpilling.
+  // Returns kNumRegisters if no free register found.
+  inline int ScanForFreeRegister() {
+    int i = 0;
+    for (; i < kNumRegisters ; ++i) {
+      if (ref_counts_[i] == 0) break;
+    }
+    return i;
+  }
+
   friend class RegisterAllocator;
 };
 
diff --git a/src/rewriter.cc b/src/rewriter.cc
index 4468066..d7f1531 100644
--- a/src/rewriter.cc
+++ b/src/rewriter.cc
@@ -42,6 +42,10 @@
   void Optimize(ZoneList<Statement*>* statements);
 
  private:
+  // Used for loop condition analysis.  Cleared before visiting a loop
+  // condition, set when a function literal is visited.
+  bool has_function_literal_;
+
   // Helpers
   void OptimizeArguments(ZoneList<Expression*>* arguments);
 
@@ -89,14 +93,14 @@
 }
 
 
-
-
 void AstOptimizer::VisitLoopStatement(LoopStatement* node) {
   if (node->init() != NULL) {
     Visit(node->init());
   }
   if (node->cond() != NULL) {
+    has_function_literal_ = false;
     Visit(node->cond());
+    node->has_function_literal_ = has_function_literal_;
   }
   if (node->body() != NULL) {
     Visit(node->body());
@@ -182,6 +186,7 @@
 
 void AstOptimizer::VisitFunctionLiteral(FunctionLiteral* node) {
   USE(node);
+  has_function_literal_ = true;
 }
 
 
diff --git a/src/runtime.cc b/src/runtime.cc
index e7019a6..38db689 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -1,4 +1,4 @@
-// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// 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:
@@ -35,6 +35,7 @@
 #include "compiler.h"
 #include "cpu.h"
 #include "dateparser.h"
+#include "dateparser-inl.h"
 #include "debug.h"
 #include "execution.h"
 #include "jsregexp.h"
@@ -43,6 +44,7 @@
 #include "scopeinfo.h"
 #include "v8threads.h"
 #include "smart-pointer.h"
+#include "parser.h"
 
 namespace v8 { namespace internal {
 
@@ -69,6 +71,13 @@
   RUNTIME_ASSERT(obj->IsBoolean());                                   \
   bool name = (obj)->IsTrue();
 
+// Cast the given object to a Smi and store its value in an int variable
+// with the given name.  If the object is not a Smi call IllegalOperation
+// and return.
+#define CONVERT_SMI_CHECKED(name, obj)                            \
+  RUNTIME_ASSERT(obj->IsSmi());                                   \
+  int name = Smi::cast(obj)->value();
+
 // Cast the given object to a double and store it in a variable with
 // the given name.  If the object is not a number (as opposed to
 // the number not-a-number) call IllegalOperation and return.
@@ -92,7 +101,103 @@
 }
 
 
-static Object* Runtime_CloneObjectLiteralBoilerplate(Arguments args) {
+static Object* DeepCopyBoilerplate(JSObject* boilerplate) {
+  StackLimitCheck check;
+  if (check.HasOverflowed()) return Top::StackOverflow();
+
+  Object* result = Heap::CopyJSObject(boilerplate);
+  if (result->IsFailure()) return result;
+  JSObject* copy = JSObject::cast(result);
+
+  // Deep copy local properties.
+  if (copy->HasFastProperties()) {
+    FixedArray* properties = copy->properties();
+    WriteBarrierMode mode = properties->GetWriteBarrierMode();
+    for (int i = 0; i < properties->length(); i++) {
+      Object* value = properties->get(i);
+      if (value->IsJSObject()) {
+        JSObject* jsObject = JSObject::cast(value);
+        result = DeepCopyBoilerplate(jsObject);
+        if (result->IsFailure()) return result;
+        properties->set(i, result, mode);
+      }
+    }
+    mode = copy->GetWriteBarrierMode();
+    for (int i = 0; i < copy->map()->inobject_properties(); i++) {
+      Object* value = copy->InObjectPropertyAt(i);
+      if (value->IsJSObject()) {
+        JSObject* jsObject = JSObject::cast(value);
+        result = DeepCopyBoilerplate(jsObject);
+        if (result->IsFailure()) return result;
+        copy->InObjectPropertyAtPut(i, result, mode);
+      }
+    }
+  } else {
+    result = Heap::AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
+    if (result->IsFailure()) return result;
+    FixedArray* names = FixedArray::cast(result);
+    copy->GetLocalPropertyNames(names, 0);
+    for (int i = 0; i < names->length(); i++) {
+      ASSERT(names->get(i)->IsString());
+      String* keyString = String::cast(names->get(i));
+      PropertyAttributes attributes =
+        copy->GetLocalPropertyAttribute(keyString);
+      // Only deep copy fields from the object literal expression.
+      // In particular, don't try to copy the length attribute of
+      // an array.
+      if (attributes != NONE) continue;
+      Object* value = copy->GetProperty(keyString, &attributes);
+      ASSERT(!value->IsFailure());
+      if (value->IsJSObject()) {
+        JSObject* jsObject = JSObject::cast(value);
+        result = DeepCopyBoilerplate(jsObject);
+        if (result->IsFailure()) return result;
+        result = copy->SetProperty(keyString, result, NONE);
+        if (result->IsFailure()) return result;
+      }
+    }
+  }
+
+  // Deep copy local elements.
+  if (copy->HasFastElements()) {
+    FixedArray* elements = copy->elements();
+    WriteBarrierMode mode = elements->GetWriteBarrierMode();
+    for (int i = 0; i < elements->length(); i++) {
+      Object* value = elements->get(i);
+      if (value->IsJSObject()) {
+        JSObject* jsObject = JSObject::cast(value);
+        result = DeepCopyBoilerplate(jsObject);
+        if (result->IsFailure()) return result;
+        elements->set(i, result, mode);
+      }
+    }
+  } else {
+    Dictionary* element_dictionary = copy->element_dictionary();
+    int capacity = element_dictionary->Capacity();
+    for (int i = 0; i < capacity; i++) {
+      Object* k = element_dictionary->KeyAt(i);
+      if (element_dictionary->IsKey(k)) {
+        Object* value = element_dictionary->ValueAt(i);
+        if (value->IsJSObject()) {
+          JSObject* jsObject = JSObject::cast(value);
+          result = DeepCopyBoilerplate(jsObject);
+          if (result->IsFailure()) return result;
+          element_dictionary->ValueAtPut(i, result);
+        }
+      }
+    }
+  }
+  return copy;
+}
+
+
+static Object* Runtime_CloneLiteralBoilerplate(Arguments args) {
+  CONVERT_CHECKED(JSObject, boilerplate, args[0]);
+  return DeepCopyBoilerplate(boilerplate);
+}
+
+
+static Object* Runtime_CloneShallowLiteralBoilerplate(Arguments args) {
   CONVERT_CHECKED(JSObject, boilerplate, args[0]);
   return Heap::CopyJSObject(boilerplate);
 }
@@ -131,14 +236,14 @@
 }
 
 
-static Object* Runtime_CreateObjectLiteralBoilerplate(Arguments args) {
-  HandleScope scope;
-  ASSERT(args.length() == 3);
-  // Copy the arguments.
-  Handle<FixedArray> literals = args.at<FixedArray>(0);
-  int literals_index = Smi::cast(args[1])->value();
-  Handle<FixedArray> constant_properties = args.at<FixedArray>(2);
+static Handle<Object> CreateLiteralBoilerplate(
+    Handle<FixedArray> literals,
+    Handle<FixedArray> constant_properties);
 
+
+static Handle<Object> CreateObjectLiteralBoilerplate(
+    Handle<FixedArray> literals,
+    Handle<FixedArray> constant_properties) {
   // Get the global context from the literals array.  This is the
   // context in which the function was created and we use the object
   // function from this context to create the object literal.  We do
@@ -161,6 +266,13 @@
     for (int index = 0; index < length; index +=2) {
       Handle<Object> key(constant_properties->get(index+0));
       Handle<Object> value(constant_properties->get(index+1));
+      if (value->IsFixedArray()) {
+        // The value contains the constant_properties of a
+        // simple object literal.
+        Handle<FixedArray> array = Handle<FixedArray>::cast(value);
+        value = CreateLiteralBoilerplate(literals, array);
+        if (value.is_null()) return value;
+      }
       Handle<Object> result;
       uint32_t element_index = 0;
       if (key->IsSymbol()) {
@@ -185,39 +297,97 @@
       // exception, the exception is converted to an empty handle in
       // the handle based operations.  In that case, we need to
       // convert back to an exception.
-      if (result.is_null()) return Failure::Exception();
+      if (result.is_null()) return result;
     }
   }
 
-  // Update the functions literal and return the boilerplate.
-  literals->set(literals_index, *boilerplate);
-
-  return *boilerplate;
+  return boilerplate;
 }
 
 
-static Object* Runtime_CreateArrayLiteral(Arguments args) {
+static Handle<Object> CreateArrayLiteralBoilerplate(
+    Handle<FixedArray> literals,
+    Handle<FixedArray> elements) {
+  // Create the JSArray.
+  Handle<JSFunction> constructor(
+      JSFunction::GlobalContextFromLiterals(*literals)->array_function());
+  Handle<Object> object = Factory::NewJSObject(constructor);
+
+  Handle<Object> copied_elements = Factory::CopyFixedArray(elements);
+
+  Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
+  for (int i = 0; i < content->length(); i++) {
+    if (content->get(i)->IsFixedArray()) {
+      // The value contains the constant_properties of a
+      // simple object literal.
+      Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
+      Handle<Object> result =
+        CreateLiteralBoilerplate(literals, fa);
+      if (result.is_null()) return result;
+      content->set(i, *result);
+    }
+  }
+
+  // Set the elements.
+  Handle<JSArray>::cast(object)->SetContent(*content);
+  return object;
+}
+
+
+static Handle<Object> CreateLiteralBoilerplate(
+    Handle<FixedArray> literals,
+    Handle<FixedArray> array) {
+  Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
+  switch (CompileTimeValue::GetType(array)) {
+    case CompileTimeValue::OBJECT_LITERAL:
+      return CreateObjectLiteralBoilerplate(literals, elements);
+    case CompileTimeValue::ARRAY_LITERAL:
+      return CreateArrayLiteralBoilerplate(literals, elements);
+    default:
+      UNREACHABLE();
+      return Handle<Object>::null();
+  }
+}
+
+
+static Object* Runtime_CreateObjectLiteralBoilerplate(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 3);
+  // Copy the arguments.
+  CONVERT_ARG_CHECKED(FixedArray, literals, 0);
+  CONVERT_SMI_CHECKED(literals_index, args[1]);
+  CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
+
+  Handle<Object> result =
+    CreateObjectLiteralBoilerplate(literals, constant_properties);
+
+  if (result.is_null()) return Failure::Exception();
+
+  // Update the functions literal and return the boilerplate.
+  literals->set(literals_index, *result);
+
+  return *result;
+}
+
+
+static Object* Runtime_CreateArrayLiteralBoilerplate(Arguments args) {
   // Takes a FixedArray of elements containing the literal elements of
   // the array literal and produces JSArray with those elements.
   // Additionally takes the literals array of the surrounding function
   // which contains the context from which to get the Array function
   // to use for creating the array literal.
-  ASSERT(args.length() == 2);
-  CONVERT_CHECKED(FixedArray, elements, args[0]);
-  CONVERT_CHECKED(FixedArray, literals, args[1]);
-  JSFunction* constructor =
-      JSFunction::GlobalContextFromLiterals(literals)->array_function();
-  // Create the JSArray.
-  Object* object = Heap::AllocateJSObject(constructor);
-  if (object->IsFailure()) return object;
+  HandleScope scope;
+  ASSERT(args.length() == 3);
+  CONVERT_ARG_CHECKED(FixedArray, literals, 0);
+  CONVERT_SMI_CHECKED(literals_index, args[1]);
+  CONVERT_ARG_CHECKED(FixedArray, elements, 2);
 
-  // Copy the elements.
-  Object* content = elements->Copy();
-  if (content->IsFailure()) return content;
+  Handle<Object> object = CreateArrayLiteralBoilerplate(literals, elements);
+  if (object.is_null()) return Failure::Exception();
 
-  // Set the elements.
-  JSArray::cast(object)->SetContent(FixedArray::cast(content));
-  return object;
+  // Update the functions literal and return the boilerplate.
+  literals->set(literals_index, *object);
+  return *object;
 }
 
 
@@ -1077,12 +1247,11 @@
   // Flatten the string.  If someone wants to get a char at an index
   // in a cons string, it is likely that more indices will be
   // accessed.
-  subject->TryFlattenIfNotFlat(StringShape(subject));
-  StringShape shape(subject);
-  if (i >= static_cast<uint32_t>(subject->length(shape))) {
+  subject->TryFlattenIfNotFlat();
+  if (i >= static_cast<uint32_t>(subject->length())) {
     return Heap::nan_value();
   }
-  return Smi::FromInt(subject->Get(shape, i));
+  return Smi::FromInt(subject->Get(i));
 }
 
 
@@ -1108,6 +1277,541 @@
   return Heap::empty_string();
 }
 
+// Forward declarations.
+static const int kStringBuilderConcatHelperLengthBits = 11;
+static const int kStringBuilderConcatHelperPositionBits = 19;
+
+template <typename schar>
+static inline void StringBuilderConcatHelper(String*,
+                                             schar*,
+                                             FixedArray*,
+                                             int);
+
+typedef BitField<int, 0, 11> StringBuilderSubstringLength;
+typedef BitField<int, 11, 19> StringBuilderSubstringPosition;
+
+class ReplacementStringBuilder {
+ public:
+  ReplacementStringBuilder(Handle<String> subject, int estimated_part_count)
+      : subject_(subject),
+        parts_(Factory::NewFixedArray(estimated_part_count)),
+        part_count_(0),
+        character_count_(0),
+        is_ascii_(StringShape(*subject).IsAsciiRepresentation()) {
+    // Require a non-zero initial size. Ensures that doubling the size to
+    // extend the array will work.
+    ASSERT(estimated_part_count > 0);
+  }
+
+  void EnsureCapacity(int elements) {
+    int length = parts_->length();
+    int required_length = part_count_ + elements;
+    if (length < required_length) {
+      int new_length = length;
+      do {
+        new_length *= 2;
+      } while (new_length < required_length);
+      Handle<FixedArray> extended_array =
+          Factory::NewFixedArray(new_length);
+      parts_->CopyTo(0, *extended_array, 0, part_count_);
+      parts_ = extended_array;
+    }
+  }
+
+  void AddSubjectSlice(int from, int to) {
+    ASSERT(from >= 0);
+    int length = to - from;
+    ASSERT(length > 0);
+    // Can we encode the slice in 11 bits for length and 19 bits for
+    // start position - as used by StringBuilderConcatHelper?
+    if (StringBuilderSubstringLength::is_valid(length) &&
+        StringBuilderSubstringPosition::is_valid(from)) {
+      int encoded_slice = StringBuilderSubstringLength::encode(length) |
+          StringBuilderSubstringPosition::encode(from);
+      AddElement(Smi::FromInt(encoded_slice));
+    } else {
+      Handle<String> slice = Factory::NewStringSlice(subject_, from, to);
+      AddElement(*slice);
+    }
+    IncrementCharacterCount(length);
+  }
+
+
+  void AddString(Handle<String> string) {
+    int length = string->length();
+    ASSERT(length > 0);
+    AddElement(*string);
+    if (!StringShape(*string).IsAsciiRepresentation()) {
+      is_ascii_ = false;
+    }
+    IncrementCharacterCount(length);
+  }
+
+
+  Handle<String> ToString() {
+    if (part_count_ == 0) {
+      return Factory::empty_string();
+    }
+
+    Handle<String> joined_string;
+    if (is_ascii_) {
+      joined_string = NewRawAsciiString(character_count_);
+      AssertNoAllocation no_alloc;
+      SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
+      char* char_buffer = seq->GetChars();
+      StringBuilderConcatHelper(*subject_,
+                                char_buffer,
+                                *parts_,
+                                part_count_);
+    } else {
+      // Non-ASCII.
+      joined_string = NewRawTwoByteString(character_count_);
+      AssertNoAllocation no_alloc;
+      SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
+      uc16* char_buffer = seq->GetChars();
+      StringBuilderConcatHelper(*subject_,
+                                char_buffer,
+                                *parts_,
+                                part_count_);
+    }
+    return joined_string;
+  }
+
+
+  void IncrementCharacterCount(int by) {
+    if (character_count_ > Smi::kMaxValue - by) {
+      V8::FatalProcessOutOfMemory("String.replace result too large.");
+    }
+    character_count_ += by;
+  }
+
+ private:
+
+  Handle<String> NewRawAsciiString(int size) {
+    CALL_HEAP_FUNCTION(Heap::AllocateRawAsciiString(size), String);
+  }
+
+
+  Handle<String> NewRawTwoByteString(int size) {
+    CALL_HEAP_FUNCTION(Heap::AllocateRawTwoByteString(size), String);
+  }
+
+
+  void AddElement(Object* element) {
+    ASSERT(element->IsSmi() || element->IsString());
+    parts_->set(part_count_, element);
+    part_count_++;
+  }
+
+  Handle<String> subject_;
+  Handle<FixedArray> parts_;
+  int part_count_;
+  int character_count_;
+  bool is_ascii_;
+};
+
+
+class CompiledReplacement {
+ public:
+  CompiledReplacement()
+      : parts_(1), replacement_substrings_(0) {}
+
+  void Compile(Handle<String> replacement,
+               int capture_count,
+               int subject_length);
+
+  void Apply(ReplacementStringBuilder* builder,
+             int match_from,
+             int match_to,
+             Handle<JSArray> last_match_info);
+
+  // Number of distinct parts of the replacement pattern.
+  int parts() {
+    return parts_.length();
+  }
+ private:
+  enum PartType {
+    SUBJECT_PREFIX = 1,
+    SUBJECT_SUFFIX,
+    SUBJECT_CAPTURE,
+    REPLACEMENT_SUBSTRING,
+    REPLACEMENT_STRING,
+
+    NUMBER_OF_PART_TYPES
+  };
+
+  struct ReplacementPart {
+    static inline ReplacementPart SubjectMatch() {
+      return ReplacementPart(SUBJECT_CAPTURE, 0);
+    }
+    static inline ReplacementPart SubjectCapture(int capture_index) {
+      return ReplacementPart(SUBJECT_CAPTURE, capture_index);
+    }
+    static inline ReplacementPart SubjectPrefix() {
+      return ReplacementPart(SUBJECT_PREFIX, 0);
+    }
+    static inline ReplacementPart SubjectSuffix(int subject_length) {
+      return ReplacementPart(SUBJECT_SUFFIX, subject_length);
+    }
+    static inline ReplacementPart ReplacementString() {
+      return ReplacementPart(REPLACEMENT_STRING, 0);
+    }
+    static inline ReplacementPart ReplacementSubString(int from, int to) {
+      ASSERT(from >= 0);
+      ASSERT(to > from);
+      return ReplacementPart(-from, to);
+    }
+
+    // If tag <= 0 then it is the negation of a start index of a substring of
+    // the replacement pattern, otherwise it's a value from PartType.
+    ReplacementPart(int tag, int data)
+        : tag(tag), data(data) {
+      // Must be non-positive or a PartType value.
+      ASSERT(tag < NUMBER_OF_PART_TYPES);
+    }
+    // Either a value of PartType or a non-positive number that is
+    // the negation of an index into the replacement string.
+    int tag;
+    // The data value's interpretation depends on the value of tag:
+    // tag == SUBJECT_PREFIX ||
+    // tag == SUBJECT_SUFFIX:  data is unused.
+    // tag == SUBJECT_CAPTURE: data is the number of the capture.
+    // tag == REPLACEMENT_SUBSTRING ||
+    // tag == REPLACEMENT_STRING:    data is index into array of substrings
+    //                               of the replacement string.
+    // tag <= 0: Temporary representation of the substring of the replacement
+    //           string ranging over -tag .. data.
+    //           Is replaced by REPLACEMENT_{SUB,}STRING when we create the
+    //           substring objects.
+    int data;
+  };
+
+  template<typename Char>
+  static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
+                                      Vector<Char> characters,
+                                      int capture_count,
+                                      int subject_length) {
+    int length = characters.length();
+    int last = 0;
+    for (int i = 0; i < length; i++) {
+      Char c = characters[i];
+      if (c == '$') {
+        int next_index = i + 1;
+        if (next_index == length) {  // No next character!
+          break;
+        }
+        Char c2 = characters[next_index];
+        switch (c2) {
+        case '$':
+          if (i > last) {
+            // There is a substring before. Include the first "$".
+            parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
+            last = next_index + 1;  // Continue after the second "$".
+          } else {
+            // Let the next substring start with the second "$".
+            last = next_index;
+          }
+          i = next_index;
+          break;
+        case '`':
+          if (i > last) {
+            parts->Add(ReplacementPart::ReplacementSubString(last, i));
+          }
+          parts->Add(ReplacementPart::SubjectPrefix());
+          i = next_index;
+          last = i + 1;
+          break;
+        case '\'':
+          if (i > last) {
+            parts->Add(ReplacementPart::ReplacementSubString(last, i));
+          }
+          parts->Add(ReplacementPart::SubjectSuffix(subject_length));
+          i = next_index;
+          last = i + 1;
+          break;
+        case '&':
+          if (i > last) {
+            parts->Add(ReplacementPart::ReplacementSubString(last, i));
+          }
+          parts->Add(ReplacementPart::SubjectMatch());
+          i = next_index;
+          last = i + 1;
+          break;
+        case '0':
+        case '1':
+        case '2':
+        case '3':
+        case '4':
+        case '5':
+        case '6':
+        case '7':
+        case '8':
+        case '9': {
+          int capture_ref = c2 - '0';
+          if (capture_ref > capture_count) {
+            i = next_index;
+            continue;
+          }
+          int second_digit_index = next_index + 1;
+          if (second_digit_index < length) {
+            // Peek ahead to see if we have two digits.
+            Char c3 = characters[second_digit_index];
+            if ('0' <= c3 && c3 <= '9') {  // Double digits.
+              int double_digit_ref = capture_ref * 10 + c3 - '0';
+              if (double_digit_ref <= capture_count) {
+                next_index = second_digit_index;
+                capture_ref = double_digit_ref;
+              }
+            }
+          }
+          if (capture_ref > 0) {
+            if (i > last) {
+              parts->Add(ReplacementPart::ReplacementSubString(last, i));
+            }
+            parts->Add(ReplacementPart::SubjectCapture(capture_ref));
+            last = next_index + 1;
+          }
+          i = next_index;
+          break;
+        }
+        default:
+          i = next_index;
+          break;
+        }
+      }
+    }
+    if (length > last) {
+      if (last == 0) {
+        parts->Add(ReplacementPart::ReplacementString());
+      } else {
+        parts->Add(ReplacementPart::ReplacementSubString(last, length));
+      }
+    }
+  }
+
+  ZoneList<ReplacementPart> parts_;
+  ZoneList<Handle<String> > replacement_substrings_;
+};
+
+
+void CompiledReplacement::Compile(Handle<String> replacement,
+                                  int capture_count,
+                                  int subject_length) {
+  ASSERT(replacement->IsFlat());
+  if (StringShape(*replacement).IsAsciiRepresentation()) {
+    AssertNoAllocation no_alloc;
+    ParseReplacementPattern(&parts_,
+                            replacement->ToAsciiVector(),
+                            capture_count,
+                            subject_length);
+  } else {
+    ASSERT(StringShape(*replacement).IsTwoByteRepresentation());
+    AssertNoAllocation no_alloc;
+
+    ParseReplacementPattern(&parts_,
+                            replacement->ToUC16Vector(),
+                            capture_count,
+                            subject_length);
+  }
+  // Find substrings of replacement string and create them as String objects..
+  int substring_index = 0;
+  for (int i = 0, n = parts_.length(); i < n; i++) {
+    int tag = parts_[i].tag;
+    if (tag <= 0) {  // A replacement string slice.
+      int from = -tag;
+      int to = parts_[i].data;
+      replacement_substrings_.Add(Factory::NewStringSlice(replacement,
+                                                          from,
+                                                          to));
+      parts_[i].tag = REPLACEMENT_SUBSTRING;
+      parts_[i].data = substring_index;
+      substring_index++;
+    } else if (tag == REPLACEMENT_STRING) {
+      replacement_substrings_.Add(replacement);
+      parts_[i].data = substring_index;
+      substring_index++;
+    }
+  }
+}
+
+
+void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
+                                int match_from,
+                                int match_to,
+                                Handle<JSArray> last_match_info) {
+  for (int i = 0, n = parts_.length(); i < n; i++) {
+    ReplacementPart part = parts_[i];
+    switch (part.tag) {
+      case SUBJECT_PREFIX:
+        if (match_from > 0) builder->AddSubjectSlice(0, match_from);
+        break;
+      case SUBJECT_SUFFIX: {
+        int subject_length = part.data;
+        if (match_to < subject_length) {
+          builder->AddSubjectSlice(match_to, subject_length);
+        }
+        break;
+      }
+      case SUBJECT_CAPTURE: {
+        int capture = part.data;
+        FixedArray* match_info = last_match_info->elements();
+        int from = RegExpImpl::GetCapture(match_info, capture * 2);
+        int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
+        if (from >= 0 && to > from) {
+          builder->AddSubjectSlice(from, to);
+        }
+        break;
+      }
+      case REPLACEMENT_SUBSTRING:
+      case REPLACEMENT_STRING:
+        builder->AddString(replacement_substrings_[part.data]);
+        break;
+      default:
+        UNREACHABLE();
+    }
+  }
+}
+
+
+
+static Object* StringReplaceRegExpWithString(String* subject,
+                                             JSRegExp* regexp,
+                                             String* replacement,
+                                             JSArray* last_match_info) {
+  ASSERT(subject->IsFlat());
+  ASSERT(replacement->IsFlat());
+
+  HandleScope handles;
+
+  int length = subject->length();
+  Handle<String> subject_handle(subject);
+  Handle<JSRegExp> regexp_handle(regexp);
+  Handle<String> replacement_handle(replacement);
+  Handle<JSArray> last_match_info_handle(last_match_info);
+  Handle<Object> match = RegExpImpl::Exec(regexp_handle,
+                                          subject_handle,
+                                          0,
+                                          last_match_info_handle);
+  if (match.is_null()) {
+    return Failure::Exception();
+  }
+  if (match->IsNull()) {
+    return *subject_handle;
+  }
+
+  int capture_count = regexp_handle->CaptureCount();
+
+  // CompiledReplacement uses zone allocation.
+  ZoneScope zone(DELETE_ON_EXIT);
+  CompiledReplacement compiled_replacement;
+  compiled_replacement.Compile(replacement_handle,
+                               capture_count,
+                               length);
+
+  bool is_global = regexp_handle->GetFlags().is_global();
+
+  // Guessing the number of parts that the final result string is built
+  // from. Global regexps can match any number of times, so we guess
+  // conservatively.
+  int expected_parts =
+      (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
+  ReplacementStringBuilder builder(subject_handle, expected_parts);
+
+  // Index of end of last match.
+  int prev = 0;
+
+  // Number of parts added by compiled replacement plus preceeding string
+  // and possibly suffix after last match.
+  const int parts_added_per_loop = compiled_replacement.parts() + 2;
+  bool matched = true;
+  do {
+    ASSERT(last_match_info_handle->HasFastElements());
+    // Increase the capacity of the builder before entering local handle-scope,
+    // so its internal buffer can safely allocate a new handle if it grows.
+    builder.EnsureCapacity(parts_added_per_loop);
+
+    HandleScope loop_scope;
+    int start, end;
+    {
+      AssertNoAllocation match_info_array_is_not_in_a_handle;
+      FixedArray* match_info_array = last_match_info_handle->elements();
+
+      ASSERT_EQ(capture_count * 2 + 2,
+                RegExpImpl::GetLastCaptureCount(match_info_array));
+      start = RegExpImpl::GetCapture(match_info_array, 0);
+      end = RegExpImpl::GetCapture(match_info_array, 1);
+    }
+
+    if (prev < start) {
+      builder.AddSubjectSlice(prev, start);
+    }
+    compiled_replacement.Apply(&builder,
+                               start,
+                               end,
+                               last_match_info_handle);
+    prev = end;
+
+    // Only continue checking for global regexps.
+    if (!is_global) break;
+
+    // Continue from where the match ended, unless it was an empty match.
+    int next = end;
+    if (start == end) {
+      next = end + 1;
+      if (next > length) break;
+    }
+
+    match = RegExpImpl::Exec(regexp_handle,
+                             subject_handle,
+                             next,
+                             last_match_info_handle);
+    if (match.is_null()) {
+      return Failure::Exception();
+    }
+    matched = !match->IsNull();
+  } while (matched);
+
+  if (prev < length) {
+    builder.AddSubjectSlice(prev, length);
+  }
+
+  return *(builder.ToString());
+}
+
+
+static Object* Runtime_StringReplaceRegExpWithString(Arguments args) {
+  ASSERT(args.length() == 4);
+
+  CONVERT_CHECKED(String, subject, args[0]);
+  if (!subject->IsFlat()) {
+    Object* flat_subject = subject->TryFlatten();
+    if (flat_subject->IsFailure()) {
+      return flat_subject;
+    }
+    subject = String::cast(flat_subject);
+  }
+
+  CONVERT_CHECKED(String, replacement, args[2]);
+  if (!replacement->IsFlat()) {
+    Object* flat_replacement = replacement->TryFlatten();
+    if (flat_replacement->IsFailure()) {
+      return flat_replacement;
+    }
+    replacement = String::cast(flat_replacement);
+  }
+
+  CONVERT_CHECKED(JSRegExp, regexp, args[1]);
+  CONVERT_CHECKED(JSArray, last_match_info, args[3]);
+
+  ASSERT(last_match_info->HasFastElements());
+
+  return StringReplaceRegExpWithString(subject,
+                                       regexp,
+                                       replacement,
+                                       last_match_info);
+}
+
+
 
 // Cap on the maximal shift in the Boyer-Moore implementation. By setting a
 // limit, we can fix the size of tables.
@@ -1245,10 +1949,10 @@
 // Uses only the bad-shift table of Boyer-Moore and only uses it
 // for the character compared to the last character of the needle.
 template <typename schar, typename pchar>
-static int BoyerMooreHorsepool(Vector<const schar> subject,
-                               Vector<const pchar> pattern,
-                               int start_index,
-                               bool* complete) {
+static int BoyerMooreHorspool(Vector<const schar> subject,
+                              Vector<const pchar> pattern,
+                              int start_index,
+                              bool* complete) {
   int n = subject.length();
   int m = pattern.length();
   // Only preprocess at most kBMMaxShift last characters of pattern.
@@ -1448,7 +2152,7 @@
   bool complete;
   int idx = SimpleIndexOf(sub, pat, start_index, &complete);
   if (complete) return idx;
-  idx = BoyerMooreHorsepool(sub, pat, idx, &complete);
+  idx = BoyerMooreHorspool(sub, pat, idx, &complete);
   if (complete) return idx;
   return BoyerMooreIndexOf(sub, pat, idx);
 }
@@ -1460,27 +2164,24 @@
                          Handle<String> pat,
                          int start_index) {
   ASSERT(0 <= start_index);
-  StringShape sub_shape(*sub);
-  ASSERT(start_index <= sub->length(sub_shape));
+  ASSERT(start_index <= sub->length());
 
   int pattern_length = pat->length();
   if (pattern_length == 0) return start_index;
 
-  int subject_length = sub->length(sub_shape);
+  int subject_length = sub->length();
   if (start_index + pattern_length > subject_length) return -1;
 
-  if (!sub->IsFlat(sub_shape)) {
+  if (!sub->IsFlat()) {
     FlattenString(sub);
-    sub_shape = StringShape(*sub);
   }
-  StringShape pat_shape(*pat);
   // Searching for one specific character is common.  For one
   // character patterns linear search is necessary, so any smart
   // algorithm is unnecessary overhead.
   if (pattern_length == 1) {
     AssertNoAllocation no_heap_allocation;  // ensure vectors stay valid
-    if (sub_shape.IsAsciiRepresentation()) {
-      uc16 pchar = pat->Get(pat_shape, 0);
+    if (StringShape(*sub).IsAsciiRepresentation()) {
+      uc16 pchar = pat->Get(0);
       if (pchar > String::kMaxAsciiCharCode) {
         return -1;
       }
@@ -1495,28 +2196,24 @@
       return reinterpret_cast<const char*>(pos) - ascii_vector.start()
           + start_index;
     }
-    return SingleCharIndexOf(sub->ToUC16Vector(),
-                             pat->Get(pat_shape, 0),
-                             start_index);
+    return SingleCharIndexOf(sub->ToUC16Vector(), pat->Get(0), start_index);
   }
 
-  if (!pat->IsFlat(pat_shape)) {
+  if (!pat->IsFlat()) {
     FlattenString(pat);
-    pat_shape = StringShape(*pat);
-    sub_shape = StringShape(*sub);
   }
 
   AssertNoAllocation no_heap_allocation;  // ensure vectors stay valid
   // dispatch on type of strings
-  if (pat_shape.IsAsciiRepresentation()) {
+  if (StringShape(*pat).IsAsciiRepresentation()) {
     Vector<const char> pat_vector = pat->ToAsciiVector();
-    if (sub_shape.IsAsciiRepresentation()) {
+    if (StringShape(*sub).IsAsciiRepresentation()) {
       return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index);
     }
     return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index);
   }
   Vector<const uc16> pat_vector = pat->ToUC16Vector();
-  if (sub_shape.IsAsciiRepresentation()) {
+  if (StringShape(*sub).IsAsciiRepresentation()) {
     return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index);
   }
   return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index);
@@ -1548,17 +2245,14 @@
   CONVERT_CHECKED(String, pat, args[1]);
   Object* index = args[2];
 
-  sub->TryFlattenIfNotFlat(StringShape(sub));
-  pat->TryFlattenIfNotFlat(StringShape(pat));
-
-  StringShape sub_shape(sub);
-  StringShape pat_shape(pat);
+  sub->TryFlattenIfNotFlat();
+  pat->TryFlattenIfNotFlat();
 
   uint32_t start_index;
   if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1);
 
-  uint32_t pattern_length = pat->length(pat_shape);
-  uint32_t sub_length = sub->length(sub_shape);
+  uint32_t pattern_length = pat->length();
+  uint32_t sub_length = sub->length();
 
   if (start_index + pattern_length > sub_length) {
     start_index = sub_length - pattern_length;
@@ -1567,7 +2261,7 @@
   for (int i = start_index; i >= 0; i--) {
     bool found = true;
     for (uint32_t j = 0; j < pattern_length; j++) {
-      if (sub->Get(sub_shape, i + j) != pat->Get(pat_shape, j)) {
+      if (sub->Get(i + j) != pat->Get(j)) {
         found = false;
         break;
       }
@@ -1587,10 +2281,8 @@
   CONVERT_CHECKED(String, str2, args[1]);
 
   if (str1 == str2) return Smi::FromInt(0);  // Equal.
-  StringShape shape1(str1);
-  StringShape shape2(str2);
-  int str1_length = str1->length(shape1);
-  int str2_length = str2->length(shape2);
+  int str1_length = str1->length();
+  int str2_length = str2->length();
 
   // Decide trivial cases without flattening.
   if (str1_length == 0) {
@@ -1605,11 +2297,11 @@
   // No need to flatten if we are going to find the answer on the first
   // character.  At this point we know there is at least one character
   // in each string, due to the trivial case handling above.
-  int d = str1->Get(shape1, 0) - str2->Get(shape2, 0);
+  int d = str1->Get(0) - str2->Get(0);
   if (d != 0) return Smi::FromInt(d);
 
-  str1->TryFlattenIfNotFlat(shape1);  // Shapes are no longer valid now!
-  str2->TryFlattenIfNotFlat(shape2);
+  str1->TryFlattenIfNotFlat();
+  str2->TryFlattenIfNotFlat();
 
   static StringInputBuffer buf1;
   static StringInputBuffer buf2;
@@ -1744,11 +2436,10 @@
 // Returns a single character string where first character equals
 // string->Get(index).
 static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
-  StringShape shape(*string);
-  if (index < static_cast<uint32_t>(string->length(shape))) {
-    string->TryFlattenIfNotFlat(shape);  // Invalidates shape!
+  if (index < static_cast<uint32_t>(string->length())) {
+    string->TryFlattenIfNotFlat();
     return LookupSingleCharacterStringFromCode(
-        string->Get(StringShape(*string), index));
+        string->Get(index));
   }
   return Execution::CharAt(string, index);
 }
@@ -1939,7 +2630,7 @@
       result = SetElement(js_object, index, value);
     } else {
       Handle<String> key_string = Handle<String>::cast(key);
-      key_string->TryFlattenIfNotFlat(StringShape(*key_string));
+      key_string->TryFlattenIfNotFlat();
       result = SetProperty(js_object, key_string, value, attr);
     }
     if (result.is_null()) return Failure::Exception();
@@ -2233,7 +2924,7 @@
   NoHandleAllocation ha;
   ASSERT(args.length() == 1);
   CONVERT_CHECKED(String, subject, args[0]);
-  subject->TryFlattenIfNotFlat(StringShape(subject));
+  subject->TryFlattenIfNotFlat();
   return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
 }
 
@@ -2263,11 +2954,10 @@
 
   if (object->IsFailure()) return object;
   String* result = String::cast(object);
-  StringShape result_shape(result);
   for (int i = 0; i < length; i++) {
     Object* element = codes->GetElement(i);
     CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
-    result->Set(result_shape, i, chr & 0xffff);
+    result->Set(i, chr & 0xffff);
   }
   return result;
 }
@@ -2316,7 +3006,7 @@
   ASSERT(args.length() == 1);
   CONVERT_CHECKED(String, source, args[0]);
 
-  source->TryFlattenIfNotFlat(StringShape(source));
+  source->TryFlattenIfNotFlat();
 
   int escaped_length = 0;
   int length = source->length();
@@ -2346,7 +3036,6 @@
   Object* o = Heap::AllocateRawAsciiString(escaped_length);
   if (o->IsFailure()) return o;
   String* destination = String::cast(o);
-  StringShape dshape(destination);
   int dest_position = 0;
 
   Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
@@ -2354,20 +3043,20 @@
   while (buffer->has_more()) {
     uint16_t chr = buffer->GetNext();
     if (chr >= 256) {
-      destination->Set(dshape, dest_position, '%');
-      destination->Set(dshape, dest_position+1, 'u');
-      destination->Set(dshape, dest_position+2, hex_chars[chr >> 12]);
-      destination->Set(dshape, dest_position+3, hex_chars[(chr >> 8) & 0xf]);
-      destination->Set(dshape, dest_position+4, hex_chars[(chr >> 4) & 0xf]);
-      destination->Set(dshape, dest_position+5, hex_chars[chr & 0xf]);
+      destination->Set(dest_position, '%');
+      destination->Set(dest_position+1, 'u');
+      destination->Set(dest_position+2, hex_chars[chr >> 12]);
+      destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
+      destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
+      destination->Set(dest_position+5, hex_chars[chr & 0xf]);
       dest_position += 6;
     } else if (IsNotEscaped(chr)) {
-      destination->Set(dshape, dest_position, chr);
+      destination->Set(dest_position, chr);
       dest_position++;
     } else {
-      destination->Set(dshape, dest_position, '%');
-      destination->Set(dshape, dest_position+1, hex_chars[chr >> 4]);
-      destination->Set(dshape, dest_position+2, hex_chars[chr & 0xf]);
+      destination->Set(dest_position, '%');
+      destination->Set(dest_position+1, hex_chars[chr >> 4]);
+      destination->Set(dest_position+2, hex_chars[chr & 0xf]);
       dest_position += 3;
     }
   }
@@ -2396,26 +3085,25 @@
 
 
 static inline int Unescape(String* source,
-                           StringShape shape,
                            int i,
                            int length,
                            int* step) {
-  uint16_t character = source->Get(shape, i);
+  uint16_t character = source->Get(i);
   int32_t hi = 0;
   int32_t lo = 0;
   if (character == '%' &&
       i <= length - 6 &&
-      source->Get(shape, i + 1) == 'u' &&
-      (hi = TwoDigitHex(source->Get(shape, i + 2),
-                        source->Get(shape, i + 3))) != -1 &&
-      (lo = TwoDigitHex(source->Get(shape, i + 4),
-                        source->Get(shape, i + 5))) != -1) {
+      source->Get(i + 1) == 'u' &&
+      (hi = TwoDigitHex(source->Get(i + 2),
+                        source->Get(i + 3))) != -1 &&
+      (lo = TwoDigitHex(source->Get(i + 4),
+                        source->Get(i + 5))) != -1) {
     *step = 6;
     return (hi << 8) + lo;
   } else if (character == '%' &&
       i <= length - 3 &&
-      (lo = TwoDigitHex(source->Get(shape, i + 1),
-                        source->Get(shape, i + 2))) != -1) {
+      (lo = TwoDigitHex(source->Get(i + 1),
+                        source->Get(i + 2))) != -1) {
     *step = 3;
     return lo;
   } else {
@@ -2430,22 +3118,17 @@
   ASSERT(args.length() == 1);
   CONVERT_CHECKED(String, source, args[0]);
 
-  source->TryFlattenIfNotFlat(StringShape(source));
-  StringShape source_shape(source);
+  source->TryFlattenIfNotFlat();
 
   bool ascii = true;
-  int length = source->length(source_shape);
+  int length = source->length();
 
   int unescaped_length = 0;
   for (int i = 0; i < length; unescaped_length++) {
     int step;
-    if (Unescape(source,
-                 source_shape,
-                 i,
-                 length,
-                 &step) >
-        String::kMaxAsciiCharCode)
+    if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
       ascii = false;
+    }
     i += step;
   }
 
@@ -2458,14 +3141,11 @@
               Heap::AllocateRawTwoByteString(unescaped_length);
   if (o->IsFailure()) return o;
   String* destination = String::cast(o);
-  StringShape destination_shape(destination);
 
   int dest_position = 0;
   for (int i = 0; i < length; dest_position++) {
     int step;
-    destination->Set(destination_shape,
-                     dest_position,
-                     Unescape(source, source_shape, i, length, &step));
+    destination->Set(dest_position, Unescape(source, i, length, &step));
     i += step;
   }
   return destination;
@@ -2479,33 +3159,31 @@
   CONVERT_DOUBLE_CHECKED(n, args[1]);
   int radix = FastD2I(n);
 
-  s->TryFlattenIfNotFlat(StringShape(s));
+  s->TryFlattenIfNotFlat();
 
-  StringShape shape(s);
-
-  int len = s->length(shape);
+  int len = s->length();
   int i;
 
   // Skip leading white space.
-  for (i = 0; i < len && Scanner::kIsWhiteSpace.get(s->Get(shape, i)); i++) ;
+  for (i = 0; i < len && Scanner::kIsWhiteSpace.get(s->Get(i)); i++) ;
   if (i == len) return Heap::nan_value();
 
   // Compute the sign (default to +).
   int sign = 1;
-  if (s->Get(shape, i) == '-') {
+  if (s->Get(i) == '-') {
     sign = -1;
     i++;
-  } else if (s->Get(shape, i) == '+') {
+  } else if (s->Get(i) == '+') {
     i++;
   }
 
   // Compute the radix if 0.
   if (radix == 0) {
     radix = 10;
-    if (i < len && s->Get(shape, i) == '0') {
+    if (i < len && s->Get(i) == '0') {
       radix = 8;
       if (i + 1 < len) {
-        int c = s->Get(shape, i + 1);
+        int c = s->Get(i + 1);
         if (c == 'x' || c == 'X') {
           radix = 16;
           i += 2;
@@ -2514,8 +3192,8 @@
     }
   } else if (radix == 16) {
     // Allow 0x or 0X prefix if radix is 16.
-    if (i + 1 < len && s->Get(shape, i) == '0') {
-      int c = s->Get(shape, i + 1);
+    if (i + 1 < len && s->Get(i) == '0') {
+      int c = s->Get(i + 1);
       if (c == 'x' || c == 'X') i += 2;
     }
   }
@@ -2547,40 +3225,26 @@
 
 
 template <class Converter>
-static Object* ConvertCase(Arguments args,
-                           unibrow::Mapping<Converter, 128>* mapping) {
-  NoHandleAllocation ha;
-
-  CONVERT_CHECKED(String, s, args[0]);
-  s->TryFlattenIfNotFlat(StringShape(s));
-  StringShape shape(s);
-
-  int raw_string_length = s->length(shape);
-  // Assume that the string is not empty; we need this assumption later
-  if (raw_string_length == 0) return s;
-  int length = raw_string_length;
-
-
-  // We try this twice, once with the assumption that the result is
-  // no longer than the input and, if that assumption breaks, again
-  // with the exact length.  This is implemented using a goto back
-  // to this label if we discover that the assumption doesn't hold.
-  // I apologize sincerely for this and will give a vaffel-is to
-  // the first person who can implement it in a nicer way.
- try_convert:
-
+static Object* ConvertCaseHelper(String* s,
+                                 int length,
+                                 int input_string_length,
+                                 unibrow::Mapping<Converter, 128>* mapping) {
+  // We try this twice, once with the assumption that the result is no longer
+  // than the input and, if that assumption breaks, again with the exact
+  // length.  This may not be pretty, but it is nicer than what was here before
+  // and I hereby claim my vaffel-is.
+  //
   // Allocate the resulting string.
   //
   // NOTE: This assumes that the upper/lower case of an ascii
   // character is also ascii.  This is currently the case, but it
   // might break in the future if we implement more context and locale
   // dependent upper/lower conversions.
-  Object* o = shape.IsAsciiRepresentation()
+  Object* o = StringShape(s).IsAsciiRepresentation()
       ? Heap::AllocateRawAsciiString(length)
       : Heap::AllocateRawTwoByteString(length);
   if (o->IsFailure()) return o;
   String* result = String::cast(o);
-  StringShape result_shape(result);
   bool has_changed_character = false;
 
   // Convert all characters to upper case, assuming that they will fit
@@ -2588,24 +3252,23 @@
   Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
   buffer->Reset(s);
   unibrow::uchar chars[Converter::kMaxWidth];
-  int i = 0;
   // We can assume that the string is not empty
   uc32 current = buffer->GetNext();
-  while (i < length) {
+  for (int i = 0; i < length;) {
     bool has_next = buffer->has_more();
     uc32 next = has_next ? buffer->GetNext() : 0;
     int char_length = mapping->get(current, next, chars);
     if (char_length == 0) {
       // The case conversion of this character is the character itself.
-      result->Set(result_shape, i, current);
+      result->Set(i, current);
       i++;
     } else if (char_length == 1) {
       // Common case: converting the letter resulted in one character.
       ASSERT(static_cast<uc32>(chars[0]) != current);
-      result->Set(result_shape, i, chars[0]);
+      result->Set(i, chars[0]);
       has_changed_character = true;
       i++;
-    } else if (length == raw_string_length) {
+    } else if (length == input_string_length) {
       // We've assumed that the result would be as long as the
       // input but here is a character that converts to several
       // characters.  No matter, we calculate the exact length
@@ -2632,12 +3295,16 @@
         int char_length = mapping->get(current, 0, chars);
         if (char_length == 0) char_length = 1;
         current_length += char_length;
+        if (current_length > Smi::kMaxValue) {
+          Top::context()->mark_out_of_memory();
+          return Failure::OutOfMemoryException();
+        }
       }
-      length = current_length;
-      goto try_convert;
+      // Try again with the real length.
+      return Smi::FromInt(current_length);
     } else {
       for (int j = 0; j < char_length; j++) {
-        result->Set(result_shape, i, chars[j]);
+        result->Set(i, chars[j]);
         i++;
       }
       has_changed_character = true;
@@ -2656,6 +3323,28 @@
 }
 
 
+template <class Converter>
+static Object* ConvertCase(Arguments args,
+                           unibrow::Mapping<Converter, 128>* mapping) {
+  NoHandleAllocation ha;
+
+  CONVERT_CHECKED(String, s, args[0]);
+  s->TryFlattenIfNotFlat();
+
+  int input_string_length = s->length();
+  // Assume that the string is not empty; we need this assumption later
+  if (input_string_length == 0) return s;
+  int length = input_string_length;
+
+  Object* answer = ConvertCaseHelper(s, length, length, mapping);
+  if (answer->IsSmi()) {
+    // Retry with correct length.
+    answer = ConvertCaseHelper(s, Smi::cast(answer)->value(), length, mapping);
+  }
+  return answer;  // This may be a failure.
+}
+
+
 static Object* Runtime_StringToLowerCase(Arguments args) {
   return ConvertCase<unibrow::ToLowercase>(args, &to_lower_mapping);
 }
@@ -2842,7 +3531,6 @@
 
 template<typename sinkchar>
 static inline void StringBuilderConcatHelper(String* special,
-                                             StringShape special_shape,
                                              sinkchar* sink,
                                              FixedArray* fixed_array,
                                              int array_length) {
@@ -2850,20 +3538,18 @@
   for (int i = 0; i < array_length; i++) {
     Object* element = fixed_array->get(i);
     if (element->IsSmi()) {
-      int len = Smi::cast(element)->value();
-      int pos = len >> 11;
-      len &= 0x7ff;
+      int encoded_slice = Smi::cast(element)->value();
+      int pos = StringBuilderSubstringPosition::decode(encoded_slice);
+      int len = StringBuilderSubstringLength::decode(encoded_slice);
       String::WriteToFlat(special,
-                          special_shape,
                           sink + position,
                           pos,
                           pos + len);
       position += len;
     } else {
       String* string = String::cast(element);
-      StringShape shape(string);
-      int element_length = string->length(shape);
-      String::WriteToFlat(string, shape, sink + position, 0, element_length);
+      int element_length = string->length();
+      String::WriteToFlat(string, sink + position, 0, element_length);
       position += element_length;
     }
   }
@@ -2875,8 +3561,7 @@
   ASSERT(args.length() == 2);
   CONVERT_CHECKED(JSArray, array, args[0]);
   CONVERT_CHECKED(String, special, args[1]);
-  StringShape special_shape(special);
-  int special_length = special->length(special_shape);
+  int special_length = special->length();
   Object* smi_array_length = array->length();
   if (!smi_array_length->IsSmi()) {
     Top::context()->mark_out_of_memory();
@@ -2898,7 +3583,7 @@
     if (first->IsString()) return first;
   }
 
-  bool ascii = special_shape.IsAsciiRepresentation();
+  bool ascii = StringShape(special).IsAsciiRepresentation();
   int position = 0;
   for (int i = 0; i < array_length; i++) {
     Object* elt = fixed_array->get(i);
@@ -2912,14 +3597,13 @@
       position += len;
     } else if (elt->IsString()) {
       String* element = String::cast(elt);
-      StringShape element_shape(element);
-      int element_length = element->length(element_shape);
+      int element_length = element->length();
       if (!Smi::IsValid(element_length + position)) {
         Top::context()->mark_out_of_memory();
         return Failure::OutOfMemoryException();
       }
       position += element_length;
-      if (ascii && !element_shape.IsAsciiRepresentation()) {
+      if (ascii && !StringShape(element).IsAsciiRepresentation()) {
         ascii = false;
       }
     } else {
@@ -2935,7 +3619,6 @@
     if (object->IsFailure()) return object;
     SeqAsciiString* answer = SeqAsciiString::cast(object);
     StringBuilderConcatHelper(special,
-                              special_shape,
                               answer->GetChars(),
                               fixed_array,
                               array_length);
@@ -2945,7 +3628,6 @@
     if (object->IsFailure()) return object;
     SeqTwoByteString* answer = SeqTwoByteString::cast(object);
     StringBuilderConcatHelper(special,
-                              special_shape,
                               answer->GetChars(),
                               fixed_array,
                               array_length);
@@ -3140,24 +3822,21 @@
   CONVERT_CHECKED(String, x, args[0]);
   CONVERT_CHECKED(String, y, args[1]);
 
-  StringShape x_shape(x);
-  StringShape y_shape(y);
-
   // A few fast case tests before we flatten.
   if (x == y) return Smi::FromInt(EQUAL);
-  if (y->length(y_shape) == 0) {
-    if (x->length(x_shape) == 0) return Smi::FromInt(EQUAL);
+  if (y->length() == 0) {
+    if (x->length() == 0) return Smi::FromInt(EQUAL);
     return Smi::FromInt(GREATER);
-  } else if (x->length(x_shape) == 0) {
+  } else if (x->length() == 0) {
     return Smi::FromInt(LESS);
   }
 
-  int d = x->Get(x_shape, 0) - y->Get(y_shape, 0);
+  int d = x->Get(0) - y->Get(0);
   if (d < 0) return Smi::FromInt(LESS);
   else if (d > 0) return Smi::FromInt(GREATER);
 
-  x->TryFlattenIfNotFlat(x_shape);  // Shapes are no longer valid!
-  y->TryFlattenIfNotFlat(y_shape);
+  x->TryFlattenIfNotFlat();
+  y->TryFlattenIfNotFlat();
 
   static StringInputBuffer bufx;
   static StringInputBuffer bufy;
@@ -3753,8 +4432,10 @@
     context_ext = Handle<JSObject>(Top::context()->global());
   }
 
-  // Set the property, but ignore if read_only variable.
-  if ((attributes & READ_ONLY) == 0) {
+  // Set the property, but ignore if read_only variable on the context
+  // extension object itself.
+  if ((attributes & READ_ONLY) == 0 ||
+      (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
     Handle<Object> set = SetProperty(context_ext, name, value, attributes);
     if (set.is_null()) {
       // Failure::Exception is converted to a null handle in the
@@ -3970,16 +4651,30 @@
 
 static Object* Runtime_DateParseString(Arguments args) {
   HandleScope scope;
-  ASSERT(args.length() == 1);
+  ASSERT(args.length() == 2);
 
-  CONVERT_CHECKED(String, string_object, args[0]);
+  CONVERT_ARG_CHECKED(String, str, 0);
+  FlattenString(str);
 
-  Handle<String> str(string_object);
-  Handle<FixedArray> output = Factory::NewFixedArray(DateParser::OUTPUT_SIZE);
-  if (DateParser::Parse(*str, *output)) {
-    return *Factory::NewJSArrayWithElements(output);
+  CONVERT_ARG_CHECKED(JSArray, output, 1);
+  RUNTIME_ASSERT(output->HasFastElements());
+
+  AssertNoAllocation no_allocation;
+
+  FixedArray* output_array = output->elements();
+  RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
+  bool result;
+  if (StringShape(*str).IsAsciiRepresentation()) {
+    result = DateParser::Parse(str->ToAsciiVector(), output_array);
   } else {
-    return *Factory::null_value();
+    ASSERT(StringShape(*str).IsTwoByteRepresentation());
+    result = DateParser::Parse(str->ToUC16Vector(), output_array);
+  }
+
+  if (result) {
+    return *output;
+  } else {
+    return Heap::null_value();
   }
 }
 
@@ -5223,6 +5918,78 @@
 }
 
 
+static Object* Runtime_GetThreadCount(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 1);
+
+  // Check arguments.
+  Object* result = Runtime_CheckExecutionState(args);
+  if (result->IsFailure()) return result;
+
+  // Count all archived V8 threads.
+  int n = 0;
+  for (ThreadState* thread = ThreadState::FirstInUse();
+       thread != NULL;
+       thread = thread->Next()) {
+    n++;
+  }
+
+  // Total number of threads is current thread and archived threads.
+  return Smi::FromInt(n + 1);
+}
+
+
+static const int kThreadDetailsCurrentThreadIndex = 0;
+static const int kThreadDetailsThreadIdIndex = 1;
+static const int kThreadDetailsSize = 2;
+
+// Return an array with thread details
+// args[0]: number: break id
+// args[1]: number: thread index
+//
+// The array returned contains the following information:
+// 0: Is current thread?
+// 1: Thread id
+static Object* Runtime_GetThreadDetails(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 2);
+
+  // Check arguments.
+  Object* check = Runtime_CheckExecutionState(args);
+  if (check->IsFailure()) return check;
+  CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
+
+  // Allocate array for result.
+  Handle<FixedArray> details = Factory::NewFixedArray(kThreadDetailsSize);
+
+  // Thread index 0 is current thread.
+  if (index == 0) {
+    // Fill the details.
+    details->set(kThreadDetailsCurrentThreadIndex, Heap::true_value());
+    details->set(kThreadDetailsThreadIdIndex,
+                 Smi::FromInt(ThreadManager::CurrentId()));
+  } else {
+    // Find the thread with the requested index.
+    int n = 1;
+    ThreadState* thread = ThreadState::FirstInUse();
+    while (index != n && thread != NULL) {
+      thread = thread->Next();
+      n++;
+    }
+    if (thread == NULL) {
+      return Heap::undefined_value();
+    }
+
+    // Fill the details.
+    details->set(kThreadDetailsCurrentThreadIndex, Heap::false_value());
+    details->set(kThreadDetailsThreadIdIndex, Smi::FromInt(thread->id()));
+  }
+
+  // Convert to JS array and return.
+  return *Factory::NewJSArrayWithElements(details);
+}
+
+
 static Object* Runtime_GetBreakLocations(Arguments args) {
   HandleScope scope;
   ASSERT(args.length() == 1);
diff --git a/src/runtime.h b/src/runtime.h
index 5377e42..3bed31b 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -146,6 +146,7 @@
   F(StringLastIndexOf, 3) \
   F(StringLocaleCompare, 2) \
   F(StringSlice, 3) \
+  F(StringReplaceRegExpWithString, 4) \
   \
   /* Numbers */ \
   F(NumberToRadixString, 2) \
@@ -184,7 +185,7 @@
   \
   /* Dates */ \
   F(DateCurrentTime, 0) \
-  F(DateParseString, 1) \
+  F(DateParseString, 2) \
   F(DateLocalTimezone, 1) \
   F(DateLocalTimeOffset, 0) \
   F(DateDaylightSavingsOffset, 1) \
@@ -233,6 +234,8 @@
   F(GetFrameCount, 1) \
   F(GetFrameDetails, 2) \
   F(GetCFrames, 1) \
+  F(GetThreadCount, 1) \
+  F(GetThreadDetails, 2) \
   F(GetBreakLocations, 1) \
   F(SetFunctionBreakPoint, 3) \
   F(SetScriptBreakPoint, 3) \
@@ -250,9 +253,10 @@
   \
   /* Literals */ \
   F(MaterializeRegExpLiteral, 4)\
-  F(CreateArrayLiteral, 2) \
+  F(CreateArrayLiteralBoilerplate, 3) \
   F(CreateObjectLiteralBoilerplate, 3) \
-  F(CloneObjectLiteralBoilerplate, 1) \
+  F(CloneLiteralBoilerplate, 1) \
+  F(CloneShallowLiteralBoilerplate, 1) \
   \
   /* Catch context extension objects */ \
   F(CreateCatchExtensionObject, 2) \
@@ -325,7 +329,6 @@
     kNofFunctions
 #undef F
   };
-  static Object* CreateArrayLiteral(Arguments args);
 
   // Runtime function descriptor.
   struct Function {
diff --git a/src/string.js b/src/string.js
index f8efab6..18ef3d8 100644
--- a/src/string.js
+++ b/src/string.js
@@ -236,51 +236,16 @@
 // needle is a string rather than a regexp.  In this case we can't update
 // lastMatchArray without erroneously affecting the properties on the global
 // RegExp object.
-var reusableMatchInfo = [2, -1, -1, "", ""];
-var reusableMatchArray = [ void 0 ];
+var reusableMatchInfo = [2, "", "", -1, -1];
 
 
 // Helper function for regular expressions in String.prototype.replace.
 function StringReplaceRegExp(subject, regexp, replace) {
-  // Compute an array of matches; each match is really a list of
-  // captures - pairs of (start, end) indexes into the subject string.
-  var matches;
-  if (regexp.global) {
-    matches = DoRegExpExecGlobal(regexp, subject);
-    if (matches.length == 0) return subject;
-  } else {
-    var lastMatchInfo = DoRegExpExec(regexp, subject, 0);
-    if (IS_NULL(lastMatchInfo)) return subject;
-    reusableMatchArray[0] = lastMatchInfo;
-    matches = reusableMatchArray;
-  }
-
-  // Determine the number of matches.
-  var length = matches.length;
-
-  // Build the resulting string of subject slices and replacements.
-  var result = new ReplaceResultBuilder(subject);
-  var previous = 0;
-  // The caller of StringReplaceRegExp must ensure that replace is not a
-  // function.
   replace = ToString(replace);
-  if (%StringIndexOf(replace, "$", 0) < 0) {
-    for (var i = 0; i < length; i++) {
-      var matchInfo = matches[i];
-      result.addSpecialSlice(previous, matchInfo[CAPTURE0]);
-      result.add(replace);
-      previous = matchInfo[CAPTURE1];  // continue after match
-    }
-  } else {
-    for (var i = 0; i < length; i++) {
-      var matchInfo = matches[i];
-      result.addSpecialSlice(previous, matchInfo[CAPTURE0]);
-      ExpandReplacement(replace, subject, matchInfo, result);
-      previous = matchInfo[CAPTURE1];  // continue after match
-    }
-  }
-  result.addSpecialSlice(previous, subject.length);
-  return result.generate();
+  return %StringReplaceRegExpWithString(subject,
+                                        regexp,
+                                        replace,
+                                        lastMatchInfo);
 };
 
 
diff --git a/src/unicode.cc b/src/unicode.cc
index 8b06dba..4a9e070 100644
--- a/src/unicode.cc
+++ b/src/unicode.cc
@@ -28,8 +28,8 @@
 // This file was generated at 2008-11-25 16:02:40.592795
 
 #include "unicode-inl.h"
-#include <cstdlib>
-#include <cstdio>
+#include <stdlib.h>
+#include <stdio.h>
 
 namespace unibrow {
 
diff --git a/src/v8-counters.cc b/src/v8-counters.cc
index 473dbd3..3a8286a 100644
--- a/src/v8-counters.cc
+++ b/src/v8-counters.cc
@@ -31,12 +31,10 @@
 
 namespace v8 { namespace internal {
 
-#define SR(name, caption) \
-  StatsRate Counters::name = { \
-  { { "t:" #caption, NULL, false }, 0, 0 }, \
-  { "c:" #caption, NULL, false } };
+#define HT(name, caption) \
+  HistogramTimer Counters::name = { #caption, NULL, false, 0, 0 }; \
 
-  STATS_RATE_LIST(SR)
+  HISTOGRAM_TIMER_LIST(HT)
 #undef SR
 
 #define SC(name, caption) \
diff --git a/src/v8-counters.h b/src/v8-counters.h
index acd3b23..6596dbf 100644
--- a/src/v8-counters.h
+++ b/src/v8-counters.h
@@ -32,16 +32,16 @@
 
 namespace v8 { namespace internal {
 
-#define STATS_RATE_LIST(SR)                                             \
-  SR(gc_compactor, V8.GCCompactor) /* GC Compactor time */              \
-  SR(gc_scavenger, V8.GCScavenger) /* GC Scavenger time */              \
-  SR(gc_context, V8.GCContext)     /* GC context cleanup time */        \
-  SR(compile, V8.Compile)          /* Compile time*/                    \
-  SR(compile_eval, V8.CompileEval) /* Eval compile time */              \
-  SR(compile_lazy, V8.CompileLazy) /* Lazy compile time */              \
-  SR(parse, V8.Parse)              /* Parse time */                     \
-  SR(parse_lazy, V8.ParseLazy)     /* Lazy parse time */                \
-  SR(pre_parse, V8.PreParse)       /* Pre-parse time */
+#define HISTOGRAM_TIMER_LIST(HT)                                 \
+  HT(gc_compactor, V8.GCCompactor) /* GC Compactor time */       \
+  HT(gc_scavenger, V8.GCScavenger) /* GC Scavenger time */       \
+  HT(gc_context, V8.GCContext)     /* GC context cleanup time */ \
+  HT(compile, V8.Compile)          /* Compile time*/             \
+  HT(compile_eval, V8.CompileEval) /* Eval compile time */       \
+  HT(compile_lazy, V8.CompileLazy) /* Lazy compile time */       \
+  HT(parse, V8.Parse)              /* Parse time */              \
+  HT(parse_lazy, V8.ParseLazy)     /* Lazy parse time */         \
+  HT(pre_parse, V8.PreParse)       /* Pre-parse time */
 
 // WARNING: STATS_COUNTER_LIST_* is a very large macro that is causing MSVC
 // Intellisense to crash.  It was broken into two macros (each of length 40
@@ -128,10 +128,10 @@
 // This file contains all the v8 counters that are in use.
 class Counters : AllStatic {
  public:
-#define SR(name, caption) \
-  static StatsRate name;
-  STATS_RATE_LIST(SR)
-#undef SR
+#define HT(name, caption) \
+  static HistogramTimer name;
+  HISTOGRAM_TIMER_LIST(HT)
+#undef HT
 
 #define SC(name, caption) \
   static StatsCounter name;
@@ -141,7 +141,7 @@
 
   enum Id {
 #define RATE_ID(name, caption) k_##name,
-    STATS_RATE_LIST(RATE_ID)
+    HISTOGRAM_TIMER_LIST(RATE_ID)
 #undef RATE_ID
 #define COUNTER_ID(name, caption) k_##name,
   STATS_COUNTER_LIST_1(COUNTER_ID)
diff --git a/src/v8natives.js b/src/v8natives.js
index 094f79c..9772e2f 100644
--- a/src/v8natives.js
+++ b/src/v8natives.js
@@ -74,7 +74,6 @@
 // ECMA-262 - 15.1.2.2
 function GlobalParseInt(string, radix) {
   if (radix === void 0) {
-    radix = 0;
     // Some people use parseInt instead of Math.floor.  This
     // optimization makes parseInt on a Smi 12 times faster (60ns
     // vs 800ns).  The following optimization makes parseInt on a
@@ -87,6 +86,7 @@
       // Truncate number.
       return string | 0;
     }
+    radix = 0;
   } else {
     radix = TO_INT32(radix);
     if (!(radix == 0 || (2 <= radix && radix <= 36)))
diff --git a/src/v8threads.cc b/src/v8threads.cc
index f4a7f72..e8f6f9b 100644
--- a/src/v8threads.cc
+++ b/src/v8threads.cc
@@ -38,6 +38,8 @@
 
 static internal::Thread::LocalStorageKey thread_state_key =
     internal::Thread::CreateThreadLocalKey();
+static internal::Thread::LocalStorageKey thread_id_key =
+    internal::Thread::CreateThreadLocalKey();
 
 
 // Track whether this V8 instance has ever called v8::Locker. This allows the
@@ -61,6 +63,9 @@
     }
   }
   ASSERT(internal::ThreadManager::IsLockedByCurrentThread());
+
+  // Make sure this thread is assigned a thread id.
+  internal::ThreadManager::AssignId();
 }
 
 
@@ -115,6 +120,7 @@
     lazily_archived_thread_.Initialize(ThreadHandle::INVALID);
     ASSERT(Thread::GetThreadLocal(thread_state_key) ==
            lazily_archived_thread_state_);
+    lazily_archived_thread_state_->set_id(kInvalidId);
     lazily_archived_thread_state_->LinkInto(ThreadState::FREE_LIST);
     lazily_archived_thread_state_ = NULL;
     Thread::SetThreadLocal(thread_state_key, NULL);
@@ -143,6 +149,7 @@
   from = RegExpStack::RestoreStack(from);
   from = Bootstrapper::RestoreState(from);
   Thread::SetThreadLocal(thread_state_key, NULL);
+  state->set_id(kInvalidId);
   state->Unlink();
   state->LinkInto(ThreadState::FREE_LIST);
   return true;
@@ -176,7 +183,8 @@
 ThreadState* ThreadState::in_use_anchor_ = new ThreadState();
 
 
-ThreadState::ThreadState() : next_(this), previous_(this) {
+ThreadState::ThreadState() : id_(ThreadManager::kInvalidId),
+                             next_(this), previous_(this) {
 }
 
 
@@ -224,6 +232,7 @@
 }
 
 
+int ThreadManager::next_id_ = 0;
 Mutex* ThreadManager::mutex_ = OS::CreateMutex();
 ThreadHandle ThreadManager::mutex_owner_(ThreadHandle::INVALID);
 ThreadHandle ThreadManager::lazily_archived_thread_(ThreadHandle::INVALID);
@@ -238,6 +247,9 @@
   Thread::SetThreadLocal(thread_state_key, reinterpret_cast<void*>(state));
   lazily_archived_thread_.Initialize(ThreadHandle::SELF);
   lazily_archived_thread_state_ = state;
+  ASSERT(state->id() == kInvalidId);
+  state->set_id(CurrentId());
+  ASSERT(state->id() != kInvalidId);
 }
 
 
@@ -290,6 +302,18 @@
 }
 
 
+int ThreadManager::CurrentId() {
+  return bit_cast<int, void*>(Thread::GetThreadLocal(thread_id_key));
+}
+
+
+void ThreadManager::AssignId() {
+  if (Thread::GetThreadLocal(thread_id_key) == NULL) {
+    Thread::SetThreadLocal(thread_id_key, bit_cast<void*, int>(next_id_++));
+  }
+}
+
+
 // This is the ContextSwitcher singleton. There is at most a single thread
 // running which delivers preemption events to V8 threads.
 ContextSwitcher* ContextSwitcher::singleton_ = NULL;
diff --git a/src/v8threads.h b/src/v8threads.h
index 35db9ad..b651fc3 100644
--- a/src/v8threads.h
+++ b/src/v8threads.h
@@ -45,6 +45,10 @@
 
   static ThreadState* GetFree();
 
+  // Id of thread.
+  void set_id(int id) { id_ = id; }
+  int id() { return id_; }
+
   // Get data area for archiving a thread.
   char* data() { return data_; }
  private:
@@ -52,9 +56,11 @@
 
   void AllocateSpace();
 
+  int id_;
   char* data_;
   ThreadState* next_;
   ThreadState* previous_;
+
   // In the following two lists there is always at least one object on the list.
   // The first object is a flying anchor that is only there to simplify linking
   // and unlinking.
@@ -77,9 +83,15 @@
   static void MarkCompactPrologue(bool is_compacting);
   static void MarkCompactEpilogue(bool is_compacting);
   static bool IsLockedByCurrentThread() { return mutex_owner_.IsSelf(); }
+
+  static int CurrentId();
+  static void AssignId();
+
+  static const int kInvalidId = -1;
  private:
   static void EagerlyArchiveThread();
 
+  static int next_id_;  // V8 threads are identified through an integer.
   static Mutex* mutex_;
   static ThreadHandle mutex_owner_;
   static ThreadHandle lazily_archived_thread_;
diff --git a/src/virtual-frame-arm.cc b/src/virtual-frame-arm.cc
index d375638..5d48a9c 100644
--- a/src/virtual-frame-arm.cc
+++ b/src/virtual-frame-arm.cc
@@ -27,9 +27,9 @@
 
 #include "v8.h"
 
-#include "codegen.h"
 #include "codegen-inl.h"
-#include "virtual-frame.h"
+#include "register-allocator-inl.h"
+#include "scopes.h"
 
 namespace v8 { namespace internal {
 
@@ -290,14 +290,9 @@
 }
 
 
-// Before changing an element which is copied, adjust so that the
-// first copy becomes the new backing store and all the other copies
-// are updated.  If the original was in memory, the new backing store
-// is allocated to a register.  Return a copy of the new backing store
-// or an invalid element if the original was not a copy.
-FrameElement VirtualFrame::AdjustCopies(int index) {
+int VirtualFrame::InvalidateFrameSlotAt(int index) {
   UNIMPLEMENTED();
-  return FrameElement::InvalidElement();
+  return kIllegalIndex;
 }
 
 
diff --git a/src/virtual-frame-arm.h b/src/virtual-frame-arm.h
index 99b0a82..e05e087 100644
--- a/src/virtual-frame-arm.h
+++ b/src/virtual-frame-arm.h
@@ -28,6 +28,8 @@
 #ifndef V8_VIRTUAL_FRAME_ARM_H_
 #define V8_VIRTUAL_FRAME_ARM_H_
 
+#include "register-allocator.h"
+
 namespace v8 { namespace internal {
 
 // -------------------------------------------------------------------------
@@ -57,6 +59,9 @@
     bool previous_state_;
   };
 
+  // An illegal index into the virtual frame.
+  static const int kIllegalIndex = -1;
+
   // Construct an initial virtual frame on entry to a JS function.
   explicit VirtualFrame(CodeGenerator* cgen);
 
@@ -310,9 +315,6 @@
   void Nip(int num_dropped);
 
  private:
-  // An illegal index into the virtual frame.
-  static const int kIllegalIndex = -1;
-
   static const int kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset;
   static const int kFunctionOffset = JavaScriptFrameConstants::kFunctionOffset;
   static const int kContextOffset = StandardFrameConstants::kContextOffset;
@@ -438,13 +440,12 @@
   // should be equal.
   void MergeMoveMemoryToRegisters(VirtualFrame* expected);
 
-  // Helper function to implement the copy-on-write semantics of an
-  // element's copies just before writing to the element.  The copies
-  // are updated, but the element is not changed.  A copy of the new
-  // backing store of all the copies is returned if there were any
-  // copies and in invalid frame element is returned if there were no
-  // copies.
-  FrameElement AdjustCopies(int index);
+  // Invalidates a frame slot (puts an invalid frame element in it).
+  // Copies on the frame are correctly handled, and if this slot was
+  // the backing store of copies, the index of the new backing store
+  // is returned.  Otherwise, returns kIllegalIndex.
+  // Register counts are correctly updated.
+  int InvalidateFrameSlotAt(int index);
 
   // Call a code stub that has already been prepared for calling (via
   // PrepareForCall).
diff --git a/src/virtual-frame-ia32.cc b/src/virtual-frame-ia32.cc
index b31c394..bdd8373 100644
--- a/src/virtual-frame-ia32.cc
+++ b/src/virtual-frame-ia32.cc
@@ -27,9 +27,9 @@
 
 #include "v8.h"
 
-#include "codegen.h"
 #include "codegen-inl.h"
-#include "virtual-frame.h"
+#include "register-allocator-inl.h"
+#include "scopes.h"
 
 namespace v8 { namespace internal {
 
@@ -171,11 +171,10 @@
   MergeMoveRegistersToRegisters(expected);
   MergeMoveMemoryToRegisters(expected);
 
-  // Fix any sync bit problems from the bottom-up, stopping when we
-  // hit the stack pointer or the top of the frame if the stack
-  // pointer is floating above the frame.
-  int limit = Min(stack_pointer_, elements_.length() - 1);
-  for (int i = 0; i <= limit; i++) {
+  // Fix any sync flag problems from the bottom-up and make the copied
+  // flags exact.  This assumes that the backing store of copies is
+  // always lower in the frame.
+  for (int i = 0; i < elements_.length(); i++) {
     FrameElement source = elements_[i];
     FrameElement target = expected->elements_[i];
     if (source.is_synced() && !target.is_synced()) {
@@ -183,6 +182,10 @@
     } else if (!source.is_synced() && target.is_synced()) {
       SyncElementAt(i);
     }
+    elements_[i].clear_copied();
+    if (elements_[i].is_copy()) {
+      elements_[elements_[i].index()].set_copied();
+    }
   }
 
   // Adjust the stack point downard if necessary.
@@ -495,62 +498,60 @@
 }
 
 
-// Before changing an element which is copied, adjust so that the
-// first copy becomes the new backing store and all the other copies
-// are updated.  If the original was in memory, the new backing store
-// is allocated to a register.  Return a copy of the new backing store
-// or an invalid element if the original was not a copy.
-FrameElement VirtualFrame::AdjustCopies(int index) {
+int VirtualFrame::InvalidateFrameSlotAt(int index) {
   FrameElement original = elements_[index];
-  ASSERT(original.is_memory() || original.is_register());
 
-  // Go looking for a first copy above index.
-  int i = index + 1;
-  while (i < elements_.length()) {
-    FrameElement elt = elements_[i];
-    if (elt.is_copy() && elt.index() == index) break;
-    i++;
-  }
-
-  if (i < elements_.length()) {
-    // There was a first copy.  Make it the new backing element.
-    Register backing_reg;
-    if (original.is_memory()) {
-      Result fresh = cgen_->allocator()->Allocate();
-      ASSERT(fresh.is_valid());
-      backing_reg = fresh.reg();
-      __ mov(backing_reg, Operand(ebp, fp_relative(index)));
-    } else {
-      // The original was in a register.
-      backing_reg = original.reg();
-    }
-    FrameElement new_backing_element =
-        FrameElement::RegisterElement(backing_reg, FrameElement::NOT_SYNCED);
-    if (elements_[i].is_synced()) {
-      new_backing_element.set_sync();
-    }
-    Use(backing_reg);
-    elements_[i] = new_backing_element;
-
-    // Update the other copies.
-    FrameElement copy = CopyElementAt(i);
-    for (int j = i; j < elements_.length(); j++) {
-      FrameElement elt = elements_[j];
-      if (elt.is_copy() && elt.index() == index) {
-        if (elt.is_synced()) {
-          copy.set_sync();
-        } else {
-          copy.clear_sync();
-        }
-        elements_[j] = copy;
+  // Is this element the backing store of any copies?
+  int new_backing_index = kIllegalIndex;
+  if (original.is_copied()) {
+    // Verify it is copied, and find first copy.
+    for (int i = index + 1; i < elements_.length(); i++) {
+      if (elements_[i].is_copy() && elements_[i].index() == index) {
+        new_backing_index = i;
+        break;
       }
     }
-
-    copy.clear_sync();
-    return copy;
   }
 
-  return FrameElement::InvalidElement();
+  if (new_backing_index == kIllegalIndex) {
+    // No copies found, return kIllegalIndex.
+    if (original.is_register()) {
+      Unuse(original.reg());
+    }
+    elements_[index] = FrameElement::InvalidElement();
+    return kIllegalIndex;
+  }
+
+  // This is the backing store of copies.
+  Register backing_reg;
+  if (original.is_memory()) {
+    Result fresh = cgen_->allocator()->Allocate();
+    ASSERT(fresh.is_valid());
+    Use(fresh.reg());
+    backing_reg = fresh.reg();
+    __ mov(backing_reg, Operand(ebp, fp_relative(index)));
+  } else {
+    // The original was in a register.
+    backing_reg = original.reg();
+  }
+  // Invalidate the element at index.
+  elements_[index] = FrameElement::InvalidElement();
+  // Set the new backing element.
+  if (elements_[new_backing_index].is_synced()) {
+    elements_[new_backing_index] =
+        FrameElement::RegisterElement(backing_reg, FrameElement::SYNCED);
+  } else {
+    elements_[new_backing_index] =
+        FrameElement::RegisterElement(backing_reg, FrameElement::NOT_SYNCED);
+  }
+  // Update the other copies.
+  for (int i = new_backing_index + 1; i < elements_.length(); i++) {
+    if (elements_[i].is_copy() && elements_[i].index() == index) {
+      elements_[i].set_index(new_backing_index);
+      elements_[new_backing_index].set_copied();
+    }
+  }
+  return new_backing_index;
 }
 
 
@@ -558,69 +559,38 @@
   ASSERT(index >= 0);
   ASSERT(index <= elements_.length());
   FrameElement original = elements_[index];
+  int new_backing_store_index = InvalidateFrameSlotAt(index);
+  if (new_backing_store_index != kIllegalIndex) {
+    elements_.Add(CopyElementAt(new_backing_store_index));
+    return;
+  }
 
   switch (original.type()) {
-    case FrameElement::INVALID:
-      UNREACHABLE();
-      break;
-
     case FrameElement::MEMORY: {
-      // Allocate the element to a register.  If it is not copied,
-      // push that register on top of the frame.  If it is copied,
-      // make the first copy the backing store and push a fresh copy
-      // on top of the frame.
-      FrameElement copy = AdjustCopies(index);
-      if (copy.is_valid()) {
-        // The original element was a copy.  Push the copy of the new
-        // backing store.
-        elements_.Add(copy);
-      } else {
-        // The element was not a copy.  Move it to a register and push
-        // that.
-        Result fresh = cgen_->allocator()->Allocate();
-        ASSERT(fresh.is_valid());
-        FrameElement new_element =
-            FrameElement::RegisterElement(fresh.reg(),
-                                          FrameElement::NOT_SYNCED);
-        Use(fresh.reg());
-        elements_.Add(new_element);
-        __ mov(fresh.reg(), Operand(ebp, fp_relative(index)));
-      }
+      // Emit code to load the original element's data into a register.
+      // Push that register as a FrameElement on top of the frame.
+      Result fresh = cgen_->allocator()->Allocate();
+      ASSERT(fresh.is_valid());
+      FrameElement new_element =
+          FrameElement::RegisterElement(fresh.reg(),
+                                        FrameElement::NOT_SYNCED);
+      Use(fresh.reg());
+      elements_.Add(new_element);
+      __ mov(fresh.reg(), Operand(ebp, fp_relative(index)));
       break;
     }
-
-    case FrameElement::REGISTER: {
-      // If the element is not copied, push it on top of the frame.
-      // If it is copied, make the first copy be the new backing store
-      // and push a fresh copy on top of the frame.
-      FrameElement copy = AdjustCopies(index);
-      if (copy.is_valid()) {
-        // The original element was a copy.  Push the copy of the new
-        // backing store.
-        elements_.Add(copy);
-        // This is the only case where we have to unuse the original
-        // register.  The original is still counted and so is the new
-        // backing store of the copies.
-        Unuse(original.reg());
-      } else {
-        // The element was not a copy.  Push it.
-        original.clear_sync();
-        elements_.Add(original);
-      }
-      break;
-    }
-
+    case FrameElement::REGISTER:
+      Use(original.reg());
+      // Fall through.
     case FrameElement::CONSTANT:
-      original.clear_sync();
-      elements_.Add(original);
-      break;
-
     case FrameElement::COPY:
       original.clear_sync();
       elements_.Add(original);
       break;
+    case FrameElement::INVALID:
+      UNREACHABLE();
+      break;
   }
-  elements_[index] = FrameElement::InvalidElement();
 }
 
 
@@ -631,22 +601,14 @@
   ASSERT(index >= 0);
   ASSERT(index < elements_.length());
 
-  FrameElement original = elements_[index];
-  // If the stored-to slot may be copied, adjust to preserve the
-  // copy-on-write semantics of copied elements.
-  if (original.is_register() || original.is_memory()) {
-    FrameElement ignored = AdjustCopies(index);
-  }
-
-  // If the stored-to slot is a register reference, deallocate it.
-  if (original.is_register()) {
-    Unuse(original.reg());
-  }
-
   int top_index = elements_.length() - 1;
   FrameElement top = elements_[top_index];
+  FrameElement original = elements_[index];
+  if (top.is_copy() && top.index() == index) return;
   ASSERT(top.is_valid());
 
+  InvalidateFrameSlotAt(index);
+
   if (top.is_copy()) {
     // There are two cases based on the relative positions of the
     // stored-to slot and the backing slot of the top element.
@@ -698,16 +660,11 @@
       // All the copies of the old backing element (including the top
       // element) become copies of the new backing element.
       for (int i = backing_index + 1; i < elements_.length(); i++) {
-        FrameElement current = elements_[i];
-        if (current.is_copy() && current.index() == backing_index) {
-          elements_[i] = new_element;
-          if (current.is_synced()) {
-            elements_[i].set_sync();
-          }
+        if (elements_[i].is_copy() && elements_[i].index() == backing_index) {
+          elements_[i].set_index(index);
         }
       }
     }
-
     return;
   }
 
diff --git a/src/virtual-frame-ia32.h b/src/virtual-frame-ia32.h
index 5b3a320..d4008a6 100644
--- a/src/virtual-frame-ia32.h
+++ b/src/virtual-frame-ia32.h
@@ -28,6 +28,8 @@
 #ifndef V8_VIRTUAL_FRAME_IA32_H_
 #define V8_VIRTUAL_FRAME_IA32_H_
 
+#include "register-allocator.h"
+
 namespace v8 { namespace internal {
 
 // -------------------------------------------------------------------------
@@ -57,6 +59,9 @@
     bool previous_state_;
   };
 
+  // An illegal index into the virtual frame.
+  static const int kIllegalIndex = -1;
+
   // Construct an initial virtual frame on entry to a JS function.
   explicit VirtualFrame(CodeGenerator* cgen);
 
@@ -305,9 +310,6 @@
   void Nip(int num_dropped);
 
  private:
-  // An illegal index into the virtual frame.
-  static const int kIllegalIndex = -1;
-
   static const int kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset;
   static const int kFunctionOffset = JavaScriptFrameConstants::kFunctionOffset;
   static const int kContextOffset = StandardFrameConstants::kContextOffset;
@@ -433,13 +435,12 @@
   // should be equal.
   void MergeMoveMemoryToRegisters(VirtualFrame* expected);
 
-  // Helper function to implement the copy-on-write semantics of an
-  // element's copies just before writing to the element.  The copies
-  // are updated, but the element is not changed.  A copy of the new
-  // backing store of all the copies is returned if there were any
-  // copies and in invalid frame element is returned if there were no
-  // copies.
-  FrameElement AdjustCopies(int index);
+  // Invalidates a frame slot (puts an invalid frame element in it).
+  // Copies on the frame are correctly handled, and if this slot was
+  // the backing store of copies, the index of the new backing store
+  // is returned.  Otherwise, returns kIllegalIndex.
+  // Register counts are correctly updated.
+  int InvalidateFrameSlotAt(int index);
 
   // Call a code stub that has already been prepared for calling (via
   // PrepareForCall).
diff --git a/src/virtual-frame.cc b/src/virtual-frame.cc
index 60fa699..faa662f 100644
--- a/src/virtual-frame.cc
+++ b/src/virtual-frame.cc
@@ -27,9 +27,8 @@
 
 #include "v8.h"
 
-#include "codegen.h"
 #include "codegen-inl.h"
-#include "virtual-frame.h"
+#include "register-allocator-inl.h"
 
 namespace v8 { namespace internal {
 
@@ -93,9 +92,11 @@
     case FrameElement::REGISTER:
       // All copies are backed by memory or register locations.
       result.type_ =
-          FrameElement::TypeField::encode(FrameElement::COPY) |
-          FrameElement::SyncField::encode(FrameElement::NOT_SYNCED);
+          FrameElement::TypeField::encode(FrameElement::COPY)
+          | FrameElement::IsCopiedField::encode(false)
+          | FrameElement::SyncField::encode(FrameElement::NOT_SYNCED);
       result.data_.index_ = index;
+      elements_[index].set_copied();
       break;
 
     case FrameElement::INVALID:
@@ -208,11 +209,15 @@
   if (!elements_[index].is_valid()) return;
 
   SyncElementAt(index);
+  // The element is now in memory.  Its copied flag is preserved.
+  FrameElement new_element = FrameElement::MemoryElement();
+  if (elements_[index].is_copied()) {
+    new_element.set_copied();
+  }
   if (elements_[index].is_register()) {
     Unuse(elements_[index].reg());
   }
-  // The element is now in memory.
-  elements_[index] = FrameElement::MemoryElement();
+  elements_[index] = new_element;
 }
 
 
@@ -276,6 +281,11 @@
       ASSERT(source.is_valid());
       elements_[i].clear_sync();
     }
+
+    elements_[i].clear_copied();
+    if (elements_[i].is_copy()) {
+      elements_[elements_[i].index()].set_copied();
+    }
   }
 }
 
@@ -365,16 +375,7 @@
     return;
   }
 
-  // If the original may be a copy, adjust to preserve the copy-on-write
-  // semantics of copied elements.
-  if (original.is_register() || original.is_memory()) {
-    FrameElement ignored = AdjustCopies(frame_index);
-  }
-
-  // If the original is a register reference, deallocate it.
-  if (original.is_register()) {
-    Unuse(original.reg());
-  }
+  InvalidateFrameSlotAt(frame_index);
 
   FrameElement new_element;
   if (value->is_register()) {
@@ -386,25 +387,33 @@
           FrameElement::RegisterElement(value->reg(),
                                         FrameElement::NOT_SYNCED);
     } else {
-      for (int i = 0; i < elements_.length(); i++) {
-        FrameElement element = elements_[i];
-        if (element.is_register() && element.reg().is(value->reg())) {
-          // The register backing store is lower in the frame than its
-          // copy.
-          if (i < frame_index) {
-            elements_[frame_index] = CopyElementAt(i);
-          } else {
-            // There was an early bailout for the case of setting a
-            // register element to itself.
-            ASSERT(i != frame_index);
-            element.clear_sync();
-            elements_[frame_index] = element;
-            elements_[i] = CopyElementAt(frame_index);
-          }
-          // Exit the loop once the appropriate copy is inserted.
+      int i = 0;
+      for (; i < elements_.length(); i++) {
+        if (elements_[i].is_register() && elements_[i].reg().is(value->reg())) {
           break;
         }
       }
+      ASSERT(i < elements_.length());
+
+      if (i < frame_index) {
+        // The register backing store is lower in the frame than its copy.
+        elements_[frame_index] = CopyElementAt(i);
+      } else {
+        // There was an early bailout for the case of setting a
+        // register element to itself.
+        ASSERT(i != frame_index);
+        elements_[frame_index] = elements_[i];
+        elements_[i] = CopyElementAt(frame_index);
+        if (elements_[frame_index].is_synced()) {
+          elements_[i].set_sync();
+        }
+        elements_[frame_index].clear_sync();
+        for (int j = i + 1; j < elements_.length(); j++) {
+          if (elements_[j].is_copy() && elements_[j].index() == i) {
+            elements_[j].set_index(frame_index);
+          }
+        }
+      }
     }
   } else {
     ASSERT(value->is_constant());
@@ -523,8 +532,7 @@
 
 
 bool FrameElement::Equals(FrameElement other) {
-  if (type() != other.type()) return false;
-  if (is_synced() != other.is_synced()) return false;
+  if (type_ != other.type_) return false;
 
   if (is_register()) {
     if (!reg().is(other.reg())) return false;
@@ -539,17 +547,13 @@
 
 
 bool VirtualFrame::Equals(VirtualFrame* other) {
+#ifdef DEBUG
+  // These are sanity checks in debug builds, but we do not need to
+  // use them to distinguish frames at merge points.
   if (cgen_ != other->cgen_) return false;
   if (masm_ != other->masm_) return false;
-  if (elements_.length() != other->elements_.length()) return false;
-
-  for (int i = 0; i < elements_.length(); i++) {
-    if (!elements_[i].Equals(other->elements_[i])) return false;
-  }
-
   if (parameter_count_ != other->parameter_count_) return false;
   if (local_count_ != other->local_count_) return false;
-  if (stack_pointer_ != other->stack_pointer_) return false;
   if (frame_pointer_ != other->frame_pointer_) return false;
 
   for (int i = 0; i < kNumRegisters; i++) {
@@ -557,6 +561,12 @@
       return false;
     }
   }
+  if (elements_.length() != other->elements_.length()) return false;
+#endif
+  if (stack_pointer_ != other->stack_pointer_) return false;
+  for (int i = 0; i < elements_.length(); i++) {
+    if (!elements_[i].Equals(other->elements_[i])) return false;
+  }
 
   return true;
 }
diff --git a/src/virtual-frame.h b/src/virtual-frame.h
index 4702ed4..9f5cf01 100644
--- a/src/virtual-frame.h
+++ b/src/virtual-frame.h
@@ -29,7 +29,6 @@
 #define V8_VIRTUAL_FRAME_H_
 
 #include "macro-assembler.h"
-#include "register-allocator.h"
 
 namespace v8 { namespace internal {
 
@@ -54,8 +53,7 @@
 
   // The default constructor creates an invalid frame element.
   FrameElement() {
-    type_ = TypeField::encode(INVALID) | SyncField::encode(NOT_SYNCED);
-    data_.reg_ = no_reg;
+    Initialize(INVALID, no_reg, NOT_SYNCED);
   }
 
   // Factory function to construct an invalid frame element.
@@ -66,18 +64,13 @@
 
   // Factory function to construct an in-memory frame element.
   static FrameElement MemoryElement() {
-    FrameElement result;
-    result.type_ = TypeField::encode(MEMORY) | SyncField::encode(SYNCED);
-    // In-memory elements have no useful data.
-    result.data_.reg_ = no_reg;
+    FrameElement result(MEMORY, no_reg, SYNCED);
     return result;
   }
 
   // Factory function to construct an in-register frame element.
   static FrameElement RegisterElement(Register reg, SyncFlag is_synced) {
-    FrameElement result;
-    result.type_ = TypeField::encode(REGISTER) | SyncField::encode(is_synced);
-    result.data_.reg_ = reg;
+    FrameElement result(REGISTER, reg, is_synced);
     return result;
   }
 
@@ -85,9 +78,7 @@
   // compile time.
   static FrameElement ConstantElement(Handle<Object> value,
                                       SyncFlag is_synced) {
-    FrameElement result;
-    result.type_ = TypeField::encode(CONSTANT) | SyncField::encode(is_synced);
-    result.data_.handle_ = value.location();
+    FrameElement result(value, is_synced);
     return result;
   }
 
@@ -109,6 +100,16 @@
   bool is_constant() const { return type() == CONSTANT; }
   bool is_copy() const { return type() == COPY; }
 
+  bool is_copied() const { return IsCopiedField::decode(type_); }
+
+  void set_copied() {
+    type_ = (type_ & ~IsCopiedField::mask()) | IsCopiedField::encode(true);
+  }
+
+  void clear_copied() {
+    type_ = (type_ & ~IsCopiedField::mask()) | IsCopiedField::encode(false);
+  }
+
   Register reg() const {
     ASSERT(is_register());
     return data_.reg_;
@@ -137,7 +138,8 @@
 
   // BitField is <type, shift, size>.
   class SyncField : public BitField<SyncFlag, 0, 1> {};
-  class TypeField : public BitField<Type, 1, 32 - 1> {};
+  class IsCopiedField : public BitField<bool, 1, 1> {};
+  class TypeField : public BitField<Type, 2, 32 - 2> {};
 
   Type type() const { return TypeField::decode(type_); }
 
@@ -152,6 +154,22 @@
     int index_;
   } data_;
 
+  // Used to construct memory and register elements.
+  FrameElement(Type type, Register reg, SyncFlag is_synced) {
+    Initialize(type, reg, is_synced);
+  }
+
+  // Used to construct constant elements.
+  inline FrameElement(Handle<Object> value, SyncFlag is_synced);
+
+  // Used to initialize invalid, memory, and register elements.
+  inline void Initialize(Type type, Register reg, SyncFlag is_synced);
+
+  void set_index(int new_index) {
+    ASSERT(is_copy());
+    data_.index_ = new_index;
+  }
+
   friend class VirtualFrame;
 };
 
@@ -164,4 +182,25 @@
 #include "virtual-frame-ia32.h"
 #endif
 
+
+namespace v8 { namespace internal {
+
+FrameElement::FrameElement(Handle<Object> value, SyncFlag is_synced) {
+  type_ = TypeField::encode(CONSTANT)
+          | IsCopiedField::encode(false)
+          | SyncField::encode(is_synced);
+  data_.handle_ = value.location();
+}
+
+
+void FrameElement::Initialize(Type type, Register reg, SyncFlag is_synced) {
+  type_ = TypeField::encode(type)
+          | IsCopiedField::encode(false)
+          | SyncField::encode(is_synced);
+  data_.reg_ = reg;
+}
+
+
+} }  // namespace v8::internal
+
 #endif  // V8_VIRTUAL_FRAME_H_
diff --git a/test/cctest/cctest.cc b/test/cctest/cctest.cc
index 652c68a..d908890 100644
--- a/test/cctest/cctest.cc
+++ b/test/cctest/cctest.cc
@@ -44,9 +44,9 @@
     basename = strrchr(const_cast<char *>(file), '\\');
   }
   if (!basename) {
-    basename = v8::internal::OS::StrDup(file);
+    basename = v8::internal::StrDup(file);
   } else {
-    basename = v8::internal::OS::StrDup(basename + 1);
+    basename = v8::internal::StrDup(basename + 1);
   }
   // Drop the extension, if there is one.
   char *extension = strrchr(basename, '.');
@@ -82,7 +82,7 @@
       print_run_count = false;
 
     } else {
-      char* arg_copy = v8::internal::OS::StrDup(arg);
+      char* arg_copy = v8::internal::StrDup(arg);
       char* testname = strchr(arg_copy, '/');
       if (testname) {
         // Split the string in two by nulling the slash and then run
@@ -115,7 +115,7 @@
           test = test->prev();
         }
       }
-      free(arg_copy);
+      v8::internal::DeleteArray<char>(arg_copy);
     }
   }
   if (print_run_count && tests_run != 1)
diff --git a/test/cctest/cctest.status b/test/cctest/cctest.status
index aa81dd1..86b5885 100644
--- a/test/cctest/cctest.status
+++ b/test/cctest/cctest.status
@@ -30,6 +30,9 @@
 # BUG(96): Fix this flaky test.
 test-debug/ThreadedDebugging: PASS || FAIL
 
+# BUG(281): This test fails on some Linuxes.
+test-debug/DebuggerAgent: PASS, (PASS || FAIL) if $system == linux
+
 [ $arch == arm ]
 
 test-debug: SKIP
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index 3746bf5..c9f1f42 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -117,6 +117,7 @@
         gate_(v8::internal::OS::CreateSemaphore(0)),
         active_(true) {
   }
+  ~ApiTestFuzzer() { delete gate_; }
 
   // The ApiTestFuzzer is also a Thread, so it has a Run method.
   virtual void Run();
@@ -1338,6 +1339,23 @@
   CHECK_EQ(x, 3);
   *ptr = 10;
   CHECK_EQ(x, 10);
+
+  // Make sure unaligned pointers are wrapped properly.
+  char* data = i::StrDup("0123456789");
+  Local<v8::Value> zero = v8::External::Wrap(&data[0]);
+  Local<v8::Value> one = v8::External::Wrap(&data[1]);
+  Local<v8::Value> two = v8::External::Wrap(&data[2]);
+  Local<v8::Value> three = v8::External::Wrap(&data[3]);
+
+  char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
+  CHECK_EQ('0', *char_ptr);
+  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
+  CHECK_EQ('1', *char_ptr);
+  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
+  CHECK_EQ('2', *char_ptr);
+  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
+  CHECK_EQ('3', *char_ptr);
+  i::DeleteArray(data);
 }
 
 
@@ -5638,14 +5656,14 @@
   // Add more than 8 (see kMaxFastProperties) properties
   // so that the constructor will force copying map.
   // Cannot sprintf, gcc complains unsafety.
-  char buf[5];
+  char buf[4];
   for (char i = '0'; i <= '9' ; i++) {
-    buf[1] = i;
+    buf[0] = i;
     for (char j = '0'; j <= '9'; j++) {
-      buf[2] = j;
+      buf[1] = j;
       for (char k = '0'; k <= '9'; k++) {
-        buf[3] = k;
-        buf[4] = 0;
+        buf[2] = k;
+        buf[3] = 0;
         templ->Set(v8_str(buf), v8::Number::New(k));
       }
     }
@@ -5693,6 +5711,7 @@
   v8::ScriptData *sd = v8::ScriptData::PreCompile(script, strlen(script));
   CHECK_NE(sd->Length(), 0);
   CHECK_NE(sd->Data(), NULL);
+  delete sd;
 }
 
 
@@ -5755,6 +5774,8 @@
 
 class RegExpInterruptTest {
  public:
+  RegExpInterruptTest() : block_(NULL) {}
+  ~RegExpInterruptTest() { delete block_; }
   void RunTest() {
     block_ = i::OS::CreateSemaphore(0);
     gc_count_ = 0;
@@ -5809,7 +5830,7 @@
     while (gc_during_regexp_ < kRequiredGCs) {
       int gc_before = gc_count_;
       {
-        // match 15-30 "a"'s against 14 and a "b".
+        // Match 15-30 "a"'s against 14 and a "b".
         const char* c_source =
             "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
             ".exec('aaaaaaaaaaaaaaab') === null";
@@ -5822,7 +5843,7 @@
         }
       }
       {
-        // match 15-30 "a"'s against 15 and a "b".
+        // Match 15-30 "a"'s against 15 and a "b".
         const char* c_source =
             "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
             ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
@@ -5905,3 +5926,195 @@
   CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
   CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
 }
+
+
+class RegExpStringModificationTest {
+ public:
+  RegExpStringModificationTest()
+      : block_(i::OS::CreateSemaphore(0)),
+        morphs_(0),
+        morphs_during_regexp_(0),
+        ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
+        uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
+  ~RegExpStringModificationTest() { delete block_; }
+  void RunTest() {
+    regexp_success_ = false;
+    morph_success_ = false;
+
+    // Initialize the contents of two_byte_content_ to be a uc16 representation
+    // of "aaaaaaaaaaaaaab".
+    for (int i = 0; i < 14; i++) {
+      two_byte_content_[i] = 'a';
+    }
+    two_byte_content_[14] = 'b';
+
+    // Create the input string for the regexp - the one we are going to change
+    // properties of.
+    input_ = i::Factory::NewExternalStringFromAscii(&ascii_resource_);
+
+    // Inject the input as a global variable.
+    i::Handle<i::String> input_name =
+        i::Factory::NewStringFromAscii(i::Vector<const char>("input", 5));
+    i::Top::global_context()->global()->SetProperty(*input_name, *input_, NONE);
+
+
+    MorphThread morph_thread(this);
+    morph_thread.Start();
+    v8::Locker::StartPreemption(1);
+    LongRunningRegExp();
+    {
+      v8::Unlocker unlock;
+      morph_thread.Join();
+    }
+    v8::Locker::StopPreemption();
+    CHECK(regexp_success_);
+    CHECK(morph_success_);
+  }
+ private:
+
+  class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
+   public:
+    explicit AsciiVectorResource(i::Vector<const char> vector)
+        : data_(vector) {}
+    virtual ~AsciiVectorResource() {}
+    virtual size_t length() const { return data_.length(); }
+    virtual const char* data() const { return data_.start(); }
+   private:
+    i::Vector<const char> data_;
+  };
+  class UC16VectorResource : public v8::String::ExternalStringResource {
+   public:
+    explicit UC16VectorResource(i::Vector<const i::uc16> vector)
+        : data_(vector) {}
+    virtual ~UC16VectorResource() {}
+    virtual size_t length() const { return data_.length(); }
+    virtual const i::uc16* data() const { return data_.start(); }
+   private:
+    i::Vector<const i::uc16> data_;
+  };
+  // Number of string modifications required.
+  static const int kRequiredModifications = 5;
+  static const int kMaxModifications = 100;
+
+  class MorphThread : public i::Thread {
+   public:
+    explicit MorphThread(RegExpStringModificationTest* test)
+        : test_(test) {}
+    virtual void Run() {
+      test_->MorphString();
+    }
+   private:
+     RegExpStringModificationTest* test_;
+  };
+
+  void MorphString() {
+    block_->Wait();
+    while (morphs_during_regexp_ < kRequiredModifications &&
+           morphs_ < kMaxModifications) {
+      {
+        v8::Locker lock;
+        // Swap string between ascii and two-byte representation.
+        i::String* string = *input_;
+        CHECK(i::StringShape(string).IsExternal());
+        if (i::StringShape(string).IsAsciiRepresentation()) {
+          // Morph external string to be TwoByte string.
+          i::ExternalAsciiString* ext_string =
+              i::ExternalAsciiString::cast(string);
+          i::ExternalTwoByteString* morphed =
+              reinterpret_cast<i::ExternalTwoByteString*>(ext_string);
+          morphed->map()->set_instance_type(i::SHORT_EXTERNAL_STRING_TYPE);
+          morphed->set_resource(&uc16_resource_);
+        } else {
+          // Morph external string to be ASCII string.
+          i::ExternalTwoByteString* ext_string =
+              i::ExternalTwoByteString::cast(string);
+          i::ExternalAsciiString* morphed =
+              reinterpret_cast<i::ExternalAsciiString*>(ext_string);
+          morphed->map()->set_instance_type(
+              i::SHORT_EXTERNAL_ASCII_STRING_TYPE);
+          morphed->set_resource(&ascii_resource_);
+        }
+        morphs_++;
+      }
+      i::OS::Sleep(1);
+    }
+    morph_success_ = true;
+  }
+
+  void LongRunningRegExp() {
+    block_->Signal();  // Enable morphing thread on next preemption.
+    while (morphs_during_regexp_ < kRequiredModifications &&
+           morphs_ < kMaxModifications) {
+      int morphs_before = morphs_;
+      {
+        // Match 15-30 "a"'s against 14 and a "b".
+        const char* c_source =
+            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
+            ".exec(input) === null";
+        Local<String> source = String::New(c_source);
+        Local<Script> script = Script::Compile(source);
+        Local<Value> result = script->Run();
+        CHECK(result->IsTrue());
+      }
+      int morphs_after = morphs_;
+      morphs_during_regexp_ += morphs_after - morphs_before;
+    }
+    regexp_success_ = true;
+  }
+
+  i::uc16 two_byte_content_[15];
+  i::Semaphore* block_;
+  int morphs_;
+  int morphs_during_regexp_;
+  bool regexp_success_;
+  bool morph_success_;
+  i::Handle<i::String> input_;
+  AsciiVectorResource ascii_resource_;
+  UC16VectorResource uc16_resource_;
+};
+
+
+// Test that a regular expression execution can be interrupted and
+// the string changed without failing.
+TEST(RegExpStringModification) {
+  v8::Locker lock;
+  v8::V8::Initialize();
+  v8::HandleScope scope;
+  Local<Context> local_env;
+  {
+    LocalContext env;
+    local_env = env.local();
+  }
+
+  // Local context should still be live.
+  CHECK(!local_env.IsEmpty());
+  local_env->Enter();
+
+  // Should complete without problems.
+  RegExpStringModificationTest().RunTest();
+
+  local_env->Exit();
+}
+
+
+// Test that we can set a property on the global object even if there
+// is a read-only property in the prototype chain.
+TEST(ReadOnlyPropertyInGlobalProto) {
+  v8::HandleScope scope;
+  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
+  LocalContext context(0, templ);
+  v8::Handle<v8::Object> global = context->Global();
+  v8::Handle<v8::Object> global_proto =
+      v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
+  global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
+  global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
+  // Check without 'eval' or 'with'.
+  v8::Handle<v8::Value> res =
+      CompileRun("function f() { x = 42; return x; }; f()");
+  // Check with 'eval'.
+  res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
+  CHECK_EQ(v8::Integer::New(42), res);
+  // Check with 'with'.
+  res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
+  CHECK_EQ(v8::Integer::New(42), res);
+}
diff --git a/test/cctest/test-ast.cc b/test/cctest/test-ast.cc
index 8646289..2054348 100644
--- a/test/cctest/test-ast.cc
+++ b/test/cctest/test-ast.cc
@@ -53,6 +53,7 @@
 
   list->Clear();
   CHECK_EQ(0, list->length());
+  delete list;
 }
 
 
diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc
index de4a78f..30a086a 100644
--- a/test/cctest/test-debug.cc
+++ b/test/cctest/test-debug.cc
@@ -3244,7 +3244,6 @@
   v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_3, buffer_2));
   v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_3, buffer_2));
   v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_3, buffer_2));
-  v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_continue, buffer_2));
   message_queue_barriers.barrier_2.Wait();
   // Main thread compiles and runs source_2.
   // Queued commands are executed at the start of compilation of source_2.
@@ -3286,7 +3285,6 @@
   CompileRun(source_1);
   message_queue_barriers.barrier_1.Wait();
   message_queue_barriers.barrier_2.Wait();
-  v8::Debug::DebugBreak();
   CompileRun(source_2);
   message_queue_barriers.barrier_3.Wait();
   CompileRun(source_3);
@@ -3464,28 +3462,25 @@
       "\"type\":\"request\","
       "\"command\":\"setbreakpoint\","
       "\"arguments\":{\"type\":\"function\",\"target\":\"dog\",\"line\":3}}";
-  const char* command_3 = "{\"seq\":103,"
-      "\"type\":\"request\","
-      "\"command\":\"continue\"}";
-  const char* command_4 = "{\"seq\":104,"
+  const char* command_3 = "{\"seq\":104,"
       "\"type\":\"request\","
       "\"command\":\"evaluate\","
       "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":false}}";
-  const char* command_5 = "{\"seq\":105,"
+  const char* command_4 = "{\"seq\":105,"
       "\"type\":\"request\","
       "\"command\":\"evaluate\","
       "\"arguments\":{\"expression\":\"x\",\"disable_break\":true}}";
-  const char* command_6 = "{\"seq\":106,"
+  const char* command_5 = "{\"seq\":106,"
       "\"type\":\"request\","
       "\"command\":\"continue\"}";
-  const char* command_7 = "{\"seq\":107,"
+  const char* command_6 = "{\"seq\":107,"
       "\"type\":\"request\","
       "\"command\":\"continue\"}";
-  const char* command_8 = "{\"seq\":108,"
+  const char* command_7 = "{\"seq\":108,"
      "\"type\":\"request\","
      "\"command\":\"evaluate\","
      "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":true}}";
-  const char* command_9 = "{\"seq\":109,"
+  const char* command_8 = "{\"seq\":109,"
       "\"type\":\"request\","
       "\"command\":\"continue\"}";
 
@@ -3493,12 +3488,9 @@
   // v8 thread initializes, runs source_1
   breakpoints_barriers->barrier_1.Wait();
   // 1:Set breakpoint in cat().
-  v8::Debug::DebugBreak();
   v8::Debug::SendCommand(buffer, AsciiToUtf16(command_1, buffer));
   // 2:Set breakpoint in dog()
   v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer));
-  // 3:Continue
-  v8::Debug::SendCommand(buffer, AsciiToUtf16(command_3, buffer));
   breakpoints_barriers->barrier_2.Wait();
   // v8 thread starts compiling source_2.
   // Automatic break happens, to run queued commands
@@ -3508,29 +3500,31 @@
   // message callback receives break event.
   breakpoints_barriers->semaphore_1->Wait();
   // 4:Evaluate dog() (which has a breakpoint).
-  v8::Debug::SendCommand(buffer, AsciiToUtf16(command_4, buffer));
+  v8::Debug::SendCommand(buffer, AsciiToUtf16(command_3, buffer));
   // v8 thread hits breakpoint in dog()
   breakpoints_barriers->semaphore_1->Wait();  // wait for break event
   // 5:Evaluate x
-  v8::Debug::SendCommand(buffer, AsciiToUtf16(command_5, buffer));
+  v8::Debug::SendCommand(buffer, AsciiToUtf16(command_4, buffer));
   // 6:Continue evaluation of dog()
-  v8::Debug::SendCommand(buffer, AsciiToUtf16(command_6, buffer));
+  v8::Debug::SendCommand(buffer, AsciiToUtf16(command_5, buffer));
   // dog() finishes.
   // 7:Continue evaluation of source_2, finish cat(17), hit breakpoint
   // in cat(19).
-  v8::Debug::SendCommand(buffer, AsciiToUtf16(command_7, buffer));
+  v8::Debug::SendCommand(buffer, AsciiToUtf16(command_6, buffer));
   // message callback gets break event
   breakpoints_barriers->semaphore_1->Wait();  // wait for break event
   // 8: Evaluate dog() with breaks disabled
-  v8::Debug::SendCommand(buffer, AsciiToUtf16(command_8, buffer));
+  v8::Debug::SendCommand(buffer, AsciiToUtf16(command_7, buffer));
   // 9: Continue evaluation of source2, reach end.
-  v8::Debug::SendCommand(buffer, AsciiToUtf16(command_9, buffer));
+  v8::Debug::SendCommand(buffer, AsciiToUtf16(command_8, buffer));
 }
 
 BreakpointsDebuggerThread breakpoints_debugger_thread;
 BreakpointsV8Thread breakpoints_v8_thread;
 
 TEST(RecursiveBreakpoints) {
+  i::FLAG_debugger_auto_break = true;
+
   // Create a V8 environment
   Barriers stack_allocated_breakpoints_barriers;
   stack_allocated_breakpoints_barriers.Initialize();
@@ -3802,13 +3796,15 @@
 // Test that clearing the debug event listener actually clears all break points
 // and related information.
 TEST(DebuggerHostDispatch) {
+  i::FLAG_debugger_auto_break = true;
+
   v8::HandleScope scope;
   DebugLocalContext env;
 
   const int kBufferSize = 1000;
   uint16_t buffer[kBufferSize];
   const char* command_continue =
-    "{\"seq\":106,"
+    "{\"seq\":0,"
      "\"type\":\"request\","
      "\"command\":\"continue\"}";
 
@@ -3818,11 +3814,169 @@
                                     NULL);
 
   // Fill a host dispatch and a continue command on the command queue before
-  // generating a debug break.
+  // running some code.
   v8::Debug::SendHostDispatch(NULL);
   v8::Debug::SendCommand(buffer, AsciiToUtf16(command_continue, buffer));
-  CompileRun("debugger");
+  CompileRun("void 0");
 
   // The host dispatch callback should be called.
   CHECK_EQ(1, host_dispatch_hit_count);
 }
+
+
+TEST(DebuggerAgent) {
+  // Make sure this port is not used by other tests to allow tests to run in
+  // parallel.
+  const int kPort = 5858;
+
+  // Make a string with the port number.
+  const int kPortBufferLen = 6;
+  char port_str[kPortBufferLen];
+  OS::SNPrintF(i::Vector<char>(port_str, kPortBufferLen), "%d", kPort);
+
+  bool ok;
+
+  // Initialize the socket library.
+  i::Socket::Setup();
+
+  // Test starting and stopping the agent without any client connection.
+  i::Debugger::StartAgent("test", kPort);
+  i::Debugger::StopAgent();
+
+  // Test starting the agent, connecting a client and shutting down the agent
+  // with the client connected.
+  ok = i::Debugger::StartAgent("test", kPort);
+  CHECK(ok);
+  i::Socket* client = i::OS::CreateSocket();
+  ok = client->Connect("localhost", port_str);
+  CHECK(ok);
+  i::Debugger::StopAgent();
+  delete client;
+
+  // Test starting and stopping the agent with the required port already
+  // occoupied.
+  i::Socket* server = i::OS::CreateSocket();
+  server->Bind(kPort);
+
+  i::Debugger::StartAgent("test", kPort);
+  i::Debugger::StopAgent();
+
+  delete server;
+}
+
+
+class DebuggerAgentProtocolServerThread : public i::Thread {
+ public:
+  explicit DebuggerAgentProtocolServerThread(int port)
+      : port_(port), server_(NULL), client_(NULL),
+        listening_(OS::CreateSemaphore(0)) {
+  }
+  ~DebuggerAgentProtocolServerThread() {
+    // Close both sockets.
+    delete client_;
+    delete server_;
+    delete listening_;
+  }
+
+  void Run();
+  void WaitForListening() { listening_->Wait(); }
+  char* body() { return *body_; }
+
+ private:
+  int port_;
+  i::SmartPointer<char> body_;
+  i::Socket* server_;  // Server socket used for bind/accept.
+  i::Socket* client_;  // Single client connection used by the test.
+  i::Semaphore* listening_;  // Signalled when the server is in listen mode.
+};
+
+
+void DebuggerAgentProtocolServerThread::Run() {
+  bool ok;
+
+  // Create the server socket and bind it to the requested port.
+  server_ = i::OS::CreateSocket();
+  CHECK(server_ != NULL);
+  ok = server_->Bind(port_);
+  CHECK(ok);
+
+  // Listen for new connections.
+  ok = server_->Listen(1);
+  CHECK(ok);
+  listening_->Signal();
+
+  // Accept a connection.
+  client_ = server_->Accept();
+  CHECK(client_ != NULL);
+
+  // Receive a debugger agent protocol message.
+  i::DebuggerAgentUtil::ReceiveMessage(client_);
+}
+
+
+TEST(DebuggerAgentProtocolOverflowHeader) {
+  // Make sure this port is not used by other tests to allow tests to run in
+  // parallel.
+  const int kPort = 5860;
+  static const char* kLocalhost = "localhost";
+
+  // Make a string with the port number.
+  const int kPortBufferLen = 6;
+  char port_str[kPortBufferLen];
+  OS::SNPrintF(i::Vector<char>(port_str, kPortBufferLen), "%d", kPort);
+
+  // Initialize the socket library.
+  i::Socket::Setup();
+
+  // Create a socket server to receive a debugger agent message.
+  DebuggerAgentProtocolServerThread* server =
+      new DebuggerAgentProtocolServerThread(kPort);
+  server->Start();
+  server->WaitForListening();
+
+  // Connect.
+  i::Socket* client = i::OS::CreateSocket();
+  CHECK(client != NULL);
+  bool ok = client->Connect(kLocalhost, port_str);
+  CHECK(ok);
+
+  // Send headers which overflow the receive buffer.
+  static const int kBufferSize = 1000;
+  char buffer[kBufferSize];
+
+  // Long key and short value: XXXX....XXXX:0\r\n.
+  for (int i = 0; i < kBufferSize - 4; i++) {
+    buffer[i] = 'X';
+  }
+  buffer[kBufferSize - 4] = ':';
+  buffer[kBufferSize - 3] = '0';
+  buffer[kBufferSize - 2] = '\r';
+  buffer[kBufferSize - 1] = '\n';
+  client->Send(buffer, kBufferSize);
+
+  // Short key and long value: X:XXXX....XXXX\r\n.
+  buffer[0] = 'X';
+  buffer[1] = ':';
+  for (int i = 2; i < kBufferSize - 2; i++) {
+    buffer[i] = 'X';
+  }
+  buffer[kBufferSize - 2] = '\r';
+  buffer[kBufferSize - 1] = '\n';
+  client->Send(buffer, kBufferSize);
+
+  // Add empty body to request.
+  const char* content_length_zero_header = "Content-Length:0\r\n";
+  client->Send(content_length_zero_header, strlen(content_length_zero_header));
+  client->Send("\r\n", 2);
+
+  // Wait until data is received.
+  server->Join();
+
+  // Check for empty body.
+  CHECK(server->body() == NULL);
+
+  // Close the client before the server to avoid TIME_WAIT issues.
+  client->Shutdown();
+  delete client;
+  delete server;
+}
diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc
index a146c4c..e35ac5f 100644
--- a/test/cctest/test-heap.cc
+++ b/test/cctest/test-heap.cc
@@ -254,10 +254,9 @@
 
 static void VerifyStringAllocation(const char* string) {
   String* s = String::cast(Heap::AllocateStringFromUtf8(CStrVector(string)));
-  StringShape shape(s);
-  CHECK_EQ(static_cast<int>(strlen(string)), s->length(shape));
-  for (int index = 0; index < s->length(shape); index++) {
-    CHECK_EQ(static_cast<uint16_t>(string[index]), s->Get(shape, index));  }
+  CHECK_EQ(static_cast<int>(strlen(string)), s->length());
+  for (int index = 0; index < s->length(); index++) {
+    CHECK_EQ(static_cast<uint16_t>(string[index]), s->Get(index));  }
 }
 
 
diff --git a/test/cctest/test-lock.cc b/test/cctest/test-lock.cc
index 37e3853..5eecfce 100644
--- a/test/cctest/test-lock.cc
+++ b/test/cctest/test-lock.cc
@@ -38,3 +38,26 @@
   CHECK_EQ(0, mutex->Unlock());
   delete mutex;
 }
+
+
+TEST(SemaphoreTimeout) {
+  bool ok;
+  Semaphore* sem = OS::CreateSemaphore(0);
+
+  // Semaphore not signalled - timeout.
+  ok = sem->Wait(0);
+  CHECK(!ok);
+  ok = sem->Wait(100);
+  CHECK(!ok);
+  ok = sem->Wait(1000);
+  CHECK(!ok);
+
+  // Semaphore signalled - no timeout.
+  sem->Signal();
+  ok = sem->Wait(0);
+  sem->Signal();
+  ok = sem->Wait(100);
+  sem->Signal();
+  ok = sem->Wait(1000);
+  CHECK(ok);
+}
diff --git a/test/cctest/test-log-ia32.cc b/test/cctest/test-log-ia32.cc
index 588be71..b171339 100644
--- a/test/cctest/test-log-ia32.cc
+++ b/test/cctest/test-log-ia32.cc
@@ -9,6 +9,7 @@
 #include "v8.h"
 
 #include "log.h"
+#include "top.h"
 #include "cctest.h"
 
 using v8::Function;
@@ -23,6 +24,7 @@
 using v8::internal::JSFunction;
 using v8::internal::StackTracer;
 using v8::internal::TickSample;
+using v8::internal::Top;
 
 
 static v8::Persistent<v8::Context> env;
@@ -31,7 +33,7 @@
 static struct {
   StackTracer* tracer;
   TickSample* sample;
-} trace_env;
+} trace_env = { NULL, NULL };
 
 
 static void InitTraceEnv(StackTracer* tracer, TickSample* sample) {
@@ -42,62 +44,43 @@
 
 static void DoTrace(unsigned int fp) {
   trace_env.sample->fp = fp;
-  // something that is less than fp
-  trace_env.sample->sp = trace_env.sample->fp - 100;
+  // sp is only used to define stack high bound
+  trace_env.sample->sp =
+      reinterpret_cast<unsigned int>(trace_env.sample) - 10240;
   trace_env.tracer->Trace(trace_env.sample);
 }
 
 
-static void CFuncDoTrace() {
-  unsigned int fp;
-#ifdef __GNUC__
-  fp = reinterpret_cast<unsigned int>(__builtin_frame_address(0));
-#elif defined _MSC_VER
-  __asm mov [fp], ebp  // NOLINT
-#endif
+// Hide c_entry_fp to emulate situation when sampling is done while
+// pure JS code is being executed
+static void DoTraceHideCEntryFPAddress(unsigned int fp) {
+  v8::internal::Address saved_c_frame_fp = *(Top::c_entry_fp_address());
+  CHECK(saved_c_frame_fp);
+  *(Top::c_entry_fp_address()) = 0;
   DoTrace(fp);
+  *(Top::c_entry_fp_address()) = saved_c_frame_fp;
 }
 
 
-static void CFunc(int i) {
-  for (int j = i; j >= 0; --j) {
-    CFuncDoTrace();
-  }
-}
-
-
-static void CheckRetAddrIsInFunction(unsigned int ret_addr,
+static void CheckRetAddrIsInFunction(const char* func_name,
+                                     unsigned int ret_addr,
                                      unsigned int func_start_addr,
                                      unsigned int func_len) {
-  printf("CheckRetAddrIsInFunction: %08x %08x %08x\n",
-         func_start_addr, ret_addr, func_start_addr + func_len);
+  printf("CheckRetAddrIsInFunction \"%s\": %08x %08x %08x\n",
+         func_name, func_start_addr, ret_addr, func_start_addr + func_len);
   CHECK_GE(ret_addr, func_start_addr);
   CHECK_GE(func_start_addr + func_len, ret_addr);
 }
 
 
-#ifdef DEBUG
-static const int kMaxCFuncLen = 0x40;  // seems enough for a small C function
-
-static void CheckRetAddrIsInCFunction(unsigned int ret_addr,
-                                      unsigned int func_start_addr) {
-  CheckRetAddrIsInFunction(ret_addr, func_start_addr, kMaxCFuncLen);
-}
-#endif
-
-
-TEST(PureCStackTrace) {
-  TickSample sample;
-  StackTracer tracer(reinterpret_cast<unsigned int>(&sample));
-  InitTraceEnv(&tracer, &sample);
-  CFunc(0);
-#ifdef DEBUG
-  // C stack trace works only in debug mode, in release mode EBP is
-  // usually treated as a general-purpose register
-  CHECK_GT(sample.frames_count, 0);
-  CheckRetAddrIsInCFunction(reinterpret_cast<unsigned int>(sample.stack[0]),
-                            reinterpret_cast<unsigned int>(&CFunc));
-#endif
+static void CheckRetAddrIsInJSFunction(const char* func_name,
+                                       unsigned int ret_addr,
+                                       Handle<JSFunction> func) {
+  v8::internal::Code* func_code = func->code();
+  CheckRetAddrIsInFunction(
+      func_name, ret_addr,
+      reinterpret_cast<unsigned int>(func_code->instruction_start()),
+      func_code->ExecutableSize());
 }
 
 
@@ -107,27 +90,49 @@
  public:
   TraceExtension() : v8::Extension("v8/trace", kSource) { }
   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
-      v8::Handle<v8::String> name);
+      v8::Handle<String> name);
   static v8::Handle<v8::Value> Trace(const v8::Arguments& args);
+  static v8::Handle<v8::Value> JSTrace(const v8::Arguments& args);
  private:
+  static unsigned int GetFP(const v8::Arguments& args);
   static const char* kSource;
 };
 
 
-const char* TraceExtension::kSource = "native function trace();";
+const char* TraceExtension::kSource =
+    "native function trace();"
+    "native function js_trace();";
 
 
 v8::Handle<v8::FunctionTemplate> TraceExtension::GetNativeFunction(
-    v8::Handle<v8::String> str) {
-  return v8::FunctionTemplate::New(TraceExtension::Trace);
+    v8::Handle<String> name) {
+  if (name->Equals(String::New("trace"))) {
+    return v8::FunctionTemplate::New(TraceExtension::Trace);
+  } else if (name->Equals(String::New("js_trace"))) {
+    return v8::FunctionTemplate::New(TraceExtension::JSTrace);
+  } else {
+    CHECK(false);
+    return v8::Handle<v8::FunctionTemplate>();
+  }
+}
+
+
+unsigned int TraceExtension::GetFP(const v8::Arguments& args) {
+  CHECK_EQ(1, args.Length());
+  unsigned int fp = args[0]->Int32Value() << 2;
+  printf("Trace: %08x\n", fp);
+  return fp;
 }
 
 
 v8::Handle<v8::Value> TraceExtension::Trace(const v8::Arguments& args) {
-  CHECK_EQ(1, args.Length());
-  unsigned int fp = args[0]->Int32Value() << 2;
-  printf("Trace: %08x\n", fp);
-  DoTrace(fp);
+  DoTrace(GetFP(args));
+  return v8::Undefined();
+}
+
+
+v8::Handle<v8::Value> TraceExtension::JSTrace(const v8::Arguments& args) {
+  DoTraceHideCEntryFPAddress(GetFP(args));
   return v8::Undefined();
 }
 
@@ -163,6 +168,21 @@
 }
 
 
+static Handle<JSFunction> GetGlobalJSFunction(const char* name) {
+  Handle<JSFunction> js_func(JSFunction::cast(
+                                 *(v8::Utils::OpenHandle(
+                                       *GetGlobalProperty(name)))));
+  return js_func;
+}
+
+
+static void CheckRetAddrIsInJSFunction(const char* func_name,
+                                       unsigned int ret_addr) {
+  CheckRetAddrIsInJSFunction(func_name, ret_addr,
+                             GetGlobalJSFunction(func_name));
+}
+
+
 static void SetGlobalProperty(const char* name, Local<Value> value) {
   env->Global()->Set(String::New(name), value);
 }
@@ -188,17 +208,17 @@
 }
 
 
-TEST(PureJSStackTrace) {
-  TickSample sample;
-  StackTracer tracer(reinterpret_cast<unsigned int>(&sample));
-  InitTraceEnv(&tracer, &sample);
-
-  InitializeVM();
-  v8::HandleScope scope;
-  Handle<JSFunction> call_trace = CompileFunction("trace(0x6666);");
-  CHECK(!call_trace.is_null());
-  v8::internal::Code* call_trace_code = call_trace->code();
-  CHECK(call_trace_code->IsCode());
+// Creates a global function named 'func_name' that calls the tracing
+// function 'trace_func_name' with an actual EBP register value,
+// shifted right to be presented as Smi.
+static void CreateTraceCallerFunction(const char* func_name,
+                                      const char* trace_func_name) {
+  ::v8::internal::EmbeddedVector<char, 256> trace_call_buf;
+  ::v8::internal::OS::SNPrintF(trace_call_buf, "%s(0x6666);", trace_func_name);
+  Handle<JSFunction> func = CompileFunction(trace_call_buf.start());
+  CHECK(!func.is_null());
+  v8::internal::Code* func_code = func->code();
+  CHECK(func_code->IsCode());
 
   // push 0xcccc (= 0x6666 << 1)
   byte original[] = { 0x68, 0xcc, 0xcc, 0x00, 0x00 };
@@ -206,29 +226,89 @@
   byte patch[] = { 0x89, 0xe8, 0xd1, 0xe8, 0x50 };
   // Patch generated code to replace pushing of a constant with
   // pushing of ebp contents in a Smi
-  CHECK(Patch(call_trace_code->instruction_start(),
-              call_trace_code->instruction_size(),
+  CHECK(Patch(func_code->instruction_start(),
+              func_code->instruction_size(),
               original, patch, sizeof(patch)));
 
-  SetGlobalProperty("JSFuncDoTrace", v8::ToApi<Value>(call_trace));
+  SetGlobalProperty(func_name, v8::ToApi<Value>(func));
+}
 
+
+TEST(CFromJSStackTrace) {
+  TickSample sample;
+  StackTracer tracer(reinterpret_cast<unsigned int>(&sample));
+  InitTraceEnv(&tracer, &sample);
+
+  InitializeVM();
+  v8::HandleScope scope;
+  CreateTraceCallerFunction("JSFuncDoTrace", "trace");
   CompileRun(
       "function JSTrace() {"
       "  JSFuncDoTrace();"
       "};\n"
       "JSTrace();");
   CHECK_GT(sample.frames_count, 1);
-  CheckRetAddrIsInFunction(
-      reinterpret_cast<unsigned int>(sample.stack[0]),
-      reinterpret_cast<unsigned int>(call_trace_code->instruction_start()),
-      call_trace_code->instruction_size());
-  Handle<JSFunction> js_trace(JSFunction::cast(*(v8::Utils::OpenHandle(
-      *GetGlobalProperty("JSTrace")))));
-  v8::internal::Code* js_trace_code = js_trace->code();
-  CheckRetAddrIsInFunction(
-      reinterpret_cast<unsigned int>(sample.stack[1]),
-      reinterpret_cast<unsigned int>(js_trace_code->instruction_start()),
-      js_trace_code->instruction_size());
+  // Stack sampling will start from the first JS function, i.e. "JSFuncDoTrace"
+  CheckRetAddrIsInJSFunction("JSFuncDoTrace",
+                             reinterpret_cast<unsigned int>(sample.stack[0]));
+  CheckRetAddrIsInJSFunction("JSTrace",
+                             reinterpret_cast<unsigned int>(sample.stack[1]));
 }
 
+
+TEST(PureJSStackTrace) {
+  TickSample sample;
+  StackTracer tracer(reinterpret_cast<unsigned int>(&sample));
+  InitTraceEnv(&tracer, &sample);
+
+  InitializeVM();
+  v8::HandleScope scope;
+  CreateTraceCallerFunction("JSFuncDoTrace", "js_trace");
+  CompileRun(
+      "function JSTrace() {"
+      "  JSFuncDoTrace();"
+      "};\n"
+      "function OuterJSTrace() {"
+      "  JSTrace();"
+      "};\n"
+      "OuterJSTrace();");
+  CHECK_GT(sample.frames_count, 1);
+  // Stack sampling will start from the caller of JSFuncDoTrace, i.e. "JSTrace"
+  CheckRetAddrIsInJSFunction("JSTrace",
+                             reinterpret_cast<unsigned int>(sample.stack[0]));
+  CheckRetAddrIsInJSFunction("OuterJSTrace",
+                             reinterpret_cast<unsigned int>(sample.stack[1]));
+}
+
+
+static void CFuncDoTrace() {
+  unsigned int fp;
+#ifdef __GNUC__
+  fp = reinterpret_cast<unsigned int>(__builtin_frame_address(0));
+#elif defined _MSC_VER
+  __asm mov [fp], ebp  // NOLINT
+#endif
+  DoTrace(fp);
+}
+
+
+static int CFunc(int depth) {
+  if (depth <= 0) {
+    CFuncDoTrace();
+    return 0;
+  } else {
+    return CFunc(depth - 1) + 1;
+  }
+}
+
+
+TEST(PureCStackTrace) {
+  TickSample sample;
+  StackTracer tracer(reinterpret_cast<unsigned int>(&sample));
+  InitTraceEnv(&tracer, &sample);
+  // Check that sampler doesn't crash
+  CHECK_EQ(10, CFunc(10));
+}
+
+
 #endif  // ENABLE_LOGGING_AND_PROFILING
diff --git a/test/cctest/test-regexp.cc b/test/cctest/test-regexp.cc
index ed2e9ab..afd9679 100644
--- a/test/cctest/test-regexp.cc
+++ b/test/cctest/test-regexp.cc
@@ -641,9 +641,10 @@
   Handle<ByteArray> array = Handle<ByteArray>::cast(m.GetCode(source));
   int captures[5];
 
-  Handle<String> f1 =
-      Factory::NewStringFromAscii(CStrVector("foobar"));
-  Handle<String> f1_16 = RegExpImpl::StringToTwoByte(f1);
+  const uc16 str1[] = {'f', 'o', 'o', 'b', 'a', 'r'};
+  Handle<String> f1_16 =
+      Factory::NewStringFromTwoByte(Vector<const uc16>(str1, 6));
+
   CHECK(IrregexpInterpreter::Match(array, f1_16, captures, 0));
   CHECK_EQ(0, captures[0]);
   CHECK_EQ(3, captures[1]);
@@ -651,9 +652,10 @@
   CHECK_EQ(2, captures[3]);
   CHECK_EQ(84, captures[4]);
 
-  Handle<String> f2 =
-      Factory::NewStringFromAscii(CStrVector("barfoo"));
-  Handle<String> f2_16 = RegExpImpl::StringToTwoByte(f2);
+  const uc16 str2[] = {'b', 'a', 'r', 'f', 'o', 'o'};
+  Handle<String> f2_16 =
+      Factory::NewStringFromTwoByte(Vector<const uc16>(str2, 6));
+
   CHECK(!IrregexpInterpreter::Match(array, f2_16, captures, 0));
   CHECK_EQ(42, captures[0]);
 }
@@ -677,36 +679,20 @@
   v8::internal::StackGuard stack_guard_;
 };
 
-// Helper functions for calling the Execute method.
-template <typename T>
-static RegExpMacroAssemblerIA32::Result ExecuteIA32(Code* code,
-                                                    const T** input,
-                                                    int start_offset,
-                                                    int end_offset,
-                                                    int* captures,
-                                                    bool at_start) {
-  return RegExpMacroAssemblerIA32::Execute(
-      code,
-      reinterpret_cast<Address*>(
-          reinterpret_cast<void*>(const_cast<T**>(input))),
-      start_offset,
-      end_offset,
-      captures,
-      at_start);
-}
 
-template <typename T>
 static RegExpMacroAssemblerIA32::Result ExecuteIA32(Code* code,
-                                                    T** input,
+                                                    String* input,
                                                     int start_offset,
-                                                    int end_offset,
+                                                    const byte* input_start,
+                                                    const byte* input_end,
                                                     int* captures,
                                                     bool at_start) {
   return RegExpMacroAssemblerIA32::Execute(
       code,
-      reinterpret_cast<Address*>(reinterpret_cast<void*>(input)),
+      input,
       start_offset,
-      end_offset,
+      input_start,
+      input_end,
       captures,
       at_start);
 }
@@ -727,15 +713,15 @@
   int captures[4] = {42, 37, 87, 117};
   Handle<String> input = Factory::NewStringFromAscii(CStrVector("foofoo"));
   Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input);
-  Address start_adr = seq_input->GetCharsAddress();
-  int start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
-  int end_offset = start_offset + seq_input->length();
+  const byte* start_adr =
+      reinterpret_cast<const byte*>(seq_input->GetCharsAddress());
 
   RegExpMacroAssemblerIA32::Result result =
       ExecuteIA32(*code,
-                  seq_input.location(),
-                  start_offset,
-                  end_offset,
+                  *input,
+                  0,
+                  start_adr,
+                  start_adr + seq_input->length(),
                   captures,
                   true);
 
@@ -773,14 +759,13 @@
   Handle<String> input = Factory::NewStringFromAscii(CStrVector("foofoo"));
   Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input);
   Address start_adr = seq_input->GetCharsAddress();
-  int start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
-  int end_offset = start_offset + seq_input->length();
 
   RegExpMacroAssemblerIA32::Result result =
       ExecuteIA32(*code,
-                  seq_input.location(),
-                  start_offset,
-                  end_offset,
+                  *input,
+                  0,
+                  start_adr,
+                  start_adr + input->length(),
                   captures,
                   true);
 
@@ -793,13 +778,12 @@
   input = Factory::NewStringFromAscii(CStrVector("barbarbar"));
   seq_input = Handle<SeqAsciiString>::cast(input);
   start_adr = seq_input->GetCharsAddress();
-  start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
-  end_offset = start_offset + seq_input->length();
 
   result = ExecuteIA32(*code,
-                       seq_input.location(),
-                       start_offset,
-                       end_offset,
+                       *input,
+                       0,
+                       start_adr,
+                       start_adr + input->length(),
                        captures,
                        true);
 
@@ -835,14 +819,13 @@
       Factory::NewStringFromTwoByte(Vector<const uc16>(input_data, 6));
   Handle<SeqTwoByteString> seq_input = Handle<SeqTwoByteString>::cast(input);
   Address start_adr = seq_input->GetCharsAddress();
-  int start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
-  int end_offset = start_offset + seq_input->length() * sizeof(uc16);
 
   RegExpMacroAssemblerIA32::Result result =
       ExecuteIA32(*code,
-                  seq_input.location(),
-                  start_offset,
-                  end_offset,
+                  *input,
+                  0,
+                  start_adr,
+                  start_adr + input->length(),
                   captures,
                   true);
 
@@ -856,13 +839,12 @@
   input = Factory::NewStringFromTwoByte(Vector<const uc16>(input_data2, 9));
   seq_input = Handle<SeqTwoByteString>::cast(input);
   start_adr = seq_input->GetCharsAddress();
-  start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
-  end_offset = start_offset + seq_input->length() * sizeof(uc16);
 
   result = ExecuteIA32(*code,
-                       seq_input.location(),
-                       start_offset,
-                       end_offset,
+                       *input,
+                       0,
+                       start_adr,
+                       start_adr + input->length() * 2,
                        captures,
                        true);
 
@@ -894,14 +876,13 @@
   Handle<String> input = Factory::NewStringFromAscii(CStrVector("foofoo"));
   Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input);
   Address start_adr = seq_input->GetCharsAddress();
-  int start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
-  int end_offset = start_offset + seq_input->length();
 
   RegExpMacroAssemblerIA32::Result result =
       ExecuteIA32(*code,
-                  seq_input.location(),
-                  start_offset,
-                  end_offset,
+                  *input,
+                  0,
+                  start_adr,
+                  start_adr + input->length(),
                   NULL,
                   true);
 
@@ -937,15 +918,14 @@
   Handle<String> input = Factory::NewStringFromAscii(CStrVector("fooofo"));
   Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input);
   Address start_adr = seq_input->GetCharsAddress();
-  int start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
-  int end_offset = start_offset + seq_input->length();
 
   int output[3];
   RegExpMacroAssemblerIA32::Result result =
       ExecuteIA32(*code,
-                  seq_input.location(),
-                  start_offset,
-                  end_offset,
+                  *input,
+                  0,
+                  start_adr,
+                  start_adr + input->length(),
                   output,
                   true);
 
@@ -987,15 +967,13 @@
   Handle<SeqTwoByteString> seq_input = Handle<SeqTwoByteString>::cast(input);
   Address start_adr = seq_input->GetCharsAddress();
 
-  int start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
-  int end_offset = start_offset + seq_input->length() * sizeof(input_data[0]);
-
   int output[3];
   RegExpMacroAssemblerIA32::Result result =
       ExecuteIA32(*code,
-                  seq_input.location(),
-                  start_offset,
-                  end_offset,
+                  *input,
+                  0,
+                  start_adr,
+                  start_adr + input->length() * 2,
                   output,
                   true);
 
@@ -1041,24 +1019,23 @@
   Handle<String> input = Factory::NewStringFromAscii(CStrVector("foobar"));
   Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input);
   Address start_adr = seq_input->GetCharsAddress();
-  int start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
-  int end_offset = start_offset + seq_input->length();
 
   RegExpMacroAssemblerIA32::Result result =
       ExecuteIA32(*code,
-                  seq_input.location(),
-                  start_offset,
-                  end_offset,
+                  *input,
+                  0,
+                  start_adr,
+                  start_adr + input->length(),
                   NULL,
                   true);
 
   CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result);
 
-  start_offset += 3;
   result = ExecuteIA32(*code,
-                       seq_input.location(),
-                       start_offset,
-                       end_offset,
+                       *input,
+                       3,
+                       start_adr + 3,
+                       start_adr + input->length(),
                        NULL,
                        false);
 
@@ -1103,15 +1080,14 @@
       Factory::NewStringFromAscii(CStrVector("aBcAbCABCxYzab"));
   Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input);
   Address start_adr = seq_input->GetCharsAddress();
-  int start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
-  int end_offset = start_offset + seq_input->length();
 
   int output[4];
   RegExpMacroAssemblerIA32::Result result =
       ExecuteIA32(*code,
-                  seq_input.location(),
-                  start_offset,
-                  end_offset,
+                  *input,
+                  0,
+                  start_adr,
+                  start_adr + input->length(),
                   output,
                   true);
 
@@ -1204,15 +1180,14 @@
       Factory::NewStringFromAscii(CStrVector("foofoofoofoofoo"));
   Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input);
   Address start_adr = seq_input->GetCharsAddress();
-  int start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
-  int end_offset = start_offset + seq_input->length();
 
   int output[5];
   RegExpMacroAssemblerIA32::Result result =
       ExecuteIA32(*code,
-                  seq_input.location(),
-                  start_offset,
-                  end_offset,
+                  *input,
+                  0,
+                  start_adr,
+                  start_adr + input->length(),
                   output,
                   true);
 
@@ -1246,14 +1221,13 @@
       Factory::NewStringFromAscii(CStrVector("dummy"));
   Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input);
   Address start_adr = seq_input->GetCharsAddress();
-  int start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
-  int end_offset = start_offset + seq_input->length();
 
   RegExpMacroAssemblerIA32::Result result =
       ExecuteIA32(*code,
-                  seq_input.location(),
-                  start_offset,
-                  end_offset,
+                  *input,
+                  0,
+                  start_adr,
+                  start_adr + input->length(),
                   NULL,
                   true);
 
@@ -1292,15 +1266,14 @@
       Factory::NewStringFromAscii(CStrVector("sample text"));
   Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input);
   Address start_adr = seq_input->GetCharsAddress();
-  int start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
-  int end_offset = start_offset + seq_input->length();
 
   int captures[2];
   RegExpMacroAssemblerIA32::Result result =
       ExecuteIA32(*code,
-                  seq_input.location(),
-                  start_offset,
-                  end_offset,
+                  *input,
+                  0,
+                  start_adr,
+                  start_adr + input->length(),
                   captures,
                   true);
 
diff --git a/test/cctest/test-sockets.cc b/test/cctest/test-sockets.cc
index 9316a26..a4b2285 100644
--- a/test/cctest/test-sockets.cc
+++ b/test/cctest/test-sockets.cc
@@ -8,13 +8,10 @@
 using namespace ::v8::internal;
 
 
-static const char* kPort = "5858";
-static const char* kLocalhost = "localhost";
-
 class SocketListenerThread : public Thread {
  public:
-  explicit SocketListenerThread(int data_size)
-      : data_size_(data_size), server_(NULL), client_(NULL),
+  explicit SocketListenerThread(int port, int data_size)
+      : port_(port), data_size_(data_size), server_(NULL), client_(NULL),
         listening_(OS::CreateSemaphore(0)) {
     data_ = new char[data_size_];
   }
@@ -22,6 +19,8 @@
     // Close both sockets.
     delete client_;
     delete server_;
+    delete listening_;
+    delete[] data_;
   }
 
   void Run();
@@ -29,6 +28,7 @@
   char* data() { return data_; }
 
  private:
+  int port_;
   char* data_;
   int data_size_;
   Socket* server_;  // Server socket used for bind/accept.
@@ -43,7 +43,7 @@
   // Create the server socket and bind it to the requested port.
   server_ = OS::CreateSocket();
   CHECK(server_ != NULL);
-  ok = server_->Bind(5858);
+  ok = server_->Bind(port_);
   CHECK(ok);
 
   // Listen for new connections.
@@ -76,18 +76,25 @@
 }
 
 
-static void SendAndReceive(char *data, int len) {
+static void SendAndReceive(int port, char *data, int len) {
+  static const char* kLocalhost = "localhost";
+
   bool ok;
 
+  // Make a string with the port number.
+  const int kPortBuferLen = 6;
+  char port_str[kPortBuferLen];
+  OS::SNPrintF(Vector<char>(port_str, kPortBuferLen), "%d", port);
+
   // Create a socket listener.
-  SocketListenerThread* listener = new SocketListenerThread(len);
+  SocketListenerThread* listener = new SocketListenerThread(port, len);
   listener->Start();
   listener->WaitForListening();
 
   // Connect and write some data.
   Socket* client = OS::CreateSocket();
   CHECK(client != NULL);
-  ok = client->Connect(kLocalhost, kPort);
+  ok = client->Connect(kLocalhost, port_str);
   CHECK(ok);
 
   // Send all the data.
@@ -103,12 +110,17 @@
   }
 
   // Close the client before the listener to avoid TIME_WAIT issues.
+  client->Shutdown();
   delete client;
   delete listener;
 }
 
 
 TEST(Socket) {
+  // Make sure this port is not used by other tests to allow tests to run in
+  // parallel.
+  static const int kPort = 5859;
+
   bool ok;
 
   // Initialize socket support.
@@ -118,7 +130,7 @@
   // Send and receive some data.
   static const int kBufferSizeSmall = 20;
   char small_data[kBufferSizeSmall + 1] = "1234567890abcdefghij";
-  SendAndReceive(small_data, kBufferSizeSmall);
+  SendAndReceive(kPort, small_data, kBufferSizeSmall);
 
   // Send and receive some more data.
   static const int kBufferSizeMedium = 10000;
@@ -126,7 +138,8 @@
   for (int i = 0; i < kBufferSizeMedium; i++) {
     medium_data[i] = i % 256;
   }
-  SendAndReceive(medium_data, kBufferSizeMedium);
+  SendAndReceive(kPort, medium_data, kBufferSizeMedium);
+  delete[] medium_data;
 
   // Send and receive even more data.
   static const int kBufferSizeLarge = 1000000;
@@ -134,7 +147,8 @@
   for (int i = 0; i < kBufferSizeLarge; i++) {
     large_data[i] = i % 256;
   }
-  SendAndReceive(large_data, kBufferSizeLarge);
+  SendAndReceive(kPort, large_data, kBufferSizeLarge);
+  delete[] large_data;
 }
 
 
diff --git a/test/cctest/test-strings.cc b/test/cctest/test-strings.cc
index c5e7352..f8c1a46 100644
--- a/test/cctest/test-strings.cc
+++ b/test/cctest/test-strings.cc
@@ -62,8 +62,7 @@
         building_blocks[i] =
             Factory::NewStringFromTwoByte(Vector<const uc16>(buf, len));
         for (int j = 0; j < len; j++) {
-          StringShape shape(*building_blocks[i]);
-          CHECK_EQ(buf[j], building_blocks[i]->Get(shape, j));
+          CHECK_EQ(buf[j], building_blocks[i]->Get(j));
         }
         break;
       }
@@ -75,8 +74,7 @@
         building_blocks[i] =
             Factory::NewStringFromAscii(Vector<const char>(buf, len));
         for (int j = 0; j < len; j++) {
-          StringShape shape(*building_blocks[i]);
-          CHECK_EQ(buf[j], building_blocks[i]->Get(shape, j));
+          CHECK_EQ(buf[j], building_blocks[i]->Get(j));
         }
         break;
       }
@@ -101,8 +99,7 @@
         Resource* resource = new Resource(Vector<const uc16>(buf, len));
         building_blocks[i] = Factory::NewExternalStringFromTwoByte(resource);
         for (int j = 0; j < len; j++) {
-          StringShape shape(*building_blocks[i]);
-          CHECK_EQ(buf[j], building_blocks[i]->Get(shape, j));
+          CHECK_EQ(buf[j], building_blocks[i]->Get(j));
         }
         break;
       }
@@ -114,9 +111,9 @@
         building_blocks[i] =
             Factory::NewStringFromAscii(Vector<const char>(buf, len));
         for (int j = 0; j < len; j++) {
-          StringShape shape(*building_blocks[i]);
-          CHECK_EQ(buf[j], building_blocks[i]->Get(shape, j));
+          CHECK_EQ(buf[j], building_blocks[i]->Get(j));
         }
+        DeleteArray<char>(buf);
         break;
       }
     }
@@ -131,9 +128,7 @@
   for (int i = 0; i < depth; i++) {
     answer = Factory::NewConsString(
         answer,
-        StringShape(*answer),
-        building_blocks[i % NUMBER_OF_BUILDING_BLOCKS],
-        StringShape(*building_blocks[i % NUMBER_OF_BUILDING_BLOCKS]));
+        building_blocks[i % NUMBER_OF_BUILDING_BLOCKS]);
   }
   return answer;
 }
@@ -146,9 +141,7 @@
   for (int i = depth - 1; i >= 0; i--) {
     answer = Factory::NewConsString(
         building_blocks[i % NUMBER_OF_BUILDING_BLOCKS],
-        StringShape(*building_blocks[i % NUMBER_OF_BUILDING_BLOCKS]),
-        answer,
-        StringShape(*answer));
+        answer);
   }
   return answer;
 }
@@ -165,19 +158,13 @@
   if (to - from == 2) {
     return Factory::NewConsString(
         building_blocks[from % NUMBER_OF_BUILDING_BLOCKS],
-        StringShape(*building_blocks[from % NUMBER_OF_BUILDING_BLOCKS]),
-        building_blocks[(from+1) % NUMBER_OF_BUILDING_BLOCKS],
-        StringShape(*building_blocks[(from+1) % NUMBER_OF_BUILDING_BLOCKS]));
+        building_blocks[(from+1) % NUMBER_OF_BUILDING_BLOCKS]);
   }
   Handle<String> part1 =
     ConstructBalancedHelper(building_blocks, from, from + ((to - from) / 2));
   Handle<String> part2 =
     ConstructBalancedHelper(building_blocks, from + ((to - from) / 2), to);
-  return Factory::NewConsString(
-      part1,
-      StringShape(*part1),
-      part2,
-      StringShape(*part2));
+  return Factory::NewConsString(part1, part2);
 }
 
 
@@ -215,8 +202,8 @@
     CHECK_EQ(c, buffer2.GetNext());
     i++;
   }
-  s1->Get(StringShape(*s1), s1->length() - 1);
-  s2->Get(StringShape(*s2), s2->length() - 1);
+  s1->Get(s1->length() - 1);
+  s2->Get(s2->length() - 1);
 }
 
 
@@ -298,19 +285,13 @@
     Handle<String> rhs = building_blocks[(from+1) % NUMBER_OF_BUILDING_BLOCKS];
     if (gen() % 2 == 0)
       rhs = SliceOf(rhs);
-    return Factory::NewConsString(lhs,
-                                  StringShape(*lhs),
-                                  rhs,
-                                  StringShape(*rhs));
+    return Factory::NewConsString(lhs, rhs);
   }
   Handle<String> part1 =
     ConstructBalancedHelper(building_blocks, from, from + ((to - from) / 2));
   Handle<String> part2 =
     ConstructBalancedHelper(building_blocks, from + ((to - from) / 2), to);
-  Handle<String> branch = Factory::NewConsString(part1,
-                                                 StringShape(*part1),
-                                                 part2,
-                                                 StringShape(*part2));
+  Handle<String> branch = Factory::NewConsString(part1, part2);
   if (gen() % 2 == 0)
     return branch;
   return(SliceOf(branch));
@@ -350,20 +331,15 @@
       Factory::NewStringFromAscii(Vector<const char>(foo, DEEP_ASCII_DEPTH));
   Handle<String> foo_string = Factory::NewStringFromAscii(CStrVector("foo"));
   for (int i = 0; i < DEEP_ASCII_DEPTH; i += 10) {
-    string = Factory::NewConsString(string,
-                                    StringShape(*string),
-                                    foo_string,
-                                    StringShape(*foo_string));
+    string = Factory::NewConsString(string, foo_string);
   }
-  Handle<String> flat_string = Factory::NewConsString(string,
-                                                      StringShape(*string),
-                                                      foo_string,
-                                                      StringShape(*foo_string));
+  Handle<String> flat_string = Factory::NewConsString(string, foo_string);
   FlattenString(flat_string);
 
   for (int i = 0; i < 500; i++) {
     TraverseFirst(flat_string, string, DEEP_ASCII_DEPTH);
   }
+  DeleteArray<char>(foo);
 }
 
 
diff --git a/test/cctest/test-utils.cc b/test/cctest/test-utils.cc
index 187cba9..acb5d3c 100644
--- a/test/cctest/test-utils.cc
+++ b/test/cctest/test-utils.cc
@@ -174,5 +174,6 @@
     } else {
       CHECK_EQ(length, strlen(buffer.start()));
     }
+    buffer.Dispose();
   }
 }
diff --git a/test/mjsunit/big-array-literal.js b/test/mjsunit/big-array-literal.js
new file mode 100644
index 0000000..d64c968
--- /dev/null
+++ b/test/mjsunit/big-array-literal.js
@@ -0,0 +1,111 @@
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test that we can make large object literals that work.
+// Also test that we can attempt to make even larger object literals without
+// crashing.
+function testLiteral(size, array_in_middle) {
+  print(size);
+
+  var f;
+
+  // Build object-literal string.
+  var literal = "function f() { return ";
+
+  for (var i = 0; i < size; i++) {
+    literal += "[";
+  }
+
+  literal += array_in_middle ? " [42.2]" : "{a:42.2}";
+
+  for (var i = 0; i < size; i++) {
+    literal += "]";
+  }
+
+  literal += "; }";
+
+  // Create the object literal.
+  eval(literal);
+
+  var x = f();
+
+  // Check that the properties have the expected values.
+  for (var i = 0; i < size; i++) {
+    x = x[0];
+  }
+
+  if (array_in_middle) {
+    assertEquals(42.2, x[0]), "x array in middle";
+    x[0] = 41.2;
+  } else {
+    assertEquals(42.2, x.a, "x object in middle");
+    x.a = 41.2;
+  }
+
+  var y = f();
+  for (var i = 0; i < size; i++) {
+    y = y[0];
+  }
+
+  if (array_in_middle) {
+    assertEquals(42.2, y[0], "y array in middle");
+    y[0] = 41.2;
+  } else {
+    assertEquals(42.2, y.a, "y object in middle");
+    y.a = 41.2;
+  }
+}
+
+// The sizes to test.
+var sizes = [1, 2, 100, 200, 400];
+
+// Run the test.
+for (var i = 0; i < sizes.length; i++) {
+  testLiteral(sizes[i], false);
+  testLiteral(sizes[i], true);
+}
+
+function testLiteralAndCatch(size) {
+  var big_enough = false;
+  try {
+    testLiteral(size, false);
+  } catch (e) {
+    big_enough = true;
+  }
+  try {
+    testLiteral(size, true);
+  } catch (e) {
+    big_enough = true;
+  }
+  return big_enough;
+}
+
+// Catch stack overflows.
+
+testLiteralAndCatch(1000) ||
+testLiteralAndCatch(20000) ||
+testLiteralAndCatch(200000);
diff --git a/test/mjsunit/big-object-literal.js b/test/mjsunit/big-object-literal.js
new file mode 100644
index 0000000..0099ce9
--- /dev/null
+++ b/test/mjsunit/big-object-literal.js
@@ -0,0 +1,114 @@
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test that we can make large object literals that work.
+// Also test that we can attempt to make even larger object literals without
+// crashing.
+function testLiteral(size, array_in_middle) {
+  print(size);
+
+  var f;
+
+  // Build object-literal string.
+  var literal = "function f() { return ";
+
+  for (var i = 0; i < size; i++) {
+    literal += "{a:";
+  }
+
+  literal += array_in_middle ? " [42.2]" : "{a:42.2}";
+
+  for (var i = 0; i < size; i++) {
+    literal += "}";
+    if (i < size - 1) {
+      literal += ", b:42, c:/asd/, x:'foo', y:[], z:new Object()";
+    }
+  }
+
+  literal += "; }";
+
+  // Create the object literal.
+  eval(literal);
+
+  var x = f();
+
+  // Check that the properties have the expected values.
+  for (var i = 0; i < size; i++) {
+    x = x.a;
+  }
+
+  if (array_in_middle) {
+    assertEquals(42.2, x[0]), "x array in middle";
+    x[0] = 41.2;
+  } else {
+    assertEquals(42.2, x.a, "x object in middle");
+    x.a = 41.2;
+  }
+
+  var y = f();
+  for (var i = 0; i < size; i++) {
+    y = y.a;
+  }
+
+  if (array_in_middle) {
+    assertEquals(42.2, y[0], "y array in middle");
+    y[0] = 41.2;
+  } else {
+    assertEquals(42.2, y.a, "y object in middle");
+    y.a = 41.2;
+  }
+}
+
+// The sizes to test.
+var sizes = [1, 2, 100, 200, 400];
+
+// Run the test.
+for (var i = 0; i < sizes.length; i++) {
+  testLiteral(sizes[i], false);
+  testLiteral(sizes[i], true);
+}
+
+function testLiteralAndCatch(size) {
+  var big_enough = false;
+  try {
+    testLiteral(size, false);
+  } catch (e) {
+    big_enough = true;
+  }
+  try {
+    testLiteral(size, true);
+  } catch (e) {
+    big_enough = true;
+  }
+  return big_enough;
+}
+
+// Catch stack overflows.
+
+testLiteralAndCatch(1000) ||
+testLiteralAndCatch(20000) ||
+testLiteralAndCatch(200000);
diff --git a/test/mjsunit/date-parse.js b/test/mjsunit/date-parse.js
index 1e09db5..4464727 100644
--- a/test/mjsunit/date-parse.js
+++ b/test/mjsunit/date-parse.js
@@ -41,12 +41,13 @@
 // number of milliseconds to make it timezone independent.
 function testDateParseLocalTime(string) {
   var d = Date.parse(string);
-  assertTrue(d > 0 && !isNaN(d));
+  assertTrue(!isNaN(d), string + " is NaN.");
+  assertTrue(d > 0, string + " <= 0.");
 };
 
 
 function testDateParseMisc(array) {
-  assertTrue(array.length == 2);
+  assertEquals(2, array.length, "array [" + array + "] length != 2.");
   var string = array[0];
   var expected = array[1];
   var d = Date.parse(string);
@@ -262,4 +263,6 @@
     'May 25 2008 1:30( )AM (PM)',
     'May 25 2008 AAA (GMT)'];
 
-testCasesNegative.forEach(function (s) { assertTrue(isNaN(Date.parse(s))); });
+testCasesNegative.forEach(function (s) {
+    assertTrue(isNaN(Date.parse(s)), s + " is not NaN.");
+});
diff --git a/test/mjsunit/fuzz-natives.js b/test/mjsunit/fuzz-natives.js
index 64331d1..debcc9a 100644
--- a/test/mjsunit/fuzz-natives.js
+++ b/test/mjsunit/fuzz-natives.js
@@ -121,7 +121,9 @@
   "PushContext": true,
   "LazyCompile": true,
   "CreateObjectLiteralBoilerplate": true,
-  "CloneObjectLiteralBoilerplate": true,
+  "CloneLiteralBoilerplate": true,
+  "CloneShallowLiteralBoilerplate": true,
+  "CreateArrayLiteralBoilerplate": true,
   "IS_VAR": true,
   "ResolvePossiblyDirectEval": true,
   "Log": true
diff --git a/test/mjsunit/getter-in-prototype.js b/test/mjsunit/getter-in-prototype.js
new file mode 100644
index 0000000..dd26c53
--- /dev/null
+++ b/test/mjsunit/getter-in-prototype.js
@@ -0,0 +1,50 @@
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test that exceptions are thrown when setting properties on object
+// that have only a getter in a prototype object.
+
+var o = {};
+var p = {};
+p.__defineGetter__('x', function(){});
+o.__proto__ = p;
+
+assertThrows("o.x = 42");
+
+function f() {
+  with(o) {
+    x = 42;
+  }
+}
+assertThrows("f()");
+
+__proto__ = p;
+function g() {
+  eval('1');
+  x = 42;
+}
+assertThrows("g()");
diff --git a/test/mjsunit/indexed-accessors.js b/test/mjsunit/indexed-accessors.js
new file mode 100644
index 0000000..07ce243
--- /dev/null
+++ b/test/mjsunit/indexed-accessors.js
@@ -0,0 +1,100 @@
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test that getters can be defined and called with an index as a parameter.
+
+var o = {};
+o.x = 42;
+o.__defineGetter__('0', function() { return o.x; });
+assertEquals(o.x, o[0]);
+assertEquals(o.x, o.__lookupGetter__('0')());
+
+o.__defineSetter__('0', function(y) { o.x = y; });
+assertEquals(o.x, o[0]);
+assertEquals(o.x, o.__lookupGetter__('0')());
+o[0] = 21;
+assertEquals(21, o.x);
+o.__lookupSetter__(0)(7);
+assertEquals(7, o.x);
+
+function Pair(x, y) {
+  this.x = x;
+  this.y = y;
+};
+Pair.prototype.__defineGetter__('0', function() { return this.x; });
+Pair.prototype.__defineGetter__('1', function() { return this.y; });
+Pair.prototype.__defineSetter__('0', function(x) { this.x = x; });
+Pair.prototype.__defineSetter__('1', function(y) { this.y = y; });
+
+var p = new Pair(2, 3);
+assertEquals(2, p[0]);
+assertEquals(3, p[1]);
+p.x = 7;
+p[1] = 8;
+assertEquals(7, p[0]);
+assertEquals(7, p.x);
+assertEquals(8, p[1]);
+assertEquals(8, p.y);
+
+
+// Testing that a defined getter doesn't get lost due to inline caching.
+var expected = {};
+var actual = {};
+for (var i = 0; i < 10; i++) {
+  expected[i] = actual[i] = i;
+}
+function testArray() {
+  for (var i = 0; i < 10; i++) {
+    assertEquals(expected[i], actual[i]);
+  }
+}
+actual[1000000] = -1;
+testArray();
+testArray();
+actual.__defineGetter__('0', function() { return expected[0]; });
+expected[0] = 42;
+testArray();
+expected[0] = 111;
+testArray();
+
+// The functionality is not implemented for arrays due to performance issues.
+var a = [ 1 ];
+a.__defineGetter__('2', function() { return 7; });
+assertEquals(undefined, a[2]);
+assertEquals(1, a.length);
+var b = 0;
+a.__defineSetter__('5', function(y) { b = y; });
+assertEquals(1, a.length);
+a[5] = 42;
+assertEquals(0, b);
+assertEquals(42, a[5]);
+assertEquals(6, a.length);
+
+// Using a setter where only a getter is defined throws an exception.
+var q = {};
+q.__defineGetter__('0', function() { return 42; });
+assertThrows('q[0] = 7');
diff --git a/test/mjsunit/mjsunit.status b/test/mjsunit/mjsunit.status
index 375978e..276f5a4 100644
--- a/test/mjsunit/mjsunit.status
+++ b/test/mjsunit/mjsunit.status
@@ -34,6 +34,8 @@
 # too long to run in debug mode on ARM.
 fuzz-natives: PASS, SKIP if ($mode == release || $arch == arm)
 
+big-object-literal: PASS, SKIP if ($arch == arm)
+
 # Bug realiably triggers a debug assertion and crashed in release mode.
 bugs/bug-269: CRASH, FAIL if $mode == debug
 
diff --git a/test/mjsunit/object-literal.js b/test/mjsunit/object-literal.js
index e2da84b..cc6f59d 100644
--- a/test/mjsunit/object-literal.js
+++ b/test/mjsunit/object-literal.js
@@ -58,6 +58,48 @@
   }
 }
 
-arr[0].a = 2;
-assertEquals(2, arr[0].a);
-assertEquals(7, arr[1].a);
+arr[0].b.x = 2;
+assertEquals(2, arr[0].b.x);
+assertEquals(12, arr[1].b.x);
+
+
+function makeSparseArray() {
+  return {
+    '0': { x: 12, y: 24 },
+    '1000000': { x: 0, y: 0 }
+  };
+}
+
+var sa1 = makeSparseArray();
+sa1[0].x = 0;
+var sa2 = makeSparseArray();
+assertEquals(12, sa2[0].x);
+
+// Test that non-constant literals work.
+var n = new Object();
+
+function makeNonConstantArray() { return [ [ n ] ]; }
+
+var a = makeNonConstantArray();
+a[0][0].foo = "bar";
+assertEquals("bar", n.foo);
+
+function makeNonConstantObject() { return { a: { b: n } }; }
+
+a = makeNonConstantObject();
+a.a.b.bar = "foo";
+assertEquals("foo", n.bar);
+
+// Test that exceptions for regexps still hold.
+function makeRegexpInArray() { return [ [ /a*/, {} ] ]; }
+
+a = makeRegexpInArray();
+var b = makeRegexpInArray();
+assertTrue(a[0][0] === b[0][0]);
+assertFalse(a[0][1] === b[0][1]);
+
+function makeRegexpInObject() { return { a: { b: /b*/, c: {} } }; }
+a = makeRegexpInObject();
+b = makeRegexpInObject();
+assertTrue(a.a.b === b.a.b);
+assertFalse(a.a.c === b.a.c);
diff --git a/test/mjsunit/regress/regress-279.js b/test/mjsunit/regress/regress-279.js
index 7f95b16..e500dd6 100644
--- a/test/mjsunit/regress/regress-279.js
+++ b/test/mjsunit/regress/regress-279.js
@@ -50,4 +50,13 @@
 a = makeObjectInArray();
 a[0].bar = 1;
 b = makeObjectInArray();
-assertEquals('undefined', typeof(b[0].bar), "Object in object");
+assertEquals('undefined', typeof(b[0].bar), "Object in array");
+
+function makeArrayInArray() {
+  return [ [] ];
+}
+
+a = makeArrayInArray();
+a[0].push(5);
+b = makeArrayInArray();
+assertEquals(0, b[0].length, "Array in array");
diff --git a/test/mjsunit/regress/regress-284.js b/test/mjsunit/regress/regress-284.js
new file mode 100644
index 0000000..ecfdeea
--- /dev/null
+++ b/test/mjsunit/regress/regress-284.js
@@ -0,0 +1,50 @@
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// See http://code.google.com/p/v8/issues/detail?id=284
+
+function continueWithinLoop() {
+  var result;
+  for (var key in [0]) {
+    result = "hopla";
+    continue;
+  }
+  return result;
+};
+
+assertEquals("hopla", continueWithinLoop());
+
+function breakWithinLoop() {
+  var result;
+  for (var key in [0]) {
+    result = "hopla";
+    break;
+  }
+  return result;
+};
+
+assertEquals("hopla", continueWithinLoop());
diff --git a/test/mjsunit/regress/regress-286.js b/test/mjsunit/regress/regress-286.js
new file mode 100644
index 0000000..361b726
--- /dev/null
+++ b/test/mjsunit/regress/regress-286.js
@@ -0,0 +1,36 @@
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// See http://code.google.com/p/v8/issues/detail?id=286
+
+function test() {
+  var o = [1];
+  var a = o[o ^= 1];
+  return a;
+};
+
+assertEquals(1, test());
diff --git a/test/mjsunit/string-replace-gc.js b/test/mjsunit/string-replace-gc.js
new file mode 100644
index 0000000..26fba10
--- /dev/null
+++ b/test/mjsunit/string-replace-gc.js
@@ -0,0 +1,57 @@
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --always-compact
+//
+// Regression test for the r1512 fix.
+
+var foo = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
+
+foo = foo + foo;
+foo = foo + foo;
+foo = foo + foo;
+foo = foo + foo;
+foo = foo + foo;
+foo = foo + foo;
+foo = foo + foo;
+foo = foo + foo;
+foo = foo + foo;
+foo = foo + foo;
+foo = foo + foo;
+foo = foo + foo;
+foo = foo + foo;
+foo = foo + foo;
+foo = foo + foo;
+
+foo.replace(/[b]/, "c");  // Flatten foo.
+
+var moving_string = "b" + "c";
+
+var bar = foo.replace(/[a]/g, moving_string);
+
+print(bar.length);
+
diff --git a/test/mjsunit/string-replace.js b/test/mjsunit/string-replace.js
new file mode 100644
index 0000000..d5ec2aa
--- /dev/null
+++ b/test/mjsunit/string-replace.js
@@ -0,0 +1,173 @@
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+/**
+ * @fileoverview Test String.prototype.replace
+ */
+
+function replaceTest(result, subject, pattern, replacement) {
+  var name = 
+    "\"" + subject + "\".replace(" + pattern + ", " + replacement + ")";
+  assertEquals(result, subject.replace(pattern, replacement), name);
+}
+
+
+var short = "xaxbxcx";
+
+replaceTest("axbxcx", short, "x", "");
+replaceTest("axbxcx", short, /x/, "");
+replaceTest("abc", short, /x/g, "");
+
+replaceTest("xaxxcx", short, "b", "");
+replaceTest("xaxxcx", short, /b/, "");
+replaceTest("xaxxcx", short, /b/g, "");
+
+
+replaceTest("[]axbxcx", short, "x", "[]");
+replaceTest("[]axbxcx", short, /x/, "[]");
+replaceTest("[]a[]b[]c[]", short, /x/g, "[]");
+
+replaceTest("xax[]xcx", short, "b", "[]");
+replaceTest("xax[]xcx", short, /b/, "[]");
+replaceTest("xax[]xcx", short, /b/g, "[]");
+
+
+replaceTest("[$]axbxcx", short, "x", "[$$]");
+replaceTest("[$]axbxcx", short, /x/, "[$$]");
+replaceTest("[$]a[$]b[$]c[$]", short, /x/g, "[$$]");
+
+replaceTest("xax[$]xcx", short, "b", "[$$]");
+replaceTest("xax[$]xcx", short, /b/, "[$$]");
+replaceTest("xax[$]xcx", short, /b/g, "[$$]");
+
+
+replaceTest("[]axbxcx", short, "x", "[$`]");
+replaceTest("[]axbxcx", short, /x/, "[$`]");
+replaceTest("[]a[xa]b[xaxb]c[xaxbxc]", short, /x/g, "[$`]");
+
+replaceTest("xax[xax]xcx", short, "b", "[$`]");
+replaceTest("xax[xax]xcx", short, /b/, "[$`]");
+replaceTest("xax[xax]xcx", short, /b/g, "[$`]");
+
+
+replaceTest("[x]axbxcx", short, "x", "[$&]");
+replaceTest("[x]axbxcx", short, /x/, "[$&]");
+replaceTest("[x]a[x]b[x]c[x]", short, /x/g, "[$&]");
+
+replaceTest("xax[b]xcx", short, "b", "[$&]");
+replaceTest("xax[b]xcx", short, /b/, "[$&]");
+replaceTest("xax[b]xcx", short, /b/g, "[$&]");
+
+
+replaceTest("[axbxcx]axbxcx", short, "x", "[$']");
+replaceTest("[axbxcx]axbxcx", short, /x/, "[$']");
+replaceTest("[axbxcx]a[bxcx]b[cx]c[]", short, /x/g, "[$']");
+
+replaceTest("xax[xcx]xcx", short, "b", "[$']");
+replaceTest("xax[xcx]xcx", short, /b/, "[$']");
+replaceTest("xax[xcx]xcx", short, /b/g, "[$']");
+
+
+replaceTest("[$1]axbxcx", short, "x", "[$1]");
+replaceTest("[$1]axbxcx", short, /x/, "[$1]");
+replaceTest("[]axbxcx", short, /x()/, "[$1]");
+replaceTest("[$1]a[$1]b[$1]c[$1]", short, /x/g, "[$1]");
+replaceTest("[]a[]b[]c[]", short, /x()/g, "[$1]");
+
+replaceTest("xax[$1]xcx", short, "b", "[$1]");
+replaceTest("xax[$1]xcx", short, /b/, "[$1]");
+replaceTest("xax[]xcx", short, /b()/, "[$1]");
+replaceTest("xax[$1]xcx", short, /b/g, "[$1]");
+replaceTest("xax[]xcx", short, /b()/g, "[$1]");
+
+
+replaceTest("[$$$1$$a1abb1bb0$002$3$03][$$$1$$b1bcc1cc0$002$3$03]c", 
+            "abc", /(.)(?=(.))/g, "[$$$$$$1$$$$$11$01$2$21$02$020$002$3$03]"); 
+
+// Replace with functions.
+
+
+var ctr = 0;
+replaceTest("0axbxcx", short, "x", function r(m, i, s) {
+  assertEquals(3, arguments.length, "replace('x',func) func-args");
+  assertEquals("x", m, "replace('x',func(m,..))");
+  assertEquals(0, i, "replace('x',func(..,i,..))");
+  assertEquals(short, s, "replace('x',func(..,s))");
+  return String(ctr++);
+});
+assertEquals(1, ctr, "replace('x',func) num-match");
+
+ctr = 0;
+replaceTest("0axbxcx", short, /x/, function r(m, i, s) {
+  assertEquals(3, arguments.length, "replace(/x/,func) func-args");
+  assertEquals("x", m, "replace(/x/,func(m,..))");
+  assertEquals(0, i, "replace(/x/,func(..,i,..))");
+  assertEquals(short, s, "replace(/x/,func(..,s))");
+  return String(ctr++);
+});
+assertEquals(1, ctr, "replace(/x/,func) num-match");
+
+ctr = 0;
+replaceTest("0a1b2c3", short, /x/g, function r(m, i, s) {
+  assertEquals(3, arguments.length, "replace(/x/g,func) func-args");
+  assertEquals("x", m, "replace(/x/g,func(m,..))");
+  assertEquals(ctr * 2, i, "replace(/x/g,func(..,i,.))");
+  assertEquals(short, s, "replace(/x/g,func(..,s))");
+  return String(ctr++);
+});
+assertEquals(4, ctr, "replace(/x/g,func) num-match");
+
+ctr = 0;
+replaceTest("0a1b2cx", short, /(x)(?=(.))/g, function r(m, c1, c2, i, s) {
+  assertEquals(5, arguments.length, "replace(/(x)(?=(.))/g,func) func-args");
+  assertEquals("x", m, "replace(/(x)(?=(.))/g,func(m,..))");
+  assertEquals("x", c1, "replace(/(x)(?=(.))/g,func(..,c1,..))");
+  assertEquals(["a","b","c"][ctr], c2, "replace(/(x)(?=(.))/g,func(..,c2,..))");
+  assertEquals(ctr * 2, i, "replace(/(x)(?=(.))/g,func(..,i,..))");
+  assertEquals(short, s, "replace(/(x)(?=(.))/g,func(..,s))");
+  return String(ctr++);
+});
+assertEquals(3, ctr, "replace(/x/g,func) num-match");
+
+
+// Test special cases of replacement parts longer than 1<<11.
+var longstring = "xyzzy";
+longstring = longstring + longstring;
+longstring = longstring + longstring;
+longstring = longstring + longstring;
+longstring = longstring + longstring;
+longstring = longstring + longstring;
+longstring = longstring + longstring;
+longstring = longstring + longstring;
+longstring = longstring + longstring;
+longstring = longstring + longstring;
+longstring = longstring + longstring;
+longstring = longstring + longstring;
+// longstring.length == 5 << 11
+
+replaceTest(longstring + longstring, 
+            "<" + longstring + ">", /<(.*)>/g, "$1$1");
diff --git a/test/mjsunit/with-prototype.js b/test/mjsunit/with-prototype.js
new file mode 100644
index 0000000..e760f4e
--- /dev/null
+++ b/test/mjsunit/with-prototype.js
@@ -0,0 +1,44 @@
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test the behavior of an assignment in a with statement where the
+// extension object contains a property with the name assigned to in
+// the prototype chain.
+
+var o = {};
+var p = { x: 42 };
+o.__proto__ = p;
+
+function f() {
+  with (o) {
+    x = 123;
+  }
+}
+f();
+
+assertEquals(42, p.x);
+assertEquals(123, o.x);
diff --git a/tools/test.py b/tools/test.py
index 0ed5e9b..2b55d65 100755
--- a/tools/test.py
+++ b/tools/test.py
@@ -479,7 +479,7 @@
     try:
       os.unlink(name)
     except OSError, e:
-      PrintError(str(e))
+      PrintError("os.unlink() " + str(e))
   CheckedUnlink(outname)
   CheckedUnlink(errname)
   return CommandOutput(exit_code, timed_out, output, errors)
@@ -590,7 +590,7 @@
       test.GetTestStatus(context, sections, defs)
 
 
-PREFIX = {'debug': '_g', 'release': ''}
+SUFFIX = {'debug': '_g', 'release': ''}
 
 
 class Context(object):
@@ -605,11 +605,10 @@
     self.suppress_dialogs = suppress_dialogs
 
   def GetVm(self, mode):
-    name = self.vm_root + PREFIX[mode]
-    if utils.IsWindows():
-      return name + '.exe'
-    else:
-      return name
+    name = self.vm_root + SUFFIX[mode]
+    if utils.IsWindows() and not name.endswith('.exe'):
+      name = name + '.exe'
+    return name
 
 def RunTestCases(all_cases, progress, tasks):
   def DoSkip(case):
@@ -1092,6 +1091,7 @@
         dest="suppress_dialogs", default=True, action="store_true")
   result.add_option("--no-suppress-dialogs", help="Display Windows dialogs for crashing tests",
         dest="suppress_dialogs", action="store_false")
+  result.add_option("--shell", help="Path to V8 shell", default="shell");
   return result
 
 
@@ -1222,21 +1222,22 @@
     run_valgrind = join(workspace, "tools", "run-valgrind.py")
     options.special_command = "python -u " + run_valgrind + " @"
 
-  # First build the required targets
-  buildspace = abspath('.')
+  shell = abspath(options.shell)
+  buildspace = dirname(shell)
   context = Context(workspace, buildspace, VERBOSE,
-                    join(buildspace, 'shell'),
+                    shell,
                     options.timeout,
                     GetSpecialCommandProcessor(options.special_command),
                     options.suppress_dialogs)
-  if options.j != 1:
-    options.scons_flags += ['-j', str(options.j)]
+  # First build the required targets
   if not options.no_build:
     reqs = [ ]
     for path in paths:
       reqs += root.GetBuildRequirements(path, context)
     reqs = list(set(reqs))
     if len(reqs) > 0:
+      if options.j != 1:
+        options.scons_flags += ['-j', str(options.j)]
       if not BuildRequirements(context, reqs, options.mode, options.scons_flags):
         return 1
 
@@ -1253,6 +1254,9 @@
   globally_unused_rules = None
   for path in paths:
     for mode in options.mode:
+      if not exists(context.GetVm(mode)):
+        print "Can't find shell executable: '%s'" % context.GetVm(mode)
+        continue
       env = {
         'mode': mode,
         'system': utils.GuessOS(),