Enabled new regular expression engine.

Made a number of changes to the debugger protocol.

Fixed a number of bugs in the preemption support.

Added -p option to the developer shell to run files in parallel using preemption.

Fixed a number of minor bugs (including issues 176, 187, 189, 192, 193, 198 and 201).

Fixed a number of bugs in the serialization/deserialization support for the ARM platform.


git-svn-id: http://v8.googlecode.com/svn/trunk@1172 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/ChangeLog b/ChangeLog
index 943ef34..cea2d03 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+2009-01-27: Version 0.4.9
+
+        Enabled new regular expression engine.
+
+        Made a number of changes to the debugger protocol.
+
+        Fixed a number of bugs in the preemption support.
+
+        Added -p option to the developer shell to run files in parallel
+        using preemption.
+
+        Fixed a number of minor bugs (including issues 176, 187, 189, 192,
+        193, 198 and 201).
+
+        Fixed a number of bugs in the serialization/deserialization
+        support for the ARM platform.
+
+
 2009-01-19: Version 0.4.8.1
 
         Minor patch to debugger support.
diff --git a/SConstruct b/SConstruct
index 0f73dac..ccf412d 100644
--- a/SConstruct
+++ b/SConstruct
@@ -52,7 +52,7 @@
       'CPPDEFINES':   ['ENABLE_DISASSEMBLER', 'DEBUG']
     },
     'mode:release': {
-      'CCFLAGS':      ['-O3', '-fomit-frame-pointer']
+      'CCFLAGS':      ['-O3', '-fomit-frame-pointer', '-fdata-sections', '-ffunction-sections']
     },
     'os:freebsd': {
       'LIBS':         ['execinfo']
diff --git a/include/v8.h b/include/v8.h
index 1876a54..fc8b47a 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -396,19 +396,11 @@
  */
 class EXPORT HandleScope {
  public:
-  HandleScope() : previous_(current_), is_closed_(false) {
-    current_.extensions = 0;
-  }
+  HandleScope();
 
-  ~HandleScope() {
-    // TODO(1245391): In a perfect world, there would be a way of not
-    // having to check for explicitly closed scopes maybe through
-    // subclassing HandleScope?
-    if (!is_closed_) RestorePreviousState();
-  }
+  ~HandleScope();
 
   /**
-   * TODO(1245391): Consider introducing a subclass for this.
    * Closes the handle scope and returns the value as a handle in the
    * previous scope, which is the new current scope after the call.
    */
@@ -432,6 +424,8 @@
   void* operator new(size_t size);
   void operator delete(void*, size_t);
 
+  // This Data class is accessible internally through a typedef in the
+  // ImplementationUtilities class.
   class EXPORT Data {
    public:
     int extensions;
@@ -443,31 +437,13 @@
     }
   };
 
-  static Data current_;
-  const Data previous_;
+  Data previous_;
 
-  /**
-   * Re-establishes the previous scope state. Should be called only
-   * once, and only for the current scope.
-   */
-  void RestorePreviousState() {
-    if (current_.extensions > 0) DeleteExtensions();
-    current_ = previous_;
-#ifdef DEBUG
-    ZapRange(current_.next, current_.limit);
-#endif
-  }
-
-  // TODO(1245391): Consider creating a subclass for this.
+  // Allow for the active closing of HandleScopes which allows to pass a handle
+  // from the HandleScope being closed to the next top most HandleScope.
   bool is_closed_;
   void** RawClose(void** value);
 
-  /** Deallocates any extensions used by the current scope.*/
-  static void DeleteExtensions();
-
-  // Zaps the handles in the half-open interval [start, end).
-  static void ZapRange(void** start, void** end);
-
   friend class ImplementationUtilities;
 };
 
@@ -2284,10 +2260,17 @@
    */
   static bool IsLocked();
 
+  /**
+   * Returns whether v8::Locker is being used by this V8 instance.
+   */
+  static bool IsActive() { return active_; }
+
  private:
   bool has_lock_;
   bool top_level_;
 
+  static bool active_;
+
   // Disallow copying and assigning.
   Locker(const Locker&);
   void operator=(const Locker&);
diff --git a/src/api.cc b/src/api.cc
index 4069740..f617876 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -36,6 +36,7 @@
 #include "platform.h"
 #include "serialize.h"
 #include "snapshot.h"
+#include "v8threads.h"
 
 
 namespace i = v8::internal;
@@ -73,6 +74,15 @@
   } while (false)
 
 
+#define API_ENTRY_CHECK(msg)                                                   \
+  do {                                                                         \
+    if (v8::Locker::IsActive()) {                                              \
+      ApiCheck(i::ThreadManager::IsLockedByCurrentThread(),                    \
+               msg,                                                            \
+               "Entering the V8 API without proper locking in place");         \
+    }                                                                          \
+  } while (false)
+
 // --- D a t a   t h a t   i s   s p e c i f i c   t o   a   t h r e a d ---
 
 
@@ -190,6 +200,19 @@
 }
 
 
+ImplementationUtilities::HandleScopeData*
+    ImplementationUtilities::CurrentHandleScope() {
+  return &i::HandleScope::current_;
+}
+
+
+#ifdef DEBUG
+void ImplementationUtilities::ZapHandleRange(void** begin, void** end) {
+  i::HandleScope::ZapRange(begin, end);
+}
+#endif
+
+
 v8::Handle<v8::Primitive> ImplementationUtilities::Undefined() {
   if (IsDeadCheck("v8::Undefined()")) return v8::Handle<v8::Primitive>();
   EnsureInitialized("v8::Undefined()");
@@ -359,55 +382,26 @@
 // --- H a n d l e s ---
 
 
-HandleScope::Data HandleScope::current_ = { -1, NULL, NULL };
+HandleScope::HandleScope() : is_closed_(false) {
+  API_ENTRY_CHECK("HandleScope::HandleScope");
+  i::HandleScope::Enter(&previous_);
+}
+
+
+HandleScope::~HandleScope() {
+  if (!is_closed_) {
+    i::HandleScope::Leave(&previous_);
+  }
+}
 
 
 int HandleScope::NumberOfHandles() {
-  int n = thread_local.Blocks()->length();
-  if (n == 0) return 0;
-  return ((n - 1) * i::kHandleBlockSize) +
-       (current_.next - thread_local.Blocks()->last());
+  return i::HandleScope::NumberOfHandles();
 }
 
 
 void** v8::HandleScope::CreateHandle(void* value) {
-  void** result = current_.next;
-  if (result == current_.limit) {
-    // Make sure there's at least one scope on the stack and that the
-    // top of the scope stack isn't a barrier.
-    if (!ApiCheck(current_.extensions >= 0,
-                  "v8::HandleScope::CreateHandle()",
-                  "Cannot create a handle without a HandleScope")) {
-      return NULL;
-    }
-    // If there's more room in the last block, we use that. This is used
-    // for fast creation of scopes after scope barriers.
-    if (!thread_local.Blocks()->is_empty()) {
-      void** limit = &thread_local.Blocks()->last()[i::kHandleBlockSize];
-      if (current_.limit != limit) {
-        current_.limit = limit;
-      }
-    }
-
-    // If we still haven't found a slot for the handle, we extend the
-    // current handle scope by allocating a new handle block.
-    if (result == current_.limit) {
-      // If there's a spare block, use it for growing the current scope.
-      result = thread_local.GetSpareOrNewBlock();
-      // Add the extension to the global list of blocks, but count the
-      // extension as part of the current scope.
-      thread_local.Blocks()->Add(result);
-      current_.extensions++;
-      current_.limit = &result[i::kHandleBlockSize];
-    }
-  }
-
-  // Update the current next field, set the value in the created
-  // handle, and return the result.
-  ASSERT(result < current_.limit);
-  current_.next = result + 1;
-  *result = value;
-  return result;
+  return i::HandleScope::CreateHandle(value);
 }
 
 
@@ -436,20 +430,6 @@
 }
 
 
-void v8::HandleScope::DeleteExtensions() {
-  ASSERT(current_.extensions != 0);
-  thread_local.DeleteExtensions(current_.extensions);
-}
-
-
-void HandleScope::ZapRange(void** start, void** end) {
-  if (start == NULL) return;
-  for (void** p = start; p < end; p++) {
-    *p = reinterpret_cast<void*>(v8::internal::kHandleZapValue);
-  }
-}
-
-
 void** v8::HandleScope::RawClose(void** value) {
   if (!ApiCheck(!is_closed_,
                 "v8::HandleScope::Close()",
@@ -461,7 +441,7 @@
   // Read the result before popping the handle block.
   i::Object* result = reinterpret_cast<i::Object*>(*value);
   is_closed_ = true;
-  RestorePreviousState();
+  i::HandleScope::Leave(&previous_);
 
   // Allocate a new handle on the previous handle block.
   i::Handle<i::Object> handle(result);
@@ -2037,7 +2017,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->TryFlatten(i::StringShape(*str));
+  str->TryFlattenIfNotFlat(i::StringShape(*str));
   int end = length;
   if ( (length == -1) || (length > str->length() - start) )
     end = str->length() - start;
@@ -2062,7 +2042,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->TryFlatten(i::StringShape(*str));
+  str->TryFlattenIfNotFlat(i::StringShape(*str));
   int end = length;
   if ( (length == -1) || (length > str->length() - start) )
     end = str->length() - start;
@@ -2204,7 +2184,7 @@
 
 
 const char* v8::V8::GetVersion() {
-  return "0.4.8.1";
+  return "0.4.9";
 }
 
 
@@ -2951,8 +2931,8 @@
 
 
 char* HandleScopeImplementer::ArchiveThreadHelper(char* storage) {
-  ImplementationUtilities::HandleScopeData* current =
-      ImplementationUtilities::CurrentHandleScope();
+  v8::ImplementationUtilities::HandleScopeData* current =
+      v8::ImplementationUtilities::CurrentHandleScope();
   handle_scope_data_ = *current;
   memcpy(storage, this, sizeof(*this));
 
@@ -2975,7 +2955,7 @@
 
 char* HandleScopeImplementer::RestoreThreadHelper(char* storage) {
   memcpy(this, storage, sizeof(*this));
-  *ImplementationUtilities::CurrentHandleScope() = handle_scope_data_;
+  *v8::ImplementationUtilities::CurrentHandleScope() = handle_scope_data_;
   return storage + ArchiveSpacePerThread();
 }
 
@@ -2983,7 +2963,7 @@
 void HandleScopeImplementer::Iterate(
     ObjectVisitor* v,
     List<void**>* blocks,
-    ImplementationUtilities::HandleScopeData* handle_data) {
+    v8::ImplementationUtilities::HandleScopeData* handle_data) {
   // Iterate over all handles in the blocks except for the last.
   for (int i = blocks->length() - 2; i >= 0; --i) {
     Object** block =
@@ -3000,8 +2980,8 @@
 
 
 void HandleScopeImplementer::Iterate(ObjectVisitor* v) {
-  ImplementationUtilities::HandleScopeData* current =
-      ImplementationUtilities::CurrentHandleScope();
+  v8::ImplementationUtilities::HandleScopeData* current =
+      v8::ImplementationUtilities::CurrentHandleScope();
   Iterate(v, thread_local.Blocks(), current);
 }
 
@@ -3010,7 +2990,7 @@
   HandleScopeImplementer* thread_local =
       reinterpret_cast<HandleScopeImplementer*>(storage);
   List<void**>* blocks_of_archived_thread = thread_local->Blocks();
-  ImplementationUtilities::HandleScopeData* handle_data_of_archived_thread =
+  v8::ImplementationUtilities::HandleScopeData* handle_data_of_archived_thread =
       &thread_local->handle_scope_data_;
   Iterate(v, blocks_of_archived_thread, handle_data_of_archived_thread);
 
diff --git a/src/api.h b/src/api.h
index f4cea8b..85b13ec 100644
--- a/src/api.h
+++ b/src/api.h
@@ -28,6 +28,7 @@
 #ifndef V8_API_H_
 #define V8_API_H_
 
+#include "apiutils.h"
 #include "factory.h"
 
 namespace v8 {
@@ -159,45 +160,6 @@
 };
 
 
-class ImplementationUtilities {
- public:
-  static v8::Handle<v8::Primitive> Undefined();
-  static v8::Handle<v8::Primitive> Null();
-  static v8::Handle<v8::Boolean> True();
-  static v8::Handle<v8::Boolean> False();
-
-  static int GetNameCount(ExtensionConfiguration* that) {
-    return that->name_count_;
-  }
-
-  static const char** GetNames(ExtensionConfiguration* that) {
-    return that->names_;
-  }
-
-  static v8::Arguments NewArguments(Local<Value> data,
-                                    Local<Object> holder,
-                                    Local<Function> callee,
-                                    bool is_construct_call,
-                                    void** argv, int argc) {
-    return v8::Arguments(data, holder, callee, is_construct_call, argv, argc);
-  }
-
-  // Introduce an alias for the handle scope data to allow non-friends
-  // to access the HandleScope data.
-  typedef v8::HandleScope::Data HandleScopeData;
-
-  static HandleScopeData* CurrentHandleScope() {
-    return &v8::HandleScope::current_;
-  }
-
-#ifdef DEBUG
-  static void ZapHandleRange(void** begin, void** end) {
-    v8::HandleScope::ZapRange(begin, end);
-  }
-#endif
-};
-
-
 class Utils {
  public:
   static bool ReportApiFailure(const char* location, const char* message);
@@ -275,7 +237,7 @@
 
 template <class T>
 v8::internal::Handle<T> v8::internal::Handle<T>::EscapeFrom(
-    HandleScope* scope) {
+    v8::HandleScope* scope) {
   return Utils::OpenHandle(*scope->Close(Utils::ToLocal(*this)));
 }
 
@@ -408,11 +370,11 @@
   List<Handle<Object> > saved_contexts_;
   bool ignore_out_of_memory;
   // This is only used for threading support.
-  ImplementationUtilities::HandleScopeData handle_scope_data_;
+  v8::ImplementationUtilities::HandleScopeData handle_scope_data_;
 
   static void Iterate(ObjectVisitor* v,
-                      List<void**>* blocks,
-                      ImplementationUtilities::HandleScopeData* handle_data);
+      List<void**>* blocks,
+      v8::ImplementationUtilities::HandleScopeData* handle_data);
   char* RestoreThreadHelper(char* from);
   char* ArchiveThreadHelper(char* to);
 
@@ -474,13 +436,14 @@
   for (int i = extensions; i > 1; --i) {
     void** block = blocks.RemoveLast();
 #ifdef DEBUG
-    ImplementationUtilities::ZapHandleRange(block, &block[kHandleBlockSize]);
+    v8::ImplementationUtilities::ZapHandleRange(block,
+                                                &block[kHandleBlockSize]);
 #endif
     DeleteArray(block);
   }
   spare = reinterpret_cast<Object**>(blocks.RemoveLast());
 #ifdef DEBUG
-  ImplementationUtilities::ZapHandleRange(
+  v8::ImplementationUtilities::ZapHandleRange(
       reinterpret_cast<void**>(spare),
       reinterpret_cast<void**>(&spare[kHandleBlockSize]));
 #endif
diff --git a/src/apiutils.h b/src/apiutils.h
new file mode 100644
index 0000000..5745343
--- /dev/null
+++ b/src/apiutils.h
@@ -0,0 +1,69 @@
+// 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_APIUTILS_H_
+#define V8_APIUTILS_H_
+
+namespace v8 {
+
+class ImplementationUtilities {
+ public:
+  static v8::Handle<v8::Primitive> Undefined();
+  static v8::Handle<v8::Primitive> Null();
+  static v8::Handle<v8::Boolean> True();
+  static v8::Handle<v8::Boolean> False();
+
+  static int GetNameCount(ExtensionConfiguration* that) {
+    return that->name_count_;
+  }
+
+  static const char** GetNames(ExtensionConfiguration* that) {
+    return that->names_;
+  }
+
+  static v8::Arguments NewArguments(Local<Value> data,
+                                    Local<Object> holder,
+                                    Local<Function> callee,
+                                    bool is_construct_call,
+                                    void** argv, int argc) {
+    return v8::Arguments(data, holder, callee, is_construct_call, argv, argc);
+  }
+
+  // Introduce an alias for the handle scope data to allow non-friends
+  // to access the HandleScope data.
+  typedef v8::HandleScope::Data HandleScopeData;
+
+  static HandleScopeData* CurrentHandleScope();
+
+#ifdef DEBUG
+  static void ZapHandleRange(void** begin, void** end);
+#endif
+};
+
+}  // namespace v8
+
+#endif  // V8_APIUTILS_H_
diff --git a/src/assembler-ia32-inl.h b/src/assembler-ia32-inl.h
index 8b5fc64..7b65225 100644
--- a/src/assembler-ia32-inl.h
+++ b/src/assembler-ia32-inl.h
@@ -270,8 +270,7 @@
 }
 
 
-void Operand::set_modrm(int mod,  // reg == 0
-                        Register rm) {
+void Operand::set_modrm(int mod, Register rm) {
   ASSERT((mod & -4) == 0);
   buf_[0] = mod << 6 | rm.code();
   len_ = 1;
diff --git a/src/assembler-ia32.cc b/src/assembler-ia32.cc
index 3f663df..a4c3c9d 100644
--- a/src/assembler-ia32.cc
+++ b/src/assembler-ia32.cc
@@ -255,12 +255,6 @@
 }
 
 
-void Operand::set_reg(Register reg) const {
-  ASSERT(len_ > 0);
-  buf_[0] = (buf_[0] & ~0x38) | static_cast<byte>(reg.code() << 3);
-}
-
-
 bool Operand::is_reg(Register reg) const {
   return ((buf_[0] & 0xF8) == 0xC0)  // addressing mode is register only.
       && ((buf_[0] & 0x07) == reg.code());  // register codes match.
@@ -2098,10 +2092,18 @@
 
 
 void Assembler::emit_operand(Register reg, const Operand& adr) {
-  adr.set_reg(reg);
-  memmove(pc_, adr.buf_, adr.len_);
-  pc_ += adr.len_;
-  if (adr.len_ >= sizeof(int32_t) && adr.rmode_ != RelocInfo::NONE) {
+  const unsigned length = adr.len_;
+  ASSERT(length > 0);
+
+  // Emit updated ModRM byte containing the given register.
+  pc_[0] = (adr.buf_[0] & ~0x38) | (reg.code() << 3);
+
+  // Emit the rest of the encoded operand.
+  for (unsigned i = 1; i < length; i++) pc_[i] = adr.buf_[i];
+  pc_ += length;
+
+  // Emit relocation information if necessary.
+  if (length >= sizeof(int32_t) && adr.rmode_ != RelocInfo::NONE) {
     pc_ -= sizeof(int32_t);  // pc_ must be *at* disp32
     RecordRelocInfo(adr.rmode_);
     pc_ += sizeof(int32_t);
diff --git a/src/assembler-ia32.h b/src/assembler-ia32.h
index cb273c0..4219212 100644
--- a/src/assembler-ia32.h
+++ b/src/assembler-ia32.h
@@ -260,19 +260,19 @@
   bool is_reg(Register reg) const;
 
  private:
-  // Mutable because reg in ModR/M byte is set by Assembler via set_reg().
-  mutable byte buf_[6];
+  byte buf_[6];
   // The number of bytes in buf_.
   unsigned int len_;
   // Only valid if len_ > 4.
   RelocInfo::Mode rmode_;
 
-  inline void set_modrm(int mod,  // reg == 0
-                        Register rm);
+  // Set the ModRM byte without an encoded 'reg' register. The
+  // register is encoded later as part of the emit_operand operation.
+  inline void set_modrm(int mod, Register rm);
+
   inline void set_sib(ScaleFactor scale, Register index, Register base);
   inline void set_disp8(int8_t disp);
   inline void set_dispr(int32_t disp, RelocInfo::Mode rmode);
-  inline void set_reg(Register reg) const;
 
   friend class Assembler;
 };
diff --git a/src/ast.cc b/src/ast.cc
index 5034151..a5f4dc8 100644
--- a/src/ast.cc
+++ b/src/ast.cc
@@ -244,6 +244,36 @@
 }
 
 
+bool RegExpAssertion::IsAnchored() {
+  return type() == RegExpAssertion::START_OF_INPUT;
+}
+
+
+bool RegExpAlternative::IsAnchored() {
+  return this->nodes()->at(0)->IsAnchored();
+}
+
+
+bool RegExpDisjunction::IsAnchored() {
+  ZoneList<RegExpTree*>* alternatives = this->alternatives();
+  for (int i = 0; i < alternatives->length(); i++) {
+    if (!alternatives->at(i)->IsAnchored())
+      return false;
+  }
+  return true;
+}
+
+
+bool RegExpLookahead::IsAnchored() {
+  return is_positive() && body()->IsAnchored();
+}
+
+
+bool RegExpCapture::IsAnchored() {
+  return body()->IsAnchored();
+}
+
+
 // Convert regular expression trees to a simple sexp representation.
 // This representation should be different from the input grammar
 // in as many cases as possible, to make it more difficult for incorrect
@@ -417,6 +447,7 @@
 
 RegExpDisjunction::RegExpDisjunction(ZoneList<RegExpTree*>* alternatives)
     : alternatives_(alternatives) {
+  ASSERT(alternatives->length() > 1);
   RegExpTree* first_alternative = alternatives->at(0);
   min_match_ = first_alternative->min_match();
   max_match_ = first_alternative->max_match();
@@ -430,6 +461,7 @@
 
 RegExpAlternative::RegExpAlternative(ZoneList<RegExpTree*>* nodes)
     : nodes_(nodes) {
+  ASSERT(nodes->length() > 1);
   min_match_ = 0;
   max_match_ = 0;
   for (int i = 0; i < nodes->length(); i++) {
diff --git a/src/ast.h b/src/ast.h
index 360a054..ea4c947 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -1253,6 +1253,7 @@
   virtual RegExpNode* ToNode(RegExpCompiler* compiler,
                              RegExpNode* on_success) = 0;
   virtual bool IsTextElement() { return false; }
+  virtual bool IsAnchored() { return false; }
   virtual int min_match() = 0;
   virtual int max_match() = 0;
   // Returns the interval of registers used for captures within this
@@ -1277,6 +1278,7 @@
   virtual RegExpDisjunction* AsDisjunction();
   virtual Interval CaptureRegisters();
   virtual bool IsDisjunction();
+  virtual bool IsAnchored();
   virtual int min_match() { return min_match_; }
   virtual int max_match() { return max_match_; }
   ZoneList<RegExpTree*>* alternatives() { return alternatives_; }
@@ -1296,6 +1298,7 @@
   virtual RegExpAlternative* AsAlternative();
   virtual Interval CaptureRegisters();
   virtual bool IsAlternative();
+  virtual bool IsAnchored();
   virtual int min_match() { return min_match_; }
   virtual int max_match() { return max_match_; }
   ZoneList<RegExpTree*>* nodes() { return nodes_; }
@@ -1322,6 +1325,7 @@
                              RegExpNode* on_success);
   virtual RegExpAssertion* AsAssertion();
   virtual bool IsAssertion();
+  virtual bool IsAnchored();
   virtual int min_match() { return 0; }
   virtual int max_match() { return 0; }
   Type type() { return type_; }
@@ -1382,7 +1386,7 @@
   // W : non-ASCII word character
   // d : ASCII digit
   // D : non-ASCII digit
-  // . : non-unicode newline
+  // . : non-unicode non-newline
   // * : All characters
   uc16 standard_type() { return set_.standard_set_type(); }
   ZoneList<CharacterRange>* ranges() { return set_.ranges(); }
@@ -1495,6 +1499,7 @@
                             RegExpCompiler* compiler,
                             RegExpNode* on_success);
   virtual RegExpCapture* AsCapture();
+  virtual bool IsAnchored();
   virtual Interval CaptureRegisters();
   virtual bool IsCapture();
   virtual int min_match() { return body_->min_match(); }
@@ -1516,22 +1521,33 @@
 
 class RegExpLookahead: public RegExpTree {
  public:
-  RegExpLookahead(RegExpTree* body, bool is_positive)
+  RegExpLookahead(RegExpTree* body,
+                  bool is_positive,
+                  int capture_count,
+                  int capture_from)
       : body_(body),
-        is_positive_(is_positive) { }
+        is_positive_(is_positive),
+        capture_count_(capture_count),
+        capture_from_(capture_from) { }
+
   virtual void* Accept(RegExpVisitor* visitor, void* data);
   virtual RegExpNode* ToNode(RegExpCompiler* compiler,
                              RegExpNode* on_success);
   virtual RegExpLookahead* AsLookahead();
   virtual Interval CaptureRegisters();
   virtual bool IsLookahead();
+  virtual bool IsAnchored();
   virtual int min_match() { return 0; }
   virtual int max_match() { return 0; }
   RegExpTree* body() { return body_; }
   bool is_positive() { return is_positive_; }
+  int capture_count() { return capture_count_; }
+  int capture_from() { return capture_from_; }
  private:
   RegExpTree* body_;
   bool is_positive_;
+  int capture_count_;
+  int capture_from_;
 };
 
 
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index 970acd3..7928a5e 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -265,6 +265,11 @@
   Genesis* previous() { return previous_; }
   static Genesis* current() { return current_; }
 
+  // Support for thread preemption.
+  static int ArchiveSpacePerThread();
+  static char* ArchiveState(char* to);
+  static char* RestoreState(char* from);
+
  private:
   Handle<Context> global_context_;
 
@@ -1466,4 +1471,45 @@
   result_ = global_context_;
 }
 
+
+// Support for thread preemption.
+
+// Reserve space for statics needing saving and restoring.
+int Bootstrapper::ArchiveSpacePerThread() {
+  return Genesis::ArchiveSpacePerThread();
+}
+
+
+// Archive statics that are thread local.
+char* Bootstrapper::ArchiveState(char* to) {
+  return Genesis::ArchiveState(to);
+}
+
+
+// Restore statics that are thread local.
+char* Bootstrapper::RestoreState(char* from) {
+  return Genesis::RestoreState(from);
+}
+
+
+// Reserve space for statics needing saving and restoring.
+int Genesis::ArchiveSpacePerThread() {
+  return sizeof(current_);
+}
+
+
+// Archive statics that are thread local.
+char* Genesis::ArchiveState(char* to) {
+  *reinterpret_cast<Genesis**>(to) = current_;
+  current_ = NULL;
+  return to + sizeof(current_);
+}
+
+
+// Restore statics that are thread local.
+char* Genesis::RestoreState(char* from) {
+  current_ = *reinterpret_cast<Genesis**>(from);
+  return from + sizeof(current_);
+}
+
 } }  // namespace v8::internal
diff --git a/src/bootstrapper.h b/src/bootstrapper.h
index 1314bfd..e2883dc 100644
--- a/src/bootstrapper.h
+++ b/src/bootstrapper.h
@@ -68,6 +68,11 @@
   class FixupFlagsIsPCRelative: public BitField<bool, 0, 1> {};
   class FixupFlagsUseCodeObject: public BitField<bool, 1, 1> {};
   class FixupFlagsArgumentsCount: public BitField<uint32_t, 2, 32-2> {};
+
+  // Support for thread preemption.
+  static int ArchiveSpacePerThread();
+  static char* ArchiveState(char* to);
+  static char* RestoreState(char* from);
 };
 
 }}  // namespace v8::internal
diff --git a/src/bytecodes-irregexp.h b/src/bytecodes-irregexp.h
index 7ec8635..c7cb908 100644
--- a/src/bytecodes-irregexp.h
+++ b/src/bytecodes-irregexp.h
@@ -31,49 +31,59 @@
 
 namespace v8 { namespace internal {
 
+
+static const int BYTECODE_MASK = 0xff;
+static const unsigned int MAX_FIRST_ARG = 0xffffffu;
+static const int BYTECODE_SHIFT = 8;
+
 #define BYTECODE_ITERATOR(V)                                                   \
-V(BREAK,              0, 1) /* break                                        */ \
-V(PUSH_CP,            1, 5) /* push_cp offset32                             */ \
-V(PUSH_BT,            2, 5) /* push_bt addr32                               */ \
-V(PUSH_REGISTER,      3, 2) /* push_register register_index                 */ \
-V(SET_REGISTER_TO_CP, 4, 6) /* set_register_to_cp register_index offset32   */ \
-V(SET_CP_TO_REGISTER, 5, 2) /* set_cp_to_registger register_index           */ \
-V(SET_REGISTER_TO_SP, 6, 2) /* set_register_to_sp register_index            */ \
-V(SET_SP_TO_REGISTER, 7, 2) /* set_sp_to_registger register_index           */ \
-V(SET_REGISTER,       8, 6) /* set_register register_index value32          */ \
-V(ADVANCE_REGISTER,   9, 6) /* advance_register register_index value32      */ \
-V(POP_CP,            10, 1) /* pop_cp                                       */ \
-V(POP_BT,            11, 1) /* pop_bt                                       */ \
-V(POP_REGISTER,      12, 2) /* pop_register register_index                  */ \
-V(FAIL,              13, 1) /* fail                                         */ \
-V(SUCCEED,           14, 1) /* succeed                                      */ \
-V(ADVANCE_CP,        15, 5) /* advance_cp offset32                          */ \
-V(GOTO,              16, 5) /* goto addr32                                  */ \
-V(LOAD_CURRENT_CHAR, 17, 9) /* load offset32 addr32                         */ \
-V(LOAD_CURRENT_CHAR_UNCHECKED, 18, 5) /* load offset32                      */ \
-V(LOAD_2_CURRENT_CHARS, 19, 9) /* load offset32 addr32                      */ \
-V(LOAD_2_CURRENT_CHARS_UNCHECKED, 20, 5) /* load offset32                   */ \
-V(LOAD_4_CURRENT_CHARS, 21, 9) /* load offset32 addr32                      */ \
-V(LOAD_4_CURRENT_CHARS_UNCHECKED, 22, 5) /* load offset32                   */ \
-V(CHECK_CHAR,        23, 9) /* check_char uint32 addr32                     */ \
-V(CHECK_NOT_CHAR,    24, 9) /* check_not_char uint32 addr32                 */ \
-V(AND_CHECK_CHAR,    25, 13) /* and_check_char uint32 uint32 addr32         */ \
-V(AND_CHECK_NOT_CHAR, 26, 13) /* and_check_not_char uint32 uint32 addr32    */ \
-V(MINUS_AND_CHECK_NOT_CHAR, 27, 11) /* minus_and_check_not_char uc16 uc16...*/ \
-V(CHECK_LT,          28, 7) /* check_lt uc16 addr32                         */ \
-V(CHECK_GT,          29, 7) /* check_gr uc16 addr32                         */ \
-V(CHECK_NOT_BACK_REF, 30, 6) /* check_not_back_ref capture_idx addr32       */ \
-V(CHECK_NOT_BACK_REF_NO_CASE, 31, 6) /* check_not_back_ref_no_case captu... */ \
-V(CHECK_NOT_REGS_EQUAL, 32, 7) /* check_not_regs_equal reg1 reg2 addr32     */ \
-V(LOOKUP_MAP1,       33, 11) /* l_map1 start16 bit_map_addr32 addr32        */ \
-V(LOOKUP_MAP2,       34, 99) /* l_map2 start16 half_nibble_map_addr32*      */ \
-V(LOOKUP_MAP8,       35, 99) /* l_map8 start16 byte_map addr32*             */ \
-V(LOOKUP_HI_MAP8,    36, 99) /* l_himap8 start8 byte_map_addr32 addr32*     */ \
-V(CHECK_REGISTER_LT, 37, 8) /* check_reg_lt register_index value16 addr32   */ \
-V(CHECK_REGISTER_GE, 38, 8) /* check_reg_ge register_index value16 addr32   */ \
-V(CHECK_REGISTER_EQ_POS, 39, 6) /* check_register_eq_pos index addr32       */ \
-V(CHECK_NOT_AT_START, 40, 5) /* check_not_at_start addr32                   */ \
-V(CHECK_GREEDY,      41, 5) /* check_greedy addr32                          */
+V(BREAK,              0, 4)   /* bc8                                        */ \
+V(PUSH_CP,            1, 4)   /* bc8 pad24                                  */ \
+V(PUSH_BT,            2, 8)   /* bc8 pad24 offset32                         */ \
+V(PUSH_REGISTER,      3, 4)   /* bc8 reg_idx24                              */ \
+V(SET_REGISTER_TO_CP, 4, 8)   /* bc8 reg_idx24 offset32                     */ \
+V(SET_CP_TO_REGISTER, 5, 4)   /* bc8 reg_idx24                              */ \
+V(SET_REGISTER_TO_SP, 6, 4)   /* bc8 reg_idx24                              */ \
+V(SET_SP_TO_REGISTER, 7, 4)   /* bc8 reg_idx24                              */ \
+V(SET_REGISTER,       8, 8)   /* bc8 reg_idx24 value32                      */ \
+V(ADVANCE_REGISTER,   9, 8)   /* bc8 reg_idx24 value32                      */ \
+V(POP_CP,            10, 4)   /* bc8 pad24                                  */ \
+V(POP_BT,            11, 4)   /* bc8 pad24                                  */ \
+V(POP_REGISTER,      12, 4)   /* bc8 reg_idx24                              */ \
+V(FAIL,              13, 4)   /* bc8 pad24                                  */ \
+V(SUCCEED,           14, 4)   /* bc8 pad24                                  */ \
+V(ADVANCE_CP,        15, 4)   /* bc8 offset24                               */ \
+V(GOTO,              16, 8)   /* bc8 pad24 addr32                           */ \
+V(LOAD_CURRENT_CHAR, 17, 8)   /* bc8 offset24 addr32                        */ \
+V(LOAD_CURRENT_CHAR_UNCHECKED, 18, 4) /* bc8 offset24                       */ \
+V(LOAD_2_CURRENT_CHARS, 19, 8) /* bc8 offset24 addr32                       */ \
+V(LOAD_2_CURRENT_CHARS_UNCHECKED, 20, 4) /* bc8 offset24                    */ \
+V(LOAD_4_CURRENT_CHARS, 21, 8) /* bc8 offset24 addr32                       */ \
+V(LOAD_4_CURRENT_CHARS_UNCHECKED, 22, 4) /* bc8 offset24                    */ \
+V(CHECK_4_CHARS,     23, 12)  /* bc8 pad24 uint32 addr32                    */ \
+V(CHECK_CHAR,        24, 8)   /* bc8 pad8 uint16 addr32                     */ \
+V(CHECK_NOT_4_CHARS, 25, 12)  /* bc8 pad24 uint32 addr32                    */ \
+V(CHECK_NOT_CHAR,    26, 8)   /* bc8 pad8 uint16 addr32                     */ \
+V(AND_CHECK_4_CHARS, 27, 16)  /* bc8 pad24 uint32 uint32 addr32             */ \
+V(AND_CHECK_CHAR,    28, 12)  /* bc8 pad8 uint16 uint32 addr32              */ \
+V(AND_CHECK_NOT_4_CHARS, 29, 16) /* bc8 pad24 uint32 uint32 addr32          */ \
+V(AND_CHECK_NOT_CHAR, 30, 12) /* bc8 pad8 uint16 uint32 addr32              */ \
+V(MINUS_AND_CHECK_NOT_CHAR, 31, 12) /* bc8 pad8 uc16 uc16 addr32            */ \
+V(CHECK_LT,          32, 8)   /* bc8 pad8 uc16 addr32                       */ \
+V(CHECK_GT,          33, 8)   /* bc8 pad8 uc16 addr32                       */ \
+V(CHECK_NOT_BACK_REF, 34, 8)  /* bc8 reg_idx24 addr32                       */ \
+V(CHECK_NOT_BACK_REF_NO_CASE, 35, 8) /* bc8 reg_idx24 addr32                */ \
+V(CHECK_NOT_REGS_EQUAL, 36, 12) /* bc8 regidx24 reg_idx32 addr32            */ \
+V(LOOKUP_MAP1,       37, 12)  /* bc8 pad8 start16 bit_map_addr32 addr32     */ \
+V(LOOKUP_MAP2,       38, 96)  /* bc8 pad8 start16 half_nibble_map_addr32*   */ \
+V(LOOKUP_MAP8,       39, 96)  /* bc8 pad8  start16 byte_map addr32*         */ \
+V(LOOKUP_HI_MAP8,    40, 96)  /* bc8 start24 byte_map_addr32 addr32*        */ \
+V(CHECK_REGISTER_LT, 41, 12)  /* bc8 reg_idx24 value32 addr32               */ \
+V(CHECK_REGISTER_GE, 42, 12)  /* bc8 reg_idx24 value32 addr32               */ \
+V(CHECK_REGISTER_EQ_POS, 43, 8) /* bc8 reg_idx24 addr32                     */ \
+V(CHECK_AT_START,    44, 8)   /* bc8 pad24 addr32                           */ \
+V(CHECK_NOT_AT_START, 45, 8)  /* bc8 pad24 addr32                           */ \
+V(CHECK_GREEDY,      46, 8)   /* bc8 pad24 addr32                           */
 
 #define DECLARE_BYTECODES(name, code, length) \
   static const int BC_##name = code;
diff --git a/src/checks.h b/src/checks.h
index 77c43bc..0ff79af 100644
--- a/src/checks.h
+++ b/src/checks.h
@@ -136,9 +136,9 @@
                                      void* value) {
   if (expected != value) {
     V8_Fatal(file, line,
-             "CHECK_EQ(%s, %s) failed\n#   Expected: %i\n#   Found: %i",
+             "CHECK_EQ(%s, %s) failed\n#   Expected: %p\n#   Found: %p",
              expected_source, value_source,
-             reinterpret_cast<int>(expected), reinterpret_cast<int>(value));
+             expected, value);
   }
 }
 
@@ -150,8 +150,8 @@
                                         const char* value_source,
                                         void* value) {
   if (expected == value) {
-    V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n#   Value: %i",
-             expected_source, value_source, reinterpret_cast<int>(value));
+    V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n#   Value: %p",
+             expected_source, value_source, value);
   }
 }
 
diff --git a/src/codegen-ia32.cc b/src/codegen-ia32.cc
index a9cc800..287074c 100644
--- a/src/codegen-ia32.cc
+++ b/src/codegen-ia32.cc
@@ -1014,8 +1014,8 @@
   // code size is increased by ~1% (measured on a combination of
   // different benchmarks).
 
-  // TODO(1217802): Optimize some special cases of operations
-  // involving a smi literal (multiply by 2, shift by 0, etc.).
+  // TODO(199): Optimize some special cases of operations involving a
+  // smi literal (multiply by 2, shift by 0, etc.).
 
   // Get the literal value.
   int int_value = Smi::cast(*value)->value();
@@ -1127,11 +1127,13 @@
         __ j(not_zero, deferred->enter(), not_taken);
         __ sar(ebx, kSmiTagSize);
         __ shl(ebx, shift_value);
-        __ lea(ecx, Operand(ebx, 0x40000000));
-        __ test(ecx, Immediate(0x80000000));
-        __ j(not_zero, deferred->enter(), not_taken);
-        // tag result and store it in TOS (eax)
-        ASSERT(kSmiTagSize == times_2);  // adjust code if not the case
+        // This is the Smi check for the shifted result.
+        // After signed subtraction of 0xc0000000, the valid
+        // Smis are positive.
+        __ cmp(ebx, 0xc0000000);
+        __ j(sign, deferred->enter(), not_taken);
+        // Tag the result and store it on top of the frame.
+        ASSERT(kSmiTagSize == times_2);  // Adjust the code if not true.
         __ lea(eax, Operand(ebx, ebx, times_1, kSmiTag));
         __ bind(deferred->exit());
         frame_->Push(eax);
@@ -4274,9 +4276,8 @@
         case Token::SHL:
           __ shl(eax);
           // Check that the *signed* result fits in a smi.
-          __ lea(ecx, Operand(eax, 0x40000000));
-          __ test(ecx, Immediate(0x80000000));
-          __ j(not_zero, slow, not_taken);
+          __ cmp(eax, 0xc0000000);
+          __ j(sign, slow, not_taken);
           break;
         default:
           UNREACHABLE();
diff --git a/src/contexts.cc b/src/contexts.cc
index 0f3f608..8155999 100644
--- a/src/contexts.cc
+++ b/src/contexts.cc
@@ -94,7 +94,11 @@
     // check extension/with object
     if (context->has_extension()) {
       Handle<JSObject> extension = Handle<JSObject>(context->extension());
-      if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0) {
+      // Context extension objects needs to behave as if they have no
+      // prototype.  So even if we want to follow prototype chains, we
+      // need to only do a local lookup for context extension objects.
+      if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0 ||
+          extension->IsJSContextExtensionObject()) {
         *attributes = extension->GetLocalPropertyAttribute(*name);
       } else {
         *attributes = extension->GetPropertyAttribute(*name);
diff --git a/src/d8.cc b/src/d8.cc
index 24eb722..e026d28 100644
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -33,6 +33,7 @@
 #include "debug.h"
 #include "api.h"
 #include "natives.h"
+#include "platform.h"
 
 
 namespace v8 {
@@ -383,10 +384,10 @@
 }
 
 
-// Reads a file into a v8 string.
-Handle<String> Shell::ReadFile(const char* name) {
+static char* ReadChars(const char *name, int* size_out) {
+  v8::Unlocker unlocker;  // Release the V8 lock while reading files.
   FILE* file = i::OS::FOpen(name, "rb");
-  if (file == NULL) return Handle<String>();
+  if (file == NULL) return NULL;
 
   fseek(file, 0, SEEK_END);
   int size = ftell(file);
@@ -399,7 +400,17 @@
     i += read;
   }
   fclose(file);
-  Handle<String> result = String::New(chars, size);
+  *size_out = size;
+  return chars;
+}
+
+
+// Reads a file into a v8 string.
+Handle<String> Shell::ReadFile(const char* name) {
+  int size = 0;
+  char* chars = ReadChars(name, &size);
+  if (chars == NULL) return Handle<String>();
+  Handle<String> result = String::New(chars);
   delete[] chars;
   return result;
 }
@@ -410,7 +421,9 @@
   printf("V8 version %s [console: %s]\n", V8::GetVersion(), editor->name());
   editor->Open();
   while (true) {
+    Locker locker;
     HandleScope handle_scope;
+    Context::Scope context_scope(evaluation_context_);
     i::SmartPointer<char> input = editor->Prompt(Shell::kPrompt);
     if (input.is_empty())
       break;
@@ -423,6 +436,53 @@
 }
 
 
+class ShellThread : public i::Thread {
+ public:
+  ShellThread(int no, i::Vector<const char> files)
+    : no_(no), files_(files) { }
+  virtual void Run();
+ private:
+  int no_;
+  i::Vector<const char> files_;
+};
+
+
+void ShellThread::Run() {
+  // Prepare the context for this thread.
+  Locker locker;
+  HandleScope scope;
+  Handle<ObjectTemplate> global_template = ObjectTemplate::New();
+  global_template->Set(String::New("print"),
+                       FunctionTemplate::New(Shell::Print));
+  global_template->Set(String::New("load"),
+                       FunctionTemplate::New(Shell::Load));
+  global_template->Set(String::New("version"),
+                       FunctionTemplate::New(Shell::Version));
+
+  Persistent<Context> thread_context = Context::New(NULL, global_template);
+  thread_context->SetSecurityToken(Undefined());
+
+  Context::Scope context_scope(thread_context);
+
+  char* ptr = const_cast<char*>(files_.start());
+  while ((ptr != NULL) && (*ptr != '\0')) {
+    // For each newline-separated line.
+    char *filename = ptr;
+    char* next = ::strchr(ptr, '\n');
+    if (next != NULL) {
+      *next = '\0';
+      ptr = (next + 1);
+    } else {
+      ptr = NULL;
+    }
+    Handle<String> str = Shell::ReadFile(filename);
+    Shell::ExecuteString(str, String::New(filename), false, false);
+  }
+
+  thread_context.Dispose();
+}
+
+
 int Shell::Main(int argc, char* argv[]) {
   i::FlagList::SetFlagsFromCommandLine(&argc, argv, true);
   if (i::FLAG_help) {
@@ -430,42 +490,67 @@
   }
   Initialize();
   bool run_shell = (argc == 1);
-  Context::Scope context_scope(evaluation_context_);
-  for (int i = 1; i < argc; i++) {
-    char* str = argv[i];
-    if (strcmp(str, "--shell") == 0) {
-      run_shell = true;
-    } else if (strcmp(str, "-f") == 0) {
-      // Ignore any -f flags for compatibility with other stand-alone
-      // JavaScript engines.
-      continue;
-    } else if (strncmp(str, "--", 2) == 0) {
-      printf("Warning: unknown flag %s.\nTry --help for options\n", str);
-    } else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
-      // Execute argument given to -e option directly.
-      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))
-        return 1;
-      i++;
-    } else {
-      // Use all other arguments as names of files to load and run.
-      HandleScope handle_scope;
-      Handle<String> file_name = v8::String::New(str);
-      Handle<String> source = ReadFile(str);
-      if (source.IsEmpty()) {
-        printf("Error reading '%s'\n", str);
-        return 1;
+  i::List<i::Thread*> threads(1);
+
+  {
+    // Acquire the V8 lock once initialization has finished. Since the thread
+    // below may spawn new threads accessing V8 holding the V8 lock here is
+    // mandatory.
+    Locker locker;
+    Context::Scope context_scope(evaluation_context_);
+    for (int i = 1; i < argc; i++) {
+      char* str = argv[i];
+      if (strcmp(str, "--shell") == 0) {
+        run_shell = true;
+      } else if (strcmp(str, "-f") == 0) {
+        // Ignore any -f flags for compatibility with other stand-alone
+        // JavaScript engines.
+        continue;
+      } else if (strncmp(str, "--", 2) == 0) {
+        printf("Warning: unknown flag %s.\nTry --help for options\n", str);
+      } else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
+        // Execute argument given to -e option directly.
+        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))
+          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;
+        ShellThread *thread =
+            new ShellThread(threads.length(),
+                            i::Vector<const char>(files, size));
+        thread->Start();
+        threads.Add(thread);
+      } else {
+        // Use all other arguments as names of files to load and run.
+        HandleScope handle_scope;
+        Handle<String> file_name = v8::String::New(str);
+        Handle<String> source = ReadFile(str);
+        if (source.IsEmpty()) {
+          printf("Error reading '%s'\n", str);
+          return 1;
+        }
+        if (!ExecuteString(source, file_name, false, true))
+          return 1;
       }
-      if (!ExecuteString(source, file_name, false, true))
-        return 1;
     }
+    if (i::FLAG_debugger)
+      v8::Debug::AddDebugEventListener(HandleDebugEvent);
   }
-  if (i::FLAG_debugger)
-    v8::Debug::AddDebugEventListener(HandleDebugEvent);
   if (run_shell)
     RunShell();
+  for (int i = 0; i < threads.length(); i++) {
+    i::Thread *thread = threads[i];
+    thread->Join();
+    delete thread;
+  }
   OnExit();
   return 0;
 }
diff --git a/src/d8.js b/src/d8.js
index 61467b9..0314d51 100644
--- a/src/d8.js
+++ b/src/d8.js
@@ -262,6 +262,10 @@
       this.request_ = this.printCommandToJSONRequest_(args);
       break;
 
+    case 'dir':
+      this.request_ = this.dirCommandToJSONRequest_(args);
+      break;
+
     case 'source':
       this.request_ = this.sourceCommandToJSONRequest_(args);
       break;
@@ -289,6 +293,8 @@
     default:
       throw new Error('Unknown command "' + cmd + '"');
   }
+  
+  last_cmd = cmd;
 }
 
 DebugRequest.prototype.JSONRequest = function() {
@@ -330,6 +336,27 @@
 };
 
 
+// Create a JSON request for the evaluation command.
+DebugRequest.prototype.makeEvaluateJSONRequest_ = function(expression) {
+  // Check if the expression is a handle id in the form #<handle>#.
+  var handle_match = expression.match(/^#([0-9]*)#$/);
+  if (handle_match) {
+    // Build an evaluate request.
+    var request = this.createRequest('lookup');
+    request.arguments = {};
+    request.arguments.handle = parseInt(handle_match[1]);
+    return request.toJSONProtocol();
+  } else {
+    // Build an evaluate request.
+    var request = this.createRequest('evaluate');
+    request.arguments = {};
+    request.arguments.expression = expression;
+    return request.toJSONProtocol();
+  }
+};
+
+
+
 // Create a JSON request for the continue command.
 DebugRequest.prototype.continueCommandToJSONRequest_ = function(args) {
   var request = this.createRequest('continue');
@@ -438,16 +465,21 @@
 
 // Create a JSON request for the print command.
 DebugRequest.prototype.printCommandToJSONRequest_ = function(args) {
-  // Build a evaluate request from the text command.
-  var request = this.createRequest('evaluate');
+  // Build an evaluate request from the text command.
   if (args.length == 0) {
     throw new Error('Missing expression.');
   }
+  return this.makeEvaluateJSONRequest_(args);
+};
 
-  request.arguments = {};
-  request.arguments.expression = args;
 
-  return request.toJSONProtocol();
+// Create a JSON request for the dir command.
+DebugRequest.prototype.dirCommandToJSONRequest_ = function(args) {
+  // Build an evaluate request from the text command.
+  if (args.length == 0) {
+    throw new Error('Missing expression.');
+  }
+  return this.makeEvaluateJSONRequest_(args);
 };
 
 
@@ -585,39 +617,43 @@
 }
 
 
+function formatHandleReference_(value) {
+  return '#' + value.handle() + '#';
+}
+
+
 // Convert a JSON response to text for display in a text based debugger.
 function DebugResponseDetails(json_response) {
   details = {text:'', running:false}
 
   try {
     // Convert the JSON string to an object.
-    response = eval('(' + json_response + ')');
+    var response = new ProtocolPackage(json_response);
 
-    if (!response.success) {
-      details.text = response.message;
+    if (!response.success()) {
+      details.text = response.message();
       return details;
     }
 
     // Get the running state.
-    details.running = response.running;
+    details.running = response.running();
 
-    switch (response.command) {
+    var body = response.body();
+    var result = '';
+    switch (response.command()) {
       case 'setbreakpoint':
-        var body = response.body;
         result = 'set breakpoint #';
         result += body.breakpoint;
         details.text = result;
         break;
         
       case 'clearbreakpoint':
-        var body = response.body;
         result = 'cleared breakpoint #';
         result += body.breakpoint;
         details.text = result;
         break;
         
       case 'backtrace':
-        var body = response.body;
         if (body.totalFrames == 0) {
           result = '(empty stack)';
         } else {
@@ -632,20 +668,67 @@
         break;
         
       case 'frame':
-        details.text = SourceUnderline(response.body.sourceLineText,
-                                       response.body.column);
-        Debug.State.currentSourceLine = response.body.line;
-        Debug.State.currentFrame = response.body.index;
+        details.text = SourceUnderline(body.sourceLineText,
+                                       body.column);
+        Debug.State.currentSourceLine = body.line;
+        Debug.State.currentFrame = body.index;
         break;
         
       case 'evaluate':
-        details.text =  response.body.text;
+      case 'lookup':
+        if (last_cmd == 'p' || last_cmd == 'print') {
+          details.text =  body.text;
+        } else {
+          var value = response.bodyValue();
+          if (value.isObject()) {
+            result += formatHandleReference_(value);
+            result += ', type: object'
+            result += ', constructor ';
+            var ctor = value.constructorFunctionValue();
+            result += formatHandleReference_(ctor);
+            result += ', __proto__ ';
+            var proto = value.protoObjectValue();
+            result += formatHandleReference_(proto);
+            result += ', ';
+            result += value.propertyCount();
+            result +=  ' properties.\n';
+            for (var i = 0; i < value.propertyCount(); i++) {
+              result += '  ';
+              result += value.propertyName(i);
+              result += ': ';
+              var property_value = value.propertyValue(i);
+              if (property_value && property_value.type()) {
+                result += property_value.type();
+              } else {
+                result += '<no type>';
+              }
+              result += ' ';
+              result += formatHandleReference_(property_value);
+              result += '\n';
+            }
+          } else {
+            result += 'type: ';
+            result += value.type();
+            if (!value.isUndefined() && !value.isNull()) {
+              result += ', ';
+              if (value.isString()) {
+                result += '"';
+              }
+              result += value.value();
+              if (value.isString()) {
+                result += '"';
+              }
+            }
+            result += '\n';
+          }
+        }
+        details.text = result;
         break;
         
       case 'source':
         // Get the source from the response.
-        var source = response.body.source;
-        var from_line = response.body.fromLine + 1;
+        var source = body.source;
+        var from_line = body.fromLine + 1;
         var lines = source.split('\n');
         var maxdigits = 1 + Math.floor(log10(from_line + lines.length));
         if (maxdigits < 3) {
@@ -679,25 +762,25 @@
         
       case 'scripts':
         var result = '';
-        for (i = 0; i < response.body.length; i++) {
+        for (i = 0; i < body.length; i++) {
           if (i != 0) result += '\n';
-          if (response.body[i].name) {
-            result += response.body[i].name;
+          if (body[i].name) {
+            result += body[i].name;
           } else {
             result += '[unnamed] ';
-            var sourceStart = response.body[i].sourceStart;
+            var sourceStart = body[i].sourceStart;
             if (sourceStart.length > 40) {
               sourceStart = sourceStart.substring(0, 37) + '...';
             }
             result += sourceStart;
           }
           result += ' (lines: ';
-          result += response.body[i].sourceLines;
+          result += body[i].sourceLines;
           result += ', length: ';
-          result += response.body[i].sourceLength;
-          if (response.body[i].type == Debug.ScriptType.Native) {
+          result += body[i].sourceLength;
+          if (body[i].type == Debug.ScriptType.Native) {
             result += ', native';
-          } else if (response.body[i].type == Debug.ScriptType.Extension) {
+          } else if (body[i].type == Debug.ScriptType.Extension) {
             result += ', extension';
           }
           result += ')';
@@ -722,6 +805,270 @@
 };
 
 
+/**
+ * Protocol packages send from the debugger.
+ * @param {string} json - raw protocol packet as JSON string.
+ * @constructor
+ */
+function ProtocolPackage(json) {
+  this.packet_ = eval('(' + json + ')');
+  this.refs_ = [];
+  if (this.packet_.refs) {
+    for (var i = 0; i < this.packet_.refs.length; i++) {
+      this.refs_[this.packet_.refs[i].handle] = this.packet_.refs[i];
+    }
+  }
+}
+
+
+/**
+ * Get the packet type.
+ * @return {String} the packet type
+ */
+ProtocolPackage.prototype.type = function() {
+  return this.packet_.type;
+}
+
+
+/**
+ * Get the packet event.
+ * @return {Object} the packet event
+ */
+ProtocolPackage.prototype.event = function() {
+  return this.packet_.event;
+}
+
+
+/**
+ * Get the packet request sequence.
+ * @return {number} the packet request sequence
+ */
+ProtocolPackage.prototype.requestSeq = function() {
+  return this.packet_.request_seq;
+}
+
+
+/**
+ * Get the packet request sequence.
+ * @return {number} the packet request sequence
+ */
+ProtocolPackage.prototype.running = function() {
+  return this.packet_.running ? true : false;
+}
+
+
+ProtocolPackage.prototype.success = function() {
+  return this.packet_.success ? true : false;
+}
+
+
+ProtocolPackage.prototype.message = function() {
+  return this.packet_.message;
+}
+
+
+ProtocolPackage.prototype.command = function() {
+  return this.packet_.command;
+}
+
+
+ProtocolPackage.prototype.body = function() {
+  return this.packet_.body;
+}
+
+
+ProtocolPackage.prototype.bodyValue = function() {
+  return new ProtocolValue(this.packet_.body, this);
+}
+
+
+ProtocolPackage.prototype.body = function() {
+  return this.packet_.body;
+}
+
+
+ProtocolPackage.prototype.lookup = function(handle) {
+  var value = this.refs_[handle];
+  if (value) {
+    return new ProtocolValue(value, this);
+  } else {
+    return new ProtocolReference(handle);
+  }
+}
+
+
+function ProtocolValue(value, packet) {
+  this.value_ = value;
+  this.packet_ = packet;
+}
+
+
+/**
+ * Get the value type.
+ * @return {String} the value type
+ */
+ProtocolValue.prototype.type = function() {
+  return this.value_.type;
+}
+
+
+/**
+ * Check is the value is a primitive value.
+ * @return {boolean} true if the value is primitive
+ */
+ProtocolValue.prototype.isPrimitive = function() {
+  return this.isUndefined() || this.isNull() || this.isBoolean() ||
+         this.isNumber() || this.isString();
+}
+
+
+/**
+ * Get the object handle.
+ * @return {number} the value handle
+ */
+ProtocolValue.prototype.handle = function() {
+  return this.value_.handle;
+}
+
+
+/**
+ * Check is the value is undefined.
+ * @return {boolean} true if the value is undefined
+ */
+ProtocolValue.prototype.isUndefined = function() {
+  return this.value_.type == 'undefined';
+}
+
+
+/**
+ * Check is the value is null.
+ * @return {boolean} true if the value is null
+ */
+ProtocolValue.prototype.isNull = function() {
+  return this.value_.type == 'null';
+}
+
+
+/**
+ * Check is the value is a boolean.
+ * @return {boolean} true if the value is a boolean
+ */
+ProtocolValue.prototype.isBoolean = function() {
+  return this.value_.type == 'boolean';
+}
+
+
+/**
+ * Check is the value is a number.
+ * @return {boolean} true if the value is a number
+ */
+ProtocolValue.prototype.isNumber = function() {
+  return this.value_.type == 'number';
+}
+
+
+/**
+ * Check is the value is a string.
+ * @return {boolean} true if the value is a string
+ */
+ProtocolValue.prototype.isString = function() {
+  return this.value_.type == 'string';
+}
+
+
+/**
+ * Check is the value is an object.
+ * @return {boolean} true if the value is an object
+ */
+ProtocolValue.prototype.isObject = function() {
+  return this.value_.type == 'object' || this.value_.type == 'function' ||
+         this.value_.type == 'error' || this.value_.type == 'regexp';
+}
+
+
+/**
+ * Get the constructor function
+ * @return {ProtocolValue} constructor function
+ */
+ProtocolValue.prototype.constructorFunctionValue = function() {
+  var ctor = this.value_.constructorFunction;
+  return this.packet_.lookup(ctor.ref);
+}
+
+
+/**
+ * Get the __proto__ value
+ * @return {ProtocolValue} __proto__ value
+ */
+ProtocolValue.prototype.protoObjectValue = function() {
+  var proto = this.value_.protoObject;
+  return this.packet_.lookup(proto.ref);
+}
+
+
+/**
+ * Get the number og properties.
+ * @return {number} the number of properties
+ */
+ProtocolValue.prototype.propertyCount = function() {
+  return this.value_.properties ? this.value_.properties.length : 0;
+}
+
+
+/**
+ * Get the specified property name.
+ * @return {string} property name
+ */
+ProtocolValue.prototype.propertyName = function(index) {
+  var property = this.value_.properties[index];
+  return property.name;
+}
+
+
+/**
+ * Return index for the property name.
+ * @param name The property name to look for
+ * @return {number} index for the property name
+ */
+ProtocolValue.prototype.propertyIndex = function(name) {
+  for (var i = 0; i < this.propertyCount(); i++) {
+    if (this.value_.properties[i].name == name) {
+      return i;
+    }
+  }
+  return null;
+}
+
+
+/**
+ * Get the specified property value.
+ * @return {ProtocolValue} property value
+ */
+ProtocolValue.prototype.propertyValue = function(index) {
+  var property = this.value_.properties[index];
+  return this.packet_.lookup(property.ref);
+}
+
+
+/**
+ * Check is the value is a string.
+ * @return {boolean} true if the value is a string
+ */
+ProtocolValue.prototype.value = function() {
+  return this.value_.value;
+}
+
+
+function ProtocolReference(handle) {
+  this.handle_ = handle;
+}
+
+
+ProtocolReference.prototype.handle = function() {
+  return this.handle_;
+}
+
+
 function MakeJSONPair_(name, value) {
   return '"' + name + '":' + value;
 }
diff --git a/src/debug-delay.js b/src/debug-delay.js
index d388946..71ed37f 100644
--- a/src/debug-delay.js
+++ b/src/debug-delay.js
@@ -1071,6 +1071,8 @@
         this.frameRequest_(request, response);
       } else if (request.command == 'evaluate') {
         this.evaluateRequest_(request, response);
+      } else if (request.command == 'lookup') {
+        this.lookupRequest_(request, response);
       } else if (request.command == 'source') {
         this.sourceRequest_(request, response);
       } else if (request.command == 'scripts') {
@@ -1366,7 +1368,12 @@
   }
 
   // With no arguments just keep the selected frame.
-  if (request.arguments && request.arguments.number >= 0) {
+  if (request.arguments) {
+    index = request.arguments.number;
+    if (index < 0 || this.exec_state_.frameCount() <= index) {
+      return response.failed('Invalid frame number');
+    }
+    
     this.exec_state_.setSelectedFrame(request.arguments.number);
   }
   response.body = this.exec_state_.frame();
@@ -1429,6 +1436,29 @@
 };
 
 
+DebugCommandProcessor.prototype.lookupRequest_ = function(request, response) {
+  if (!request.arguments) {
+    return response.failed('Missing arguments');
+  }
+
+  // Pull out arguments.
+  var handle = request.arguments.handle;
+
+  // Check for legal arguments.
+  if (IS_UNDEFINED(handle)) {
+    return response.failed('Argument "handle" missing');
+  }
+
+  // Lookup handle.
+  var mirror = LookupMirror(handle);
+  if (mirror) {
+    response.body = mirror;
+  } else {
+    return response.failed('Object #' + handle + '# not found');
+  }
+};
+
+
 DebugCommandProcessor.prototype.sourceRequest_ = function(request, response) {
   // No frames no source.
   if (this.exec_state_.frameCount() == 0) {
diff --git a/src/execution.cc b/src/execution.cc
index cb05314..f721cbd 100644
--- a/src/execution.cc
+++ b/src/execution.cc
@@ -191,12 +191,24 @@
 
 
 StackGuard::StackGuard() {
+  // NOTE: Overall the StackGuard code assumes that the stack grows towards
+  // lower addresses.
   ExecutionAccess access;
-  if (thread_local_.nesting_++ == 0 &&
-      thread_local_.jslimit_ != kInterruptLimit) {
-    // NOTE: We assume that the stack grows towards lower addresses.
-    ASSERT(thread_local_.jslimit_ == kIllegalLimit);
-    ASSERT(thread_local_.climit_ == kIllegalLimit);
+  if (thread_local_.nesting_++ == 0) {
+    // Initial StackGuard is being set. We will set the stack limits based on
+    // the current stack pointer allowing the stack to grow kLimitSize from
+    // here.
+
+    // Ensure that either the stack limits are unset (kIllegalLimit) or that
+    // they indicate a pending interruption. The interrupt limit will be
+    // temporarily reset through the code below and reestablished if the
+    // interrupt flags indicate that an interrupt is pending.
+    ASSERT(thread_local_.jslimit_ == kIllegalLimit ||
+           (thread_local_.jslimit_ == kInterruptLimit &&
+            thread_local_.interrupt_flags_ != 0));
+    ASSERT(thread_local_.climit_ == kIllegalLimit ||
+           (thread_local_.climit_ == kInterruptLimit &&
+            thread_local_.interrupt_flags_ != 0));
 
     thread_local_.initial_jslimit_ = thread_local_.jslimit_ =
         GENERATED_CODE_STACK_LIMIT(kLimitSize);
@@ -210,9 +222,11 @@
       set_limits(kInterruptLimit, access);
     }
   }
-  // make sure we have proper limits setup
+  // Ensure that proper limits have been set.
   ASSERT(thread_local_.jslimit_ != kIllegalLimit &&
          thread_local_.climit_ != kIllegalLimit);
+  ASSERT(thread_local_.initial_jslimit_ != kIllegalLimit &&
+         thread_local_.initial_climit_ != kIllegalLimit);
 }
 
 
diff --git a/src/execution.h b/src/execution.h
index bd37525..d5f2fb6 100644
--- a/src/execution.h
+++ b/src/execution.h
@@ -228,7 +228,12 @@
 class StackLimitCheck BASE_EMBEDDED {
  public:
   bool HasOverflowed() const {
-    return reinterpret_cast<uintptr_t>(this) < StackGuard::climit();
+    // Stack has overflowed in C++ code only if stack pointer exceeds the C++
+    // stack guard and the limits are not set to interrupt values.
+    // TODO(214): Stack overflows are ignored if a interrupt is pending. This
+    // code should probably always use the initial C++ limit.
+    return (reinterpret_cast<uintptr_t>(this) < StackGuard::climit()) &&
+           StackGuard::IsStackOverflow();
   }
 };
 
diff --git a/src/factory.cc b/src/factory.cc
index c49f58a..52d3bad 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -327,7 +327,7 @@
 
 Handle<Object> Factory::NewError(const char* maker, const char* type,
     Vector< Handle<Object> > args) {
-  HandleScope scope;
+  v8::HandleScope scope;  // Instantiate a closeable HandleScope for EscapeFrom.
   Handle<FixedArray> array = Factory::NewFixedArray(args.length());
   for (int i = 0; i < args.length(); i++) {
     array->set(i, *args[i]);
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index 194340b..b97c44b 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -199,12 +199,10 @@
 DEFINE_bool(preemption, false,
             "activate a 100ms timer that switches between V8 threads")
 
-// irregexp
-DEFINE_bool(irregexp, false, "new regular expression code")
+// Irregexp
+DEFINE_bool(irregexp, true, "new regular expression code")
 DEFINE_bool(trace_regexps, false, "trace Irregexp execution")
-DEFINE_bool(irregexp_native, false, "use native code Irregexp implementation (IA32 only)")
-DEFINE_bool(disable_jscre, false, "abort if JSCRE is used.  Only useful with --irregexp")
-DEFINE_bool(attempt_multiline_irregexp, false, "attempt to use Irregexp for multiline regexps")
+DEFINE_bool(irregexp_native, true, "use native code Irregexp implementation (IA32 only)")
 
 // Testing flags test/cctest/test-{flags,api,serialization}.cc
 DEFINE_bool(testing_bool_flag, true, "testing_bool_flag")
diff --git a/src/handles-inl.h b/src/handles-inl.h
index 0f804d7..e5899e3 100644
--- a/src/handles-inl.h
+++ b/src/handles-inl.h
@@ -29,6 +29,7 @@
 #ifndef V8_HANDLES_INL_H_
 #define V8_HANDLES_INL_H_
 
+#include "apiutils.h"
 #include "handles.h"
 #include "api.h"
 
@@ -51,8 +52,8 @@
 
 #ifdef DEBUG
 inline NoHandleAllocation::NoHandleAllocation() {
-  ImplementationUtilities::HandleScopeData* current =
-      ImplementationUtilities::CurrentHandleScope();
+  v8::ImplementationUtilities::HandleScopeData* current =
+      v8::ImplementationUtilities::CurrentHandleScope();
   extensions_ = current->extensions;
   // Shrink the current handle scope to make it impossible to do
   // handle allocations without an explicit handle scope.
@@ -64,7 +65,7 @@
 inline NoHandleAllocation::~NoHandleAllocation() {
   // Restore state in current handle scope to re-enable handle
   // allocations.
-  ImplementationUtilities::CurrentHandleScope()->extensions = extensions_;
+  v8::ImplementationUtilities::CurrentHandleScope()->extensions = extensions_;
 }
 #endif
 
diff --git a/src/handles.cc b/src/handles.cc
index 58ba472..3f198c8 100644
--- a/src/handles.cc
+++ b/src/handles.cc
@@ -40,6 +40,74 @@
 namespace v8 { namespace internal {
 
 
+v8::ImplementationUtilities::HandleScopeData HandleScope::current_ =
+    { -1, NULL, NULL };
+
+
+int HandleScope::NumberOfHandles() {
+  int n = HandleScopeImplementer::instance()->Blocks()->length();
+  if (n == 0) return 0;
+  return ((n - 1) * kHandleBlockSize) +
+      (current_.next - HandleScopeImplementer::instance()->Blocks()->last());
+}
+
+
+void** HandleScope::CreateHandle(void* value) {
+  void** result = current_.next;
+  if (result == current_.limit) {
+    // Make sure there's at least one scope on the stack and that the
+    // top of the scope stack isn't a barrier.
+    if (current_.extensions < 0) {
+      Utils::ReportApiFailure("v8::HandleScope::CreateHandle()",
+                              "Cannot create a handle without a HandleScope");
+      return NULL;
+    }
+    HandleScopeImplementer* impl = HandleScopeImplementer::instance();
+    // If there's more room in the last block, we use that. This is used
+    // for fast creation of scopes after scope barriers.
+    if (!impl->Blocks()->is_empty()) {
+      void** limit = &impl->Blocks()->last()[kHandleBlockSize];
+      if (current_.limit != limit) {
+        current_.limit = limit;
+      }
+    }
+
+    // If we still haven't found a slot for the handle, we extend the
+    // current handle scope by allocating a new handle block.
+    if (result == current_.limit) {
+      // If there's a spare block, use it for growing the current scope.
+      result = impl->GetSpareOrNewBlock();
+      // Add the extension to the global list of blocks, but count the
+      // extension as part of the current scope.
+      impl->Blocks()->Add(result);
+      current_.extensions++;
+      current_.limit = &result[kHandleBlockSize];
+    }
+  }
+
+  // Update the current next field, set the value in the created
+  // handle, and return the result.
+  ASSERT(result < current_.limit);
+  current_.next = result + 1;
+  *result = value;
+  return result;
+}
+
+
+void HandleScope::DeleteExtensions() {
+  ASSERT(current_.extensions != 0);
+  HandleScopeImplementer::instance()->DeleteExtensions(current_.extensions);
+}
+
+
+void HandleScope::ZapRange(void** start, void** end) {
+  if (start == NULL) return;
+  for (void** p = start; p < end; p++) {
+    *p = reinterpret_cast<void*>(v8::internal::kHandleZapValue);
+  }
+}
+
+
 Handle<FixedArray> AddKeysFromJSArray(Handle<FixedArray> content,
                                       Handle<JSArray> array) {
   CALL_HEAP_FUNCTION(content->AddKeysFromJSArray(*array), FixedArray);
@@ -120,7 +188,7 @@
 void FlattenString(Handle<String> string) {
   StringShape shape(*string);
   if (string->IsFlat(shape)) return;
-  CALL_HEAP_FUNCTION_VOID(string->Flatten(shape));
+  CALL_HEAP_FUNCTION_VOID(string->TryFlatten(shape));
   ASSERT(string->IsFlat(StringShape(*string)));
 }
 
diff --git a/src/handles.h b/src/handles.h
index ec0614b..dd453a7 100644
--- a/src/handles.h
+++ b/src/handles.h
@@ -28,12 +28,14 @@
 #ifndef V8_HANDLES_H_
 #define V8_HANDLES_H_
 
+#include "apiutils.h"
+
 namespace v8 { namespace internal {
 
 // ----------------------------------------------------------------------------
 // A Handle provides a reference to an object that survives relocation by
 // the garbage collector.
-// Handles are only valid withing a HandleScope.
+// Handles are only valid within a HandleScope.
 // When a handle is created for an object a cell is allocated in the heap.
 
 template<class T>
@@ -83,13 +85,82 @@
 
   // Closes the given scope, but lets this handle escape. See
   // implementation in api.h.
-  inline Handle<T> EscapeFrom(HandleScope* scope);
+  inline Handle<T> EscapeFrom(v8::HandleScope* scope);
 
  private:
   T** location_;
 };
 
 
+// A stack-allocated class that governs a number of local handles.
+// After a handle scope has been created, all local handles will be
+// allocated within that handle scope until either the handle scope is
+// deleted or another handle scope is created.  If there is already a
+// handle scope and a new one is created, all allocations will take
+// place in the new handle scope until it is deleted.  After that,
+// new handles will again be allocated in the original handle scope.
+//
+// After the handle scope of a local handle has been deleted the
+// garbage collector will no longer track the object stored in the
+// handle and may deallocate it.  The behavior of accessing a handle
+// for which the handle scope has been deleted is undefined.
+class HandleScope {
+ public:
+  HandleScope() : previous_(current_) {
+    current_.extensions = 0;
+  }
+
+  ~HandleScope() {
+    Leave(&previous_);
+  }
+
+  // Counts the number of allocated handles.
+  static int NumberOfHandles();
+
+  // Creates a new handle with the given value.
+  static void** CreateHandle(void* value);
+
+ private:
+  // Prevent heap allocation or illegal handle scopes.
+  HandleScope(const HandleScope&);
+  void operator=(const HandleScope&);
+  void* operator new(size_t size);
+  void operator delete(void* size_t);
+
+  static v8::ImplementationUtilities::HandleScopeData current_;
+  const v8::ImplementationUtilities::HandleScopeData previous_;
+
+  // Pushes a fresh handle scope to be used when allocating new handles.
+  static void Enter(
+      v8::ImplementationUtilities::HandleScopeData* previous) {
+    *previous = current_;
+    current_.extensions = 0;
+  }
+
+  // Re-establishes the previous scope state. Should be called only
+  // once, and only for the current scope.
+  static void Leave(
+      const v8::ImplementationUtilities::HandleScopeData* previous) {
+    if (current_.extensions > 0) {
+      DeleteExtensions();
+    }
+    current_ = *previous;
+#ifdef DEBUG
+    ZapRange(current_.next, current_.limit);
+#endif
+  }
+
+  // Deallocates any extensions used by the current scope.
+  static void DeleteExtensions();
+
+  // Zaps the handles in the half-open interval [start, end).
+  static void ZapRange(void** start, void** end);
+
+  friend class v8::HandleScope;
+  friend class v8::ImplementationUtilities;
+};
+
+
 // ----------------------------------------------------------------------------
 // Handle operations.
 // They might invoke garbage collection. The result is an handle to
diff --git a/src/heap.cc b/src/heap.cc
index f8caa49..b0a2db4 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -1724,9 +1724,12 @@
 
 
 Object* Heap::AllocateFunctionPrototype(JSFunction* function) {
-  // Allocate the prototype.
-  Object* prototype =
-      AllocateJSObject(Top::context()->global_context()->object_function());
+  // Allocate the prototype.  Make sure to use the object function
+  // from the function's context, since the function can be from a
+  // different context.
+  JSFunction* object_function =
+      function->context()->global_context()->object_function();
+  Object* prototype = AllocateJSObject(object_function);
   if (prototype->IsFailure()) return prototype;
   // When creating the prototype for the function we must set its
   // constructor to the function.
diff --git a/src/interpreter-irregexp.cc b/src/interpreter-irregexp.cc
index 8ffc040..c6ccda1 100644
--- a/src/interpreter-irregexp.cc
+++ b/src/interpreter-irregexp.cc
@@ -97,7 +97,7 @@
            current_char,
            printable ? current_char : '.',
            bytecode_name);
-    for (int i = 1; i < bytecode_length; i++) {
+    for (int i = 0; i < bytecode_length; i++) {
       printf(", %02x", pc[i]);
     }
     printf(" ");
@@ -129,6 +129,17 @@
 #endif
 
 
+static int32_t Load32Aligned(const byte* pc) {
+  ASSERT((reinterpret_cast<int>(pc) & 3) == 0);
+  return *reinterpret_cast<const int32_t *>(pc);
+}
+
+
+static int32_t Load16Aligned(const byte* pc) {
+  ASSERT((reinterpret_cast<int>(pc) & 1) == 0);
+  return *reinterpret_cast<const uint16_t *>(pc);
+}
+
 
 template <typename Char>
 static bool RawMatch(const byte* code_base,
@@ -147,7 +158,8 @@
   }
 #endif
   while (true) {
-    switch (*pc) {
+    int32_t insn = Load32Aligned(pc);
+    switch (insn & BYTECODE_MASK) {
       BYTECODE(BREAK)
         UNREACHABLE();
         return false;
@@ -155,45 +167,45 @@
         if (--backtrack_stack_space < 0) {
           return false;  // No match on backtrack stack overflow.
         }
-        *backtrack_sp++ = current + Load32(pc + 1);
+        *backtrack_sp++ = current;
         pc += BC_PUSH_CP_LENGTH;
         break;
       BYTECODE(PUSH_BT)
         if (--backtrack_stack_space < 0) {
           return false;  // No match on backtrack stack overflow.
         }
-        *backtrack_sp++ = Load32(pc + 1);
+        *backtrack_sp++ = Load32Aligned(pc + 4);
         pc += BC_PUSH_BT_LENGTH;
         break;
       BYTECODE(PUSH_REGISTER)
         if (--backtrack_stack_space < 0) {
           return false;  // No match on backtrack stack overflow.
         }
-        *backtrack_sp++ = registers[pc[1]];
+        *backtrack_sp++ = registers[insn >> BYTECODE_SHIFT];
         pc += BC_PUSH_REGISTER_LENGTH;
         break;
       BYTECODE(SET_REGISTER)
-        registers[pc[1]] = Load32(pc + 2);
+        registers[insn >> BYTECODE_SHIFT] = Load32Aligned(pc + 4);
         pc += BC_SET_REGISTER_LENGTH;
         break;
       BYTECODE(ADVANCE_REGISTER)
-        registers[pc[1]] += Load32(pc + 2);
+        registers[insn >> BYTECODE_SHIFT] += Load32Aligned(pc + 4);
         pc += BC_ADVANCE_REGISTER_LENGTH;
         break;
       BYTECODE(SET_REGISTER_TO_CP)
-        registers[pc[1]] = current + Load32(pc + 2);
+        registers[insn >> BYTECODE_SHIFT] = current + Load32Aligned(pc + 4);
         pc += BC_SET_REGISTER_TO_CP_LENGTH;
         break;
       BYTECODE(SET_CP_TO_REGISTER)
-        current = registers[pc[1]];
+        current = registers[insn >> BYTECODE_SHIFT];
         pc += BC_SET_CP_TO_REGISTER_LENGTH;
         break;
       BYTECODE(SET_REGISTER_TO_SP)
-        registers[pc[1]] = backtrack_sp - backtrack_stack;
+        registers[insn >> BYTECODE_SHIFT] = backtrack_sp - backtrack_stack;
         pc += BC_SET_REGISTER_TO_SP_LENGTH;
         break;
       BYTECODE(SET_SP_TO_REGISTER)
-        backtrack_sp = backtrack_stack + registers[pc[1]];
+        backtrack_sp = backtrack_stack + registers[insn >> BYTECODE_SHIFT];
         backtrack_stack_space = kBacktrackStackSize -
                                 (backtrack_sp - backtrack_stack);
         pc += BC_SET_SP_TO_REGISTER_LENGTH;
@@ -212,7 +224,7 @@
       BYTECODE(POP_REGISTER)
         backtrack_stack_space++;
         --backtrack_sp;
-        registers[pc[1]] = *backtrack_sp;
+        registers[insn >> BYTECODE_SHIFT] = *backtrack_sp;
         pc += BC_POP_REGISTER_LENGTH;
         break;
       BYTECODE(FAIL)
@@ -220,25 +232,25 @@
       BYTECODE(SUCCEED)
         return true;
       BYTECODE(ADVANCE_CP)
-        current += Load32(pc + 1);
+        current += insn >> BYTECODE_SHIFT;
         pc += BC_ADVANCE_CP_LENGTH;
         break;
       BYTECODE(GOTO)
-        pc = code_base + Load32(pc + 1);
+        pc = code_base + Load32Aligned(pc + 4);
         break;
       BYTECODE(CHECK_GREEDY)
         if (current == backtrack_sp[-1]) {
           backtrack_sp--;
           backtrack_stack_space++;
-          pc = code_base + Load32(pc + 1);
+          pc = code_base + Load32Aligned(pc + 4);
         } else {
           pc += BC_CHECK_GREEDY_LENGTH;
         }
         break;
       BYTECODE(LOAD_CURRENT_CHAR) {
-        int pos = current + Load32(pc + 1);
+        int pos = current + (insn >> BYTECODE_SHIFT);
         if (pos >= subject.length()) {
-          pc = code_base + Load32(pc + 5);
+          pc = code_base + Load32Aligned(pc + 4);
         } else {
           current_char = subject[pos];
           pc += BC_LOAD_CURRENT_CHAR_LENGTH;
@@ -246,15 +258,15 @@
         break;
       }
       BYTECODE(LOAD_CURRENT_CHAR_UNCHECKED) {
-        int pos = current + Load32(pc + 1);
+        int pos = current + (insn >> BYTECODE_SHIFT);
         current_char = subject[pos];
         pc += BC_LOAD_CURRENT_CHAR_UNCHECKED_LENGTH;
         break;
       }
       BYTECODE(LOAD_2_CURRENT_CHARS) {
-        int pos = current + Load32(pc + 1);
+        int pos = current + (insn >> BYTECODE_SHIFT);
         if (pos + 2 > subject.length()) {
-          pc = code_base + Load32(pc + 5);
+          pc = code_base + Load32Aligned(pc + 4);
         } else {
           Char next = subject[pos + 1];
           current_char =
@@ -264,7 +276,7 @@
         break;
       }
       BYTECODE(LOAD_2_CURRENT_CHARS_UNCHECKED) {
-        int pos = current + Load32(pc + 1);
+        int pos = current + (insn >> BYTECODE_SHIFT);
         Char next = subject[pos + 1];
         current_char = (subject[pos] | (next << (kBitsPerByte * sizeof(Char))));
         pc += BC_LOAD_2_CURRENT_CHARS_UNCHECKED_LENGTH;
@@ -272,9 +284,9 @@
       }
       BYTECODE(LOAD_4_CURRENT_CHARS) {
         ASSERT(sizeof(Char) == 1);
-        int pos = current + Load32(pc + 1);
+        int pos = current + (insn >> BYTECODE_SHIFT);
         if (pos + 4 > subject.length()) {
-          pc = code_base + Load32(pc + 5);
+          pc = code_base + Load32Aligned(pc + 4);
         } else {
           Char next1 = subject[pos + 1];
           Char next2 = subject[pos + 2];
@@ -289,7 +301,7 @@
       }
       BYTECODE(LOAD_4_CURRENT_CHARS_UNCHECKED) {
         ASSERT(sizeof(Char) == 1);
-        int pos = current + Load32(pc + 1);
+        int pos = current + (insn >> BYTECODE_SHIFT);
         Char next1 = subject[pos + 1];
         Char next2 = subject[pos + 2];
         Char next3 = subject[pos + 3];
@@ -300,100 +312,136 @@
         pc += BC_LOAD_4_CURRENT_CHARS_UNCHECKED_LENGTH;
         break;
       }
-      BYTECODE(CHECK_CHAR) {
-        uint32_t c = Load32(pc + 1);
+      BYTECODE(CHECK_4_CHARS) {
+        uint32_t c = Load32Aligned(pc + 4);
         if (c == current_char) {
-          pc = code_base + Load32(pc + 5);
+          pc = code_base + Load32Aligned(pc + 8);
+        } else {
+          pc += BC_CHECK_4_CHARS_LENGTH;
+        }
+        break;
+      }
+      BYTECODE(CHECK_CHAR) {
+        uint32_t c = (insn >> BYTECODE_SHIFT);
+        if (c == current_char) {
+          pc = code_base + Load32Aligned(pc + 4);
         } else {
           pc += BC_CHECK_CHAR_LENGTH;
         }
         break;
       }
-      BYTECODE(CHECK_NOT_CHAR) {
-        uint32_t c = Load32(pc + 1);
+      BYTECODE(CHECK_NOT_4_CHARS) {
+        uint32_t c = Load32Aligned(pc + 4);
         if (c != current_char) {
-          pc = code_base + Load32(pc + 5);
+          pc = code_base + Load32Aligned(pc + 8);
+        } else {
+          pc += BC_CHECK_NOT_4_CHARS_LENGTH;
+        }
+        break;
+      }
+      BYTECODE(CHECK_NOT_CHAR) {
+        uint32_t c = (insn >> BYTECODE_SHIFT);
+        if (c != current_char) {
+          pc = code_base + Load32Aligned(pc + 4);
         } else {
           pc += BC_CHECK_NOT_CHAR_LENGTH;
         }
         break;
       }
+      BYTECODE(AND_CHECK_4_CHARS) {
+        uint32_t c = Load32Aligned(pc + 4);
+        if (c == (current_char & Load32Aligned(pc + 8))) {
+          pc = code_base + Load32Aligned(pc + 12);
+        } else {
+          pc += BC_AND_CHECK_4_CHARS_LENGTH;
+        }
+        break;
+      }
       BYTECODE(AND_CHECK_CHAR) {
-        uint32_t c = Load32(pc + 1);
-        if (c == (current_char & Load32(pc + 5))) {
-          pc = code_base + Load32(pc + 9);
+        uint32_t c = (insn >> BYTECODE_SHIFT);
+        if (c == (current_char & Load32Aligned(pc + 4))) {
+          pc = code_base + Load32Aligned(pc + 8);
         } else {
           pc += BC_AND_CHECK_CHAR_LENGTH;
         }
         break;
       }
+      BYTECODE(AND_CHECK_NOT_4_CHARS) {
+        uint32_t c = Load32Aligned(pc + 4);
+        if (c != (current_char & Load32Aligned(pc + 8))) {
+          pc = code_base + Load32Aligned(pc + 12);
+        } else {
+          pc += BC_AND_CHECK_NOT_4_CHARS_LENGTH;
+        }
+        break;
+      }
       BYTECODE(AND_CHECK_NOT_CHAR) {
-        uint32_t c = Load32(pc + 1);
-        if (c != (current_char & Load32(pc + 5))) {
-          pc = code_base + Load32(pc + 9);
+        uint32_t c = (insn >> BYTECODE_SHIFT);
+        if (c != (current_char & Load32Aligned(pc + 4))) {
+          pc = code_base + Load32Aligned(pc + 8);
         } else {
           pc += BC_AND_CHECK_NOT_CHAR_LENGTH;
         }
         break;
       }
       BYTECODE(MINUS_AND_CHECK_NOT_CHAR) {
-        uint32_t c = Load16(pc + 1);
-        uint32_t minus = Load16(pc + 3);
-        uint32_t mask = Load16(pc + 5);
+        uint32_t c = (insn >> BYTECODE_SHIFT);
+        uint32_t minus = Load16Aligned(pc + 4);
+        uint32_t mask = Load16Aligned(pc + 6);
         if (c != ((current_char - minus) & mask)) {
-          pc = code_base + Load32(pc + 7);
+          pc = code_base + Load32Aligned(pc + 8);
         } else {
           pc += BC_MINUS_AND_CHECK_NOT_CHAR_LENGTH;
         }
         break;
       }
       BYTECODE(CHECK_LT) {
-        uint32_t limit = Load16(pc + 1);
+        uint32_t limit = (insn >> BYTECODE_SHIFT);
         if (current_char < limit) {
-          pc = code_base + Load32(pc + 3);
+          pc = code_base + Load32Aligned(pc + 4);
         } else {
           pc += BC_CHECK_LT_LENGTH;
         }
         break;
       }
       BYTECODE(CHECK_GT) {
-        uint32_t limit = Load16(pc + 1);
+        uint32_t limit = (insn >> BYTECODE_SHIFT);
         if (current_char > limit) {
-          pc = code_base + Load32(pc + 3);
+          pc = code_base + Load32Aligned(pc + 4);
         } else {
           pc += BC_CHECK_GT_LENGTH;
         }
         break;
       }
       BYTECODE(CHECK_REGISTER_LT)
-        if (registers[pc[1]] < Load16(pc + 2)) {
-          pc = code_base + Load32(pc + 4);
+        if (registers[insn >> BYTECODE_SHIFT] < Load32Aligned(pc + 4)) {
+          pc = code_base + Load32Aligned(pc + 8);
         } else {
           pc += BC_CHECK_REGISTER_LT_LENGTH;
         }
         break;
       BYTECODE(CHECK_REGISTER_GE)
-        if (registers[pc[1]] >= Load16(pc + 2)) {
-          pc = code_base + Load32(pc + 4);
+        if (registers[insn >> BYTECODE_SHIFT] >= Load32Aligned(pc + 4)) {
+          pc = code_base + Load32Aligned(pc + 8);
         } else {
           pc += BC_CHECK_REGISTER_GE_LENGTH;
         }
         break;
       BYTECODE(CHECK_REGISTER_EQ_POS)
-        if (registers[pc[1]] == current) {
-          pc = code_base + Load32(pc + 2);
+        if (registers[insn >> BYTECODE_SHIFT] == current) {
+          pc = code_base + Load32Aligned(pc + 4);
         } else {
           pc += BC_CHECK_REGISTER_EQ_POS_LENGTH;
         }
         break;
       BYTECODE(LOOKUP_MAP1) {
         // Look up character in a bitmap.  If we find a 0, then jump to the
-        // location at pc + 7.  Otherwise fall through!
-        int index = current_char - Load16(pc + 1);
-        byte map = code_base[Load32(pc + 3) + (index >> 3)];
+        // location at pc + 8.  Otherwise fall through!
+        int index = current_char - (insn >> BYTECODE_SHIFT);
+        byte map = code_base[Load32Aligned(pc + 4) + (index >> 3)];
         map = ((map >> (index & 7)) & 1);
         if (map == 0) {
-          pc = code_base + Load32(pc + 7);
+          pc = code_base + Load32Aligned(pc + 8);
         } else {
           pc += BC_LOOKUP_MAP1_LENGTH;
         }
@@ -401,22 +449,22 @@
       }
       BYTECODE(LOOKUP_MAP2) {
         // Look up character in a half-nibble map.  If we find 00, then jump to
-        // the location at pc + 7.   If we find 01 then jump to location at
+        // the location at pc + 8.   If we find 01 then jump to location at
         // pc + 11, etc.
-        int index = (current_char - Load16(pc + 1)) << 1;
-        byte map = code_base[Load32(pc + 3) + (index >> 3)];
+        int index = (current_char - (insn >> BYTECODE_SHIFT)) << 1;
+        byte map = code_base[Load32Aligned(pc + 3) + (index >> 3)];
         map = ((map >> (index & 7)) & 3);
         if (map < 2) {
           if (map == 0) {
-            pc = code_base + Load32(pc + 7);
+            pc = code_base + Load32Aligned(pc + 8);
           } else {
-            pc = code_base + Load32(pc + 11);
+            pc = code_base + Load32Aligned(pc + 12);
           }
         } else {
           if (map == 2) {
-            pc = code_base + Load32(pc + 15);
+            pc = code_base + Load32Aligned(pc + 16);
           } else {
-            pc = code_base + Load32(pc + 19);
+            pc = code_base + Load32Aligned(pc + 20);
           }
         }
         break;
@@ -424,43 +472,44 @@
       BYTECODE(LOOKUP_MAP8) {
         // Look up character in a byte map.  Use the byte as an index into a
         // table that follows this instruction immediately.
-        int index = current_char - Load16(pc + 1);
-        byte map = code_base[Load32(pc + 3) + index];
-        const byte* new_pc = code_base + Load32(pc + 7) + (map << 2);
-        pc = code_base + Load32(new_pc);
+        int index = current_char - (insn >> BYTECODE_SHIFT);
+        byte map = code_base[Load32Aligned(pc + 4) + index];
+        const byte* new_pc = code_base + Load32Aligned(pc + 8) + (map << 2);
+        pc = code_base + Load32Aligned(new_pc);
         break;
       }
       BYTECODE(LOOKUP_HI_MAP8) {
         // Look up high byte of this character in a byte map.  Use the byte as
         // an index into a table that follows this instruction immediately.
-        int index = (current_char >> 8) - pc[1];
-        byte map = code_base[Load32(pc + 2) + index];
-        const byte* new_pc = code_base + Load32(pc + 6) + (map << 2);
-        pc = code_base + Load32(new_pc);
+        int index = (current_char >> 8) - (insn >> BYTECODE_SHIFT);
+        byte map = code_base[Load32Aligned(pc + 4) + index];
+        const byte* new_pc = code_base + Load32Aligned(pc + 8) + (map << 2);
+        pc = code_base + Load32Aligned(new_pc);
         break;
       }
       BYTECODE(CHECK_NOT_REGS_EQUAL)
-        if (registers[pc[1]] == registers[pc[2]]) {
+        if (registers[insn >> BYTECODE_SHIFT] ==
+            registers[Load32Aligned(pc + 4)]) {
           pc += BC_CHECK_NOT_REGS_EQUAL_LENGTH;
         } else {
-          pc = code_base + Load32(pc + 3);
+          pc = code_base + Load32Aligned(pc + 8);
         }
         break;
       BYTECODE(CHECK_NOT_BACK_REF) {
-        int from = registers[pc[1]];
-        int len = registers[pc[1] + 1] - from;
+        int from = registers[insn >> BYTECODE_SHIFT];
+        int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
         if (from < 0 || len <= 0) {
           pc += BC_CHECK_NOT_BACK_REF_LENGTH;
           break;
         }
         if (current + len > subject.length()) {
-          pc = code_base + Load32(pc + 2);
+          pc = code_base + Load32Aligned(pc + 4);
           break;
         } else {
           int i;
           for (i = 0; i < len; i++) {
             if (subject[from + i] != subject[current + i]) {
-              pc = code_base + Load32(pc + 2);
+              pc = code_base + Load32Aligned(pc + 4);
               break;
             }
           }
@@ -471,30 +520,37 @@
         break;
       }
       BYTECODE(CHECK_NOT_BACK_REF_NO_CASE) {
-        int from = registers[pc[1]];
-        int len = registers[pc[1] + 1] - from;
+        int from = registers[insn >> BYTECODE_SHIFT];
+        int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
         if (from < 0 || len <= 0) {
           pc += BC_CHECK_NOT_BACK_REF_NO_CASE_LENGTH;
           break;
         }
         if (current + len > subject.length()) {
-          pc = code_base + Load32(pc + 2);
+          pc = code_base + Load32Aligned(pc + 4);
           break;
         } else {
           if (BackRefMatchesNoCase(from, current, len, subject)) {
             current += len;
             pc += BC_CHECK_NOT_BACK_REF_NO_CASE_LENGTH;
           } else {
-            pc = code_base + Load32(pc + 2);
+            pc = code_base + Load32Aligned(pc + 4);
           }
         }
         break;
       }
+      BYTECODE(CHECK_AT_START)
+        if (current == 0) {
+          pc = code_base + Load32Aligned(pc + 4);
+        } else {
+          pc += BC_CHECK_AT_START_LENGTH;
+        }
+        break;
       BYTECODE(CHECK_NOT_AT_START)
         if (current == 0) {
           pc += BC_CHECK_NOT_AT_START_LENGTH;
         } else {
-          pc = code_base + Load32(pc + 1);
+          pc = code_base + Load32Aligned(pc + 4);
         }
         break;
       default:
diff --git a/src/jsregexp.cc b/src/jsregexp.cc
index aa11a69..fef0b0d 100644
--- a/src/jsregexp.cc
+++ b/src/jsregexp.cc
@@ -298,21 +298,10 @@
       return AtomExec(regexp, subject, index);
     case JSRegExp::IRREGEXP: {
       Handle<Object> result = IrregexpExec(regexp, subject, index);
-      if (!result.is_null() || Top::has_pending_exception()) {
-        return result;
-      }
-      // We couldn't handle the regexp using Irregexp, so fall back
-      // on JSCRE.
-      // Reset the JSRegExp to use JSCRE.
-      JscrePrepare(regexp,
-                   Handle<String>(regexp->Pattern()),
-                   regexp->GetFlags());
-      // Fall-through to JSCRE.
+      if (result.is_null()) ASSERT(Top::has_pending_exception());
+      return result;
     }
     case JSRegExp::JSCRE:
-      if (FLAG_disable_jscre) {
-        UNIMPLEMENTED();
-      }
       return JscreExec(regexp, subject, index);
     default:
       UNREACHABLE();
@@ -328,22 +317,10 @@
       return AtomExecGlobal(regexp, subject);
     case JSRegExp::IRREGEXP: {
       Handle<Object> result = IrregexpExecGlobal(regexp, subject);
-      if (!result.is_null() || Top::has_pending_exception()) {
-        return result;
-      }
-      // Empty handle as result but no exception thrown means that
-      // the regexp contains features not yet handled by the irregexp
-      // compiler.
-      // We have to fall back on JSCRE. Reset the JSRegExp to use JSCRE.
-      JscrePrepare(regexp,
-                   Handle<String>(regexp->Pattern()),
-                   regexp->GetFlags());
-      // Fall-through to JSCRE.
+      if (result.is_null()) ASSERT(Top::has_pending_exception());
+      return result;
     }
     case JSRegExp::JSCRE:
-      if (FLAG_disable_jscre) {
-        UNIMPLEMENTED();
-      }
       return JscreExecGlobal(regexp, subject);
     default:
       UNREACHABLE();
@@ -460,7 +437,7 @@
                                      &JSREMalloc,
                                      &JSREFree);
   if (*code == NULL && (malloc_failure->IsRetryAfterGC() ||
-                       malloc_failure->IsOutOfMemoryFailure())) {
+                        malloc_failure->IsOutOfMemoryFailure())) {
     return malloc_failure;
   } else {
     // It doesn't matter which object we return here, we just need to return
@@ -697,7 +674,7 @@
   Handle<String> pattern(re->Pattern());
   StringShape shape(*pattern);
   if (!pattern->IsFlat(shape)) {
-    pattern->Flatten(shape);
+    FlattenString(pattern);
   }
 
   RegExpCompileData compile_data;
@@ -824,7 +801,7 @@
   Handle<Object> matches;
 
   if (!subject->IsFlat(shape)) {
-    subject->Flatten(shape);
+    FlattenString(subject);
   }
 
   while (true) {
@@ -920,6 +897,7 @@
             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();
@@ -1197,7 +1175,13 @@
  public:
   RegExpCompiler(int capture_count, bool ignore_case, bool is_ascii);
 
-  int AllocateRegister() { return next_register_++; }
+  int AllocateRegister() {
+    if (next_register_ >= RegExpMacroAssembler::kMaxRegister) {
+      reg_exp_too_big_ = true;
+      return next_register_;
+    }
+    return next_register_++;
+  }
 
   Handle<FixedArray> Assemble(RegExpMacroAssembler* assembler,
                               RegExpNode* start,
@@ -1218,6 +1202,8 @@
   inline void IncrementRecursionDepth() { recursion_depth_++; }
   inline void DecrementRecursionDepth() { recursion_depth_--; }
 
+  void SetRegExpTooBig() { reg_exp_too_big_ = true; }
+
   inline bool ignore_case() { return ignore_case_; }
   inline bool ascii() { return ascii_; }
 
@@ -1230,6 +1216,7 @@
   RegExpMacroAssembler* macro_assembler_;
   bool ignore_case_;
   bool ascii_;
+  bool reg_exp_too_big_;
 };
 
 
@@ -1244,6 +1231,18 @@
 };
 
 
+static Handle<FixedArray> IrregexpRegExpTooBig(Handle<String> pattern) {
+  Handle<JSArray> array = Factory::NewJSArray(2);
+  SetElement(array, 0, pattern);
+  const char* message = "RegExp too big";
+  SetElement(array, 1, Factory::NewStringFromUtf8(CStrVector(message)));
+  Handle<Object> regexp_err =
+      Factory::NewSyntaxError("malformed_regexp", array);
+  Top::Throw(*regexp_err);
+  return Handle<FixedArray>();
+}
+
+
 // Attempts to compile the regexp using an Irregexp code generator.  Returns
 // a fixed array or a null handle depending on whether it succeeded.
 RegExpCompiler::RegExpCompiler(int capture_count, bool ignore_case, bool ascii)
@@ -1251,8 +1250,10 @@
       work_list_(NULL),
       recursion_depth_(0),
       ignore_case_(ignore_case),
-      ascii_(ascii) {
+      ascii_(ascii),
+      reg_exp_too_big_(false) {
   accept_ = new EndNode(EndNode::ACCEPT);
+  ASSERT(next_register_ - 1 <= RegExpMacroAssembler::kMaxRegister);
 }
 
 
@@ -1272,17 +1273,13 @@
   Label fail;
   macro_assembler->PushBacktrack(&fail);
   Trace new_trace;
-  if (!start->Emit(this, &new_trace)) {
-    fail.Unuse();
-    return Handle<FixedArray>::null();
-  }
+  start->Emit(this, &new_trace);
   macro_assembler_->Bind(&fail);
   macro_assembler_->Fail();
   while (!work_list.is_empty()) {
-    if (!work_list.RemoveLast()->Emit(this, &new_trace)) {
-      return Handle<FixedArray>::null();
-    }
+    work_list.RemoveLast()->Emit(this, &new_trace);
   }
+  if (reg_exp_too_big_) return IrregexpRegExpTooBig(pattern);
   Handle<FixedArray> array =
       Factory::NewFixedArray(RegExpImpl::kIrregexpDataLength);
   array->set(RegExpImpl::kIrregexpImplementationIndex,
@@ -1302,6 +1299,7 @@
   return array;
 }
 
+
 bool Trace::DeferredAction::Mentions(int that) {
   if (type() == ActionNode::CLEAR_CAPTURES) {
     Interval range = static_cast<DeferredClearCaptures*>(this)->range();
@@ -1360,41 +1358,44 @@
 }
 
 
-void Trace::PushAffectedRegisters(RegExpMacroAssembler* assembler,
-                                  int max_register,
-                                  OutSet& affected_registers) {
-  // Stay safe and check every half times the limit.
-  // (Round up in case the limit is 1).
-  int push_limit = (assembler->stack_limit_slack() + 1) / 2;
-  for (int reg = 0, pushes = 0; reg <= max_register; reg++) {
-    if (affected_registers.Get(reg)) {
-      pushes++;
-      RegExpMacroAssembler::StackCheckFlag check_stack_limit =
-          (pushes % push_limit) == 0 ?
-                RegExpMacroAssembler::kCheckStackLimit :
-                RegExpMacroAssembler::kNoStackLimitCheck;
-      assembler->PushRegister(reg, check_stack_limit);
-    }
-  }
-}
-
-
 void Trace::RestoreAffectedRegisters(RegExpMacroAssembler* assembler,
                                      int max_register,
-                                     OutSet& affected_registers) {
+                                     OutSet& registers_to_pop,
+                                     OutSet& registers_to_clear) {
   for (int reg = max_register; reg >= 0; reg--) {
-    if (affected_registers.Get(reg)) assembler->PopRegister(reg);
+    if (registers_to_pop.Get(reg)) assembler->PopRegister(reg);
+    else if (registers_to_clear.Get(reg)) {
+      int clear_to = reg;
+      while (reg > 0 && registers_to_clear.Get(reg - 1)) {
+        reg--;
+      }
+      assembler->ClearRegisters(reg, clear_to);
+    }
   }
 }
 
 
 void Trace::PerformDeferredActions(RegExpMacroAssembler* assembler,
                                    int max_register,
-                                   OutSet& affected_registers) {
+                                   OutSet& affected_registers,
+                                   OutSet* registers_to_pop,
+                                   OutSet* registers_to_clear) {
+  // The "+1" is to avoid a push_limit of zero if stack_limit_slack() is 1.
+  const int push_limit = (assembler->stack_limit_slack() + 1) / 2;
+
   for (int reg = 0; reg <= max_register; reg++) {
     if (!affected_registers.Get(reg)) {
       continue;
     }
+    // Count pushes performed to force a stack limit check occasionally.
+    int pushes = 0;
+
+    // The chronologically first deferred action in the trace
+    // is used to infer the action needed to restore a register
+    // to its previous state (or not, if it's safe to ignore it).
+    enum DeferredActionUndoType { IGNORE, RESTORE, CLEAR };
+    DeferredActionUndoType undo_action = IGNORE;
+
     int value = 0;
     bool absolute = false;
     bool clear = false;
@@ -1409,8 +1410,16 @@
           case ActionNode::SET_REGISTER: {
             Trace::DeferredSetRegister* psr =
                 static_cast<Trace::DeferredSetRegister*>(action);
-            value += psr->value();
-            absolute = true;
+            if (!absolute) {
+              value += psr->value();
+              absolute = true;
+            }
+            // SET_REGISTER is currently only used for newly introduced loop
+            // counters. They can have a significant previous value if they
+            // occour in a loop. TODO(lrn): Propagate this information, so
+            // we can set undo_action to IGNORE if we know there is no value to
+            // restore.
+            undo_action = RESTORE;
             ASSERT_EQ(store_position, -1);
             ASSERT(!clear);
             break;
@@ -1421,6 +1430,7 @@
             }
             ASSERT_EQ(store_position, -1);
             ASSERT(!clear);
+            undo_action = RESTORE;
             break;
           case ActionNode::STORE_POSITION: {
             Trace::DeferredCapture* pc =
@@ -1428,6 +1438,19 @@
             if (!clear && store_position == -1) {
               store_position = pc->cp_offset();
             }
+
+            // For captures we know that stores and clears alternate.
+            // Other register, are never cleared, and if the occur
+            // inside a loop, they might be assigned more than once.
+            if (reg <= 1) {
+              // Registers zero and one, aka "capture zero", is
+              // always set correctly if we succeed. There is no
+              // need to undo a setting on backtrack, because we
+              // will set it again or fail.
+              undo_action = IGNORE;
+            } else {
+              undo_action = pc->is_capture() ? CLEAR : RESTORE;
+            }
             ASSERT(!absolute);
             ASSERT_EQ(value, 0);
             break;
@@ -1436,8 +1459,10 @@
             // Since we're scanning in reverse order, if we've already
             // set the position we have to ignore historically earlier
             // clearing operations.
-            if (store_position == -1)
+            if (store_position == -1) {
               clear = true;
+            }
+            undo_action = RESTORE;
             ASSERT(!absolute);
             ASSERT_EQ(value, 0);
             break;
@@ -1448,10 +1473,27 @@
         }
       }
     }
+    // Prepare for the undo-action (e.g., push if it's going to be popped).
+    if (undo_action == RESTORE) {
+      pushes++;
+      RegExpMacroAssembler::StackCheckFlag stack_check =
+          RegExpMacroAssembler::kNoStackLimitCheck;
+      if (pushes == push_limit) {
+        stack_check = RegExpMacroAssembler::kCheckStackLimit;
+        pushes = 0;
+      }
+
+      assembler->PushRegister(reg, stack_check);
+      registers_to_pop->Set(reg);
+    } else if (undo_action == CLEAR) {
+      registers_to_clear->Set(reg);
+    }
+    // Perform the chronologically last action (or accumulated increment)
+    // for the register.
     if (store_position != -1) {
       assembler->WriteCurrentPositionToRegister(reg, store_position);
     } else if (clear) {
-      assembler->ClearRegister(reg);
+      assembler->ClearRegisters(reg, reg);
     } else if (absolute) {
       assembler->SetRegister(reg, value);
     } else if (value != 0) {
@@ -1464,7 +1506,7 @@
 // This is called as we come into a loop choice node and some other tricky
 // nodes.  It normalizes the state of the code generator to ensure we can
 // generate generic code.
-bool Trace::Flush(RegExpCompiler* compiler, RegExpNode* successor) {
+void Trace::Flush(RegExpCompiler* compiler, RegExpNode* successor) {
   RegExpMacroAssembler* assembler = compiler->macro_assembler();
 
   ASSERT(actions_ != NULL ||
@@ -1481,14 +1523,21 @@
     if (cp_offset_ != 0) assembler->AdvanceCurrentPosition(cp_offset_);
     // Create a new trivial state and generate the node with that.
     Trace new_state;
-    return successor->Emit(compiler, &new_state);
+    successor->Emit(compiler, &new_state);
+    return;
   }
 
   // Generate deferred actions here along with code to undo them again.
   OutSet affected_registers;
+
   int max_register = FindAffectedRegisters(&affected_registers);
-  PushAffectedRegisters(assembler, max_register, affected_registers);
-  PerformDeferredActions(assembler, max_register, affected_registers);
+  OutSet registers_to_pop;
+  OutSet registers_to_clear;
+  PerformDeferredActions(assembler,
+                         max_register,
+                         affected_registers,
+                         &registers_to_pop,
+                         &registers_to_clear);
   if (backtrack() != NULL) {
     // Here we have a concrete backtrack location.  These are set up by choice
     // nodes and so they indicate that we have a deferred save of the current
@@ -1503,58 +1552,56 @@
   Label undo;
   assembler->PushBacktrack(&undo);
   Trace new_state;
-  bool ok = successor->Emit(compiler, &new_state);
+  successor->Emit(compiler, &new_state);
 
   // On backtrack we need to restore state.
   assembler->Bind(&undo);
-  if (!ok) return false;
   if (backtrack() != NULL) {
     assembler->PopCurrentPosition();
   }
-  RestoreAffectedRegisters(assembler, max_register, affected_registers);
+  RestoreAffectedRegisters(assembler,
+                           max_register,
+                           registers_to_pop,
+                           registers_to_clear);
   if (backtrack() == NULL) {
     assembler->Backtrack();
   } else {
     assembler->GoTo(backtrack());
   }
-
-  return true;
 }
 
 
-void EndNode::EmitInfoChecks(RegExpMacroAssembler* assembler, Trace* trace) {
-  if (info()->at_end) {
-    Label succeed;
-    // LoadCurrentCharacter will go to the label if we are at the end of the
-    // input string.
-    assembler->LoadCurrentCharacter(0, &succeed);
-    assembler->GoTo(trace->backtrack());
-    assembler->Bind(&succeed);
-  }
-}
-
-
-bool NegativeSubmatchSuccess::Emit(RegExpCompiler* compiler, Trace* trace) {
-  if (!trace->is_trivial()) {
-    return trace->Flush(compiler, this);
-  }
+void NegativeSubmatchSuccess::Emit(RegExpCompiler* compiler, Trace* trace) {
   RegExpMacroAssembler* assembler = compiler->macro_assembler();
+
+  // Omit flushing the trace. We discard the entire stack frame anyway.
+
   if (!label()->is_bound()) {
+    // We are completely independent of the trace, since we ignore it,
+    // so this code can be used as the generic version.
     assembler->Bind(label());
   }
-  EmitInfoChecks(assembler, trace);
+
+  // Throw away everything on the backtrack stack since the start
+  // of the negative submatch and restore the character position.
   assembler->ReadCurrentPositionFromRegister(current_position_register_);
   assembler->ReadStackPointerFromRegister(stack_pointer_register_);
+  if (clear_capture_count_ > 0) {
+    // Clear any captures that might have been performed during the success
+    // of the body of the negative look-ahead.
+    int clear_capture_end = clear_capture_start_ + clear_capture_count_ - 1;
+    assembler->ClearRegisters(clear_capture_start_, clear_capture_end);
+  }
   // Now that we have unwound the stack we find at the top of the stack the
   // backtrack that the BeginSubmatch node got.
   assembler->Backtrack();
-  return true;
 }
 
 
-bool EndNode::Emit(RegExpCompiler* compiler, Trace* trace) {
+void EndNode::Emit(RegExpCompiler* compiler, Trace* trace) {
   if (!trace->is_trivial()) {
-    return trace->Flush(compiler, this);
+    trace->Flush(compiler, this);
+    return;
   }
   RegExpMacroAssembler* assembler = compiler->macro_assembler();
   if (!label()->is_bound()) {
@@ -1562,19 +1609,16 @@
   }
   switch (action_) {
     case ACCEPT:
-      EmitInfoChecks(assembler, trace);
       assembler->Succeed();
-      return true;
+      return;
     case BACKTRACK:
-      ASSERT(!info()->at_end);
       assembler->GoTo(trace->backtrack());
-      return true;
+      return;
     case NEGATIVE_SUBMATCH_SUCCESS:
       // This case is handled in a different virtual method.
       UNREACHABLE();
   }
   UNIMPLEMENTED();
-  return false;
 }
 
 
@@ -1602,9 +1646,12 @@
 }
 
 
-ActionNode* ActionNode::StorePosition(int reg, RegExpNode* on_success) {
+ActionNode* ActionNode::StorePosition(int reg,
+                                      bool is_capture,
+                                      RegExpNode* on_success) {
   ActionNode* result = new ActionNode(STORE_POSITION, on_success);
   result->data_.u_position_register.reg = reg;
+  result->data_.u_position_register.is_capture = is_capture;
   return result;
 }
 
@@ -1630,10 +1677,14 @@
 
 ActionNode* ActionNode::PositiveSubmatchSuccess(int stack_reg,
                                                 int position_reg,
+                                                int clear_register_count,
+                                                int clear_register_from,
                                                 RegExpNode* on_success) {
   ActionNode* result = new ActionNode(POSITIVE_SUBMATCH_SUCCESS, on_success);
   result->data_.u_submatch.stack_pointer_register = stack_reg;
   result->data_.u_submatch.current_position_register = position_reg;
+  result->data_.u_submatch.clear_register_count = clear_register_count;
+  result->data_.u_submatch.clear_register_from = clear_register_from;
   return result;
 }
 
@@ -1849,6 +1900,9 @@
       // ASCII optimizations for us.
       macro_assembler->GoTo(on_failure);
     }
+    if (check_offset) {
+      macro_assembler->CheckPosition(cp_offset, on_failure);
+    }
     return;
   }
 
@@ -1856,10 +1910,8 @@
       !cc->is_negated() &&
       ranges->at(0).IsEverything(max_char)) {
     // This is a common case hit by non-anchored expressions.
-    // TODO(erikcorry): We should have a macro assembler instruction that just
-    // checks for end of string without loading the character.
     if (check_offset) {
-      macro_assembler->LoadCurrentCharacter(cp_offset, on_failure);
+      macro_assembler->CheckPosition(cp_offset, on_failure);
     }
     return;
   }
@@ -1935,13 +1987,6 @@
 
 RegExpNode::LimitResult RegExpNode::LimitVersions(RegExpCompiler* compiler,
                                                   Trace* trace) {
-  // TODO(erikcorry): Implement support.
-  if (info_.follows_word_interest ||
-      info_.follows_newline_interest ||
-      info_.follows_start_interest) {
-    return FAIL;
-  }
-
   // If we are generating a greedy loop then don't stop and don't reuse code.
   if (trace->stop_node() != NULL) {
     return CONTINUE;
@@ -1978,27 +2023,62 @@
   // If we get here code has been generated for this node too many times or
   // recursion is too deep.  Time to switch to a generic version.  The code for
   // generic versions above can handle deep recursion properly.
-  bool ok = trace->Flush(compiler, this);
-  return ok ? DONE : FAIL;
+  trace->Flush(compiler, this);
+  return DONE;
 }
 
 
-int ActionNode::EatsAtLeast(int recursion_depth) {
+int ActionNode::EatsAtLeast(int still_to_find, int recursion_depth) {
   if (recursion_depth > RegExpCompiler::kMaxRecursion) return 0;
   if (type_ == POSITIVE_SUBMATCH_SUCCESS) return 0;  // Rewinds input!
-  return on_success()->EatsAtLeast(recursion_depth + 1);
+  return on_success()->EatsAtLeast(still_to_find, recursion_depth + 1);
 }
 
 
-int TextNode::EatsAtLeast(int recursion_depth) {
+int AssertionNode::EatsAtLeast(int still_to_find, int recursion_depth) {
+  if (recursion_depth > RegExpCompiler::kMaxRecursion) return 0;
+  return on_success()->EatsAtLeast(still_to_find, recursion_depth + 1);
+}
+
+
+int BackReferenceNode::EatsAtLeast(int still_to_find, int recursion_depth) {
+  if (recursion_depth > RegExpCompiler::kMaxRecursion) return 0;
+  return on_success()->EatsAtLeast(still_to_find, recursion_depth + 1);
+}
+
+
+int TextNode::EatsAtLeast(int still_to_find, int recursion_depth) {
   int answer = Length();
-  if (answer >= 4) return answer;
+  if (answer >= still_to_find) return answer;
   if (recursion_depth > RegExpCompiler::kMaxRecursion) return answer;
-  return answer + on_success()->EatsAtLeast(recursion_depth + 1);
+  return answer + on_success()->EatsAtLeast(still_to_find - answer,
+                                            recursion_depth + 1);
 }
 
 
-int ChoiceNode::EatsAtLeastHelper(int recursion_depth,
+int NegativeLookaheadChoiceNode:: EatsAtLeast(int still_to_find,
+                                              int recursion_depth) {
+  if (recursion_depth > RegExpCompiler::kMaxRecursion) return 0;
+  // Alternative 0 is the negative lookahead, alternative 1 is what comes
+  // afterwards.
+  RegExpNode* node = alternatives_->at(1).node();
+  return node->EatsAtLeast(still_to_find, recursion_depth + 1);
+}
+
+
+void NegativeLookaheadChoiceNode::GetQuickCheckDetails(
+    QuickCheckDetails* details,
+    RegExpCompiler* compiler,
+    int filled_in) {
+  // Alternative 0 is the negative lookahead, alternative 1 is what comes
+  // afterwards.
+  RegExpNode* node = alternatives_->at(1).node();
+  return node->GetQuickCheckDetails(details, compiler, filled_in);
+}
+
+
+int ChoiceNode::EatsAtLeastHelper(int still_to_find,
+                                  int recursion_depth,
                                   RegExpNode* ignore_this_node) {
   if (recursion_depth > RegExpCompiler::kMaxRecursion) return 0;
   int min = 100;
@@ -2006,20 +2086,21 @@
   for (int i = 0; i < choice_count; i++) {
     RegExpNode* node = alternatives_->at(i).node();
     if (node == ignore_this_node) continue;
-    int node_eats_at_least = node->EatsAtLeast(recursion_depth + 1);
+    int node_eats_at_least = node->EatsAtLeast(still_to_find,
+                                               recursion_depth + 1);
     if (node_eats_at_least < min) min = node_eats_at_least;
   }
   return min;
 }
 
 
-int LoopChoiceNode::EatsAtLeast(int recursion_depth) {
-  return EatsAtLeastHelper(recursion_depth, loop_node_);
+int LoopChoiceNode::EatsAtLeast(int still_to_find, int recursion_depth) {
+  return EatsAtLeastHelper(still_to_find, recursion_depth, loop_node_);
 }
 
 
-int ChoiceNode::EatsAtLeast(int recursion_depth) {
-  return EatsAtLeastHelper(recursion_depth, NULL);
+int ChoiceNode::EatsAtLeast(int still_to_find, int recursion_depth) {
+  return EatsAtLeastHelper(still_to_find, recursion_depth, NULL);
 }
 
 
@@ -2257,7 +2338,7 @@
 
 
 void QuickCheckDetails::Advance(int by, bool ascii) {
-  ASSERT(by > 0);
+  ASSERT(by >= 0);
   if (by >= characters_) {
     Clear();
     return;
@@ -2342,6 +2423,150 @@
 }
 
 
+// Check for [0-9A-Z_a-z].
+static void EmitWordCheck(RegExpMacroAssembler* assembler,
+                          Label* word,
+                          Label* non_word,
+                          bool fall_through_on_word) {
+  assembler->CheckCharacterGT('z', non_word);
+  assembler->CheckCharacterLT('0', non_word);
+  assembler->CheckCharacterGT('a' - 1, word);
+  assembler->CheckCharacterLT('9' + 1, word);
+  assembler->CheckCharacterLT('A', non_word);
+  assembler->CheckCharacterLT('Z' + 1, word);
+  if (fall_through_on_word) {
+    assembler->CheckNotCharacter('_', non_word);
+  } else {
+    assembler->CheckCharacter('_', word);
+  }
+}
+
+
+// Emit the code to check for a ^ in multiline mode (1-character lookbehind
+// that matches newline or the start of input).
+static void EmitHat(RegExpCompiler* compiler,
+                    RegExpNode* on_success,
+                    Trace* trace) {
+  RegExpMacroAssembler* assembler = compiler->macro_assembler();
+  // We will be loading the previous character into the current character
+  // register.
+  Trace new_trace(*trace);
+  new_trace.InvalidateCurrentCharacter();
+
+  Label ok;
+  if (new_trace.cp_offset() == 0) {
+    // The start of input counts as a newline in this context, so skip to
+    // ok if we are at the start.
+    assembler->CheckAtStart(&ok);
+  }
+  // We already checked that we are not at the start of input so it must be
+  // OK to load the previous character.
+  assembler->LoadCurrentCharacter(new_trace.cp_offset() -1,
+                                  new_trace.backtrack(),
+                                  false);
+  // Newline means \n, \r, 0x2028 or 0x2029.
+  if (!compiler->ascii()) {
+    assembler->CheckCharacterAfterAnd(0x2028, 0xfffe, &ok);
+  }
+  assembler->CheckCharacter('\n', &ok);
+  assembler->CheckNotCharacter('\r', new_trace.backtrack());
+  assembler->Bind(&ok);
+  on_success->Emit(compiler, &new_trace);
+}
+
+
+// Emit the code to handle \b and \B (word-boundary or non-word-boundary).
+static void EmitBoundaryCheck(AssertionNode::AssertionNodeType type,
+                              RegExpCompiler* compiler,
+                              RegExpNode* on_success,
+                              Trace* trace) {
+  RegExpMacroAssembler* assembler = compiler->macro_assembler();
+  Label before_non_word;
+  Label before_word;
+  if (trace->characters_preloaded() != 1) {
+    assembler->LoadCurrentCharacter(trace->cp_offset(), &before_non_word);
+  }
+  // Fall through on non-word.
+  EmitWordCheck(assembler, &before_word, &before_non_word, false);
+
+  // We will be loading the previous character into the current character
+  // register.
+  Trace new_trace(*trace);
+  new_trace.InvalidateCurrentCharacter();
+
+  Label ok;
+  Label* boundary;
+  Label* not_boundary;
+  if (type == AssertionNode::AT_BOUNDARY) {
+    boundary = &ok;
+    not_boundary = new_trace.backtrack();
+  } else {
+    not_boundary = &ok;
+    boundary = new_trace.backtrack();
+  }
+
+  // Next character is not a word character.
+  assembler->Bind(&before_non_word);
+  if (new_trace.cp_offset() == 0) {
+    // The start of input counts as a non-word character, so the question is
+    // decided if we are at the start.
+    assembler->CheckAtStart(not_boundary);
+  }
+  // We already checked that we are not at the start of input so it must be
+  // OK to load the previous character.
+  assembler->LoadCurrentCharacter(new_trace.cp_offset() - 1,
+                                  &ok,  // Unused dummy label in this call.
+                                  false);
+  // Fall through on non-word.
+  EmitWordCheck(assembler, boundary, not_boundary, false);
+  assembler->GoTo(not_boundary);
+
+  // Next character is a word character.
+  assembler->Bind(&before_word);
+  if (new_trace.cp_offset() == 0) {
+    // The start of input counts as a non-word character, so the question is
+    // decided if we are at the start.
+    assembler->CheckAtStart(boundary);
+  }
+  // We already checked that we are not at the start of input so it must be
+  // OK to load the previous character.
+  assembler->LoadCurrentCharacter(new_trace.cp_offset() - 1,
+                                  &ok,  // Unused dummy label in this call.
+                                  false);
+  bool fall_through_on_word = (type == AssertionNode::AT_NON_BOUNDARY);
+  EmitWordCheck(assembler, not_boundary, boundary, fall_through_on_word);
+
+  assembler->Bind(&ok);
+
+  on_success->Emit(compiler, &new_trace);
+}
+
+
+void AssertionNode::Emit(RegExpCompiler* compiler, Trace* trace) {
+  RegExpMacroAssembler* assembler = compiler->macro_assembler();
+  switch (type_) {
+    case AT_END: {
+      Label ok;
+      assembler->CheckPosition(trace->cp_offset(), &ok);
+      assembler->GoTo(trace->backtrack());
+      assembler->Bind(&ok);
+      break;
+    }
+    case AT_START:
+      assembler->CheckNotAtStart(trace->backtrack());
+      break;
+    case AFTER_NEWLINE:
+      EmitHat(compiler, on_success(), trace);
+      return;
+    case AT_NON_BOUNDARY:
+    case AT_BOUNDARY:
+      EmitBoundaryCheck(type_, compiler, on_success(), trace);
+      return;
+  }
+  on_success()->Emit(compiler, trace);
+}
+
+
 // We call this repeatedly to generate code for each pass over the text node.
 // The passes are in increasing order of difficulty because we hope one
 // of the first passes will fail in which case we are saved the work of the
@@ -2481,21 +2706,14 @@
 // pass from left to right.  Instead we pass over the text node several times,
 // emitting code for some character positions every time.  See the comment on
 // TextEmitPass for details.
-bool TextNode::Emit(RegExpCompiler* compiler, Trace* trace) {
+void TextNode::Emit(RegExpCompiler* compiler, Trace* trace) {
   LimitResult limit_result = LimitVersions(compiler, trace);
-  if (limit_result == FAIL) return false;
-  if (limit_result == DONE) return true;
+  if (limit_result == DONE) return;
   ASSERT(limit_result == CONTINUE);
 
-  if (info()->follows_word_interest ||
-      info()->follows_newline_interest ||
-      info()->follows_start_interest) {
-    return false;
-  }
-
-  if (info()->at_end) {
-    compiler->macro_assembler()->GoTo(trace->backtrack());
-    return true;
+  if (trace->cp_offset() + Length() > RegExpMacroAssembler::kMaxCPOffset) {
+    compiler->SetRegExpTooBig();
+    return;
   }
 
   if (compiler->ascii()) {
@@ -2555,13 +2773,18 @@
                &bound_checked_to);
 
   Trace successor_trace(*trace);
-  successor_trace.AdvanceCurrentPositionInTrace(Length(), compiler->ascii());
+  successor_trace.AdvanceCurrentPositionInTrace(Length(), compiler);
   RecursionCheck rc(compiler);
-  return on_success()->Emit(compiler, &successor_trace);
+  on_success()->Emit(compiler, &successor_trace);
 }
 
 
-void Trace::AdvanceCurrentPositionInTrace(int by, bool ascii) {
+void Trace::InvalidateCurrentCharacter() {
+  characters_preloaded_ = 0;
+}
+
+
+void Trace::AdvanceCurrentPositionInTrace(int by, RegExpCompiler* compiler) {
   ASSERT(by > 0);
   // We don't have an instruction for shifting the current character register
   // down or for using a shifted value for anything so lets just forget that
@@ -2570,8 +2793,12 @@
   // Adjust the offsets of the quick check performed information.  This
   // information is used to find out what we already determined about the
   // characters by means of mask and compare.
-  quick_check_performed_.Advance(by, ascii);
+  quick_check_performed_.Advance(by, compiler->ascii());
   cp_offset_ += by;
+  if (cp_offset_ > RegExpMacroAssembler::kMaxCPOffset) {
+    compiler->SetRegExpTooBig();
+    cp_offset_ = 0;
+  }
   bound_checked_up_to_ = Max(0, bound_checked_up_to_ - by);
 }
 
@@ -2616,12 +2843,6 @@
     if (recursion_depth++ > RegExpCompiler::kMaxRecursion) {
       return kNodeIsTooComplexForGreedyLoops;
     }
-    NodeInfo* info = node->info();
-    if (info->follows_word_interest ||
-        info->follows_newline_interest ||
-        info->follows_start_interest) {
-      return kNodeIsTooComplexForGreedyLoops;
-    }
     int node_length = node->GreedyLoopTextLength();
     if (node_length == kNodeIsTooComplexForGreedyLoops) {
       return kNodeIsTooComplexForGreedyLoops;
@@ -2648,7 +2869,7 @@
 }
 
 
-bool LoopChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) {
+void LoopChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) {
   RegExpMacroAssembler* macro_assembler = compiler->macro_assembler();
   if (trace->stop_node() == this) {
     int text_length = GreedyLoopTextLength(&(alternatives_->at(0)));
@@ -2658,18 +2879,19 @@
     ASSERT(trace->cp_offset() == text_length);
     macro_assembler->AdvanceCurrentPosition(text_length);
     macro_assembler->GoTo(trace->loop_label());
-    return true;
+    return;
   }
   ASSERT(trace->stop_node() == NULL);
   if (!trace->is_trivial()) {
-    return trace->Flush(compiler, this);
+    trace->Flush(compiler, this);
+    return;
   }
-  return ChoiceNode::Emit(compiler, trace);
+  ChoiceNode::Emit(compiler, trace);
 }
 
 
 int ChoiceNode::CalculatePreloadCharacters(RegExpCompiler* compiler) {
-  int preload_characters = EatsAtLeast(0);
+  int preload_characters = EatsAtLeast(4, 0);
 #ifdef CAN_READ_UNALIGNED
   bool ascii = compiler->ascii();
   if (ascii) {
@@ -2817,7 +3039,7 @@
  */
 
 
-bool ChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) {
+void ChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) {
   RegExpMacroAssembler* macro_assembler = compiler->macro_assembler();
   int choice_count = alternatives_->length();
 #ifdef DEBUG
@@ -2832,8 +3054,7 @@
 #endif
 
   LimitResult limit_result = LimitVersions(compiler, trace);
-  if (limit_result == DONE) return true;
-  if (limit_result == FAIL) return false;
+  if (limit_result == DONE) return;
   ASSERT(limit_result == CONTINUE);
 
   RecursionCheck rc(compiler);
@@ -2864,13 +3085,8 @@
     macro_assembler->Bind(&loop_label);
     greedy_match_trace.set_stop_node(this);
     greedy_match_trace.set_loop_label(&loop_label);
-    bool ok = alternatives_->at(0).node()->Emit(compiler,
-                                                &greedy_match_trace);
+    alternatives_->at(0).node()->Emit(compiler, &greedy_match_trace);
     macro_assembler->Bind(&greedy_match_failed);
-    if (!ok) {
-      greedy_loop_label.Unuse();
-      return false;
-    }
   }
 
   Label second_choice;  // For use in greedy matches.
@@ -2903,7 +3119,8 @@
     new_trace.quick_check_performed()->Clear();
     alt_gen->expects_preload = preload_is_current;
     bool generate_full_check_inline = false;
-    if (alternative.node()->EmitQuickCheck(compiler,
+    if (try_to_emit_quick_check_for_alternative(i) &&
+        alternative.node()->EmitQuickCheck(compiler,
                                            &new_trace,
                                            preload_has_checked_bounds,
                                            &alt_gen->possible_success,
@@ -2941,10 +3158,7 @@
       for (int j = 0; j < guard_count; j++) {
         GenerateGuard(macro_assembler, guards->at(j), &new_trace);
       }
-      if (!alternative.node()->Emit(compiler, &new_trace)) {
-        greedy_loop_label.Unuse();
-        return false;
-      }
+      alternative.node()->Emit(compiler, &new_trace);
       preload_is_current = false;
     }
     macro_assembler->Bind(&alt_gen->after);
@@ -2962,26 +3176,23 @@
   // label was bound.
   for (int i = first_normal_choice; i < choice_count - 1; i++) {
     AlternativeGeneration* alt_gen = alt_gens.at(i);
-    if (!EmitOutOfLineContinuation(compiler,
-                                   current_trace,
-                                   alternatives_->at(i),
-                                   alt_gen,
-                                   preload_characters,
-                                   alt_gens.at(i + 1)->expects_preload)) {
-      return false;
-    }
+    EmitOutOfLineContinuation(compiler,
+                              current_trace,
+                              alternatives_->at(i),
+                              alt_gen,
+                              preload_characters,
+                              alt_gens.at(i + 1)->expects_preload);
   }
-  return true;
 }
 
 
-bool ChoiceNode::EmitOutOfLineContinuation(RegExpCompiler* compiler,
+void ChoiceNode::EmitOutOfLineContinuation(RegExpCompiler* compiler,
                                            Trace* trace,
                                            GuardedAlternative alternative,
                                            AlternativeGeneration* alt_gen,
                                            int preload_characters,
                                            bool next_expects_preload) {
-  if (!alt_gen->possible_success.is_linked()) return true;
+  if (!alt_gen->possible_success.is_linked()) return;
 
   RegExpMacroAssembler* macro_assembler = compiler->macro_assembler();
   macro_assembler->Bind(&alt_gen->possible_success);
@@ -2996,7 +3207,7 @@
     for (int j = 0; j < guard_count; j++) {
       GenerateGuard(macro_assembler, guards->at(j), &out_of_line_trace);
     }
-    bool ok = alternative.node()->Emit(compiler, &out_of_line_trace);
+    alternative.node()->Emit(compiler, &out_of_line_trace);
     macro_assembler->Bind(&reload_current_char);
     // Reload the current character, since the next quick check expects that.
     // We don't need to check bounds here because we only get into this
@@ -3006,22 +3217,20 @@
                                           false,
                                           preload_characters);
     macro_assembler->GoTo(&(alt_gen->after));
-    return ok;
   } else {
     out_of_line_trace.set_backtrack(&(alt_gen->after));
     for (int j = 0; j < guard_count; j++) {
       GenerateGuard(macro_assembler, guards->at(j), &out_of_line_trace);
     }
-    return alternative.node()->Emit(compiler, &out_of_line_trace);
+    alternative.node()->Emit(compiler, &out_of_line_trace);
   }
 }
 
 
-bool ActionNode::Emit(RegExpCompiler* compiler, Trace* trace) {
+void ActionNode::Emit(RegExpCompiler* compiler, Trace* trace) {
   RegExpMacroAssembler* assembler = compiler->macro_assembler();
   LimitResult limit_result = LimitVersions(compiler, trace);
-  if (limit_result == DONE) return true;
-  if (limit_result == FAIL) return false;
+  if (limit_result == DONE) return;
   ASSERT(limit_result == CONTINUE);
 
   RecursionCheck rc(compiler);
@@ -3029,24 +3238,29 @@
   switch (type_) {
     case STORE_POSITION: {
       Trace::DeferredCapture
-          new_capture(data_.u_position_register.reg, trace);
+          new_capture(data_.u_position_register.reg,
+                      data_.u_position_register.is_capture,
+                      trace);
       Trace new_trace = *trace;
       new_trace.add_action(&new_capture);
-      return on_success()->Emit(compiler, &new_trace);
+      on_success()->Emit(compiler, &new_trace);
+      break;
     }
     case INCREMENT_REGISTER: {
       Trace::DeferredIncrementRegister
           new_increment(data_.u_increment_register.reg);
       Trace new_trace = *trace;
       new_trace.add_action(&new_increment);
-      return on_success()->Emit(compiler, &new_trace);
+      on_success()->Emit(compiler, &new_trace);
+      break;
     }
     case SET_REGISTER: {
       Trace::DeferredSetRegister
           new_set(data_.u_store_register.reg, data_.u_store_register.value);
       Trace new_trace = *trace;
       new_trace.add_action(&new_set);
-      return on_success()->Emit(compiler, &new_trace);
+      on_success()->Emit(compiler, &new_trace);
+      break;
     }
     case CLEAR_CAPTURES: {
       Trace::DeferredClearCaptures
@@ -3054,15 +3268,20 @@
                              data_.u_clear_captures.range_to));
       Trace new_trace = *trace;
       new_trace.add_action(&new_capture);
-      return on_success()->Emit(compiler, &new_trace);
+      on_success()->Emit(compiler, &new_trace);
+      break;
     }
     case BEGIN_SUBMATCH:
-      if (!trace->is_trivial()) return trace->Flush(compiler, this);
-      assembler->WriteCurrentPositionToRegister(
-          data_.u_submatch.current_position_register, 0);
-      assembler->WriteStackPointerToRegister(
-          data_.u_submatch.stack_pointer_register);
-      return on_success()->Emit(compiler, trace);
+      if (!trace->is_trivial()) {
+        trace->Flush(compiler, this);
+      } else {
+        assembler->WriteCurrentPositionToRegister(
+            data_.u_submatch.current_position_register, 0);
+        assembler->WriteStackPointerToRegister(
+            data_.u_submatch.stack_pointer_register);
+        on_success()->Emit(compiler, trace);
+      }
+      break;
     case EMPTY_MATCH_CHECK: {
       int start_pos_reg = data_.u_empty_match_check.start_register;
       int stored_pos = 0;
@@ -3073,84 +3292,84 @@
         // If we know we haven't advanced and there is no minimum we
         // can just backtrack immediately.
         assembler->GoTo(trace->backtrack());
-        return true;
       } else if (know_dist && stored_pos < trace->cp_offset()) {
         // If we know we've advanced we can generate the continuation
         // immediately.
-        return on_success()->Emit(compiler, trace);
+        on_success()->Emit(compiler, trace);
+      } else if (!trace->is_trivial()) {
+        trace->Flush(compiler, this);
+      } else {
+        Label skip_empty_check;
+        // If we have a minimum number of repetitions we check the current
+        // number first and skip the empty check if it's not enough.
+        if (has_minimum) {
+          int limit = data_.u_empty_match_check.repetition_limit;
+          assembler->IfRegisterLT(rep_reg, limit, &skip_empty_check);
+        }
+        // If the match is empty we bail out, otherwise we fall through
+        // to the on-success continuation.
+        assembler->IfRegisterEqPos(data_.u_empty_match_check.start_register,
+                                   trace->backtrack());
+        assembler->Bind(&skip_empty_check);
+        on_success()->Emit(compiler, trace);
       }
-      if (!trace->is_trivial()) return trace->Flush(compiler, this);
-      Label skip_empty_check;
-      // If we have a minimum number of repetitions we check the current
-      // number first and skip the empty check if it's not enough.
-      if (has_minimum) {
-        int limit = data_.u_empty_match_check.repetition_limit;
-        assembler->IfRegisterLT(rep_reg, limit, &skip_empty_check);
-      }
-      // If the match is empty we bail out, otherwise we fall through
-      // to the on-success continuation.
-      assembler->IfRegisterEqPos(data_.u_empty_match_check.start_register,
-                                 trace->backtrack());
-      assembler->Bind(&skip_empty_check);
-      return on_success()->Emit(compiler, trace);
+      break;
     }
-    case POSITIVE_SUBMATCH_SUCCESS:
-      if (!trace->is_trivial()) return trace->Flush(compiler, this);
-      // TODO(erikcorry): Implement support.
-      if (info()->follows_word_interest ||
-          info()->follows_newline_interest ||
-          info()->follows_start_interest) {
-        return false;
-      }
-      if (info()->at_end) {
-        Label at_end;
-        // Load current character jumps to the label if we are beyond the string
-        // end.
-        assembler->LoadCurrentCharacter(0, &at_end);
-        assembler->GoTo(trace->backtrack());
-        assembler->Bind(&at_end);
+    case POSITIVE_SUBMATCH_SUCCESS: {
+      if (!trace->is_trivial()) {
+        trace->Flush(compiler, this);
+        return;
       }
       assembler->ReadCurrentPositionFromRegister(
           data_.u_submatch.current_position_register);
       assembler->ReadStackPointerFromRegister(
           data_.u_submatch.stack_pointer_register);
-      return on_success()->Emit(compiler, trace);
+      int clear_register_count = data_.u_submatch.clear_register_count;
+      if (clear_register_count == 0) {
+        on_success()->Emit(compiler, trace);
+        return;
+      }
+      int clear_registers_from = data_.u_submatch.clear_register_from;
+      Label clear_registers_backtrack;
+      Trace new_trace = *trace;
+      new_trace.set_backtrack(&clear_registers_backtrack);
+      on_success()->Emit(compiler, &new_trace);
+
+      assembler->Bind(&clear_registers_backtrack);
+      int clear_registers_to = clear_registers_from + clear_register_count - 1;
+      assembler->ClearRegisters(clear_registers_from, clear_registers_to);
+
+      ASSERT(trace->backtrack() == NULL);
+      assembler->Backtrack();
+      return;
+    }
     default:
       UNREACHABLE();
-      return false;
   }
 }
 
 
-bool BackReferenceNode::Emit(RegExpCompiler* compiler, Trace* trace) {
+void BackReferenceNode::Emit(RegExpCompiler* compiler, Trace* trace) {
   RegExpMacroAssembler* assembler = compiler->macro_assembler();
   if (!trace->is_trivial()) {
-    return trace->Flush(compiler, this);
+    trace->Flush(compiler, this);
+    return;
   }
 
   LimitResult limit_result = LimitVersions(compiler, trace);
-  if (limit_result == DONE) return true;
-  if (limit_result == FAIL) return false;
+  if (limit_result == DONE) return;
   ASSERT(limit_result == CONTINUE);
 
   RecursionCheck rc(compiler);
 
   ASSERT_EQ(start_reg_ + 1, end_reg_);
-  if (info()->at_end) {
-    // If we are constrained to match at the end of the input then succeed
-    // iff the back reference is empty.
-    assembler->CheckNotRegistersEqual(start_reg_,
-                                      end_reg_,
-                                      trace->backtrack());
+  if (compiler->ignore_case()) {
+    assembler->CheckNotBackReferenceIgnoreCase(start_reg_,
+                                               trace->backtrack());
   } else {
-    if (compiler->ignore_case()) {
-      assembler->CheckNotBackReferenceIgnoreCase(start_reg_,
-                                                 trace->backtrack());
-    } else {
-      assembler->CheckNotBackReference(start_reg_, trace->backtrack());
-    }
+    assembler->CheckNotBackReference(start_reg_, trace->backtrack());
   }
-  return on_success()->Emit(compiler, trace);
+  on_success()->Emit(compiler, trace);
 }
 
 
@@ -3389,6 +3608,33 @@
 }
 
 
+void DotPrinter::VisitAssertion(AssertionNode* that) {
+  stream()->Add("  n%p [", that);
+  switch (that->type()) {
+    case AssertionNode::AT_END:
+      stream()->Add("label=\"$\", shape=septagon");
+      break;
+    case AssertionNode::AT_START:
+      stream()->Add("label=\"^\", shape=septagon");
+      break;
+    case AssertionNode::AT_BOUNDARY:
+      stream()->Add("label=\"\\b\", shape=septagon");
+      break;
+    case AssertionNode::AT_NON_BOUNDARY:
+      stream()->Add("label=\"\\B\", shape=septagon");
+      break;
+    case AssertionNode::AFTER_NEWLINE:
+      stream()->Add("label=\"(?<=\\n)\", shape=septagon");
+      break;
+  }
+  stream()->Add("];\n");
+  PrintAttributes(that);
+  RegExpNode* successor = that->on_success();
+  stream()->Add("  n%p -> n%p;\n", that, successor);
+  Visit(successor);
+}
+
+
 void DotPrinter::VisitAction(ActionNode* that) {
   stream()->Add("  n%p [", that);
   switch (that->type_) {
@@ -3713,7 +3959,7 @@
   if (body_can_be_empty) {
     // If the body can be empty we need to store the start position
     // so we can bail out if it was empty.
-    body_node = ActionNode::StorePosition(body_start_reg, body_node);
+    body_node = ActionNode::StorePosition(body_start_reg, false, body_node);
   }
   if (needs_capture_clearing) {
     // Before entering the body of this loop we need to clear captures.
@@ -3749,22 +3995,51 @@
   NodeInfo info;
   switch (type()) {
     case START_OF_LINE:
-      info.follows_newline_interest = true;
-      break;
+      return AssertionNode::AfterNewline(on_success);
     case START_OF_INPUT:
-      info.follows_start_interest = true;
-      break;
-    case BOUNDARY: case NON_BOUNDARY:
-      info.follows_word_interest = true;
-      break;
+      return AssertionNode::AtStart(on_success);
+    case BOUNDARY:
+      return AssertionNode::AtBoundary(on_success);
+    case NON_BOUNDARY:
+      return AssertionNode::AtNonBoundary(on_success);
     case END_OF_INPUT:
-      info.at_end = true;
-      break;
-    case END_OF_LINE:
-      // This is wrong but has the effect of making the compiler abort.
-      info.at_end = true;
+      return AssertionNode::AtEnd(on_success);
+    case END_OF_LINE: {
+      // Compile $ in multiline regexps as an alternation with a positive
+      // lookahead in one side and an end-of-input on the other side.
+      // We need two registers for the lookahead.
+      int stack_pointer_register = compiler->AllocateRegister();
+      int position_register = compiler->AllocateRegister();
+      // The ChoiceNode to distinguish between a newline and end-of-input.
+      ChoiceNode* result = new ChoiceNode(2);
+      // Create a newline atom.
+      ZoneList<CharacterRange>* newline_ranges =
+          new ZoneList<CharacterRange>(3);
+      CharacterRange::AddClassEscape('n', newline_ranges);
+      RegExpCharacterClass* newline_atom = new RegExpCharacterClass('n');
+      TextNode* newline_matcher = new TextNode(
+         newline_atom,
+         ActionNode::PositiveSubmatchSuccess(stack_pointer_register,
+                                             position_register,
+                                             0,  // No captures inside.
+                                             -1,  // Ignored if no captures.
+                                             on_success));
+      // Create an end-of-input matcher.
+      RegExpNode* end_of_line = ActionNode::BeginSubmatch(
+          stack_pointer_register,
+          position_register,
+          newline_matcher);
+      // Add the two alternatives to the ChoiceNode.
+      GuardedAlternative eol_alternative(end_of_line);
+      result->AddAlternative(eol_alternative);
+      GuardedAlternative end_alternative(AssertionNode::AtEnd(on_success));
+      result->AddAlternative(end_alternative);
+      return result;
+    }
+    default:
+      UNREACHABLE();
   }
-  return on_success->PropagateForward(&info);
+  return on_success;
 }
 
 
@@ -3786,16 +4061,26 @@
                                     RegExpNode* on_success) {
   int stack_pointer_register = compiler->AllocateRegister();
   int position_register = compiler->AllocateRegister();
+
+  const int registers_per_capture = 2;
+  const int register_of_first_capture = 2;
+  int register_count = capture_count_ * registers_per_capture;
+  int register_start =
+    register_of_first_capture + capture_from_ * registers_per_capture;
+
   RegExpNode* success;
   if (is_positive()) {
-    return ActionNode::BeginSubmatch(
+    RegExpNode* node = ActionNode::BeginSubmatch(
         stack_pointer_register,
         position_register,
         body()->ToNode(
             compiler,
             ActionNode::PositiveSubmatchSuccess(stack_pointer_register,
                                                 position_register,
+                                                register_count,
+                                                register_start,
                                                 on_success)));
+    return node;
   } else {
     // We use a ChoiceNode for a negative lookahead because it has most of
     // the characteristics we need.  It has the body of the lookahead as its
@@ -3804,19 +4089,19 @@
     // NegativeSubmatchSuccess will unwind the stack including everything the
     // choice node set up and backtrack.  If the first alternative fails then
     // the second alternative is tried, which is exactly the desired result
-    // for a negative lookahead.  In the case where the dispatch table
-    // determines that the first alternative cannot match we will save time
-    // by not trying it.  Things are not quite so well-optimized if the
-    // dispatch table determines that the second alternative cannot match.
-    // In this case we could optimize by immediately backtracking.
-    ChoiceNode* choice_node = new ChoiceNode(2);
+    // for a negative lookahead.  The NegativeLookaheadChoiceNode is a special
+    // ChoiceNode that knows to ignore the first exit when calculating quick
+    // checks.
     GuardedAlternative body_alt(
         body()->ToNode(
             compiler,
             success = new NegativeSubmatchSuccess(stack_pointer_register,
-                                                  position_register)));
-    choice_node->AddAlternative(body_alt);
-    choice_node->AddAlternative(GuardedAlternative(on_success));
+                                                  position_register,
+                                                  register_count,
+                                                  register_start)));
+    ChoiceNode* choice_node =
+        new NegativeLookaheadChoiceNode(body_alt,
+                                        GuardedAlternative(on_success));
     return ActionNode::BeginSubmatch(stack_pointer_register,
                                      position_register,
                                      choice_node);
@@ -3836,9 +4121,9 @@
                                   RegExpNode* on_success) {
   int start_reg = RegExpCapture::StartRegister(index);
   int end_reg = RegExpCapture::EndRegister(index);
-  RegExpNode* store_end = ActionNode::StorePosition(end_reg, on_success);
+  RegExpNode* store_end = ActionNode::StorePosition(end_reg, true, on_success);
   RegExpNode* body_node = body->ToNode(compiler, store_end);
-  return ActionNode::StorePosition(start_reg, body_node);
+  return ActionNode::StorePosition(start_reg, true, body_node);
 }
 
 
@@ -3911,6 +4196,13 @@
     case '*':
       ranges->Add(CharacterRange::Everything());
       break;
+    // This is the set of characters matched by the $ and ^ symbols
+    // in multiline mode.
+    case 'n':
+      AddClass(kLineTerminatorRanges,
+               kLineTerminatorRangeCount,
+               ranges);
+      break;
     default:
       UNREACHABLE();
   }
@@ -4096,62 +4388,6 @@
 }
 
 
-RegExpNode* ActionNode::PropagateForward(NodeInfo* info) {
-  NodeInfo full_info(*this->info());
-  full_info.AddFromPreceding(info);
-  bool cloned = false;
-  ActionNode* action = EnsureSibling(this, &full_info, &cloned);
-  action->set_on_success(action->on_success()->PropagateForward(info));
-  return action;
-}
-
-
-RegExpNode* ChoiceNode::PropagateForward(NodeInfo* info) {
-  NodeInfo full_info(*this->info());
-  full_info.AddFromPreceding(info);
-  bool cloned = false;
-  ChoiceNode* choice = EnsureSibling(this, &full_info, &cloned);
-  if (cloned) {
-    ZoneList<GuardedAlternative>* old_alternatives = alternatives();
-    int count = old_alternatives->length();
-    choice->alternatives_ = new ZoneList<GuardedAlternative>(count);
-    for (int i = 0; i < count; i++) {
-      GuardedAlternative alternative = old_alternatives->at(i);
-      alternative.set_node(alternative.node()->PropagateForward(info));
-      choice->alternatives()->Add(alternative);
-    }
-  }
-  return choice;
-}
-
-
-RegExpNode* EndNode::PropagateForward(NodeInfo* info) {
-  return PropagateToEndpoint(this, info);
-}
-
-
-RegExpNode* BackReferenceNode::PropagateForward(NodeInfo* info) {
-  NodeInfo full_info(*this->info());
-  full_info.AddFromPreceding(info);
-  bool cloned = false;
-  BackReferenceNode* back_ref = EnsureSibling(this, &full_info, &cloned);
-  if (cloned) {
-    // TODO(erikcorry): A back reference has to have two successors (by default
-    // the same node).  The first is used if the back reference matches a non-
-    // empty back reference, the second if it matches an empty one.  This
-    // doesn't matter for at_end, which is the only one implemented right now,
-    // but it will matter for other pieces of info.
-    back_ref->set_on_success(back_ref->on_success()->PropagateForward(info));
-  }
-  return back_ref;
-}
-
-
-RegExpNode* TextNode::PropagateForward(NodeInfo* info) {
-  return PropagateToEndpoint(this, info);
-}
-
-
 // -------------------------------------------------------------------
 // Splay tree
 
@@ -4389,6 +4625,11 @@
 }
 
 
+void Analysis::VisitAssertion(AssertionNode* that) {
+  EnsureAnalyzed(that->on_success());
+}
+
+
 // -------------------------------------------------------------------
 // Dispatch table construction
 
@@ -4441,6 +4682,12 @@
 }
 
 
+void DispatchTableConstructor::VisitAssertion(AssertionNode* that) {
+  RegExpNode* target = that->on_success();
+  target->Accept(this);
+}
+
+
 
 static int CompareRangeByFrom(const CharacterRange* a,
                               const CharacterRange* b) {
@@ -4504,33 +4751,32 @@
                                          bool is_multiline,
                                          Handle<String> pattern,
                                          bool is_ascii) {
+  if ((data->capture_count + 1) * 2 - 1 > RegExpMacroAssembler::kMaxRegister) {
+    return IrregexpRegExpTooBig(pattern);
+  }
   RegExpCompiler compiler(data->capture_count, ignore_case, is_ascii);
   // Wrap the body of the regexp in capture #0.
   RegExpNode* captured_body = RegExpCapture::ToNode(data->tree,
                                                     0,
                                                     &compiler,
                                                     compiler.accept());
-  // Add a .*? at the beginning, outside the body capture.
-  // Note: We could choose to not add this if the regexp is anchored at
-  //   the start of the input but I'm not sure how best to do that and
-  //   since we don't even handle ^ yet I'm saving that optimization for
-  //   later.
-  RegExpNode* node = RegExpQuantifier::ToNode(0,
-                                              RegExpTree::kInfinity,
-                                              false,
-                                              new RegExpCharacterClass('*'),
-                                              &compiler,
-                                              captured_body);
+  RegExpNode* node = captured_body;
+  if (!data->tree->IsAnchored()) {
+    // Add a .*? at the beginning, outside the body capture, unless
+    // this expression is anchored at the beginning.
+    node = RegExpQuantifier::ToNode(0,
+                                    RegExpTree::kInfinity,
+                                    false,
+                                    new RegExpCharacterClass('*'),
+                                    &compiler,
+                                    captured_body);
+  }
   data->node = node;
   Analysis analysis(ignore_case);
   analysis.EnsureAnalyzed(node);
 
   NodeInfo info = *node->info();
 
-  if (is_multiline && !FLAG_attempt_multiline_irregexp) {
-    return Handle<FixedArray>::null();
-  }
-
   if (FLAG_irregexp_native) {
 #ifdef ARM
     // Unimplemented, fall-through to bytecode implementation.
diff --git a/src/jsregexp.h b/src/jsregexp.h
index bf3bdb7..0783727 100644
--- a/src/jsregexp.h
+++ b/src/jsregexp.h
@@ -410,6 +410,7 @@
   VISIT(Action)                                                      \
   VISIT(Choice)                                                      \
   VISIT(BackReference)                                               \
+  VISIT(Assertion)                                                   \
   VISIT(Text)
 
 
@@ -587,12 +588,12 @@
   virtual ~RegExpNode();
   virtual void Accept(NodeVisitor* visitor) = 0;
   // Generates a goto to this node or actually generates the code at this point.
-  // Until the implementation is complete we will return true for success and
-  // false for failure.
-  virtual bool Emit(RegExpCompiler* compiler, Trace* trace) = 0;
+  virtual void Emit(RegExpCompiler* compiler, Trace* trace) = 0;
   // How many characters must this node consume at a minimum in order to
-  // succeed.
-  virtual int EatsAtLeast(int recursion_depth) = 0;
+  // succeed.  If we have found at least 'still_to_find' characters that
+  // must be consumed there is no need to ask any following nodes whether
+  // they are sure to eat any more characters.
+  virtual int EatsAtLeast(int still_to_find, int recursion_depth) = 0;
   // Emits some quick code that checks whether the preloaded characters match.
   // Falls through on certain failure, jumps to the label on possible success.
   // If the node cannot make a quick check it does nothing and returns false.
@@ -619,12 +620,6 @@
   // the deferred actions in the current trace and generating a goto.
   static const int kMaxCopiesCodeGenerated = 10;
 
-  // Propagates the given interest information forward.  When seeing
-  // \bfoo for instance, the \b is implemented by propagating forward
-  // to the 'foo' string that it should only succeed if its first
-  // character is a letter xor the previous character was a letter.
-  virtual RegExpNode* PropagateForward(NodeInfo* info) = 0;
-
   NodeInfo* info() { return &info_; }
 
   void AddSibling(RegExpNode* node) { siblings_.Add(node); }
@@ -640,7 +635,7 @@
   void set_siblings(SiblingList* other) { siblings_ = *other; }
 
  protected:
-  enum LimitResult { DONE, FAIL, CONTINUE };
+  enum LimitResult { DONE, CONTINUE };
   LimitResult LimitVersions(RegExpCompiler* compiler, Trace* trace);
 
   // Returns a sibling of this node whose interests and assumptions
@@ -724,27 +719,30 @@
   };
   static ActionNode* SetRegister(int reg, int val, RegExpNode* on_success);
   static ActionNode* IncrementRegister(int reg, RegExpNode* on_success);
-  static ActionNode* StorePosition(int reg, RegExpNode* on_success);
+  static ActionNode* StorePosition(int reg,
+                                   bool is_capture,
+                                   RegExpNode* on_success);
   static ActionNode* ClearCaptures(Interval range, RegExpNode* on_success);
   static ActionNode* BeginSubmatch(int stack_pointer_reg,
                                    int position_reg,
                                    RegExpNode* on_success);
   static ActionNode* PositiveSubmatchSuccess(int stack_pointer_reg,
                                              int restore_reg,
+                                             int clear_capture_count,
+                                             int clear_capture_from,
                                              RegExpNode* on_success);
   static ActionNode* EmptyMatchCheck(int start_register,
                                      int repetition_register,
                                      int repetition_limit,
                                      RegExpNode* on_success);
   virtual void Accept(NodeVisitor* visitor);
-  virtual bool Emit(RegExpCompiler* compiler, Trace* trace);
-  virtual int EatsAtLeast(int recursion_depth);
+  virtual void Emit(RegExpCompiler* compiler, Trace* trace);
+  virtual int EatsAtLeast(int still_to_find, int recursion_depth);
   virtual void GetQuickCheckDetails(QuickCheckDetails* details,
                                     RegExpCompiler* compiler,
                                     int filled_in) {
     return on_success()->GetQuickCheckDetails(details, compiler, filled_in);
   }
-  virtual RegExpNode* PropagateForward(NodeInfo* info);
   Type type() { return type_; }
   // TODO(erikcorry): We should allow some action nodes in greedy loops.
   virtual int GreedyLoopTextLength() { return kNodeIsTooComplexForGreedyLoops; }
@@ -761,10 +759,13 @@
     } u_increment_register;
     struct {
       int reg;
+      bool is_capture;
     } u_position_register;
     struct {
       int stack_pointer_register;
       int current_position_register;
+      int clear_register_count;
+      int clear_register_from;
     } u_submatch;
     struct {
       int start_register;
@@ -797,9 +798,8 @@
     elms_->Add(TextElement::CharClass(that));
   }
   virtual void Accept(NodeVisitor* visitor);
-  virtual RegExpNode* PropagateForward(NodeInfo* info);
-  virtual bool Emit(RegExpCompiler* compiler, Trace* trace);
-  virtual int EatsAtLeast(int recursion_depth);
+  virtual void Emit(RegExpCompiler* compiler, Trace* trace);
+  virtual int EatsAtLeast(int still_to_find, int recursion_depth);
   virtual void GetQuickCheckDetails(QuickCheckDetails* details,
                                     RegExpCompiler* compiler,
                                     int characters_filled_in);
@@ -831,6 +831,47 @@
 };
 
 
+class AssertionNode: public SeqRegExpNode {
+ public:
+  enum AssertionNodeType {
+    AT_END,
+    AT_START,
+    AT_BOUNDARY,
+    AT_NON_BOUNDARY,
+    AFTER_NEWLINE
+  };
+  static AssertionNode* AtEnd(RegExpNode* on_success) {
+    return new AssertionNode(AT_END, on_success);
+  }
+  static AssertionNode* AtStart(RegExpNode* on_success) {
+    return new AssertionNode(AT_START, on_success);
+  }
+  static AssertionNode* AtBoundary(RegExpNode* on_success) {
+    return new AssertionNode(AT_BOUNDARY, on_success);
+  }
+  static AssertionNode* AtNonBoundary(RegExpNode* on_success) {
+    return new AssertionNode(AT_NON_BOUNDARY, on_success);
+  }
+  static AssertionNode* AfterNewline(RegExpNode* on_success) {
+    return new AssertionNode(AFTER_NEWLINE, on_success);
+  }
+  virtual void Accept(NodeVisitor* visitor);
+  virtual void Emit(RegExpCompiler* compiler, Trace* trace);
+  virtual int EatsAtLeast(int still_to_find, int recursion_depth);
+  virtual void GetQuickCheckDetails(QuickCheckDetails* details,
+                                    RegExpCompiler* compiler,
+                                    int filled_in) {
+    return on_success()->GetQuickCheckDetails(details, compiler, filled_in);
+  }
+  virtual AssertionNode* Clone() { return new AssertionNode(*this); }
+  AssertionNodeType type() { return type_; }
+ private:
+  AssertionNode(AssertionNodeType t, RegExpNode* on_success)
+      : SeqRegExpNode(on_success), type_(t) { }
+  AssertionNodeType type_;
+};
+
+
 class BackReferenceNode: public SeqRegExpNode {
  public:
   BackReferenceNode(int start_reg,
@@ -842,14 +883,13 @@
   virtual void Accept(NodeVisitor* visitor);
   int start_register() { return start_reg_; }
   int end_register() { return end_reg_; }
-  virtual bool Emit(RegExpCompiler* compiler, Trace* trace);
-  virtual int EatsAtLeast(int recursion_depth) { return 0; }
+  virtual void Emit(RegExpCompiler* compiler, Trace* trace);
+  virtual int EatsAtLeast(int still_to_find, int recursion_depth);
   virtual void GetQuickCheckDetails(QuickCheckDetails* details,
                                     RegExpCompiler* compiler,
                                     int characters_filled_in) {
     return;
   }
-  virtual RegExpNode* PropagateForward(NodeInfo* info);
   virtual BackReferenceNode* Clone() { return new BackReferenceNode(*this); }
 
  private:
@@ -863,20 +903,16 @@
   enum Action { ACCEPT, BACKTRACK, NEGATIVE_SUBMATCH_SUCCESS };
   explicit EndNode(Action action) : action_(action) { }
   virtual void Accept(NodeVisitor* visitor);
-  virtual bool Emit(RegExpCompiler* compiler, Trace* trace);
-  virtual int EatsAtLeast(int recursion_depth) { return 0; }
+  virtual void Emit(RegExpCompiler* compiler, Trace* trace);
+  virtual int EatsAtLeast(int still_to_find, int recursion_depth) { return 0; }
   virtual void GetQuickCheckDetails(QuickCheckDetails* details,
                                     RegExpCompiler* compiler,
                                     int characters_filled_in) {
     // Returning 0 from EatsAtLeast should ensure we never get here.
     UNREACHABLE();
   }
-  virtual RegExpNode* PropagateForward(NodeInfo* info);
   virtual EndNode* Clone() { return new EndNode(*this); }
 
- protected:
-  void EmitInfoChecks(RegExpMacroAssembler* macro, Trace* trace);
-
  private:
   Action action_;
 };
@@ -884,15 +920,22 @@
 
 class NegativeSubmatchSuccess: public EndNode {
  public:
-  NegativeSubmatchSuccess(int stack_pointer_reg, int position_reg)
+  NegativeSubmatchSuccess(int stack_pointer_reg,
+                          int position_reg,
+                          int clear_capture_count,
+                          int clear_capture_start)
       : EndNode(NEGATIVE_SUBMATCH_SUCCESS),
         stack_pointer_register_(stack_pointer_reg),
-        current_position_register_(position_reg) { }
-  virtual bool Emit(RegExpCompiler* compiler, Trace* trace);
+        current_position_register_(position_reg),
+        clear_capture_count_(clear_capture_count),
+        clear_capture_start_(clear_capture_start) { }
+  virtual void Emit(RegExpCompiler* compiler, Trace* trace);
 
  private:
   int stack_pointer_register_;
   int current_position_register_;
+  int clear_capture_count_;
+  int clear_capture_start_;
 };
 
 
@@ -941,17 +984,19 @@
   void AddAlternative(GuardedAlternative node) { alternatives()->Add(node); }
   ZoneList<GuardedAlternative>* alternatives() { return alternatives_; }
   DispatchTable* GetTable(bool ignore_case);
-  virtual bool Emit(RegExpCompiler* compiler, Trace* trace);
-  virtual int EatsAtLeast(int recursion_depth);
-  int EatsAtLeastHelper(int recursion_depth, RegExpNode* ignore_this_node);
+  virtual void Emit(RegExpCompiler* compiler, Trace* trace);
+  virtual int EatsAtLeast(int still_to_find, int recursion_depth);
+  int EatsAtLeastHelper(int still_to_find,
+                        int recursion_depth,
+                        RegExpNode* ignore_this_node);
   virtual void GetQuickCheckDetails(QuickCheckDetails* details,
                                     RegExpCompiler* compiler,
                                     int characters_filled_in);
-  virtual RegExpNode* PropagateForward(NodeInfo* info);
   virtual ChoiceNode* Clone() { return new ChoiceNode(*this); }
 
   bool being_calculated() { return being_calculated_; }
   void set_being_calculated(bool b) { being_calculated_ = b; }
+  virtual bool try_to_emit_quick_check_for_alternative(int i) { return true; }
 
  protected:
   int GreedyLoopTextLength(GuardedAlternative *alternative);
@@ -964,7 +1009,7 @@
                      Guard *guard,
                      Trace* trace);
   int CalculatePreloadCharacters(RegExpCompiler* compiler);
-  bool EmitOutOfLineContinuation(RegExpCompiler* compiler,
+  void EmitOutOfLineContinuation(RegExpCompiler* compiler,
                                  Trace* trace,
                                  GuardedAlternative alternative,
                                  AlternativeGeneration* alt_gen,
@@ -975,6 +1020,27 @@
 };
 
 
+class NegativeLookaheadChoiceNode: public ChoiceNode {
+ public:
+  explicit NegativeLookaheadChoiceNode(GuardedAlternative this_must_fail,
+                                       GuardedAlternative then_do_this)
+      : ChoiceNode(2) {
+    AddAlternative(this_must_fail);
+    AddAlternative(then_do_this);
+  }
+  virtual int EatsAtLeast(int still_to_find, int recursion_depth);
+  virtual void GetQuickCheckDetails(QuickCheckDetails* details,
+                                    RegExpCompiler* compiler,
+                                    int characters_filled_in);
+  // For a negative lookahead we don't emit the quick check for the
+  // alternative that is expected to fail.  This is because quick check code
+  // starts by loading enough characters for the alternative that takes fewest
+  // characters, but on a negative lookahead the negative branch did not take
+  // part in that calculation (EatsAtLeast) so the assumptions don't hold.
+  virtual bool try_to_emit_quick_check_for_alternative(int i) { return i != 0; }
+};
+
+
 class LoopChoiceNode: public ChoiceNode {
  public:
   explicit LoopChoiceNode(bool body_can_be_zero_length)
@@ -984,8 +1050,8 @@
         body_can_be_zero_length_(body_can_be_zero_length) { }
   void AddLoopAlternative(GuardedAlternative alt);
   void AddContinueAlternative(GuardedAlternative alt);
-  virtual bool Emit(RegExpCompiler* compiler, Trace* trace);
-  virtual int EatsAtLeast(int recursion_depth);  // Returns 0.
+  virtual void Emit(RegExpCompiler* compiler, Trace* trace);
+  virtual int EatsAtLeast(int still_to_find, int recursion_depth);
   virtual void GetQuickCheckDetails(QuickCheckDetails* details,
                                     RegExpCompiler* compiler,
                                     int characters_filled_in);
@@ -1037,18 +1103,21 @@
     friend class Trace;
   };
 
-  class DeferredCapture: public DeferredAction {
+  class DeferredCapture : public DeferredAction {
    public:
-    DeferredCapture(int reg, Trace* trace)
+    DeferredCapture(int reg, bool is_capture, Trace* trace)
         : DeferredAction(ActionNode::STORE_POSITION, reg),
-          cp_offset_(trace->cp_offset()) { }
+          cp_offset_(trace->cp_offset()),
+          is_capture_(is_capture) { }
     int cp_offset() { return cp_offset_; }
+    bool is_capture() { return is_capture_; }
    private:
     int cp_offset_;
+    bool is_capture_;
     void set_cp_offset(int cp_offset) { cp_offset_ = cp_offset; }
   };
 
-  class DeferredSetRegister :public DeferredAction {
+  class DeferredSetRegister : public DeferredAction {
    public:
     DeferredSetRegister(int reg, int value)
         : DeferredAction(ActionNode::SET_REGISTER, reg),
@@ -1068,7 +1137,7 @@
     Interval range_;
   };
 
-  class DeferredIncrementRegister: public DeferredAction {
+  class DeferredIncrementRegister : public DeferredAction {
    public:
     explicit DeferredIncrementRegister(int reg)
         : DeferredAction(ActionNode::INCREMENT_REGISTER, reg) { }
@@ -1086,7 +1155,7 @@
   // and pushing a backtrack location onto the backtrack stack.  Once this is
   // done we can start a new trace or go to one that has already been
   // generated.
-  bool Flush(RegExpCompiler* compiler, RegExpNode* successor);
+  void Flush(RegExpCompiler* compiler, RegExpNode* successor);
   int cp_offset() { return cp_offset_; }
   DeferredAction* actions() { return actions_; }
   // A trivial trace is one that has no deferred actions or other state that
@@ -1133,20 +1202,19 @@
   void set_quick_check_performed(QuickCheckDetails* d) {
     quick_check_performed_ = *d;
   }
-  void clear_quick_check_performed() {
-  }
-  void AdvanceCurrentPositionInTrace(int by, bool ascii);
+  void InvalidateCurrentCharacter();
+  void AdvanceCurrentPositionInTrace(int by, RegExpCompiler* compiler);
  private:
   int FindAffectedRegisters(OutSet* affected_registers);
   void PerformDeferredActions(RegExpMacroAssembler* macro,
                                int max_register,
-                               OutSet& affected_registers);
+                               OutSet& affected_registers,
+                               OutSet* registers_to_pop,
+                               OutSet* registers_to_clear);
   void RestoreAffectedRegisters(RegExpMacroAssembler* macro,
                                 int max_register,
-                                OutSet& affected_registers);
-  void PushAffectedRegisters(RegExpMacroAssembler* macro,
-                             int max_register,
-                             OutSet& affected_registers);
+                                OutSet& registers_to_pop,
+                                OutSet& registers_to_clear);
   int cp_offset_;
   DeferredAction* actions_;
   Label* backtrack_;
diff --git a/src/mark-compact.cc b/src/mark-compact.cc
index ede5741..1d93f84 100644
--- a/src/mark-compact.cc
+++ b/src/mark-compact.cc
@@ -35,16 +35,7 @@
 
 namespace v8 { namespace internal {
 
-#ifdef DEBUG
-// The verification code used between phases of the m-c collector does not
-// currently work.
-//
-// TODO(1240833): Fix the heap verification code and turn this into a real
-// flag.
-static const bool FLAG_verify_global_gc = false;
-#endif  // DEBUG
-
-// ----------------------------------------------------------------------------
+// -------------------------------------------------------------------------
 // MarkCompactCollector
 
 bool MarkCompactCollector::compacting_collection_ = false;
@@ -177,7 +168,7 @@
 }
 
 
-// ----------------------------------------------------------------------------
+// -------------------------------------------------------------------------
 // Phase 1: tracing and marking live objects.
 //   before: all objects are in normal state.
 //   after: a live object's map pointer is marked as '00'.
@@ -729,10 +720,6 @@
   symbol_table->IterateElements(&v);
   symbol_table->ElementsRemoved(v.PointersRemoved());
 
-#ifdef DEBUG
-  if (FLAG_verify_global_gc) VerifyHeapAfterMarkingPhase();
-#endif
-
   // Remove object groups after marking phase.
   GlobalHandles::RemoveObjectGroups();
 }
@@ -765,46 +752,6 @@
     UNREACHABLE();
   }
 }
-
-
-void MarkCompactCollector::VerifyHeapAfterMarkingPhase() {
-  Heap::new_space()->Verify();
-  Heap::old_pointer_space()->Verify();
-  Heap::old_data_space()->Verify();
-  Heap::code_space()->Verify();
-  Heap::map_space()->Verify();
-
-  int live_objects;
-
-#define CHECK_LIVE_OBJECTS(it, expected)                   \
-          live_objects = 0;                                \
-          while (it.has_next()) {                          \
-            HeapObject* obj = HeapObject::cast(it.next()); \
-            if (obj->IsMarked()) live_objects++;           \
-          }                                                \
-          ASSERT(live_objects == expected);
-
-  SemiSpaceIterator new_it(Heap::new_space(), &CountMarkedCallback);
-  CHECK_LIVE_OBJECTS(new_it, live_young_objects_);
-
-  HeapObjectIterator old_pointer_it(Heap::old_pointer_space(),
-                                    &CountMarkedCallback);
-  CHECK_LIVE_OBJECTS(old_pointer_it, live_old_pointer_objects_);
-
-  HeapObjectIterator old_data_it(Heap::old_data_space(), &CountMarkedCallback);
-  CHECK_LIVE_OBJECTS(old_data_it, live_old_data_objects_);
-
-  HeapObjectIterator code_it(Heap::code_space(), &CountMarkedCallback);
-  CHECK_LIVE_OBJECTS(code_it, live_code_objects_);
-
-  HeapObjectIterator map_it(Heap::map_space(), &CountMarkedCallback);
-  CHECK_LIVE_OBJECTS(map_it, live_map_objects_);
-
-  LargeObjectIterator lo_it(Heap::lo_space(), &CountMarkedCallback);
-  CHECK_LIVE_OBJECTS(lo_it, live_lo_objects_);
-
-#undef CHECK_LIVE_OBJECTS
-}
 #endif  // DEBUG
 
 
@@ -1325,54 +1272,7 @@
 }
 
 
-#ifdef DEBUG
-static int VerifyMapObject(HeapObject* obj) {
-  InstanceType type = reinterpret_cast<Map*>(obj)->instance_type();
-  ASSERT(FIRST_TYPE <= type && type <= LAST_TYPE);
-  return Map::kSize;
-}
-
-
-void MarkCompactCollector::VerifyHeapAfterEncodingForwardingAddresses() {
-  AllSpaces spaces;
-  while (Space* space = spaces.next()) space->Verify();
-
-  ASSERT(state_ == ENCODE_FORWARDING_ADDRESSES);
-  int live_maps = IterateLiveObjects(Heap::map_space(), &VerifyMapObject);
-  ASSERT(live_maps == live_map_objects_);
-
-  // Verify page headers in paged spaces.
-  PagedSpaces paged_spaces;
-  while (PagedSpace* space = paged_spaces.next()) VerifyPageHeaders(space);
-}
-
-
-void MarkCompactCollector::VerifyPageHeaders(PagedSpace* space) {
-  PageIterator mc_it(space, PageIterator::PAGES_USED_BY_MC);
-  while (mc_it.has_next()) {
-    Page* p = mc_it.next();
-    Address mc_alloc_top = p->mc_relocation_top;
-    ASSERT(p->ObjectAreaStart() <= mc_alloc_top &&
-           mc_alloc_top <= p->ObjectAreaEnd());
-  }
-
-  int page_count = 0;
-  PageIterator it(space, PageIterator::PAGES_IN_USE);
-  while (it.has_next()) {
-    Page* p = it.next();
-    ASSERT(p->mc_page_index == page_count);
-    page_count++;
-
-    // first_forwarded could be 'deadbeed' if no live objects in this page
-    Address first_forwarded = p->mc_first_forwarded;
-    ASSERT(first_forwarded == kZapValue ||
-           space->Contains(first_forwarded));
-  }
-}
-#endif
-
-
-// ----------------------------------------------------------------------------
+// -------------------------------------------------------------------------
 // Phase 3: Update pointers
 
 // Helper class for updating pointers in HeapObjects.
@@ -1494,8 +1394,6 @@
   ASSERT(live_pointer_olds == live_old_pointer_objects_);
   ASSERT(live_codes == live_code_objects_);
   ASSERT(live_news == live_young_objects_);
-
-  if (FLAG_verify_global_gc) VerifyHeapAfterUpdatingPointers();
 #endif
 }
 
@@ -1601,19 +1499,7 @@
 }
 
 
-#ifdef DEBUG
-void MarkCompactCollector::VerifyHeapAfterUpdatingPointers() {
-  ASSERT(state_ == UPDATE_POINTERS);
-
-  AllSpaces spaces;
-  while (Space* space = spaces.next()) space->Verify();
-  PagedSpaces paged_spaces;
-  while (PagedSpace* space = paged_spaces.next()) VerifyPageHeaders(space);
-}
-#endif
-
-
-// ----------------------------------------------------------------------------
+// -------------------------------------------------------------------------
 // Phase 4: Relocate objects
 
 void MarkCompactCollector::RelocateObjects() {
@@ -1664,10 +1550,6 @@
 #endif
   PagedSpaces spaces;
   while (PagedSpace* space = spaces.next()) space->MCCommitRelocationInfo();
-
-#ifdef DEBUG
-  if (FLAG_verify_global_gc) VerifyHeapAfterRelocatingObjects();
-#endif
 }
 
 
@@ -1804,18 +1686,6 @@
 }
 
 
-#ifdef DEBUG
-class VerifyCopyingVisitor: public ObjectVisitor {
- public:
-  void VisitPointers(Object** start, Object** end) {
-    for (Object** p = start; p < end; p++) {
-      MarkCompactCollector::VerifyCopyingObjects(p);
-    }
-  }
-};
-
-#endif
-
 int MarkCompactCollector::RelocateNewObject(HeapObject* obj) {
   int obj_size = obj->Size();
 
@@ -1845,44 +1715,13 @@
   if (FLAG_gc_verbose) {
     PrintF("relocate %p -> %p\n", old_addr, new_addr);
   }
-  if (FLAG_verify_global_gc) {
-    VerifyCopyingVisitor v;
-    HeapObject* copied_to = HeapObject::FromAddress(new_addr);
-    copied_to->Iterate(&v);
-  }
 #endif
 
   return obj_size;
 }
 
 
-#ifdef DEBUG
-void MarkCompactCollector::VerifyHeapAfterRelocatingObjects() {
-  ASSERT(state_ == RELOCATE_OBJECTS);
-
-  Heap::new_space()->Verify();
-  PagedSpaces spaces;
-  while (PagedSpace* space = spaces.next()) {
-    space->Verify();
-    PageIterator it(space, PageIterator::PAGES_IN_USE);
-    while (it.has_next()) {
-      Page* p = it.next();
-      ASSERT_PAGE_OFFSET(p->Offset(p->AllocationTop()));
-    }
-  }
-}
-#endif
-
-
-#ifdef DEBUG
-void MarkCompactCollector::VerifyCopyingObjects(Object** p) {
-  if (!(*p)->IsHeapObject()) return;
-  ASSERT(!Heap::InToSpace(*p));
-}
-#endif  // DEBUG
-
-
-// -----------------------------------------------------------------------------
+// -------------------------------------------------------------------------
 // Phase 5: rebuild remembered sets
 
 void MarkCompactCollector::RebuildRSets() {
diff --git a/src/mark-compact.h b/src/mark-compact.h
index 22dd890..746aead 100644
--- a/src/mark-compact.h
+++ b/src/mark-compact.h
@@ -44,12 +44,12 @@
 class MarkingVisitor;
 
 
-// ----------------------------------------------------------------------------
+// -------------------------------------------------------------------------
 // Mark-Compact collector
 //
 // All methods are static.
 
-class MarkCompactCollector : public AllStatic {
+class MarkCompactCollector: public AllStatic {
  public:
   // Type of functions to compute forwarding addresses of objects in
   // compacted spaces.  Given an object and its size, return a (non-failure)
@@ -127,21 +127,18 @@
   // choosing spaces to compact.
   static void Prepare();
 
-  // Finishes GC, performs heap verification.
+  // Finishes GC, performs heap verification if enabled.
   static void Finish();
 
-  // --------------------------------------------------------------------------
-  // Phase 1: functions related to marking phase.
-  //   before: Heap is in normal state, collector is 'IDLE'.
+  // -----------------------------------------------------------------------
+  // Phase 1: Marking live objects.
   //
-  //           The first word of a page in old spaces has the end of
-  //           allocation address of the page.
+  //  Before: The heap has been prepared for garbage collection by
+  //          MarkCompactCollector::Prepare() and is otherwise in its
+  //          normal state.
   //
-  //           The word at Chunk::high_ address has the address of the
-  //           first page in the next chunk. (The address is tagged to
-  //           distinguish it from end-of-allocation address).
-  //
-  //    after: live objects are marked.
+  //   After: Live objects are marked and non-live objects are unmarked.
+
 
   friend class RootMarkingVisitor;
   friend class MarkingVisitor;
@@ -206,7 +203,6 @@
 
 #ifdef DEBUG
   static void UpdateLiveObjectCount(HeapObject* obj);
-  static void VerifyHeapAfterMarkingPhase();
 #endif
 
   // We sweep the large object space in the same way whether we are
@@ -216,30 +212,50 @@
   // Test whether a (possibly marked) object is a Map.
   static inline bool SafeIsMap(HeapObject* object);
 
-    // Map transitions from a live map to a dead map must be killed.
+  // Map transitions from a live map to a dead map must be killed.
   // We replace them with a null descriptor, with the same key.
   static void ClearNonLiveTransitions();
 
-  // --------------------------------------------------------------------------
-  // Phase 2: functions related to computing and encoding forwarding pointers
-  //   before: live objects' map pointers are marked as '00'
-  //    after: Map pointers of live old and map objects have encoded
-  //           forwarding pointers and map pointers
+  // -----------------------------------------------------------------------
+  // Phase 2: Sweeping to clear mark bits and free non-live objects for
+  // a non-compacting collection, or else computing and encoding
+  // forwarding addresses for a compacting collection.
   //
-  //           The 3rd word of a page has the page top offset after compaction.
+  //  Before: Live objects are marked and non-live objects are unmarked.
   //
-  //           The 4th word of a page in the map space has the map index
-  //           of this page in the map table. This word is not used in
-  //           the old space.
+  //   After: (Non-compacting collection.)  Live objects are unmarked,
+  //          non-live regions have been added to their space's free
+  //          list.
   //
-  //           The 5th and 6th words of a page have the start and end
-  //           addresses of the first free region in the page.
+  //   After: (Compacting collection.)  The forwarding address of live
+  //          objects in the paged spaces is encoded in their map word
+  //          along with their (non-forwarded) map pointer.
   //
-  //           The 7th word of a page in old spaces has the forwarding address
-  //           of the first live object in the page.
+  //          The forwarding address of live objects in the new space is
+  //          written to their map word's offset in the inactive
+  //          semispace.
   //
-  //           Live young objects have their forwarding pointers in
-  //           the from space at the same offset to the beginning of the space.
+  //          Bookkeeping data is written to the remembered-set are of
+  //          eached paged-space page that contains live objects after
+  //          compaction:
+  //
+  //          The 3rd word of the page (first word of the remembered
+  //          set) contains the relocation top address, the address of
+  //          the first word after the end of the last live object in
+  //          the page after compaction.
+  //
+  //          The 4th word contains the zero-based index of the page in
+  //          its space.  This word is only used for map space pages, in
+  //          order to encode the map addresses in 21 bits to free 11
+  //          bits per map word for the forwarding address.
+  //
+  //          The 5th word contains the (nonencoded) forwarding address
+  //          of the first live object in the page.
+  //
+  //          In both the new space and the paged spaces, a linked list
+  //          of live regions is constructructed (linked through
+  //          pointers in the non-live region immediately following each
+  //          live region) to speed further passes of the collector.
 
   // Encodes forwarding addresses of objects in compactable parts of the
   // heap.
@@ -272,19 +288,21 @@
   static void DeallocateCodeBlock(Address start, int size_in_bytes);
   static void DeallocateMapBlock(Address start, int size_in_bytes);
 
-  // Phase 2: If we are not compacting the heap, we simply sweep the spaces
-  // except for the large object space, clearing mark bits and adding
-  // unmarked regions to each space's free list.
+  // If we are not compacting the heap, we simply sweep the spaces except
+  // for the large object space, clearing mark bits and adding unmarked
+  // regions to each space's free list.
   static void SweepSpaces();
 
-#ifdef DEBUG
-  static void VerifyHeapAfterEncodingForwardingAddresses();
-#endif
-
-  // --------------------------------------------------------------------------
-  // Phase 3: function related to updating pointers and decode map pointers
-  //   before: see after phase 2
-  //    after: all pointers are updated to forwarding addresses.
+  // -----------------------------------------------------------------------
+  // Phase 3: Updating pointers in live objects.
+  //
+  //  Before: Same as after phase 2 (compacting collection).
+  //
+  //   After: All pointers in live objects, including encoded map
+  //          pointers, are updated to point to their target's new
+  //          location.  The remembered set area of each paged-space
+  //          page containing live objects still contains bookkeeping
+  //          information.
 
   friend class UpdatingVisitor;  // helper for updating visited objects
 
@@ -302,14 +320,17 @@
   // Calculates the forwarding address of an object in an old space.
   static Address GetForwardingAddressInOldSpace(HeapObject* obj);
 
-#ifdef DEBUG
-  static void VerifyHeapAfterUpdatingPointers();
-#endif
-
-  // --------------------------------------------------------------------------
-  // Phase 4: functions related to relocating objects
-  //     before: see after phase 3
-  //      after: heap is in a normal state, except remembered set is not built
+  // -----------------------------------------------------------------------
+  // Phase 4: Relocating objects.
+  //
+  //  Before: Pointers to live objects are updated to point to their
+  //          target's new location.  The remembered set area of each
+  //          paged-space page containing live objects still contains
+  //          bookkeeping information.
+  //
+  //   After: Objects have been moved to their new addresses. The
+  //          remembered set area of each paged-space page containing
+  //          live objects still contains bookkeeping information.
 
   // Relocates objects in all spaces.
   static void RelocateObjects();
@@ -334,18 +355,19 @@
   // Copy a new object.
   static int RelocateNewObject(HeapObject* obj);
 
-#ifdef DEBUG
-  static void VerifyHeapAfterRelocatingObjects();
-#endif
-
-  // ---------------------------------------------------------------------------
-  // Phase 5: functions related to rebuilding remembered sets
+  // -----------------------------------------------------------------------
+  // Phase 5: Rebuilding remembered sets.
+  //
+  //  Before: The heap is in a normal state except that remembered sets
+  //          in the paged spaces are not correct.
+  //
+  //   After: The heap is in a normal state.
 
   // Rebuild remembered set in old and map spaces.
   static void RebuildRSets();
 
 #ifdef DEBUG
-  // ---------------------------------------------------------------------------
+  // -----------------------------------------------------------------------
   // Debugging variables, functions and classes
   // Counters used for debugging the marking phase of mark-compact or
   // mark-sweep collection.
@@ -371,12 +393,6 @@
   // Number of live bytes in this collection.
   static int live_bytes_;
 
-  static void VerifyPageHeaders(PagedSpace* space);
-
-  // Verification functions when relocating objects.
-  friend class VerifyCopyingVisitor;
-  static void VerifyCopyingObjects(Object** p);
-
   friend class MarkObjectVisitor;
   static void VisitObject(HeapObject* obj);
 
diff --git a/src/messages.cc b/src/messages.cc
index e6a5084..ca0ce2a 100644
--- a/src/messages.cc
+++ b/src/messages.cc
@@ -66,7 +66,7 @@
     Vector< Handle<Object> > args,
     Handle<String> stack_trace) {
   // Build error message object
-  HandleScope scope;
+  v8::HandleScope scope;  // Instantiate a closeable HandleScope for EscapeFrom.
   Handle<Object> type_str = Factory::LookupAsciiSymbol(type);
   Handle<Object> array = Factory::NewJSArray(args.length());
   for (int i = 0; i < args.length(); i++)
diff --git a/src/mirror-delay.js b/src/mirror-delay.js
index fe6fb9c..2482029 100644
--- a/src/mirror-delay.js
+++ b/src/mirror-delay.js
@@ -58,6 +58,11 @@
     if (mirror.value() === value) {
       return mirror;
     }
+    // Special check for NaN as NaN == NaN is false.
+    if (mirror.isNumber() && isNaN(mirror.value()) &&
+        typeof value == 'number' && isNaN(value)) {
+      return mirror;
+    }
   }
   
   if (IS_UNDEFINED(value)) {
@@ -90,6 +95,18 @@
 
 
 /**
+ * Returns the mirror for a specified mirror handle.
+ *
+ * @param {number} handle the handle to find the mirror for
+ * @returns {Mirror or undefiend} the mirror with the requested handle or
+ *     undefined if no mirror with the requested handle was found
+ */
+function LookupMirror(handle) {
+  return mirror_cache_[handle];
+}
+
+  
+/**
  * Returns the mirror for the undefined value.
  *
  * @returns {Mirror} the mirror reflects the undefined value
@@ -342,6 +359,14 @@
 }
 
 
+/**
+ * Allocate a handle id for this object.
+ */
+Mirror.prototype.allocateHandle_ = function() {
+  this.handle_ = next_handle_++;
+}
+
+
 Mirror.prototype.toText = function() {
   // Simpel to text which is used when on specialization in subclass.
   return "#<" + builtins.GetInstanceName(this.constructor.name) + ">";
@@ -357,8 +382,8 @@
  */
 function ValueMirror(type, value) {
   Mirror.call(this, type);
-  this.handle_ = next_handle_++;
   this.value_ = value;
+  this.allocateHandle_();
 }
 inherits(ValueMirror, Mirror);
 
@@ -512,7 +537,7 @@
 
 
 ObjectMirror.prototype.protoObject = function() {
-  return MakeMirror(%GetPrototype(this.value_));
+  return MakeMirror(%DebugGetPrototype(this.value_));
 };
 
 
@@ -1516,6 +1541,7 @@
 function ScriptMirror(script) {
   Mirror.call(this, SCRIPT_TYPE);
   this.script_ = script;
+  this.allocateHandle_();
 }
 inherits(ScriptMirror, Mirror);
 
@@ -1656,9 +1682,10 @@
 
 JSONProtocolSerializer.prototype.serialize_ = function(mirror, reference,
                                                        details) {
-  // If serializing a reference to a value just return the reference and add the
-  // mirror to the referenced mirrors.
-  if (reference && mirror.isValue()) {
+  // If serializing a reference to a mirror just return the reference and add
+  // the mirror to the referenced mirrors.
+  if (reference &&
+      (mirror.isValue() || mirror.isScript())) {
     this.add_(mirror);
     return '{"ref":' + mirror.handle() + '}';
   }
@@ -1785,7 +1812,7 @@
       content.push(MakeJSONPair_('source', StringToJSON_(mirror.source())));
     }
     if (mirror.script()) {
-      content.push(MakeJSONPair_('script', this.serializeValue(mirror.script())));
+      content.push(MakeJSONPair_('script', this.serializeReference(mirror.script())));
     }
   }
 
diff --git a/src/mksnapshot.cc b/src/mksnapshot.cc
index 441ae18..a1c9850 100644
--- a/src/mksnapshot.cc
+++ b/src/mksnapshot.cc
@@ -114,7 +114,7 @@
 // Write C++ code that defines Snapshot::snapshot_ to contain the snapshot
 // to the file given by filename. Only the first size chars are written.
 static int WriteInternalSnapshotToFile(const char* filename,
-                                       const char* str,
+                                       const v8::internal::byte* bytes,
                                        int size) {
   FILE* f = i::OS::FOpen(filename, "wb");
   if (f == NULL) {
@@ -126,11 +126,11 @@
   fprintf(f, "#include \"platform.h\"\n\n");
   fprintf(f, "#include \"snapshot.h\"\n\n");
   fprintf(f, "namespace v8 {\nnamespace internal {\n\n");
-  fprintf(f, "const char Snapshot::data_[] = {");
+  fprintf(f, "const byte Snapshot::data_[] = {");
   int written = 0;
-  written += fprintf(f, "%i", str[0]);
+  written += fprintf(f, "0x%x", bytes[0]);
   for (int i = 1; i < size; ++i) {
-    written += fprintf(f, ",%i", str[i]);
+    written += fprintf(f, ",0x%x", bytes[i]);
     // The following is needed to keep the line length low on Visual C++:
     if (i % 512 == 0) fprintf(f, "\n");
   }
@@ -174,13 +174,13 @@
   i::Heap::CollectAllGarbage();
   i::Serializer ser;
   ser.Serialize();
-  char* str;
+  v8::internal::byte* bytes;
   int len;
-  ser.Finalize(&str, &len);
+  ser.Finalize(&bytes, &len);
 
-  WriteInternalSnapshotToFile(argv[1], str, len);
+  WriteInternalSnapshotToFile(argv[1], bytes, len);
 
-  i::DeleteArray(str);
+  i::DeleteArray(bytes);
 
   return 0;
 }
diff --git a/src/objects-debug.cc b/src/objects-debug.cc
index 6b58f25..d3ac805 100644
--- a/src/objects-debug.cc
+++ b/src/objects-debug.cc
@@ -281,6 +281,10 @@
         PrintF(" (callback)\n");
       } else if (r.type() == MAP_TRANSITION) {
         PrintF(" (map transition)\n");
+      } else if (r.type() == CONSTANT_TRANSITION) {
+        PrintF(" (constant transition)\n");
+      } else if (r.type() == NULL_DESCRIPTOR) {
+        PrintF(" (null descriptor)\n");
       } else {
         UNREACHABLE();
       }
@@ -410,6 +414,24 @@
   PrintF(" - type: %s\n", TypeToString(instance_type()));
   PrintF(" - instance size: %d\n", instance_size());
   PrintF(" - unused property fields: %d\n", unused_property_fields());
+  if (is_hidden_prototype()) {
+    PrintF(" - hidden_prototype\n");
+  }
+  if (has_named_interceptor()) {
+    PrintF(" - named_interceptor\n");
+  }
+  if (has_indexed_interceptor()) {
+    PrintF(" - indexed_interceptor\n");
+  }
+  if (is_undetectable()) {
+    PrintF(" - undetectable\n");
+  }
+  if (has_instance_call_handler()) {
+    PrintF(" - instance_call_handler\n");
+  }
+  if (is_access_check_needed()) {
+    PrintF(" - access_check_needed\n");
+  }
   PrintF(" - instance descriptors: ");
   instance_descriptors()->ShortPrint();
   PrintF("\n - prototype: ");
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 43f1a04..22d126a 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -1431,13 +1431,14 @@
 }
 
 
-void String::TryFlatten(StringShape shape) {
+Object* String::TryFlattenIfNotFlat(StringShape shape) {
   ASSERT(shape.type() == StringShape(this).type());
   // 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)) {
-    Flatten(shape);
+    return TryFlatten(shape);
   }
+  return this;
 }
 
 
diff --git a/src/objects.cc b/src/objects.cc
index 352f5bd..1aaf736 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -587,7 +587,7 @@
 }
 
 
-Object* String::Flatten(StringShape shape) {
+Object* String::TryFlatten(StringShape shape) {
 #ifdef DEBUG
   // Do not attempt to flatten in debug mode when allocation is not
   // allowed.  This is to avoid an assertion failure when allocating.
@@ -604,11 +604,11 @@
       // SlicedStrings.
       String* buf = ss->buffer();
       ASSERT(!buf->IsSlicedString());
-      Object* ok = buf->Flatten(StringShape(buf));
+      Object* ok = buf->TryFlatten(StringShape(buf));
       if (ok->IsFailure()) return ok;
-      // Under certain circumstances (TryFlatten fails in String::Slice)
-      // we can have a cons string under a slice.  In this case we need
-      // to get the flat string out of the cons!
+      // Under certain circumstances (TryFlattenIfNotFlat fails in
+      // String::Slice) we can have a cons string under a slice.
+      // In this case we need to get the flat string out of the cons!
       if (StringShape(String::cast(ok)).IsCons()) {
         ss->set_buffer(ConsString::cast(ok)->first());
       }
@@ -2413,8 +2413,8 @@
     return Heap::undefined_value();
   }
 
-  // TryFlatten before operating on the string.
-  name->TryFlatten(StringShape(name));
+  // Try to flatten before operating on the string.
+  name->TryFlattenIfNotFlat(StringShape(name));
 
   // Make sure name is not an index.
   uint32_t index;
@@ -3065,9 +3065,7 @@
   // 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.
-  if (!IsFlat(shape)) {
-    TryFlatten(shape);  // shape is now no longer valid.
-  }
+  TryFlattenIfNotFlat(shape);  // shape is now no longer valid.
   Access<StringInputBuffer> buffer(&string_input_buffer);
   buffer->Reset(0, this);
   int result = 0;
@@ -5160,6 +5158,7 @@
     uint32_t new_length = 0;
     if (IsJSArray()) {
       CHECK(Array::IndexFromObject(JSArray::cast(this)->length(), &new_length));
+      JSArray::cast(this)->set_length(Smi::FromInt(new_length));
     } else {
       new_length = Dictionary::cast(elements())->max_number_key() + 1;
     }
@@ -5695,10 +5694,10 @@
 // Fill in the names of local properties into the supplied storage. The main
 // purpose of this function is to provide reflection information for the object
 // mirrors.
-void JSObject::GetLocalPropertyNames(FixedArray* storage) {
-  ASSERT(storage->length() ==
-         NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE)));
-  int index = 0;
+void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) {
+  ASSERT(storage->length() >=
+         NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE)) -
+             index);
   if (HasFastProperties()) {
     for (DescriptorReader r(map()->instance_descriptors());
          !r.eos();
@@ -5707,7 +5706,7 @@
         storage->set(index++, r.GetKey());
       }
     }
-    ASSERT(storage->length() == index);
+    ASSERT(storage->length() >= index);
   } else {
     property_dictionary()->CopyKeysTo(storage);
   }
diff --git a/src/objects.h b/src/objects.h
index b77c0b2..7a40b70 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -1298,8 +1298,9 @@
   int NumberOfLocalProperties(PropertyAttributes filter);
   // Returns the number of enumerable properties (ignoring interceptors).
   int NumberOfEnumProperties();
-  // Fill in details for properties into storage.
-  void GetLocalPropertyNames(FixedArray* storage);
+  // Fill in details for properties into storage starting at the specified
+  // index.
+  void GetLocalPropertyNames(FixedArray* storage, int index);
 
   // Returns the number of properties on this object filtering out properties
   // with the specified attributes (ignoring interceptors).
@@ -2964,7 +2965,6 @@
 
   // Dispatched behavior.
 #ifdef DEBUG
-  void JSRegExpPrint();
   void JSRegExpVerify();
 #endif
 
@@ -3130,15 +3130,17 @@
   // to this method are not efficient unless the string is flat.
   inline uint16_t Get(StringShape shape, int index);
 
-  // Flatten the top level ConsString that is hiding behind this
+  // 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* Flatten(StringShape shape);
-  // Try to flatten the string.  Do not allow handling of allocation
-  // failures.  After calling TryFlatten, the string could still be a
-  // ConsString.
-  inline void TryFlatten(StringShape shape);
+  Object* TryFlatten(StringShape shape);
+
+  // 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);
 
   Vector<const char> ToAsciiVector();
   Vector<const uc16> ToUC16Vector();
diff --git a/src/parser.cc b/src/parser.cc
index 7f1bff2..333f1c7 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -1092,7 +1092,7 @@
   Counters::total_parse_size.Increment(source->length(shape));
 
   // Initialize parser state.
-  source->TryFlatten(shape);
+  source->TryFlattenIfNotFlat(shape);
   scanner_.Init(source, stream, 0);
   ASSERT(target_stack_ == NULL);
 
@@ -1119,7 +1119,7 @@
                                    temp_scope.materialized_literal_count(),
                                    temp_scope.contains_array_literal(),
                                    temp_scope.expected_property_count(),
-                                   0, 0, source->length(shape), false));
+                                   0, 0, source->length(), false));
     } else if (scanner().stack_overflow()) {
       Top::StackOverflow();
     }
@@ -1141,7 +1141,7 @@
                                    bool is_expression) {
   ZoneScope zone_scope(DONT_DELETE_ON_EXIT);
   StatsRateScope timer(&Counters::parse_lazy);
-  source->TryFlatten(StringShape(*source));
+  source->TryFlattenIfNotFlat(StringShape(*source));
   StringShape shape(*source);
   Counters::total_parse_size.Increment(source->length(shape));
   SafeStringInputBuffer buffer(source.location());
@@ -4052,6 +4052,7 @@
       Advance();
       return '\v';
     case 'c':
+      Advance();
       return ParseControlLetterEscape();
     case '0': case '1': case '2': case '3': case '4': case '5':
     case '6': case '7':
@@ -4148,7 +4149,10 @@
   } else {
     ASSERT(type == '=' || type == '!');
     bool is_positive = (type == '=');
-    return new RegExpLookahead(body, is_positive);
+    return new RegExpLookahead(body,
+                               is_positive,
+                               end_capture_index - capture_index,
+                               capture_index);
   }
 }
 
diff --git a/src/platform-freebsd.cc b/src/platform-freebsd.cc
index d7b3223..7b4febf 100644
--- a/src/platform-freebsd.cc
+++ b/src/platform-freebsd.cc
@@ -195,7 +195,19 @@
 
 
 char* OS::StrNDup(const char* str, size_t n) {
-  return strndup(str, 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;
 }
 
 
diff --git a/src/platform-macos.cc b/src/platform-macos.cc
index f625174..7fc71a5 100644
--- a/src/platform-macos.cc
+++ b/src/platform-macos.cc
@@ -199,12 +199,14 @@
   // Stupid implementation of strndup since macos isn't born with
   // one.
   size_t len = strlen(str);
-  if (len <= n)
+  if (len <= n) {
     return StrDup(str);
+  }
   char* result = new char[n+1];
   size_t i;
-  for (i = 0; i <= n; i++)
+  for (i = 0; i <= n; i++) {
     result[i] = str[i];
+  }
   result[i] = '\0';
   return result;
 }
diff --git a/src/platform-win32.cc b/src/platform-win32.cc
index 92fb536..71ba8ee 100644
--- a/src/platform-win32.cc
+++ b/src/platform-win32.cc
@@ -704,12 +704,14 @@
   // Stupid implementation of strndup since windows isn't born with
   // one.
   size_t len = strlen(str);
-  if (len <= n)
+  if (len <= n) {
     return StrDup(str);
+  }
   char* result = new char[n+1];
   size_t i;
-  for (i = 0; i <= n; i++)
+  for (i = 0; i <= n; i++) {
     result[i] = str[i];
+  }
   result[i] = '\0';
   return result;
 }
diff --git a/src/regexp-macro-assembler-ia32.cc b/src/regexp-macro-assembler-ia32.cc
index 824a297..e58177c 100644
--- a/src/regexp-macro-assembler-ia32.cc
+++ b/src/regexp-macro-assembler-ia32.cc
@@ -174,6 +174,20 @@
 }
 
 
+void RegExpMacroAssemblerIA32::CheckAtStart(Label* on_at_start) {
+  Label ok;
+  // Did we start the match at the start of the string at all?
+  __ cmp(Operand(ebp, kAtStart), Immediate(0));
+  BranchOrBacktrack(equal, &ok);
+  // 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));
+  BranchOrBacktrack(equal, on_at_start);
+  __ bind(&ok);
+}
+
+
 void RegExpMacroAssemblerIA32::CheckNotAtStart(Label* on_not_at_start) {
   // Did we start the match at the start of the string at all?
   __ cmp(Operand(ebp, kAtStart), Immediate(0));
@@ -317,16 +331,30 @@
     __ push(backtrack_stackpointer());
     __ push(ebx);
     const int four_arguments = 4;
-    FrameAlign(four_arguments);
-    // Put arguments into allocated stack area.
+    FrameAlign(four_arguments, 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
+    //   size_t byte_length - length of capture in bytes(!)
+
+    // Set byte_length.
     __ mov(Operand(esp, 3 * 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);
+    // Set byte_offset1.
+    // Start of capture, where eax already holds string-end negative offset.
     __ add(eax, Operand(ecx));
     __ mov(Operand(esp, 1 * kPointerSize), eax);
+    // Set buffer. Original String** parameter to regexp code.
     __ mov(eax, Operand(ebp, kInputBuffer));
     __ mov(Operand(esp, 0 * kPointerSize), eax);
+
     Address function_address = FUNCTION_ADDR(&CaseInsensitiveCompareUC16);
     CallCFunction(function_address, four_arguments);
     // Pop original values before reacting on result value.
@@ -632,7 +660,7 @@
 
   __ bind(&stack_limit_hit);
   int num_arguments = 2;
-  FrameAlign(num_arguments);
+  FrameAlign(num_arguments, ebx);
   __ mov(Operand(esp, 1 * kPointerSize), Immediate(self_));
   __ lea(eax, Operand(esp, -kPointerSize));
   __ mov(Operand(esp, 0 * kPointerSize), eax);
@@ -755,7 +783,7 @@
 
     __ bind(&retry);
     int num_arguments = 2;
-    FrameAlign(num_arguments);
+    FrameAlign(num_arguments, ebx);
     __ mov(Operand(esp, 1 * kPointerSize), Immediate(self_));
     __ lea(eax, Operand(esp, -kPointerSize));
     __ mov(Operand(esp, 0 * kPointerSize), eax);
@@ -791,7 +819,7 @@
 
     // Call GrowStack(backtrack_stackpointer())
     int num_arguments = 1;
-    FrameAlign(num_arguments);
+    FrameAlign(num_arguments, ebx);
     __ mov(Operand(esp, 0), backtrack_stackpointer());
     CallCFunction(FUNCTION_ADDR(&GrowStack), num_arguments);
     // If return NULL, we have failed to grow the stack, and
@@ -863,7 +891,7 @@
                                                     Label* on_end_of_input,
                                                     bool check_bounds,
                                                     int characters) {
-  ASSERT(cp_offset >= 0);
+  ASSERT(cp_offset >= -1);      // ^ and \b can look behind one character.
   ASSERT(cp_offset < (1<<30));  // Be sane! (And ensure negation works)
   CheckPosition(cp_offset + characters - 1, on_end_of_input);
   LoadCurrentCharacterUnchecked(cp_offset, characters);
@@ -932,9 +960,12 @@
 }
 
 
-void RegExpMacroAssemblerIA32::ClearRegister(int reg) {
+void RegExpMacroAssemblerIA32::ClearRegisters(int reg_from, int reg_to) {
+  ASSERT(reg_from <= reg_to);
   __ mov(eax, Operand(ebp, kInputStartMinusOne));
-  __ mov(register_location(reg), eax);
+  for (int reg = reg_from; reg <= reg_to; reg++) {
+    __ mov(register_location(reg), eax);
+  }
 }
 
 
@@ -973,8 +1004,8 @@
                             stack_top);
 
   if (result < 0 && !Top::has_pending_exception()) {
-    // We detected a stack overflow in RegExp code, but haven't created
-    // the exception yet.
+    // 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);
@@ -1155,16 +1186,19 @@
 }
 
 
-void RegExpMacroAssemblerIA32::FrameAlign(int num_arguments) {
+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.
   int frameAlignment = OS::ActivationFrameAlignment();
   if (frameAlignment != 0) {
     // Make stack end at alignment and make room for num_arguments words
     // and the original value of esp.
-    __ mov(ebx, esp);
+    __ mov(scratch, esp);
     __ sub(Operand(esp), Immediate((num_arguments + 1) * kPointerSize));
     ASSERT(IsPowerOf2(frameAlignment));
     __ and_(esp, -frameAlignment);
-    __ mov(Operand(esp, num_arguments * kPointerSize), ebx);
+    __ mov(Operand(esp, num_arguments * kPointerSize), scratch);
   } else {
     __ sub(Operand(esp), Immediate(num_arguments * kPointerSize));
   }
diff --git a/src/regexp-macro-assembler-ia32.h b/src/regexp-macro-assembler-ia32.h
index 8d28beb..75ab693 100644
--- a/src/regexp-macro-assembler-ia32.h
+++ b/src/regexp-macro-assembler-ia32.h
@@ -43,6 +43,7 @@
   virtual void AdvanceRegister(int reg, int by);
   virtual void Backtrack();
   virtual void Bind(Label* label);
+  virtual void CheckAtStart(Label* on_at_start);
   virtual void CheckBitmap(uc16 start, Label* bitmap, Label* on_zero);
   virtual void CheckCharacter(uint32_t c, Label* on_equal);
   virtual void CheckCharacterAfterAnd(uint32_t c,
@@ -70,6 +71,9 @@
                                               uc16 minus,
                                               uc16 mask,
                                               Label* on_not_equal);
+  // Checks whether the given offset from the current position is before
+  // the end of the string.
+  virtual void CheckPosition(int cp_offset, Label* on_outside_input);
   virtual bool CheckSpecialCharacterClass(uc16 type,
                                           int cp_offset,
                                           bool check_offset,
@@ -106,7 +110,7 @@
   virtual void SetRegister(int register_index, int to);
   virtual void Succeed();
   virtual void WriteCurrentPositionToRegister(int reg, int cp_offset);
-  virtual void ClearRegister(int reg);
+  virtual void ClearRegisters(int reg_from, int reg_to);
   virtual void WriteStackPointerToRegister(int reg);
 
   static Result Execute(Code* code,
@@ -170,10 +174,6 @@
   // This function must not trigger a garbage collection.
   static Address GrowStack(Address stack_top);
 
-  // Checks whether the given offset from the current position is before
-  // the end of the string.
-  void CheckPosition(int cp_offset, Label* on_outside_input);
-
   // The ebp-relative location of a regexp register.
   Operand register_location(int register_index);
 
@@ -218,7 +218,9 @@
   // etc., not pushed. The argument count assumes all arguments are word sized.
   // Some compilers/platforms require the stack to be aligned when calling
   // C++ code.
-  inline void FrameAlign(int num_arguments);
+  // Needs a scratch register to do some arithmetic. This register will be
+  // trashed.
+  inline void FrameAlign(int num_arguments, Register scratch);
 
   // Calls a C function and cleans up the space for arguments allocated
   // by FrameAlign. The called function is not allowed to trigger a garbage
diff --git a/src/regexp-macro-assembler-irregexp-inl.h b/src/regexp-macro-assembler-irregexp-inl.h
index faf12da..24f32c5 100644
--- a/src/regexp-macro-assembler-irregexp-inl.h
+++ b/src/regexp-macro-assembler-irregexp-inl.h
@@ -36,12 +36,15 @@
 namespace v8 { namespace internal {
 
 
-void RegExpMacroAssemblerIrregexp::Emit(uint32_t byte) {
+void RegExpMacroAssemblerIrregexp::Emit(uint32_t byte,
+                                        uint32_t twenty_four_bits) {
+  uint32_t word = ((twenty_four_bits << BYTECODE_SHIFT) | byte);
   ASSERT(pc_ <= buffer_.length());
-  if (pc_ == buffer_.length()) {
+  if (pc_  + 3 >= buffer_.length()) {
     Expand();
   }
-  buffer_[pc_++] = byte;
+  *reinterpret_cast<uint32_t*>(buffer_.start() + pc_) = word;
+  pc_ += 4;
 }
 
 
@@ -50,7 +53,7 @@
   if (pc_ + 1 >= buffer_.length()) {
     Expand();
   }
-  Store16(buffer_.start() + pc_, word);
+  *reinterpret_cast<uint16_t*>(buffer_.start() + pc_) = word;
   pc_ += 2;
 }
 
@@ -60,7 +63,7 @@
   if (pc_ + 3 >= buffer_.length()) {
     Expand();
   }
-  Store32(buffer_.start() + pc_, word);
+  *reinterpret_cast<uint32_t*>(buffer_.start() + pc_) = word;
   pc_ += 4;
 }
 
diff --git a/src/regexp-macro-assembler-irregexp.cc b/src/regexp-macro-assembler-irregexp.cc
index a36f0a7..155b197 100644
--- a/src/regexp-macro-assembler-irregexp.cc
+++ b/src/regexp-macro-assembler-irregexp.cc
@@ -60,8 +60,8 @@
     int pos = l->pos();
     while (pos != 0) {
       int fixup = pos;
-      pos = Load32(buffer_.start() + fixup);
-      Store32(buffer_.start() + fixup, pc_);
+      pos = *reinterpret_cast<int32_t*>(buffer_.start() + fixup);
+      *reinterpret_cast<uint32_t*>(buffer_.start() + fixup) = pc_;
     }
   }
   l->bind_to(pc_);
@@ -84,8 +84,9 @@
 
 
 void RegExpMacroAssemblerIrregexp::PopRegister(int register_index) {
-  Emit(BC_POP_REGISTER);
-  Emit(register_index);
+  ASSERT(register_index >= 0);
+  ASSERT(register_index <= kMaxRegister);
+  Emit(BC_POP_REGISTER, register_index);
 }
 
 
@@ -93,112 +94,115 @@
     int register_index,
     StackCheckFlag check_stack_limit) {
   ASSERT(register_index >= 0);
-  Emit(BC_PUSH_REGISTER);
-  Emit(register_index);
+  ASSERT(register_index <= kMaxRegister);
+  Emit(BC_PUSH_REGISTER, register_index);
 }
 
 
 void RegExpMacroAssemblerIrregexp::WriteCurrentPositionToRegister(
     int register_index, int cp_offset) {
   ASSERT(register_index >= 0);
-  Emit(BC_SET_REGISTER_TO_CP);
-  Emit(register_index);
+  ASSERT(register_index <= kMaxRegister);
+  Emit(BC_SET_REGISTER_TO_CP, register_index);
   Emit32(cp_offset);  // Current position offset.
 }
 
 
-void RegExpMacroAssemblerIrregexp::ClearRegister(int reg) {
-  SetRegister(reg, -1);
+void RegExpMacroAssemblerIrregexp::ClearRegisters(int reg_from, int reg_to) {
+  ASSERT(reg_from <= reg_to);
+  for (int reg = reg_from; reg <= reg_to; reg++) {
+    SetRegister(reg, -1);
+  }
 }
 
 
 void RegExpMacroAssemblerIrregexp::ReadCurrentPositionFromRegister(
     int register_index) {
   ASSERT(register_index >= 0);
-  Emit(BC_SET_CP_TO_REGISTER);
-  Emit(register_index);
+  ASSERT(register_index <= kMaxRegister);
+  Emit(BC_SET_CP_TO_REGISTER, register_index);
 }
 
 
 void RegExpMacroAssemblerIrregexp::WriteStackPointerToRegister(
     int register_index) {
   ASSERT(register_index >= 0);
-  Emit(BC_SET_REGISTER_TO_SP);
-  Emit(register_index);
+  ASSERT(register_index <= kMaxRegister);
+  Emit(BC_SET_REGISTER_TO_SP, register_index);
 }
 
 
 void RegExpMacroAssemblerIrregexp::ReadStackPointerFromRegister(
     int register_index) {
   ASSERT(register_index >= 0);
-  Emit(BC_SET_SP_TO_REGISTER);
-  Emit(register_index);
+  ASSERT(register_index <= kMaxRegister);
+  Emit(BC_SET_SP_TO_REGISTER, register_index);
 }
 
 
 void RegExpMacroAssemblerIrregexp::SetRegister(int register_index, int to) {
   ASSERT(register_index >= 0);
-  Emit(BC_SET_REGISTER);
-  Emit(register_index);
+  ASSERT(register_index <= kMaxRegister);
+  Emit(BC_SET_REGISTER, register_index);
   Emit32(to);
 }
 
 
 void RegExpMacroAssemblerIrregexp::AdvanceRegister(int register_index, int by) {
   ASSERT(register_index >= 0);
-  Emit(BC_ADVANCE_REGISTER);
-  Emit(register_index);
+  ASSERT(register_index <= kMaxRegister);
+  Emit(BC_ADVANCE_REGISTER, register_index);
   Emit32(by);
 }
 
 
 void RegExpMacroAssemblerIrregexp::PopCurrentPosition() {
-  Emit(BC_POP_CP);
+  Emit(BC_POP_CP, 0);
 }
 
 
 void RegExpMacroAssemblerIrregexp::PushCurrentPosition() {
-  Emit(BC_PUSH_CP);
-  Emit32(0);  // Current position offset.
+  Emit(BC_PUSH_CP, 0);
 }
 
 
 void RegExpMacroAssemblerIrregexp::Backtrack() {
-  Emit(BC_POP_BT);
+  Emit(BC_POP_BT, 0);
 }
 
 
 void RegExpMacroAssemblerIrregexp::GoTo(Label* l) {
-  Emit(BC_GOTO);
+  Emit(BC_GOTO, 0);
   EmitOrLink(l);
 }
 
 
 void RegExpMacroAssemblerIrregexp::PushBacktrack(Label* l) {
-  Emit(BC_PUSH_BT);
+  Emit(BC_PUSH_BT, 0);
   EmitOrLink(l);
 }
 
 
 void RegExpMacroAssemblerIrregexp::Succeed() {
-  Emit(BC_SUCCEED);
+  Emit(BC_SUCCEED, 0);
 }
 
 
 void RegExpMacroAssemblerIrregexp::Fail() {
-  Emit(BC_FAIL);
+  Emit(BC_FAIL, 0);
 }
 
 
 void RegExpMacroAssemblerIrregexp::AdvanceCurrentPosition(int by) {
-  Emit(BC_ADVANCE_CP);
-  Emit32(by);
+  ASSERT(by >= kMinCPOffset);
+  ASSERT(by <= kMaxCPOffset);
+  Emit(BC_ADVANCE_CP, by);
 }
 
 
 void RegExpMacroAssemblerIrregexp::CheckGreedyLoop(
       Label* on_tos_equals_current_position) {
-  Emit(BC_CHECK_GREEDY);
+  Emit(BC_CHECK_GREEDY, 0);
   EmitOrLink(on_tos_equals_current_position);
 }
 
@@ -207,6 +211,8 @@
                                                         Label* on_failure,
                                                         bool check_bounds,
                                                         int characters) {
+  ASSERT(cp_offset >= kMinCPOffset);
+  ASSERT(cp_offset <= kMaxCPOffset);
   int bytecode;
   if (check_bounds) {
     if (characters == 4) {
@@ -227,45 +233,56 @@
       bytecode = BC_LOAD_CURRENT_CHAR_UNCHECKED;
     }
   }
-  Emit(bytecode);
-  Emit32(cp_offset);
+  Emit(bytecode, cp_offset);
   if (check_bounds) EmitOrLink(on_failure);
 }
 
 
 void RegExpMacroAssemblerIrregexp::CheckCharacterLT(uc16 limit,
                                                     Label* on_less) {
-  Emit(BC_CHECK_LT);
-  Emit16(limit);
+  Emit(BC_CHECK_LT, limit);
   EmitOrLink(on_less);
 }
 
 
 void RegExpMacroAssemblerIrregexp::CheckCharacterGT(uc16 limit,
                                                     Label* on_greater) {
-  Emit(BC_CHECK_GT);
-  Emit16(limit);
+  Emit(BC_CHECK_GT, limit);
   EmitOrLink(on_greater);
 }
 
 
 void RegExpMacroAssemblerIrregexp::CheckCharacter(uint32_t c, Label* on_equal) {
-  Emit(BC_CHECK_CHAR);
-  Emit32(c);
+  if (c > MAX_FIRST_ARG) {
+    Emit(BC_CHECK_4_CHARS, 0);
+    Emit32(c);
+  } else {
+    Emit(BC_CHECK_CHAR, c);
+  }
   EmitOrLink(on_equal);
 }
 
 
+void RegExpMacroAssemblerIrregexp::CheckAtStart(Label* on_at_start) {
+  Emit(BC_CHECK_AT_START, 0);
+  EmitOrLink(on_at_start);
+}
+
+
 void RegExpMacroAssemblerIrregexp::CheckNotAtStart(Label* on_not_at_start) {
-  Emit(BC_CHECK_NOT_AT_START);
+  Emit(BC_CHECK_NOT_AT_START, 0);
   EmitOrLink(on_not_at_start);
 }
 
 
 void RegExpMacroAssemblerIrregexp::CheckNotCharacter(uint32_t c,
                                                      Label* on_not_equal) {
-  Emit(BC_CHECK_NOT_CHAR);
-  Emit32(c);
+  if (c > MAX_FIRST_ARG) {
+    Emit(BC_CHECK_NOT_4_CHARS, 0);
+    Emit32(c);
+  } else {
+    Emit(BC_CHECK_NOT_CHAR, c);
+  }
   EmitOrLink(on_not_equal);
 }
 
@@ -274,8 +291,12 @@
     uint32_t c,
     uint32_t mask,
     Label* on_equal) {
-  Emit(BC_AND_CHECK_CHAR);
-  Emit32(c);
+  if (c > MAX_FIRST_ARG) {
+    Emit(BC_AND_CHECK_4_CHARS, 0);
+    Emit32(c);
+  } else {
+    Emit(BC_AND_CHECK_CHAR, c);
+  }
   Emit32(mask);
   EmitOrLink(on_equal);
 }
@@ -285,8 +306,12 @@
     uint32_t c,
     uint32_t mask,
     Label* on_not_equal) {
-  Emit(BC_AND_CHECK_NOT_CHAR);
-  Emit32(c);
+  if (c > MAX_FIRST_ARG) {
+    Emit(BC_AND_CHECK_NOT_4_CHARS, 0);
+    Emit32(c);
+  } else {
+    Emit(BC_AND_CHECK_NOT_CHAR, c);
+  }
   Emit32(mask);
   EmitOrLink(on_not_equal);
 }
@@ -297,8 +322,7 @@
     uc16 minus,
     uc16 mask,
     Label* on_not_equal) {
-  Emit(BC_MINUS_AND_CHECK_NOT_CHAR);
-  Emit16(c);
+  Emit(BC_MINUS_AND_CHECK_NOT_CHAR, c);
   Emit16(minus);
   Emit16(mask);
   EmitOrLink(on_not_equal);
@@ -307,8 +331,9 @@
 
 void RegExpMacroAssemblerIrregexp::CheckNotBackReference(int start_reg,
                                                          Label* on_not_equal) {
-  Emit(BC_CHECK_NOT_BACK_REF);
-  Emit(start_reg);
+  ASSERT(start_reg >= 0);
+  ASSERT(start_reg <= kMaxRegister);
+  Emit(BC_CHECK_NOT_BACK_REF, start_reg);
   EmitOrLink(on_not_equal);
 }
 
@@ -316,8 +341,9 @@
 void RegExpMacroAssemblerIrregexp::CheckNotBackReferenceIgnoreCase(
     int start_reg,
     Label* on_not_equal) {
-  Emit(BC_CHECK_NOT_BACK_REF_NO_CASE);
-  Emit(start_reg);
+  ASSERT(start_reg >= 0);
+  ASSERT(start_reg <= kMaxRegister);
+  Emit(BC_CHECK_NOT_BACK_REF_NO_CASE, start_reg);
   EmitOrLink(on_not_equal);
 }
 
@@ -325,9 +351,10 @@
 void RegExpMacroAssemblerIrregexp::CheckNotRegistersEqual(int reg1,
                                                           int reg2,
                                                           Label* on_not_equal) {
-  Emit(BC_CHECK_NOT_REGS_EQUAL);
-  Emit(reg1);
-  Emit(reg2);
+  ASSERT(reg1 >= 0);
+  ASSERT(reg1 <= kMaxRegister);
+  Emit(BC_CHECK_NOT_REGS_EQUAL, reg1);
+  Emit32(reg2);
   EmitOrLink(on_not_equal);
 }
 
@@ -368,19 +395,18 @@
   int cp_offset,
   Label* on_failure,
   bool check_end_of_string) {
+  ASSERT(cp_offset >= kMinCPOffset);
+  ASSERT(cp_offset + str.length() - 1 <= kMaxCPOffset);
   // It is vital that this loop is backwards due to the unchecked character
   // load below.
   for (int i = str.length() - 1; i >= 0; i--) {
     if (check_end_of_string && i == str.length() - 1) {
-      Emit(BC_LOAD_CURRENT_CHAR);
-      Emit32(cp_offset + i);
+      Emit(BC_LOAD_CURRENT_CHAR, cp_offset + i);
       EmitOrLink(on_failure);
     } else {
-      Emit(BC_LOAD_CURRENT_CHAR_UNCHECKED);
-      Emit32(cp_offset + i);
+      Emit(BC_LOAD_CURRENT_CHAR_UNCHECKED, cp_offset + i);
     }
-    Emit(BC_CHECK_NOT_CHAR);
-    Emit32(str[i]);
+    Emit(BC_CHECK_NOT_CHAR, str[i]);
     EmitOrLink(on_failure);
   }
 }
@@ -389,10 +415,10 @@
 void RegExpMacroAssemblerIrregexp::IfRegisterLT(int register_index,
                                                 int comparand,
                                                 Label* on_less_than) {
-  ASSERT(comparand >= 0 && comparand <= 65535);
-  Emit(BC_CHECK_REGISTER_LT);
-  Emit(register_index);
-  Emit16(comparand);
+  ASSERT(register_index >= 0);
+  ASSERT(register_index <= kMaxRegister);
+  Emit(BC_CHECK_REGISTER_LT, register_index);
+  Emit32(comparand);
   EmitOrLink(on_less_than);
 }
 
@@ -400,25 +426,26 @@
 void RegExpMacroAssemblerIrregexp::IfRegisterGE(int register_index,
                                                 int comparand,
                                                 Label* on_greater_or_equal) {
-  ASSERT(comparand >= 0 && comparand <= 65535);
-  Emit(BC_CHECK_REGISTER_GE);
-  Emit(register_index);
-  Emit16(comparand);
+  ASSERT(register_index >= 0);
+  ASSERT(register_index <= kMaxRegister);
+  Emit(BC_CHECK_REGISTER_GE, register_index);
+  Emit32(comparand);
   EmitOrLink(on_greater_or_equal);
 }
 
 
 void RegExpMacroAssemblerIrregexp::IfRegisterEqPos(int register_index,
                                                    Label* on_eq) {
-  Emit(BC_CHECK_REGISTER_EQ_POS);
-  Emit(register_index);
+  ASSERT(register_index >= 0);
+  ASSERT(register_index <= kMaxRegister);
+  Emit(BC_CHECK_REGISTER_EQ_POS, register_index);
   EmitOrLink(on_eq);
 }
 
 
 Handle<Object> RegExpMacroAssemblerIrregexp::GetCode(Handle<String> source) {
   Bind(&backtrack_);
-  Emit(BC_POP_BT);
+  Emit(BC_POP_BT, 0);
   Handle<ByteArray> array = Factory::NewByteArray(length());
   Copy(array->GetDataStartAddress());
   return array;
diff --git a/src/regexp-macro-assembler-irregexp.h b/src/regexp-macro-assembler-irregexp.h
index 95b903c..0d5999f 100644
--- a/src/regexp-macro-assembler-irregexp.h
+++ b/src/regexp-macro-assembler-irregexp.h
@@ -66,7 +66,7 @@
   virtual void AdvanceRegister(int reg, int by);  // r[reg] += by.
   virtual void SetRegister(int register_index, int to);
   virtual void WriteCurrentPositionToRegister(int reg, int cp_offset);
-  virtual void ClearRegister(int reg);
+  virtual void ClearRegisters(int reg_from, int reg_to);
   virtual void ReadCurrentPositionFromRegister(int reg);
   virtual void WriteStackPointerToRegister(int reg);
   virtual void ReadStackPointerFromRegister(int reg);
@@ -81,6 +81,7 @@
   virtual void CheckCharacterGT(uc16 limit, Label* on_greater);
   virtual void CheckCharacterLT(uc16 limit, Label* on_less);
   virtual void CheckGreedyLoop(Label* on_tos_equals_current_position);
+  virtual void CheckAtStart(Label* on_at_start);
   virtual void CheckNotAtStart(Label* on_not_at_start);
   virtual void CheckNotCharacter(uint32_t c, Label* on_not_equal);
   virtual void CheckNotCharacterAfterAnd(uint32_t c,
@@ -119,7 +120,7 @@
   // Code and bitmap emission.
   inline void Emit32(uint32_t x);
   inline void Emit16(uint32_t x);
-  inline void Emit(uint32_t x);
+  inline void Emit(uint32_t bc, uint32_t arg);
   // Bytecode buffer.
   int length();
   void Copy(Address a);
diff --git a/src/regexp-macro-assembler-tracer.cc b/src/regexp-macro-assembler-tracer.cc
index 5caf032..74345d8 100644
--- a/src/regexp-macro-assembler-tracer.cc
+++ b/src/regexp-macro-assembler-tracer.cc
@@ -150,9 +150,9 @@
 }
 
 
-void RegExpMacroAssemblerTracer::ClearRegister(int reg) {
-  PrintF(" ClearRegister(register=%d);\n", reg);
-  assembler_->ClearRegister(reg);
+void RegExpMacroAssemblerTracer::ClearRegisters(int reg_from, int reg_to) {
+  PrintF(" ClearRegister(from=%d, to=%d);\n", reg_from, reg_to);
+  assembler_->ClearRegisters(reg_from, reg_to);
 }
 
 
@@ -210,6 +210,12 @@
 }
 
 
+void RegExpMacroAssemblerTracer::CheckAtStart(Label* on_at_start) {
+  PrintF(" CheckAtStart(label[%08x]);\n", on_at_start);
+  assembler_->CheckAtStart(on_at_start);
+}
+
+
 void RegExpMacroAssemblerTracer::CheckNotAtStart(Label* on_not_at_start) {
   PrintF(" CheckNotAtStart(label[%08x]);\n", on_not_at_start);
   assembler_->CheckNotAtStart(on_not_at_start);
diff --git a/src/regexp-macro-assembler-tracer.h b/src/regexp-macro-assembler-tracer.h
index c8088a9..d3aeff7 100644
--- a/src/regexp-macro-assembler-tracer.h
+++ b/src/regexp-macro-assembler-tracer.h
@@ -41,6 +41,7 @@
   virtual void AdvanceRegister(int reg, int by);  // r[reg] += by.
   virtual void Backtrack();
   virtual void Bind(Label* label);
+  virtual void CheckAtStart(Label* on_at_start);
   virtual void CheckBitmap(uc16 start, Label* bitmap, Label* on_zero);
   virtual void CheckCharacter(uint32_t c, Label* on_equal);
   virtual void CheckCharacterAfterAnd(uint32_t c,
@@ -106,7 +107,7 @@
   virtual void SetRegister(int register_index, int to);
   virtual void Succeed();
   virtual void WriteCurrentPositionToRegister(int reg, int cp_offset);
-  virtual void ClearRegister(int reg);
+  virtual void ClearRegisters(int reg_from, int reg_to);
   virtual void WriteStackPointerToRegister(int reg);
  private:
   RegExpMacroAssembler* assembler_;
diff --git a/src/regexp-macro-assembler.h b/src/regexp-macro-assembler.h
index e9f7731..a3f398d 100644
--- a/src/regexp-macro-assembler.h
+++ b/src/regexp-macro-assembler.h
@@ -38,6 +38,10 @@
 
 class RegExpMacroAssembler {
  public:
+  // The implementation must be able to handle at least:
+  static const int kMaxRegister = (1 << 16) - 1;
+  static const int kMaxCPOffset = (1 << 15) - 1;
+  static const int kMinCPOffset = -(1 << 15);
   enum IrregexpImplementation {
     kIA32Implementation,
     kARMImplementation,
@@ -61,6 +65,7 @@
   // stack by an earlier PushBacktrack(Label*).
   virtual void Backtrack() = 0;
   virtual void Bind(Label* label) = 0;
+  virtual void CheckAtStart(Label* on_at_start) = 0;
   // Check the current character against a bitmap.  The range of the current
   // character must be from start to start + length_of_bitmap_in_bits.
   virtual void CheckBitmap(
@@ -110,6 +115,12 @@
   virtual void CheckNotRegistersEqual(int reg1,
                                       int reg2,
                                       Label* on_not_equal) = 0;
+
+  // Checks whether the given offset from the current position is before
+  // the end of the string.  May overwrite the current character.
+  virtual void CheckPosition(int cp_offset, Label* on_outside_input) {
+    LoadCurrentCharacter(cp_offset, on_outside_input, true);
+  }
   // Check whether a standard/default character class matches the current
   // character. Returns false if the type of special character class does
   // not have custom support.
@@ -167,7 +178,7 @@
   virtual void SetRegister(int register_index, int to) = 0;
   virtual void Succeed() = 0;
   virtual void WriteCurrentPositionToRegister(int reg, int cp_offset) = 0;
-  virtual void ClearRegister(int reg) = 0;
+  virtual void ClearRegisters(int reg_from, int reg_to) = 0;
   virtual void WriteStackPointerToRegister(int reg) = 0;
 
  private:
diff --git a/src/runtime.cc b/src/runtime.cc
index fd36724..18d6c03 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -161,15 +161,16 @@
     for (int index = 0; index < length; index +=2) {
       Handle<Object> key(constant_properties->get(index+0));
       Handle<Object> value(constant_properties->get(index+1));
+      Handle<Object> result;
       uint32_t element_index = 0;
       if (key->IsSymbol()) {
         // If key is a symbol it is not an array element.
         Handle<String> name(String::cast(*key));
         ASSERT(!name->AsArrayIndex(&element_index));
-        SetProperty(boilerplate, name, value, NONE);
+        result = SetProperty(boilerplate, name, value, NONE);
       } else if (Array::IndexFromObject(*key, &element_index)) {
         // Array index (uint32).
-        SetElement(boilerplate, element_index, value);
+        result = SetElement(boilerplate, element_index, value);
       } else {
         // Non-uint32 number.
         ASSERT(key->IsNumber());
@@ -178,8 +179,13 @@
         Vector<char> buffer(arr, ARRAY_SIZE(arr));
         const char* str = DoubleToCString(num, buffer);
         Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
-        SetProperty(boilerplate, name, value, NONE);
+        result = SetProperty(boilerplate, name, value, NONE);
       }
+      // If setting the property on the boilerplate throws an
+      // 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();
     }
   }
 
@@ -758,56 +764,94 @@
 
   int index;
   PropertyAttributes attributes;
-  ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
+  ContextLookupFlags flags = FOLLOW_CHAINS;
   Handle<Object> holder =
       context->Lookup(name, flags, &index, &attributes);
 
-  // The property should always be present. It is always declared
-  // before being initialized through DeclareContextSlot.
-  ASSERT(attributes != ABSENT && (attributes & READ_ONLY) != 0);
-
-  // If the slot is in the context, we set it but only if it hasn't
-  // been set before.
+  // In most situations, the property introduced by the const
+  // declaration should be present in the context extension object.
+  // However, because declaration and initialization are separate, the
+  // property might have been deleted (if it was introduced by eval)
+  // before we reach the initialization point.
+  //
+  // Example:
+  //
+  //    function f() { eval("delete x; const x;"); }
+  //
+  // In that case, the initialization behaves like a normal assignment
+  // to property 'x'.
   if (index >= 0) {
-    // The constant context slot should always be in the function
-    // context; not in any outer context nor in the arguments object.
-    ASSERT(holder.is_identical_to(context));
-    if (context->get(index)->IsTheHole()) {
-      context->set(index, *value);
+    // Property was found in a context.
+    if (holder->IsContext()) {
+      // The holder cannot be the function context.  If it is, there
+      // should have been a const redeclaration error when declaring
+      // the const property.
+      ASSERT(!holder.is_identical_to(context));
+      if ((attributes & READ_ONLY) == 0) {
+        Handle<Context>::cast(holder)->set(index, *value);
+      }
+    } else {
+      // The holder is an arguments object.
+      ASSERT((attributes & READ_ONLY) == 0);
+      Handle<JSObject>::cast(holder)->SetElement(index, *value);
     }
     return *value;
   }
 
-  // Otherwise, the slot must be in a JS object extension.
-  Handle<JSObject> context_ext(JSObject::cast(*holder));
+  // The property could not be found, we introduce it in the global
+  // context.
+  if (attributes == ABSENT) {
+    Handle<JSObject> global = Handle<JSObject>(Top::context()->global());
+    SetProperty(global, name, value, NONE);
+    return *value;
+  }
 
-  // We must initialize the value only if it wasn't initialized
-  // before, e.g. for const declarations in a loop. The property has
-  // the hole value if it wasn't initialized yet. NOTE: We cannot use
-  // GetProperty() to get the current value as it 'unholes' the value.
-  LookupResult lookup;
-  context_ext->LocalLookupRealNamedProperty(*name, &lookup);
-  ASSERT(lookup.IsProperty());  // the property was declared
-  ASSERT(lookup.IsReadOnly());  // and it was declared as read-only
+  // The property was present in a context extension object.
+  Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
 
-  PropertyType type = lookup.type();
-  if (type == FIELD) {
-    FixedArray* properties = context_ext->properties();
-    int index = lookup.GetFieldIndex();
-    if (properties->get(index)->IsTheHole()) {
-      properties->set(index, *value);
-    }
-  } else if (type == NORMAL) {
-    Dictionary* dictionary = context_ext->property_dictionary();
-    int entry = lookup.GetDictionaryEntry();
-    if (dictionary->ValueAt(entry)->IsTheHole()) {
-      dictionary->ValueAtPut(entry, *value);
+  if (*context_ext == context->extension()) {
+    // This is the property that was introduced by the const
+    // declaration.  Set it if it hasn't been set before.  NOTE: We
+    // cannot use GetProperty() to get the current value as it
+    // 'unholes' the value.
+    LookupResult lookup;
+    context_ext->LocalLookupRealNamedProperty(*name, &lookup);
+    ASSERT(lookup.IsProperty());  // the property was declared
+    ASSERT(lookup.IsReadOnly());  // and it was declared as read-only
+
+    PropertyType type = lookup.type();
+    if (type == FIELD) {
+      FixedArray* properties = context_ext->properties();
+      int index = lookup.GetFieldIndex();
+      if (properties->get(index)->IsTheHole()) {
+        properties->set(index, *value);
+      }
+    } else if (type == NORMAL) {
+      Dictionary* dictionary = context_ext->property_dictionary();
+      int entry = lookup.GetDictionaryEntry();
+      if (dictionary->ValueAt(entry)->IsTheHole()) {
+        dictionary->ValueAtPut(entry, *value);
+      }
+    } else {
+      // We should not reach here. Any real, named property should be
+      // either a field or a dictionary slot.
+      UNREACHABLE();
     }
   } else {
-    // We should not reach here. Any real, named property should be
-    // either a field or a dictionary slot.
-    UNREACHABLE();
+    // The property was found in a different context extension object.
+    // Set it if it is not a read-only property.
+    if ((attributes & READ_ONLY) == 0) {
+      Handle<Object> set = SetProperty(context_ext, name, value, attributes);
+      // Setting a property might throw an exception.  Exceptions
+      // are converted to empty handles in handle operations.  We
+      // need to convert back to exceptions here.
+      if (set.is_null()) {
+        ASSERT(Top::has_pending_exception());
+        return Failure::Exception();
+      }
+    }
   }
+
   return *value;
 }
 
@@ -1022,7 +1066,7 @@
   // 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->TryFlatten(StringShape(subject));
+  subject->TryFlattenIfNotFlat(StringShape(subject));
   StringShape shape(subject);
   if (i >= static_cast<uint32_t>(subject->length(shape))) {
     return Heap::nan_value();
@@ -1493,8 +1537,8 @@
   CONVERT_CHECKED(String, pat, args[1]);
   Object* index = args[2];
 
-  sub->TryFlatten(StringShape(sub));
-  pat->TryFlatten(StringShape(pat));
+  sub->TryFlattenIfNotFlat(StringShape(sub));
+  pat->TryFlattenIfNotFlat(StringShape(pat));
 
   StringShape sub_shape(sub);
   StringShape pat_shape(pat);
@@ -1553,8 +1597,8 @@
   int d = str1->Get(shape1, 0) - str2->Get(shape2, 0);
   if (d != 0) return Smi::FromInt(d);
 
-  str1->TryFlatten(shape1);  // Shapes are no longer valid now!
-  str2->TryFlatten(shape2);
+  str1->TryFlattenIfNotFlat(shape1);  // Shapes are no longer valid now!
+  str2->TryFlattenIfNotFlat(shape2);
 
   static StringInputBuffer buf1;
   static StringInputBuffer buf2;
@@ -1691,7 +1735,7 @@
 static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
   StringShape shape(*string);
   if (index < static_cast<uint32_t>(string->length(shape))) {
-    string->TryFlatten(shape);  // Invalidates shape!
+    string->TryFlattenIfNotFlat(shape);  // Invalidates shape!
     return LookupSingleCharacterStringFromCode(
         string->Get(StringShape(*string), index));
   }
@@ -1884,7 +1928,7 @@
       result = SetElement(js_object, index, value);
     } else {
       Handle<String> key_string = Handle<String>::cast(key);
-      key_string->TryFlatten(StringShape(*key_string));
+      key_string->TryFlattenIfNotFlat(StringShape(*key_string));
       result = SetProperty(js_object, key_string, value, attr);
     }
     if (result.is_null()) return Failure::Exception();
@@ -2156,7 +2200,7 @@
   NoHandleAllocation ha;
   ASSERT(args.length() == 1);
   CONVERT_CHECKED(String, subject, args[0]);
-  subject->TryFlatten(StringShape(subject));
+  subject->TryFlattenIfNotFlat(StringShape(subject));
   return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
 }
 
@@ -2239,7 +2283,7 @@
   ASSERT(args.length() == 1);
   CONVERT_CHECKED(String, source, args[0]);
 
-  source->TryFlatten(StringShape(source));
+  source->TryFlattenIfNotFlat(StringShape(source));
 
   int escaped_length = 0;
   int length = source->length();
@@ -2353,7 +2397,7 @@
   ASSERT(args.length() == 1);
   CONVERT_CHECKED(String, source, args[0]);
 
-  source->TryFlatten(StringShape(source));
+  source->TryFlattenIfNotFlat(StringShape(source));
   StringShape source_shape(source);
 
   bool ascii = true;
@@ -2402,7 +2446,7 @@
   CONVERT_DOUBLE_CHECKED(n, args[1]);
   int radix = FastD2I(n);
 
-  s->TryFlatten(StringShape(s));
+  s->TryFlattenIfNotFlat(StringShape(s));
 
   StringShape shape(s);
 
@@ -2475,7 +2519,7 @@
   NoHandleAllocation ha;
 
   CONVERT_CHECKED(String, s, args[0]);
-  s->TryFlatten(StringShape(s));
+  s->TryFlattenIfNotFlat(StringShape(s));
   StringShape shape(s);
 
   int raw_string_length = s->length(shape);
@@ -3079,8 +3123,8 @@
   if (d < 0) return Smi::FromInt(LESS);
   else if (d > 0) return Smi::FromInt(GREATER);
 
-  x->TryFlatten(x_shape);  // Shapes are no longer valid!
-  y->TryFlatten(y_shape);
+  x->TryFlattenIfNotFlat(x_shape);  // Shapes are no longer valid!
+  y->TryFlattenIfNotFlat(y_shape);
 
   static StringInputBuffer bufx;
   static StringInputBuffer bufy;
@@ -3734,7 +3778,9 @@
   ASSERT(args.length() == 1);
 
   // First check if this is a real stack overflow.
-  if (StackGuard::IsStackOverflow()) return Runtime_StackOverflow(args);
+  if (StackGuard::IsStackOverflow()) {
+    return Runtime_StackOverflow(args);
+  }
 
   return Execution::HandleStackGuardInterrupt();
 }
@@ -4536,6 +4582,21 @@
 }
 
 
+// Find the length of the prototype chain that is to to handled as one. If a
+// prototype object is hidden it is to be viewed as part of the the object it
+// is prototype for.
+static int LocalPrototypeChainLength(JSObject* obj) {
+  int count = 1;
+  Object* proto = obj->GetPrototype();
+  while (proto->IsJSObject() &&
+         JSObject::cast(proto)->map()->is_hidden_prototype()) {
+    count++;
+    proto = JSObject::cast(proto)->GetPrototype();
+  }
+  return count;
+}
+
+
 static Object* DebugLookupResultValue(Object* receiver, LookupResult* result,
                                       bool* caught_exception) {
   Object* value;
@@ -4611,6 +4672,13 @@
   CONVERT_ARG_CHECKED(JSObject, obj, 0);
   CONVERT_ARG_CHECKED(String, name, 1);
 
+  // Skip the global proxy as it has no properties and always delegates to the
+  // real global object.
+  if (obj->IsJSGlobalProxy()) {
+    obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
+  }
+
+
   // Check if the name is trivially convertible to an index and get the element
   // if so.
   uint32_t index;
@@ -4621,9 +4689,22 @@
     return *Factory::NewJSArrayWithElements(details);
   }
 
-  // Perform standard local lookup on the object.
+  // Find the number of objects making up this.
+  int length = LocalPrototypeChainLength(*obj);
+
+  // Try local lookup on each of the objects.
   LookupResult result;
-  obj->LocalLookup(*name, &result);
+  Handle<JSObject> jsproto = obj;
+  for (int i = 0; i < length; i++) {
+    jsproto->LocalLookup(*name, &result);
+    if (result.IsProperty()) {
+      break;
+    }
+    if (i < length - 1) {
+      jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
+    }
+  }
+
   if (result.IsProperty()) {
     bool caught_exception = false;
     Handle<Object> value(DebugLookupResultValue(*obj, &result,
@@ -4676,9 +4757,43 @@
   }
   CONVERT_ARG_CHECKED(JSObject, obj, 0);
 
-  int n = obj->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
-  Handle<FixedArray> names = Factory::NewFixedArray(n);
-  obj->GetLocalPropertyNames(*names);
+  // Skip the global proxy as it has no properties and always delegates to the
+  // real global object.
+  if (obj->IsJSGlobalProxy()) {
+    obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
+  }
+
+  // Find the number of objects making up this.
+  int length = LocalPrototypeChainLength(*obj);
+
+  // Find the number of local properties for each of the objects.
+  int* local_property_count = NewArray<int>(length);
+  int total_property_count = 0;
+  Handle<JSObject> jsproto = obj;
+  for (int i = 0; i < length; i++) {
+    int n;
+    n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
+    local_property_count[i] = n;
+    total_property_count += n;
+    if (i < length - 1) {
+      jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
+    }
+  }
+
+  // Allocate an array with storage for all the property names.
+  Handle<FixedArray> names = Factory::NewFixedArray(total_property_count);
+
+  // Get the property names.
+  jsproto = obj;
+  for (int i = 0; i < length; i++) {
+    jsproto->GetLocalPropertyNames(*names,
+                                   i == 0 ? 0 : local_property_count[i - 1]);
+    if (i < length - 1) {
+      jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
+    }
+  }
+
+  DeleteArray(local_property_count);
   return *Factory::NewJSArrayWithElements(names);
 }
 
@@ -5806,12 +5921,15 @@
 }
 
 
-static Object* Runtime_GetPrototype(Arguments args) {
+// Find the effective prototype object as returned by __proto__.
+// args[0]: the object to find the prototype for.
+static Object* Runtime_DebugGetPrototype(Arguments args) {
   ASSERT(args.length() == 1);
 
   CONVERT_CHECKED(JSObject, obj, args[0]);
 
-  return obj->GetPrototype();
+  // Use the __proto__ accessor.
+  return Accessors::ObjectPrototype.getter(obj, NULL);
 }
 
 
diff --git a/src/runtime.h b/src/runtime.h
index ebe70a4..1924317 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -244,7 +244,7 @@
   F(DebugGetLoadedScripts, 0) \
   F(DebugReferencedBy, 3) \
   F(DebugConstructedBy, 2) \
-  F(GetPrototype, 1) \
+  F(DebugGetPrototype, 1) \
   F(SystemBreak, 0) \
   \
   /* Literals */ \
diff --git a/src/serialize.cc b/src/serialize.cc
index 4e1529c..be85ea6 100644
--- a/src/serialize.cc
+++ b/src/serialize.cc
@@ -686,15 +686,15 @@
   SnapshotWriter() {
     len_ = 0;
     max_ = 8 << 10;  // 8K initial size
-    str_ = NewArray<char>(max_);
+    str_ = NewArray<byte>(max_);
   }
 
   ~SnapshotWriter() {
     DeleteArray(str_);
   }
 
-  void GetString(char** str, int* len) {
-    *str = NewArray<char>(len_);
+  void GetBytes(byte** str, int* len) {
+    *str = NewArray<byte>(len_);
     memcpy(*str, str_, len_);
     *len = len_;
   }
@@ -742,7 +742,7 @@
   Address position() { return reinterpret_cast<Address>(&str_[len_]); }
 
  private:
-  char* str_;  // the snapshot
+  byte* str_;  // the snapshot
   int len_;   // the current length of str_
   int max_;   // the allocated size of str_
 };
@@ -752,14 +752,14 @@
   CHECK(0 <= pos && pos <= len_);
   while (len_ + bytes >= max_) {
     max_ *= 2;
-    char* old = str_;
-    str_ = NewArray<char>(max_);
+    byte* old = str_;
+    str_ = NewArray<byte>(max_);
     memcpy(str_, old, len_);
     DeleteArray(old);
   }
   if (pos < len_) {
-    char* old = str_;
-    str_ = NewArray<char>(max_);
+    byte* old = str_;
+    str_ = NewArray<byte>(max_);
     memcpy(str_, old, pos);
     memcpy(str_ + pos + bytes, old + pos, len_ - pos);
     DeleteArray(old);
@@ -814,8 +814,7 @@
 
   void Update(Address start_address) {
     for (int i = 0; i < offsets_.length(); i++) {
-      Address* p = reinterpret_cast<Address*>(start_address + offsets_[i]);
-      *p = addresses_[i];
+      memcpy(start_address + offsets_[i], &addresses_[i], sizeof(Address));
     }
   }
 
@@ -929,8 +928,8 @@
 }
 
 
-void Serializer::Finalize(char** str, int* len) {
-  writer_->GetString(str, len);
+void Serializer::Finalize(byte** str, int* len) {
+  writer_->GetBytes(str, len);
 }
 
 
@@ -1180,7 +1179,7 @@
 static const int kInitArraySize = 32;
 
 
-Deserializer::Deserializer(const char* str, int len)
+Deserializer::Deserializer(const byte* str, int len)
   : reader_(str, len),
     map_pages_(kInitArraySize),
     old_pointer_pages_(kInitArraySize),
diff --git a/src/serialize.h b/src/serialize.h
index 0679ecc..18d36f3 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -135,7 +135,7 @@
 
   // Returns the serialized buffer. Ownership is transferred to the
   // caller. Only the destructor and getters may be called after this call.
-  void Finalize(char** str, int* len);
+  void Finalize(byte** str, int* len);
 
   int roots() { return roots_; }
   int objects() { return objects_; }
@@ -211,7 +211,7 @@
 
 class SnapshotReader {
  public:
-  SnapshotReader(const char* str, int len): str_(str), end_(str + len) {}
+  SnapshotReader(const byte* str, int len): str_(str), end_(str + len) {}
 
   void ExpectC(char expected) {
     int c = GetC();
@@ -225,8 +225,8 @@
   }
 
   int GetInt() {
-    int result = *reinterpret_cast<const int*>(str_);
-    str_ += sizeof(result);
+    int result;
+    GetBytes(reinterpret_cast<Address>(&result), sizeof(result));
     return result;
   }
 
@@ -247,8 +247,8 @@
   }
 
  private:
-  const char* str_;
-  const char* end_;
+  const byte* str_;
+  const byte* end_;
 };
 
 
@@ -257,7 +257,7 @@
 class Deserializer: public ObjectVisitor {
  public:
   // Create a deserializer. The snapshot is held in str and has size len.
-  Deserializer(const char* str, int len);
+  Deserializer(const byte* str, int len);
 
   virtual ~Deserializer();
 
diff --git a/src/snapshot-common.cc b/src/snapshot-common.cc
index b0e9323..3aa1cae 100644
--- a/src/snapshot-common.cc
+++ b/src/snapshot-common.cc
@@ -35,7 +35,7 @@
 
 namespace v8 { namespace internal {
 
-bool Snapshot::Deserialize(const char* content, int len) {
+bool Snapshot::Deserialize(const byte* content, int len) {
   Deserializer des(content, len);
   des.GetFlags();
   return V8::Initialize(&des);
@@ -45,7 +45,7 @@
 bool Snapshot::Initialize(const char* snapshot_file) {
   if (snapshot_file) {
     int len;
-    char* str = ReadChars(snapshot_file, &len);
+    byte* str = ReadBytes(snapshot_file, &len);
     if (!str) return false;
     bool result = Deserialize(str, len);
     DeleteArray(str);
@@ -60,11 +60,11 @@
 bool Snapshot::WriteToFile(const char* snapshot_file) {
   Serializer ser;
   ser.Serialize();
-  char* str;
+  byte* str;
   int len;
   ser.Finalize(&str, &len);
 
-  int written = WriteChars(snapshot_file, str, len);
+  int written = WriteBytes(snapshot_file, str, len);
 
   DeleteArray(str);
   return written == len;
diff --git a/src/snapshot-empty.cc b/src/snapshot-empty.cc
index 1c8ec5f..d4cda19 100644
--- a/src/snapshot-empty.cc
+++ b/src/snapshot-empty.cc
@@ -33,7 +33,7 @@
 
 namespace v8 { namespace internal {
 
-const char Snapshot::data_[] = { 0 };
+const byte Snapshot::data_[] = { 0 };
 int Snapshot::size_ = 0;
 
 } }  // namespace v8::internal
diff --git a/src/snapshot.h b/src/snapshot.h
index 2d8b9ac..b3f23d3 100644
--- a/src/snapshot.h
+++ b/src/snapshot.h
@@ -45,10 +45,10 @@
   static bool WriteToFile(const char* snapshot_file);
 
  private:
-  static const char data_[];
+  static const byte data_[];
   static int size_;
 
-  static bool Deserialize(const char* content, int len);
+  static bool Deserialize(const byte* content, int len);
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(Snapshot);
 };
diff --git a/src/string.js b/src/string.js
index 614d541..c90c0b4 100644
--- a/src/string.js
+++ b/src/string.js
@@ -572,6 +572,9 @@
     if (ovector == null) return null;
     var nof_results = ovector.length >> 1;
     var result = new $Array(nof_results + 1);
+    // Section 15.5.4.14 paragraph two says that we do not allow zero length
+    // matches at the end of the string.
+    if (ovector[0] === subject.length) return null;
     result[0] = ovector[1];
     result[1] = subject.slice(current_index, ovector[0]);
     for (var i = 1; i < nof_results; i++) {
diff --git a/src/top.cc b/src/top.cc
index d339591..76c608e 100644
--- a/src/top.cc
+++ b/src/top.cc
@@ -37,7 +37,7 @@
 namespace v8 { namespace internal {
 
 ThreadLocalTop Top::thread_local_;
-Mutex* Top::break_access_;
+Mutex* Top::break_access_ = OS::CreateMutex();
 StackFrame::Id Top::break_frame_id_;
 int Top::break_count_;
 int Top::break_id_;
@@ -225,7 +225,6 @@
 
   InitializeThreadLocal();
 
-  break_access_ = OS::CreateMutex();
   break_frame_id_ = StackFrame::NO_ID;
   break_count_ = 0;
   break_id_ = 0;
diff --git a/src/utils.cc b/src/utils.cc
index 9310301..3920320 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -182,8 +182,9 @@
 }
 
 
-char* ReadChars(const char* filename, int* size, bool verbose) {
-  return ReadCharsFromFile(filename, size, 0, verbose);
+byte* ReadBytes(const char* filename, int* size, bool verbose) {
+  char* chars = ReadCharsFromFile(filename, size, 0, verbose);
+  return reinterpret_cast<byte*>(chars);
 }
 
 
@@ -233,6 +234,15 @@
 }
 
 
+int WriteBytes(const char* filename,
+               const byte* bytes,
+               int size,
+               bool verbose) {
+  const char* str = reinterpret_cast<const char*>(bytes);
+  return WriteChars(filename, str, size, verbose);
+}
+
+
 StringBuilder::StringBuilder(int size) {
   buffer_ = Vector<char>::New(size);
   position_ = 0;
diff --git a/src/utils.h b/src/utils.h
index 9861246..f62b47a 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -224,10 +224,10 @@
 char* ReadLine(const char* prompt);
 
 
-// Read and return the raw chars in a file. the size of the buffer is returned
+// Read and return the raw bytes in a file. the size of the buffer is returned
 // in size.
-// The returned buffer is not 0-terminated. It must be freed by the caller.
-char* ReadChars(const char* filename, int* size, bool verbose = true);
+// The returned buffer must be freed by the caller.
+byte* ReadBytes(const char* filename, int* size, bool verbose = true);
 
 
 // Write size chars from str to the file given by filename.
@@ -238,6 +238,14 @@
                bool verbose = true);
 
 
+// Write size bytes to the file given by filename.
+// The file is overwritten. Returns the number of bytes written.
+int WriteBytes(const char* filename,
+               const byte* bytes,
+               int size,
+               bool verbose = true);
+
+
 // Write the C code
 // const char* <varname> = "<str>";
 // const int <varname>_len = <len>;
@@ -527,55 +535,6 @@
 }
 
 
-static inline int Load16(const byte* ptr) {
-#ifdef CAN_READ_UNALIGNED
-  return *reinterpret_cast<const uint16_t*>(ptr);
-#else
-  uint32_t word;
-  word  = ptr[1];
-  word |= ptr[0] << 8;
-  return word;
-#endif
-}
-
-
-static inline int Load32(const byte* ptr) {
-#ifdef CAN_READ_UNALIGNED
-  return *reinterpret_cast<const uint32_t*>(ptr);
-#else
-  uint32_t word;
-  word  = ptr[3];
-  word |= ptr[2] << 8;
-  word |= ptr[1] << 16;
-  word |= ptr[0] << 24;
-  return word;
-#endif
-}
-
-
-static inline void Store16(byte* ptr, uint16_t value) {
-#ifdef CAN_READ_UNALIGNED
-  *reinterpret_cast<uint16_t*>(ptr) = value;
-#else
-  // Cast to avoid warning C4244 when compiling with Microsoft Visual C++.
-  ptr[1] = static_cast<byte>(value);
-  ptr[0] = value >> 8;
-#endif
-}
-
-
-static inline void Store32(byte* ptr, uint32_t value) {
-#ifdef CAN_READ_UNALIGNED
-  *reinterpret_cast<uint32_t*>(ptr) = value;
-#else
-  ptr[3] = value;
-  ptr[2] = value >> 8;
-  ptr[1] = value >> 16;
-  ptr[0] = value >> 24;
-#endif
-}
-
-
 } }  // namespace v8::internal
 
 #endif  // V8_UTILS_H_
diff --git a/src/v8threads.cc b/src/v8threads.cc
index 0a6c7c1..df0095d 100644
--- a/src/v8threads.cc
+++ b/src/v8threads.cc
@@ -28,6 +28,7 @@
 #include "v8.h"
 
 #include "api.h"
+#include "bootstrapper.h"
 #include "debug.h"
 #include "execution.h"
 #include "v8threads.h"
@@ -38,9 +39,17 @@
 static internal::Thread::LocalStorageKey thread_state_key =
     internal::Thread::CreateThreadLocalKey();
 
+
+// Track whether this V8 instance has ever called v8::Locker. This allows the
+// API code to verify that the lock is always held when V8 is being entered.
+bool Locker::active_ = false;
+
+
 // Constructor for the Locker object.  Once the Locker is constructed the
 // current thread will be guaranteed to have the big V8 lock.
 Locker::Locker() : has_lock_(false), top_level_(true) {
+  // Record that the Locker has been used at least once.
+  active_ = true;
   // Get the big lock if necessary.
   if (!internal::ThreadManager::IsLockedByCurrentThread()) {
     internal::ThreadManager::Lock();
@@ -111,6 +120,11 @@
     Thread::SetThreadLocal(thread_state_key, NULL);
     return true;
   }
+
+  // Make sure that the preemption thread cannot modify the thread state while
+  // it is being archived or restored.
+  ExecutionAccess access;
+
   // If there is another thread that was lazily archived then we have to really
   // archive it now.
   if (lazily_archived_thread_.IsValid()) {
@@ -127,6 +141,7 @@
   from = Debug::RestoreDebug(from);
   from = StackGuard::RestoreStackGuard(from);
   from = RegExpStack::RestoreStack(from);
+  from = Bootstrapper::RestoreState(from);
   Thread::SetThreadLocal(thread_state_key, NULL);
   state->Unlink();
   state->LinkInto(ThreadState::FREE_LIST);
@@ -152,7 +167,8 @@
                             Top::ArchiveSpacePerThread() +
                           Debug::ArchiveSpacePerThread() +
                      StackGuard::ArchiveSpacePerThread() +
-                    RegExpStack::ArchiveSpacePerThread();
+                    RegExpStack::ArchiveSpacePerThread() +
+                   Bootstrapper::ArchiveSpacePerThread();
 }
 
 
@@ -234,6 +250,7 @@
   to = Debug::ArchiveDebug(to);
   to = StackGuard::ArchiveStackGuard(to);
   to = RegExpStack::ArchiveStack(to);
+  to = Bootstrapper::ArchiveState(to);
   lazily_archived_thread_.Initialize(ThreadHandle::INVALID);
   lazily_archived_thread_state_ = NULL;
 }
diff --git a/test/cctest/cctest.status b/test/cctest/cctest.status
index 9a528d3..2be0fd0 100644
--- a/test/cctest/cctest.status
+++ b/test/cctest/cctest.status
@@ -33,7 +33,6 @@
 [ $arch == arm ]
 
 test-debug: SKIP
-test-serialize: SKIP
 
 # BUG(113): Test seems flaky on ARM.
 test-spaces/LargeObjectSpace: PASS || FAIL
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index 19f702a..942ae05 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -5607,3 +5607,36 @@
     CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
   }
 }
+
+
+// Test that cross-context new calls use the context of the callee to
+// create the new JavaScript object.
+THREADED_TEST(CrossContextNew) {
+  v8::HandleScope scope;
+  v8::Persistent<Context> context0 = Context::New();
+  v8::Persistent<Context> context1 = Context::New();
+
+  // Allow cross-domain access.
+  Local<String> token = v8_str("<security token>");
+  context0->SetSecurityToken(token);
+  context1->SetSecurityToken(token);
+
+  // Set an 'x' property on the Object prototype and define a
+  // constructor function in context0.
+  context0->Enter();
+  CompileRun("Object.prototype.x = 42; function C() {};");
+  context0->Exit();
+
+  // Call the constructor function from context0 and check that the
+  // result has the 'x' property.
+  context1->Enter();
+  context1->Global()->Set(v8_str("other"), context0->Global());
+  Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
+  CHECK(value->IsInt32());
+  CHECK_EQ(42, value->Int32Value());
+  context1->Exit();
+
+  // Dispose the contexts to allow them to be garbage collected.
+  context0.Dispose();
+  context1.Dispose();
+}
diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc
index cd85b8f..15ebf16 100644
--- a/test/cctest/test-debug.cc
+++ b/test/cctest/test-debug.cc
@@ -2749,6 +2749,101 @@
 }
 
 
+TEST(HiddenPrototypePropertyMirror) {
+  // Create a V8 environment with debug access.
+  v8::HandleScope scope;
+  DebugLocalContext env;
+  env.ExposeDebug();
+
+  v8::Handle<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
+  t0->InstanceTemplate()->Set(v8::String::New("x"), v8::Number::New(0));
+  v8::Handle<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
+  t1->SetHiddenPrototype(true);
+  t1->InstanceTemplate()->Set(v8::String::New("y"), v8::Number::New(1));
+  v8::Handle<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
+  t2->SetHiddenPrototype(true);
+  t2->InstanceTemplate()->Set(v8::String::New("z"), v8::Number::New(2));
+  v8::Handle<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
+  t3->InstanceTemplate()->Set(v8::String::New("u"), v8::Number::New(3));
+
+  // Create object and set them on the global object.
+  v8::Handle<v8::Object> o0 = t0->GetFunction()->NewInstance();
+  env->Global()->Set(v8::String::New("o0"), o0);
+  v8::Handle<v8::Object> o1 = t1->GetFunction()->NewInstance();
+  env->Global()->Set(v8::String::New("o1"), o1);
+  v8::Handle<v8::Object> o2 = t2->GetFunction()->NewInstance();
+  env->Global()->Set(v8::String::New("o2"), o2);
+  v8::Handle<v8::Object> o3 = t3->GetFunction()->NewInstance();
+  env->Global()->Set(v8::String::New("o3"), o3);
+
+  // Get mirrors for the four objects.
+  CompileRun(
+      "o0_mirror = debug.MakeMirror(o0);"
+      "o1_mirror = debug.MakeMirror(o1);"
+      "o2_mirror = debug.MakeMirror(o2);"
+      "o3_mirror = debug.MakeMirror(o3)");
+  CHECK(CompileRun("o0_mirror instanceof debug.ObjectMirror")->BooleanValue());
+  CHECK(CompileRun("o1_mirror instanceof debug.ObjectMirror")->BooleanValue());
+  CHECK(CompileRun("o2_mirror instanceof debug.ObjectMirror")->BooleanValue());
+  CHECK(CompileRun("o3_mirror instanceof debug.ObjectMirror")->BooleanValue());
+
+  // Check that each object has one property.
+  CHECK_EQ(1, CompileRun(
+              "o0_mirror.propertyNames().length")->Int32Value());
+  CHECK_EQ(1, CompileRun(
+              "o1_mirror.propertyNames().length")->Int32Value());
+  CHECK_EQ(1, CompileRun(
+              "o2_mirror.propertyNames().length")->Int32Value());
+  CHECK_EQ(1, CompileRun(
+              "o3_mirror.propertyNames().length")->Int32Value());
+
+  // Set o1 as prototype for o0. o1 has the hidden prototype flag so all
+  // properties on o1 should be seen on o0.
+  o0->Set(v8::String::New("__proto__"), o1);
+  CHECK_EQ(2, CompileRun(
+              "o0_mirror.propertyNames().length")->Int32Value());
+  CHECK_EQ(0, CompileRun(
+              "o0_mirror.property('x').value().value()")->Int32Value());
+  CHECK_EQ(1, CompileRun(
+              "o0_mirror.property('y').value().value()")->Int32Value());
+
+  // Set o2 as prototype for o0 (it will end up after o1 as o1 has the hidden
+  // prototype flag. o2 also has the hidden prototype flag so all properties
+  // on o2 should be seen on o0 as well as properties on o1.
+  o0->Set(v8::String::New("__proto__"), o2);
+  CHECK_EQ(3, CompileRun(
+              "o0_mirror.propertyNames().length")->Int32Value());
+  CHECK_EQ(0, CompileRun(
+              "o0_mirror.property('x').value().value()")->Int32Value());
+  CHECK_EQ(1, CompileRun(
+              "o0_mirror.property('y').value().value()")->Int32Value());
+  CHECK_EQ(2, CompileRun(
+              "o0_mirror.property('z').value().value()")->Int32Value());
+
+  // Set o3 as prototype for o0 (it will end up after o1 and o2 as both o1 and
+  // o2 has the hidden prototype flag. o3 does not have the hidden prototype
+  // flag so properties on o3 should not be seen on o0 whereas the properties
+  // from o1 and o2 should still be seen on o0.
+  // Final prototype chain: o0 -> o1 -> o2 -> o3
+  // Hidden prototypes:           ^^    ^^
+  o0->Set(v8::String::New("__proto__"), o3);
+  CHECK_EQ(3, CompileRun(
+              "o0_mirror.propertyNames().length")->Int32Value());
+  CHECK_EQ(1, CompileRun(
+              "o3_mirror.propertyNames().length")->Int32Value());
+  CHECK_EQ(0, CompileRun(
+              "o0_mirror.property('x').value().value()")->Int32Value());
+  CHECK_EQ(1, CompileRun(
+              "o0_mirror.property('y').value().value()")->Int32Value());
+  CHECK_EQ(2, CompileRun(
+              "o0_mirror.property('z').value().value()")->Int32Value());
+  CHECK(CompileRun("o0_mirror.property('u').isUndefined()")->BooleanValue());
+
+  // The prototype (__proto__) for o0 should be o3 as o1 and o2 are hidden.
+  CHECK(CompileRun("o0_mirror.protoObject() == o3_mirror")->BooleanValue());
+}
+
+
 // Multithreaded tests of JSON debugger protocol
 
 // Support classes
diff --git a/test/mjsunit/ascii-regexp-subject.js b/test/mjsunit/ascii-regexp-subject.js
index 01d0697..e0c2f84 100644
--- a/test/mjsunit/ascii-regexp-subject.js
+++ b/test/mjsunit/ascii-regexp-subject.js
@@ -37,9 +37,13 @@
   s = s + s;
 }
 
-var re = /^bar/;
-
-for (i = 0; i < 1000; i++) {
-  re.test(s);
-  re = new RegExp("^bar");
+function repeatRegexp(re) {
+  for (i = 0; i < 1000; i++) {
+    re.test(s);
+  }
 }
+
+repeatRegexp(/^bar/);
+repeatRegexp(/^foo|^bar|^baz/);
+repeatRegexp(/(^bar)/);
+repeatRegexp(/(?=^bar)\w+/);
diff --git a/test/mjsunit/const-eval-init.js b/test/mjsunit/const-eval-init.js
new file mode 100644
index 0000000..d3636de
--- /dev/null
+++ b/test/mjsunit/const-eval-init.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 the handling of initialization of deleted const variables.
+// This only makes sense in local scopes since the declaration and
+// initialization of consts in the global scope happen at the same
+// time.
+
+function testIntroduceGlobal() {
+  var source =
+      // Deleting 'x' removes the local const property.
+      "delete x;" +
+      // Initialization turns into assignment to global 'x'.
+      "const x = 3; assertEquals(3, x);" +
+      // No constness of the global 'x'.
+      "x = 4; assertEquals(4, x);";
+  eval(source);
+}
+
+testIntroduceGlobal();
+assertEquals(4, x);
+
+function testAssignExistingGlobal() {
+  var source =
+      // Delete 'x' to remove the local const property.
+      "delete x;" +
+      // Initialization turns into assignment to global 'x'.
+      "const x = 5; assertEquals(5, x);" +
+      // No constness of the global 'x'.
+      "x = 6; assertEquals(6, x);";
+  eval(source);
+}
+
+testAssignExistingGlobal();
+assertEquals(6, x);
+
+function testAssignmentArgument(x) {
+  function local() {
+    var source = "delete x; const x = 7; assertEquals(7, x)";
+    eval(source);
+  }
+  local();
+  assertEquals(7, x);
+}
+
+testAssignmentArgument();
+assertEquals(6, x);
+
+__defineSetter__('x', function() { throw 42; });
+function testAssignGlobalThrows() {
+  // Initialization turns into assignment to global 'x' which
+  // throws an exception.
+  var source = "delete x; const x = 8";
+  eval(source);
+}
+
+assertThrows("testAssignGlobalThrows()");
+
+function testInitFastCaseExtension() {
+  var source = "const x = 9; assertEquals(9, x); x = 10; assertEquals(9, x)";
+  eval(source);
+}
+
+testInitFastCaseExtension();
+
+function testInitSlowCaseExtension() {
+  var source = "";
+  // Introduce 100 properties on the context extension object to force
+  // it in slow case.
+  for (var i = 0; i < 100; i++) source += ("var a" + i + " = i;");
+  source += "const x = 10; assertEquals(10, x); x = 11; assertEquals(10, x)";
+  eval(source);
+}
+
+testInitSlowCaseExtension();
+
+function testAssignSurroundingContextSlot() {
+  var x = 12;
+  function local() {
+    var source = "delete x; const x = 13; assertEquals(13, x)";
+    eval(source);
+  }
+  local();
+  assertEquals(13, x);
+}
+
+testAssignSurroundingContextSlot();
diff --git a/test/mjsunit/const.js b/test/mjsunit/const.js
index 5ad0c9c..a48e82d 100644
--- a/test/mjsunit/const.js
+++ b/test/mjsunit/const.js
@@ -52,17 +52,19 @@
 function g() {
   const o = { valueOf: function() { valueOfCount++; return 42; } }
   assertEquals(42, o);
-  assertEquals(0, valueOfCount);
+  assertEquals(1, valueOfCount);
   o++;
   assertEquals(42, o);
-  assertEquals(1, valueOfCount);
+  assertEquals(3, valueOfCount);
   ++o;
   assertEquals(42, o);
-  assertEquals(2, valueOfCount);
+  assertEquals(5, valueOfCount);
   o--;
   assertEquals(42, o);
-  assertEquals(3, valueOfCount);
+  assertEquals(7, valueOfCount);
   --o;
   assertEquals(42, o);
-  assertEquals(4, valueOfCount);
+  assertEquals(9, valueOfCount);
 }
+
+g();
diff --git a/test/mjsunit/debug-handle.js b/test/mjsunit/debug-handle.js
new file mode 100644
index 0000000..7732bfd
--- /dev/null
+++ b/test/mjsunit/debug-handle.js
@@ -0,0 +1,199 @@
+// 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: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+listenerComplete = false;
+exception = false;
+
+function safeEval(code) {
+  try {
+    return eval('(' + code + ')');
+  } catch (e) {
+    assertEquals(void 0, e);
+    return undefined;
+  }
+}
+
+
+// Send an evaluation request and return the handle of the result.
+function evaluateRequest(dcp, arguments) {
+  // The base part of all evaluate requests.
+  var base_request = '"seq":0,"type":"request","command":"evaluate"'
+
+  // Generate request with the supplied arguments.
+  var request;
+  if (arguments) {
+    request = '{' + base_request + ',"arguments":' + arguments + '}';
+  } else {
+    request = '{' + base_request + '}'
+  }
+
+  var response = safeEval(dcp.processDebugJSONRequest(request));
+  assertTrue(response.success, request + ' -> ' + response.message);
+
+  return response.body.handle;
+}
+
+
+// Send a lookup request and return the evaluated JSON response.
+function lookupRequest(dcp, arguments, success) {
+  // The base part of all lookup requests.
+  var base_request = '"seq":0,"type":"request","command":"lookup"'
+  
+  // Generate request with the supplied arguments.
+  var request;
+  if (arguments) {
+    request = '{' + base_request + ',"arguments":' + arguments + '}';
+  } else {
+    request = '{' + base_request + '}'
+  }
+
+  var response = safeEval(dcp.processDebugJSONRequest(request));
+  if (success) {
+    assertTrue(response.success, request + ' -> ' + response.message);
+  } else {
+    assertFalse(response.success, request + ' -> ' + response.message);
+  }
+  assertFalse(response.running, request + ' -> expected not running');
+
+  return response;
+}
+
+
+function listener(event, exec_state, event_data, data) {
+  try {
+  if (event == Debug.DebugEvent.Break) {
+    // Get the debug command processor.
+    var dcp = exec_state.debugCommandProcessor();
+
+    // Test some illegal lookup requests.
+    lookupRequest(dcp, void 0, false);
+    lookupRequest(dcp, '{"handle":"a"}', false);
+    lookupRequest(dcp, '{"handle":-1}', false);
+
+    // Evaluate and get some handles.
+    var handle_o = evaluateRequest(dcp, '{"expression":"o"}');
+    var handle_p = evaluateRequest(dcp, '{"expression":"p"}');
+    var handle_b = evaluateRequest(dcp, '{"expression":"a"}');
+    var handle_a = evaluateRequest(dcp, '{"expression":"b","frame":1}');
+    assertEquals(handle_o, handle_a);
+    assertEquals(handle_a, handle_b);
+    assertFalse(handle_o == handle_p, "o and p have he same handle");
+
+    var response;
+    var count;
+    response = lookupRequest(dcp, '{"handle":' + handle_o + '}', true);
+    assertEquals(handle_o, response.body.handle);
+    count = 0;
+    for (i in response.body.properties) {
+      switch (response.body.properties[i].name) {
+        case 'o':
+          response.body.properties[i].ref = handle_o;
+          count++;
+          break;
+        case 'p':
+          response.body.properties[i].ref = handle_p;
+          count++;
+          break;
+      }
+    }
+    assertEquals(2, count, 'Either "o" or "p" not found');
+    response = lookupRequest(dcp, '{"handle":' + handle_p + '}', true);
+    assertEquals(handle_p, response.body.handle);
+
+    // Check handles for functions on the stack.
+    var handle_f = evaluateRequest(dcp, '{"expression":"f"}');
+    var handle_g = evaluateRequest(dcp, '{"expression":"g"}');
+    var handle_caller = evaluateRequest(dcp, '{"expression":"f.caller"}');
+
+    assertFalse(handle_f == handle_g, "f and g have he same handle");
+    assertEquals(handle_g, handle_caller, "caller for f should be g");
+
+    response = lookupRequest(dcp, '{"handle":' + handle_f + '}', true);
+    assertEquals(handle_f, response.body.handle);
+    count = 0;
+    for (i in response.body.properties) {
+      var arguments = '{"handle":' + response.body.properties[i].ref + '}'
+      switch (response.body.properties[i].name) {
+        case 'name':
+          var response_name;
+          response_name = lookupRequest(dcp, arguments, true);
+          assertEquals('string', response_name.body.type);
+          assertEquals("f", response_name.body.value);
+          count++;
+          break;
+        case 'length':
+          var response_length;
+          response_length = lookupRequest(dcp, arguments, true);
+          assertEquals('number', response_length.body.type);
+          assertEquals(1, response_length.body.value);
+          count++;
+          break;
+        case 'caller':
+          assertEquals(handle_g, response.body.properties[i].ref);
+          count++;
+          break;
+      }
+    }
+    assertEquals(3, count, 'Either "name", "length" or "caller" not found');
+
+
+    // Indicate that all was processed.
+    listenerComplete = true;
+  }
+  } catch (e) {
+    exception = e
+  };
+};
+
+// Add the debug event listener.
+Debug.addListener(listener);
+
+function f(a) {
+  debugger;
+};
+
+function g(b) {
+  f(b);
+};
+
+// Set a break point at return in f and invoke g to hit the breakpoint.
+Debug.setBreakPoint(f, 2, 0);
+o = {};
+p = {}
+o.o = o;
+o.p = p;
+p.o = o;
+p.p = p;
+g(o);
+
+// Make sure that the debug event listener vas invoked.
+assertTrue(listenerComplete, "listener did not run to completion");
+assertFalse(exception, "exception in listener")
diff --git a/test/mjsunit/mirror-number.js b/test/mjsunit/mirror-number.js
index 33488ef..68eb0d7 100644
--- a/test/mjsunit/mirror-number.js
+++ b/test/mjsunit/mirror-number.js
@@ -53,7 +53,15 @@
   if (!isNaN(n)) {
     assertEquals(n, fromJSON.value);
   } else {
-    assertTrue(isNaN(fromJSON.value));
+    // NaN values are encoded as strings.
+    assertTrue(typeof fromJSON.value == 'string');
+    if (n === Infinity) {
+      assertEquals('Infinity', fromJSON.value);
+    } else if (n === -Infinity) {
+      assertEquals('-Infinity', fromJSON.value);
+    } else {
+      assertEquals('NaN', fromJSON.value);
+    }
   }
 }
 
diff --git a/test/mjsunit/mirror-object.js b/test/mjsunit/mirror-object.js
index ec5afa3..e829a0e 100644
--- a/test/mjsunit/mirror-object.js
+++ b/test/mjsunit/mirror-object.js
@@ -135,7 +135,12 @@
 
         assertEquals(properties[i].value().type(), o.type, 'Unexpected serialized property type for ' + name);
         if (properties[i].value().isPrimitive()) {
-          assertEquals(properties[i].value().value(), o.value, 'Unexpected serialized property value for ' + name);
+          // Special check for NaN as NaN == NaN is false.
+          if (properties[i].value().isNumber() && isNaN(properties[i].value().value())) {
+            assertEquals('NaN', o.value, 'Unexpected serialized property value for ' + name);
+          } else {
+            assertEquals(properties[i].value().value(), o.value, 'Unexpected serialized property value for ' + name);
+          }
         } else if (properties[i].value().isFunction()) {
           assertEquals(properties[i].value().source(), o.source, 'Unexpected serialized property value for ' + name);
         }
@@ -159,6 +164,7 @@
 testObjectMirror({'1':void 0,'2':null,'f':function pow(x,y){return Math.pow(x,y);}}, 'Object', 'Object');
 testObjectMirror(new Point(-1.2,2.003), 'Object', 'Point');
 testObjectMirror(this, 'global', '', true);  // Global object has special properties
+testObjectMirror(this.__proto__, 'Object', '');
 testObjectMirror([], 'Array', 'Array');
 testObjectMirror([1,2], 'Array', 'Array');
 
diff --git a/test/mjsunit/mjsunit.status b/test/mjsunit/mjsunit.status
index c354300..27dfc14 100644
--- a/test/mjsunit/mjsunit.status
+++ b/test/mjsunit/mjsunit.status
@@ -63,6 +63,7 @@
 debug-stepin-constructor: CRASH, FAIL
 debug-step: SKIP
 debug-breakpoints: PASS || FAIL
+debug-handle: CRASH, FAIL if $mode == debug
 
 # Bug number 130 http://code.google.com/p/v8/issues/detail?id=130
 # Fails on real ARM hardware but not on the simulator.
diff --git a/test/mjsunit/regexp-capture.js b/test/mjsunit/regexp-capture.js
new file mode 100755
index 0000000..7227186
--- /dev/null
+++ b/test/mjsunit/regexp-capture.js
@@ -0,0 +1,52 @@
+// 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.

+

+// Tests from http://blog.stevenlevithan.com/archives/npcg-javascript

+

+assertEquals(true, /(x)?\1y/.test("y"));

+assertEquals(["y", undefined], /(x)?\1y/.exec("y"));

+assertEquals(["y", undefined], /(x)?y/.exec("y"));

+assertEquals(["y", undefined], "y".match(/(x)?\1y/));

+assertEquals(["y", undefined], "y".match(/(x)?y/));

+assertEquals(["y"], "y".match(/(x)?\1y/g));

+assertEquals(["", undefined, ""], "y".split(/(x)?\1y/));

+assertEquals(["", undefined, ""], "y".split(/(x)?y/));

+assertEquals(0, "y".search(/(x)?\1y/));

+assertEquals("z", "y".replace(/(x)?\1y/, "z"));

+assertEquals("", "y".replace(/(x)?y/, "$1"));

+assertEquals("undefined", "y".replace(/(x)?\1y/,

+    function($0, $1){ 

+        return String($1); 

+    }));

+assertEquals("undefined", "y".replace(/(x)?y/, 

+    function($0, $1){ 

+        return String($1); 

+    }));

+assertEquals("undefined", "y".replace(/(x)?y/, 

+    function($0, $1){ 

+        return $1; 

+    }));

diff --git a/test/mjsunit/regexp-lookahead.js b/test/mjsunit/regexp-lookahead.js
new file mode 100644
index 0000000..1188b56
--- /dev/null
+++ b/test/mjsunit/regexp-lookahead.js
@@ -0,0 +1,166 @@
+// 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.
+
+// Tests captures in positive and negative look-ahead in regular expressions.
+
+function stringEscape(string) {
+  // Converts string to source literal.
+  return '"' + string.replace(/["\\]/g, "\\$1") + '"';
+}
+
+function testRE(re, input, expected_result) {
+  var testName = re + ".test(" + stringEscape(input) +")";
+  if (expected_result) {
+    assertTrue(re.test(input), testName);
+  } else {
+    assertFalse(re.test(input), testName);
+  }
+}
+
+function execRE(re, input, expected_result) {
+  var testName = re + ".exec('" + stringEscape(input) +"')";
+  assertEquals(expected_result, re.exec(input), testName);
+}
+
+// Test of simple positive lookahead.
+
+var re = /^(?=a)/;
+testRE(re, "a", true);
+testRE(re, "b", false);
+execRE(re, "a", [""]);
+
+re = /^(?=\woo)f\w/;
+testRE(re, "foo", true);
+testRE(re, "boo", false);
+testRE(re, "fao", false);
+testRE(re, "foa", false);
+execRE(re, "foo", ["fo"]);
+
+re = /(?=\w).(?=\W)/;
+testRE(re, ".a! ", true);
+testRE(re, ".! ", false);
+testRE(re, ".ab! ", true);
+execRE(re, ".ab! ", ["b"]);
+
+re = /(?=f(?=[^f]o))../;
+testRE(re, ", foo!", true);
+testRE(re, ", fo!", false);
+testRE(re, ", ffo", false);
+execRE(re, ", foo!", ["fo"]);
+
+// Positive lookahead with captures.
+re = /^[^\'\"]*(?=([\'\"])).*\1(\w+)\1/;
+testRE(re, "  'foo' ", true);
+testRE(re, '  "foo" ', true);
+testRE(re, " \" 'foo' ", false);
+testRE(re, " ' \"foo\" ", false);
+testRE(re, "  'foo\" ", false);
+testRE(re, "  \"foo' ", false);
+execRE(re, "  'foo' ", ["  'foo'", "'", "foo"]);
+execRE(re, '  "foo" ', ['  "foo"', '"', 'foo']);
+
+// Captures are cleared on backtrack past the look-ahead.
+re = /^(?:(?=(.))a|b)\1$/;
+testRE(re, "aa", true);
+testRE(re, "b", true);
+testRE(re, "bb", false);
+testRE(re, "a", false);
+execRE(re, "aa", ["aa", "a"]);
+execRE(re, "b", ["b", undefined]);
+
+re = /^(?=(.)(?=(.)\1\2)\2\1)\1\2/;
+testRE(re, "abab", true);
+testRE(re, "ababxxxxxxxx", true);
+testRE(re, "aba", false);
+execRE(re, "abab", ["ab", "a", "b"]);
+
+re = /^(?:(?=(.))a|b|c)$/;
+testRE(re, "a", true);
+testRE(re, "b", true);
+testRE(re, "c", true);
+testRE(re, "d", false);
+execRE(re, "a", ["a", "a"]);
+execRE(re, "b", ["b", undefined]);
+execRE(re, "c", ["c", undefined]);
+
+execRE(/^(?=(b))b/, "b", ["b", "b"]);
+execRE(/^(?:(?=(b))|a)b/, "ab", ["ab", undefined]);
+execRE(/^(?:(?=(b)(?:(?=(c))|d))|)bd/, "bd", ["bd", "b", undefined]);
+
+
+
+// Test of Negative Look-Ahead.
+
+re = /(?!x)./;
+testRE(re, "y", true);
+testRE(re, "x", false);
+execRE(re, "y", ["y"]);
+
+re = /(?!(\d))|\d/;
+testRE(re, "4", true);
+execRE(re, "4", ["4", undefined]);
+execRE(re, "x", ["", undefined]);
+
+
+// Test mixed nested look-ahead with captures.
+
+re = /^(?=(x)(?=(y)))/;
+testRE(re, "xy", true);
+testRE(re, "xz", false);
+execRE(re, "xy", ["", "x", "y"]);
+
+re = /^(?!(x)(?!(y)))/;
+testRE(re, "xy", true);
+testRE(re, "xz", false);
+execRE(re, "xy", ["", undefined, undefined]);
+
+re = /^(?=(x)(?!(y)))/;
+testRE(re, "xz", true);
+testRE(re, "xy", false)
+execRE(re, "xz", ["", "x", undefined]);
+
+re = /^(?!(x)(?=(y)))/;
+testRE(re, "xz", true);
+testRE(re, "xy", false);
+execRE(re, "xz", ["", undefined, undefined]);
+
+re = /^(?=(x)(?!(y)(?=(z))))/;
+testRE(re, "xaz", true);
+testRE(re, "xya", true);
+testRE(re, "xyz", false);
+testRE(re, "a", false);
+execRE(re, "xaz", ["", "x", undefined, undefined]);
+execRE(re, "xya", ["", "x", undefined, undefined]);
+
+re = /^(?!(x)(?=(y)(?!(z))))/;
+testRE(re, "a", true);
+testRE(re, "xa", true);
+testRE(re, "xyz", true);
+testRE(re, "xya", false);
+execRE(re, "a", ["", undefined, undefined, undefined]);
+execRE(re, "xa", ["", undefined, undefined, undefined]);
+execRE(re, "xyz", ["", undefined, undefined, undefined]);
diff --git a/test/mjsunit/regexp.js b/test/mjsunit/regexp.js
index 4422211..705754b 100644
--- a/test/mjsunit/regexp.js
+++ b/test/mjsunit/regexp.js
@@ -94,6 +94,22 @@
 //assertTrue(/\c[a/]/.test( "\x1ba/]" ));
 
 
+// Test \c in character class
+re = /^[\cM]$/;
+assertTrue(re.test("\r"));
+assertFalse(re.test("M"));
+assertFalse(re.test("c"));
+assertFalse(re.test("\\"));
+assertFalse(re.test("\x03"));  // I.e., read as \cc
+
+re = /^[\c]]$/;
+assertTrue(re.test("c]"));
+assertFalse(re.test("\\]"));
+assertFalse(re.test("\x1d"));  // ']' & 0x1f
+assertFalse(re.test("\\]"));
+assertFalse(re.test("\x03]"));  // I.e., read as \cc
+
+
 // Test that we handle \s and \S correctly inside some bizarre
 // character classes.
 re = /[\s-:]/;
@@ -316,3 +332,7 @@
 assertFalse(/()x\1y([0-7]%%%x|[0-6]%%%y)/.test('xy7%%%y'), 'qt6');
 assertFalse(/xy([0-7]%%%x|[0-6]%%%y)/.test('xy7%%%y'), 'qt7');
 assertFalse(/x([0-7]%%%x|[0-6]%%%y)/.test('x7%%%y'), 'qt8');
+
+
+// Don't hang on this one.
+/[^\xfe-\xff]*/.test("");
diff --git a/test/mjsunit/bugs/bug-187.js b/test/mjsunit/regress/regress-187.js
similarity index 100%
rename from test/mjsunit/bugs/bug-187.js
rename to test/mjsunit/regress/regress-187.js
diff --git a/test/mjsunit/regress/regress-189.js b/test/mjsunit/regress/regress-189.js
new file mode 100644
index 0000000..a84b620
--- /dev/null
+++ b/test/mjsunit/regress/regress-189.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.
+
+// Test that we can handle initialization of a deleted const variable.
+
+// See http://code.google.com/p/v8/issues/detail?id=189.
+
+function f() {
+  eval("delete x; const x = 32");
+}
+
+f();
diff --git a/test/mjsunit/regress/regress-192.js b/test/mjsunit/regress/regress-192.js
new file mode 100644
index 0000000..8f0978f
--- /dev/null
+++ b/test/mjsunit/regress/regress-192.js
@@ -0,0 +1,38 @@
+// 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 correctly propagated when creating object
+// literals.
+
+// See http://code.google.com/p/v8/issues/detail?id=192
+
+Object.prototype.__defineGetter__("x", function() {});
+
+// Creating this object literal will throw an exception because we are
+// assigning to a property that has only a getter.
+assertThrows("({ x: 42 })");
+
diff --git a/test/mjsunit/regress/regress-193.js b/test/mjsunit/regress/regress-193.js
new file mode 100644
index 0000000..f803483
--- /dev/null
+++ b/test/mjsunit/regress/regress-193.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 that context extension objects do not have a constructor
+// property.
+
+// See http://code.google.com/p/v8/issues/detail?id=193.
+
+function f() {
+  return eval("var x; constructor");
+}
+
+// It should be ok to call the constructor function returned by f.
+f()();
+
+// The call to f should get the constructor of the receiver which is
+// the constructor of the global object.
+assertEquals(constructor, f());
+
+
diff --git a/test/mjsunit/regress/regress-201.js b/test/mjsunit/regress/regress-201.js
new file mode 100644
index 0000000..8847fc0
--- /dev/null
+++ b/test/mjsunit/regress/regress-201.js
@@ -0,0 +1,37 @@
+// 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=201.
+
+function testsort(n) {
+  n=1*n;
+  var numbers=new Array(n);
+  for (var i=0;i<n;i++) numbers[i]=i;
+  numbers.sort();
+}
+
+testsort("5001")
diff --git a/test/mozilla/mozilla.status b/test/mozilla/mozilla.status
index 2e5a823..97182f3 100644
--- a/test/mozilla/mozilla.status
+++ b/test/mozilla/mozilla.status
@@ -240,11 +240,8 @@
 # 'minimum repeat count' is reached, the empty string must not match.
 # In this case, we are similar but not identical to JSC.  Hard to
 # support the JS behavior with PCRE, so maybe emulate JSC?
-#
-# Note: We do not support toSource currently so we cannot run this
-# test. We should make an isolated test case for the regexp issue.
-ecma_3/RegExp/regress-209919: FAIL_OK
-js1_5/extensions/regress-459606: FAIL_OK
+ecma_3/RegExp/regress-209919: PASS || FAIL_OK
+js1_5/extensions/regress-459606: PASS || FAIL_OK
 
 
 # PCRE's match limit is reached.  SpiderMonkey hangs on the first one,
@@ -265,11 +262,6 @@
 js1_5/Regress/regress-230216-2: FAIL_OK
 
 
-# According to ECMA-262, \b is a 'word' boundary, where words are only
-# ASCII characters.  PCRE supports non-ASCII word characters.
-js1_5/Regress/regress-247179: FAIL_OK
-
-
 # Regexp too long for PCRE.
 js1_5/Regress/regress-280769: PASS || FAIL
 js1_5/Regress/regress-280769-1: PASS || FAIL
@@ -471,7 +463,7 @@
 # A non-breaking space doesn't match \s in a regular expression.  This behaviour
 # matches JSC.  All the VMs have different behaviours in which characters match
 # \s so we do the same as JSC until they change.
-ecma_3/Unicode/uc-002: FAIL_OK
+ecma_3/Unicode/uc-002: PASS || FAIL_OK
 
 
 # String.prototype.split on empty strings always returns an array
@@ -521,10 +513,12 @@
 
 # Regular expression test failures due to PCRE. We match JSC (ie, perl)
 # behavior and not the ECMA spec.
-ecma_3/RegExp/15.10.2-1: FAIL_OK
-ecma_3/RegExp/perlstress-001: FAIL_OK
+ecma_3/RegExp/perlstress-001: PASS || FAIL_OK
 ecma_3/RegExp/regress-334158: PASS || FAIL
 
+# This test fails due to http://code.google.com/p/v8/issues/detail?id=187
+# Failure to clear captures when a lookahead is unwound.
+ecma_3/RegExp/15.10.2-1: PASS || FAIL_OK
 
 # This test requires a failure if we try to compile a function with more
 # than 65536 arguments.  This seems to be a Mozilla restriction.
diff --git a/tools/v8.xcodeproj/project.pbxproj b/tools/v8.xcodeproj/project.pbxproj
index 8adfd0e..aa1790d 100644
--- a/tools/v8.xcodeproj/project.pbxproj
+++ b/tools/v8.xcodeproj/project.pbxproj
@@ -16,6 +16,7 @@
 				7BF8919B0E7309AD000BAF8A /* PBXTargetDependency */,
 				7BF891970E73099F000BAF8A /* PBXTargetDependency */,
 				7BF891990E73099F000BAF8A /* PBXTargetDependency */,
+				893988100F2A3647007D5254 /* PBXTargetDependency */,
 				896FD03E0E78D731003DFB6A /* PBXTargetDependency */,
 				896FD0400E78D735003DFB6A /* PBXTargetDependency */,
 			);
@@ -31,6 +32,11 @@
 		890A14020EE9C4B400E49346 /* regexp-macro-assembler-irregexp.cc in Sources */ = {isa = PBXBuildFile; fileRef = 89A15C750EE466D000B48DEB /* regexp-macro-assembler-irregexp.cc */; };
 		890A14030EE9C4B500E49346 /* regexp-macro-assembler-tracer.cc in Sources */ = {isa = PBXBuildFile; fileRef = 89A15C770EE466D000B48DEB /* regexp-macro-assembler-tracer.cc */; };
 		890A14040EE9C4B700E49346 /* regexp-macro-assembler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 89A15C790EE466D000B48DEB /* regexp-macro-assembler.cc */; };
+		893988060F2A35FA007D5254 /* libjscre.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 897FF1BF0E719CB600D62E90 /* libjscre.a */; };
+		893988070F2A35FA007D5254 /* libv8.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8970F2F00E719FB2006AE7B5 /* libv8.a */; };
+		8939880D0F2A362A007D5254 /* d8.cc in Sources */ = {isa = PBXBuildFile; fileRef = 89A15C920EE46A1700B48DEB /* d8.cc */; };
+		893988160F2A3688007D5254 /* d8-debug.cc in Sources */ = {isa = PBXBuildFile; fileRef = 893988150F2A3686007D5254 /* d8-debug.cc */; };
+		893988330F2A3B8F007D5254 /* d8-js.cc in Sources */ = {isa = PBXBuildFile; fileRef = 893988320F2A3B8B007D5254 /* d8-js.cc */; };
 		893CCE640E71D83700357A03 /* code-stubs.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1110E719B8F00D62E90 /* code-stubs.cc */; };
 		8944AD100F1D4D500028D560 /* regexp-stack.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8944AD0E0F1D4D3A0028D560 /* regexp-stack.cc */; };
 		8944AD110F1D4D570028D560 /* regexp-stack.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8944AD0E0F1D4D3A0028D560 /* regexp-stack.cc */; };
@@ -213,6 +219,27 @@
 			remoteGlobalIDString = 897FF1BE0E719CB600D62E90;
 			remoteInfo = jscre;
 		};
+		893988000F2A35FA007D5254 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 8915B8680E719336009C4E19 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 897FF1BE0E719CB600D62E90;
+			remoteInfo = jscre;
+		};
+		893988020F2A35FA007D5254 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 8915B8680E719336009C4E19 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 8970F2EF0E719FB2006AE7B5;
+			remoteInfo = v8;
+		};
+		8939880F0F2A3647007D5254 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 8915B8680E719336009C4E19 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 893987FE0F2A35FA007D5254;
+			remoteInfo = d8_shell;
+		};
 		896FD03B0E78D71F003DFB6A /* PBXContainerItemProxy */ = {
 			isa = PBXContainerItemProxy;
 			containerPortal = 8915B8680E719336009C4E19 /* Project object */;
@@ -259,6 +286,10 @@
 
 /* Begin PBXFileReference section */
 		8900116B0E71CA2300F91F35 /* libraries.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = libraries.cc; sourceTree = "<group>"; };
+		893986D40F29020C007D5254 /* apiutils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = apiutils.h; sourceTree = "<group>"; };
+		8939880B0F2A35FA007D5254 /* v8_shell */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = v8_shell; sourceTree = BUILT_PRODUCTS_DIR; };
+		893988150F2A3686007D5254 /* d8-debug.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "d8-debug.cc"; path = "../src/d8-debug.cc"; sourceTree = "<group>"; };
+		893988320F2A3B8B007D5254 /* d8-js.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "d8-js.cc"; sourceTree = "<group>"; };
 		8944AD0E0F1D4D3A0028D560 /* regexp-stack.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "regexp-stack.cc"; sourceTree = "<group>"; };
 		8944AD0F0F1D4D3A0028D560 /* regexp-stack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "regexp-stack.h"; sourceTree = "<group>"; };
 		89471C7F0EB23EE400B6874B /* flag-definitions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "flag-definitions.h"; sourceTree = "<group>"; };
@@ -504,6 +535,15 @@
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
+		893988050F2A35FA007D5254 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				893988060F2A35FA007D5254 /* libjscre.a in Frameworks */,
+				893988070F2A35FA007D5254 /* libv8.a in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
 		8970F2EE0E719FB2006AE7B5 /* Frameworks */ = {
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
@@ -595,6 +635,7 @@
 				897FF0F90E719B8F00D62E90 /* allocation.h */,
 				897FF0FA0E719B8F00D62E90 /* api.cc */,
 				897FF0FB0E719B8F00D62E90 /* api.h */,
+				893986D40F29020C007D5254 /* apiutils.h */,
 				897FF0FC0E719B8F00D62E90 /* arguments.h */,
 				897FF0FD0E719B8F00D62E90 /* assembler-arm-inl.h */,
 				897FF0FE0E719B8F00D62E90 /* assembler-arm.cc */,
@@ -854,6 +895,7 @@
 			isa = PBXGroup;
 			children = (
 				89A15C910EE46A1700B48DEB /* d8-readline.cc */,
+				893988150F2A3686007D5254 /* d8-debug.cc */,
 				89A15C920EE46A1700B48DEB /* d8.cc */,
 				89A15C930EE46A1700B48DEB /* d8.h */,
 				89A15C940EE46A1700B48DEB /* d8.js */,
@@ -880,6 +922,7 @@
 				897F767A0E71B4CC007ACF34 /* v8_shell */,
 				89F23C870E78D5B2006B2466 /* libv8-arm.a */,
 				89F23C950E78D5B6006B2466 /* v8_shell-arm */,
+				8939880B0F2A35FA007D5254 /* v8_shell */,
 			);
 			name = Products;
 			sourceTree = "<group>";
@@ -887,6 +930,7 @@
 		89A9C1630E71C8E300BE6CCA /* generated */ = {
 			isa = PBXGroup;
 			children = (
+				893988320F2A3B8B007D5254 /* d8-js.cc */,
 				8900116B0E71CA2300F91F35 /* libraries.cc */,
 			);
 			path = generated;
@@ -895,6 +939,25 @@
 /* End PBXGroup section */
 
 /* Begin PBXNativeTarget section */
+		893987FE0F2A35FA007D5254 /* d8_shell */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 893988080F2A35FA007D5254 /* Build configuration list for PBXNativeTarget "d8_shell" */;
+			buildPhases = (
+				893988220F2A376C007D5254 /* ShellScript */,
+				893988030F2A35FA007D5254 /* Sources */,
+				893988050F2A35FA007D5254 /* Frameworks */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				893987FF0F2A35FA007D5254 /* PBXTargetDependency */,
+				893988010F2A35FA007D5254 /* PBXTargetDependency */,
+			);
+			name = d8_shell;
+			productName = v8_shell;
+			productReference = 8939880B0F2A35FA007D5254 /* v8_shell */;
+			productType = "com.apple.product-type.tool";
+		};
 		8970F2EF0E719FB2006AE7B5 /* v8 */ = {
 			isa = PBXNativeTarget;
 			buildConfigurationList = 8970F2F70E719FC1006AE7B5 /* Build configuration list for PBXNativeTarget "v8" */;
@@ -998,6 +1061,7 @@
 				897FF1BE0E719CB600D62E90 /* jscre */,
 				8970F2EF0E719FB2006AE7B5 /* v8 */,
 				897F76790E71B4CC007ACF34 /* v8_shell */,
+				893987FE0F2A35FA007D5254 /* d8_shell */,
 				89F23C3C0E78D5B2006B2466 /* v8-arm */,
 				89F23C880E78D5B6006B2466 /* v8_shell-arm */,
 			);
@@ -1005,6 +1069,19 @@
 /* End PBXProject section */
 
 /* Begin PBXShellScriptBuildPhase section */
+		893988220F2A376C007D5254 /* ShellScript */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "set -ex\nJS_FILES=\"d8.js\"\\\n\" macros.py\"\n\nV8ROOT=\"${SRCROOT}/..\"\n\nSRC_DIR=\"${V8ROOT}/src\"\n\nNATIVE_JS_FILES=\"\"\n\nfor i in ${JS_FILES} ; do\n  NATIVE_JS_FILES+=\"${SRC_DIR}/${i} \"\ndone\n\nV8_GENERATED_SOURCES_DIR=\"${CONFIGURATION_TEMP_DIR}/generated\"\nmkdir -p \"${V8_GENERATED_SOURCES_DIR}\"\n\nD8_CC=\"${V8_GENERATED_SOURCES_DIR}/d8-js.cc\"\nD8_EMPTY_CC=\"${V8_GENERATED_SOURCES_DIR}/d8-js-empty.cc\"\n\npython \"${V8ROOT}/tools/js2c.py\" \\\n  \"${D8_CC}.new\" \\\n  \"${D8_EMPTY_CC}.new\" \\\n  \"D8\" \\\n  ${NATIVE_JS_FILES}\n\n# Only use the new files if they're different from the existing files (if any),\n# preserving the existing files' timestamps when there are no changes.  This\n# minimizes unnecessary build activity for a no-change build.\n\nif ! diff -q \"${D8_CC}.new\" \"${D8_CC}\" >& /dev/null ; then\n  mv \"${D8_CC}.new\" \"${D8_CC}\"\nelse\n  rm \"${D8_CC}.new\"\nfi\n\nif ! diff -q \"${D8_EMPTY_CC}.new\" \"${D8_EMPTY_CC}\" >& /dev/null ; then\n  mv \"${D8_EMPTY_CC}.new\" \"${D8_EMPTY_CC}\"\nelse\n  rm \"${D8_EMPTY_CC}.new\"\nfi\n";
+		};
 		89EA6FB50E71AA1F00F59E1B /* ShellScript */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 2147483647;
@@ -1034,6 +1111,16 @@
 /* End PBXShellScriptBuildPhase section */
 
 /* Begin PBXSourcesBuildPhase section */
+		893988030F2A35FA007D5254 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				8939880D0F2A362A007D5254 /* d8.cc in Sources */,
+				893988160F2A3688007D5254 /* d8-debug.cc in Sources */,
+				893988330F2A3B8F007D5254 /* d8-js.cc in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
 		8970F2ED0E719FB2006AE7B5 /* Sources */ = {
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
@@ -1247,6 +1334,21 @@
 			target = 897FF1BE0E719CB600D62E90 /* jscre */;
 			targetProxy = 7BF8919A0E7309AD000BAF8A /* PBXContainerItemProxy */;
 		};
+		893987FF0F2A35FA007D5254 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 897FF1BE0E719CB600D62E90 /* jscre */;
+			targetProxy = 893988000F2A35FA007D5254 /* PBXContainerItemProxy */;
+		};
+		893988010F2A35FA007D5254 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 8970F2EF0E719FB2006AE7B5 /* v8 */;
+			targetProxy = 893988020F2A35FA007D5254 /* PBXContainerItemProxy */;
+		};
+		893988100F2A3647007D5254 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 893987FE0F2A35FA007D5254 /* d8_shell */;
+			targetProxy = 8939880F0F2A3647007D5254 /* PBXContainerItemProxy */;
+		};
 		896FD03C0E78D71F003DFB6A /* PBXTargetDependency */ = {
 			isa = PBXTargetDependency;
 			target = 89F23C3C0E78D5B2006B2466 /* v8-arm */;
@@ -1366,6 +1468,22 @@
 			};
 			name = Release;
 		};
+		893988090F2A35FA007D5254 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				HEADER_SEARCH_PATHS = ../src;
+				PRODUCT_NAME = v8_shell;
+			};
+			name = Debug;
+		};
+		8939880A0F2A35FA007D5254 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				HEADER_SEARCH_PATHS = ../src;
+				PRODUCT_NAME = v8_shell;
+			};
+			name = Release;
+		};
 		8970F2F10E719FB2006AE7B5 /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
@@ -1504,6 +1622,15 @@
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;
 		};
+		893988080F2A35FA007D5254 /* Build configuration list for PBXNativeTarget "d8_shell" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				893988090F2A35FA007D5254 /* Debug */,
+				8939880A0F2A35FA007D5254 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
 		8970F2F70E719FC1006AE7B5 /* Build configuration list for PBXNativeTarget "v8" */ = {
 			isa = XCConfigurationList;
 			buildConfigurations = (