Version 3.3.5

Fixed build on FreeBSD. Patch by Akinori MUSHA.

Added check that receiver is JSObject on API calls.

Implemented CallAsConstructor method for Object in the API (Issue 1348).
Patch by Peter Varga.

Added CallAsFunction method to the Object class in the API (Issue 1336).
Patch by Peter Varga.

Added per-isolate locking and unlocking.

Fixed bug in x64 >>> operator (Issue 1359).

Review URL: http://codereview.chromium.org/6960009

git-svn-id: http://v8.googlecode.com/svn/trunk@7816 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/AUTHORS b/AUTHORS
index 57b155f..60d5998 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -8,6 +8,7 @@
 ARM Ltd.
 Hewlett-Packard Development Company, LP
 
+Akinori MUSHA <knu@FreeBSD.org>
 Alexander Botero-Lowry <alexbl@FreeBSD.org>
 Alexander Karpinsky <homm86@gmail.com>
 Alexandre Vassalotti <avassalotti@gmail.com>
diff --git a/ChangeLog b/ChangeLog
index b089e41..80b29ae 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2011-05-09: Version 3.3.5
+
+        Fixed build on FreeBSD. Patch by Akinori MUSHA.
+
+        Added check that receiver is JSObject on API calls.
+
+        Implemented CallAsConstructor method for Object in the API (Issue 1348).
+        Patch by Peter Varga.
+
+        Added CallAsFunction method to the Object class in the API (Issue 1336).
+        Patch by Peter Varga.
+
+        Added per-isolate locking and unlocking.
+
+        Fixed bug in x64 >>> operator (Issue 1359).
+
+
 2011-05-04: Version 3.3.4
 
         Implemented API to disallow code generation from strings for a context
diff --git a/include/v8-preparser.h b/include/v8-preparser.h
index 4d46bad..f11d05e 100644
--- a/include/v8-preparser.h
+++ b/include/v8-preparser.h
@@ -66,7 +66,8 @@
 
 namespace v8 {
 
-
+// The result of preparsing is either a stack overflow error, or an opaque
+// blob of data that can be passed back into the parser.
 class V8EXPORT PreParserData {
  public:
   PreParserData(size_t size, const uint8_t* data)
diff --git a/include/v8.h b/include/v8.h
index 4dcbf28..5fc8059 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -1606,6 +1606,22 @@
   V8EXPORT ExternalArrayType GetIndexedPropertiesExternalArrayDataType();
   V8EXPORT int GetIndexedPropertiesExternalArrayDataLength();
 
+  /**
+   * Call an Object as a function if a callback is set by the 
+   * ObjectTemplate::SetCallAsFunctionHandler method.
+   */
+  V8EXPORT Local<Value> CallAsFunction(Handle<Object> recv,
+                                       int argc,
+                                       Handle<Value> argv[]);
+
+  /**
+   * Call an Object as a consturctor if a callback is set by the
+   * ObjectTemplate::SetCallAsFunctionHandler method.
+   * Note: This method behaves like the Function::NewInstance method.
+   */
+  V8EXPORT Local<Value> CallAsConstructor(int argc,
+                                          Handle<Value> argv[]);
+
   V8EXPORT static Local<Object> New();
   static inline Object* Cast(Value* obj);
  private:
@@ -3385,26 +3401,20 @@
  * to the user of V8 to ensure (perhaps with locking) that this
  * constraint is not violated.
  *
- * More then one thread and multiple V8 isolates can be used
- * without any locking if each isolate is created and accessed
- * by a single thread only. For example, one thread can use
- * multiple isolates or multiple threads can each create and run
- * their own isolate.
+ * v8::Locker is a scoped lock object. While it's
+ * active (i.e. between its construction and destruction) the current thread is
+ * allowed to use the locked isolate. V8 guarantees that an isolate can be locked
+ * by at most one thread at any time. In other words, the scope of a v8::Locker is
+ * a critical section.
  *
- * If you wish to start using V8 isolate in more then one thread
- * you can do this by constructing a v8::Locker object to guard
- * access to the isolate. After the code using V8 has completed
- * for the current thread you can call the destructor.  This can
- * be combined with C++ scope-based construction as follows
- * (assumes the default isolate that is used if not specified as
- * a parameter for the Locker):
- *
- * \code
+ * Sample usage:
+* \code
  * ...
  * {
- *   v8::Locker locker;
+ *   v8::Locker locker(isolate);
+ *   v8::Isolate::Scope isolate_scope(isolate);
  *   ...
- *   // Code using V8 goes here.
+ *   // Code using V8 and isolate goes here.
  *   ...
  * } // Destructor called here
  * \endcode
@@ -3415,11 +3425,13 @@
  *
  * \code
  * {
- *   v8::Unlocker unlocker;
+ *   isolate->Exit();
+ *   v8::Unlocker unlocker(isolate);
  *   ...
  *   // Code not using V8 goes here while V8 can run in another thread.
  *   ...
  * } // Destructor called here.
+ * isolate->Enter();
  * \endcode
  *
  * The Unlocker object is intended for use in a long-running callback
@@ -3439,32 +3451,45 @@
  * \code
  * // V8 not locked.
  * {
- *   v8::Locker locker;
+ *   v8::Locker locker(isolate);
+ *   Isolate::Scope isolate_scope(isolate);
  *   // V8 locked.
  *   {
- *     v8::Locker another_locker;
+ *     v8::Locker another_locker(isolate);
  *     // V8 still locked (2 levels).
  *     {
- *       v8::Unlocker unlocker;
+ *       isolate->Exit();
+ *       v8::Unlocker unlocker(isolate);
  *       // V8 not locked.
  *     }
+ *     isolate->Enter();
  *     // V8 locked again (2 levels).
  *   }
  *   // V8 still locked (1 level).
  * }
  * // V8 Now no longer locked.
  * \endcode
+ *
+ * 
  */
 class V8EXPORT Unlocker {
  public:
-  Unlocker();
+  /**
+   * Initialize Unlocker for a given Isolate. NULL means default isolate.
+   */
+  explicit Unlocker(Isolate* isolate = NULL);
   ~Unlocker();
+ private:
+  internal::Isolate* isolate_;
 };
 
 
 class V8EXPORT Locker {
  public:
-  Locker();
+  /**
+   * Initialize Locker for a given Isolate. NULL means default isolate.
+   */
+  explicit Locker(Isolate* isolate = NULL);
   ~Locker();
 
   /**
@@ -3482,9 +3507,10 @@
   static void StopPreemption();
 
   /**
-   * Returns whether or not the locker is locked by the current thread.
+   * Returns whether or not the locker for a given isolate, or default isolate if NULL is given,
+   * is locked by the current thread.
    */
-  static bool IsLocked();
+  static bool IsLocked(Isolate* isolate = NULL);
 
   /**
    * Returns whether v8::Locker is being used by this V8 instance.
@@ -3494,6 +3520,7 @@
  private:
   bool has_lock_;
   bool top_level_;
+  internal::Isolate* isolate_;
 
   static bool active_;
 
diff --git a/preparser/preparser-process.cc b/preparser/preparser-process.cc
index fb6e386..4860946 100644
--- a/preparser/preparser-process.cc
+++ b/preparser/preparser-process.cc
@@ -28,16 +28,29 @@
 #include <stdlib.h>
 #include <stdarg.h>
 #include <stdio.h>
+#include <string.h>
 
 #include "../include/v8stdint.h"
 #include "../include/v8-preparser.h"
 
+#include "../src/preparse-data-format.h"
+
+namespace i = v8::internal;
+
 // This file is only used for testing the stand-alone preparser
 // library.
-// The first (and only) argument must be the path of a JavaScript file.
-// This file is preparsed and the resulting preparser data is written
-// to stdout. Diagnostic output is output on stderr.
-// The file must contain only ASCII characters (UTF-8 isn't supported).
+// The first argument must be the path of a JavaScript source file.
+// Optionally this can be followed by the word "throws" (case sensitive),
+// which signals that the parsing is expected to throw - the default is
+// to expect the parsing to not throw.
+// The command line can further be followed by a message text (the
+// *type* of the exception to throw), and even more optionally, the
+// start and end position reported with the exception.
+//
+// This source file is preparsed and tested against the expectations, and if
+// successful, the resulting preparser data is written to stdout.
+// Diagnostic output is output on stderr.
+// The source file must contain only ASCII characters (UTF-8 isn't supported).
 // The file is read into memory, so it should have a reasonable size.
 
 
@@ -97,6 +110,69 @@
 }
 
 
+class PreparseDataInterpreter {
+ public:
+  PreparseDataInterpreter(const uint8_t* data, int length)
+      : data_(data), length_(length), message_(NULL) { }
+
+  ~PreparseDataInterpreter() {
+    if (message_ != NULL) delete[] message_;
+  }
+
+  bool valid() {
+    int header_length =
+      i::PreparseDataConstants::kHeaderSize * sizeof(int);  // NOLINT
+    return length_ >= header_length;
+  }
+
+  bool throws() {
+    return valid() &&
+        word(i::PreparseDataConstants::kHasErrorOffset) != 0;
+  }
+
+  const char* message() {
+    if (message_ != NULL) return message_;
+    if (!throws()) return NULL;
+    int text_pos = i::PreparseDataConstants::kHeaderSize +
+                   i::PreparseDataConstants::kMessageTextPos;
+    int length = word(text_pos);
+    char* buffer = new char[length + 1];
+    for (int i = 1; i <= length; i++) {
+      int character = word(text_pos + i);
+      buffer[i - 1] = character;
+    }
+    buffer[length] = '\0';
+    message_ = buffer;
+    return buffer;
+  }
+
+  int beg_pos() {
+    if (!throws()) return -1;
+    return word(i::PreparseDataConstants::kHeaderSize +
+                i::PreparseDataConstants::kMessageStartPos);
+  }
+
+  int end_pos() {
+    if (!throws()) return -1;
+    return word(i::PreparseDataConstants::kHeaderSize +
+                i::PreparseDataConstants::kMessageEndPos);
+  }
+
+ private:
+  int word(int offset) {
+    const int* word_data = reinterpret_cast<const int*>(data_);
+    if (word_data + offset < reinterpret_cast<const int*>(data_ + length_)) {
+      return word_data[offset];
+    }
+    return -1;
+  }
+
+  const uint8_t* const data_;
+  const int length_;
+  const char* message_;
+};
+
+
 template <typename T>
 class ScopedPointer {
  public:
@@ -109,15 +185,93 @@
 };
 
 
+
+void fail(v8::PreParserData* data, const char* message, ...) {
+  va_list args;
+  va_start(args, message);
+  vfprintf(stderr, message, args);
+  va_end(args);
+  fflush(stderr);
+  // Print preparser data to stdout.
+  uint32_t size = data->size();
+  fprintf(stderr, "LOG: data size: %u\n", size);
+  if (!WriteBuffer(stdout, data->data(), size)) {
+    perror("ERROR: Writing data");
+    fflush(stderr);
+  }
+  exit(EXIT_FAILURE);
+};
+
+
+void CheckException(v8::PreParserData* data,
+                    bool throws,
+                    const char* message,
+                    int beg_pos,
+                    int end_pos) {
+  PreparseDataInterpreter reader(data->data(), data->size());
+  if (throws) {
+    if (!reader.throws()) {
+      if (message == NULL) {
+        fail(data, "Didn't throw as expected\n");
+      } else {
+        fail(data, "Didn't throw \"%s\" as expected\n", message);
+      }
+    }
+    if (message != NULL) {
+      const char* actual_message = reader.message();
+      if (strcmp(message, actual_message)) {
+        fail(data, "Wrong error message. Expected <%s>, found <%s>\n",
+             message, actual_message);
+      }
+    }
+    if (beg_pos >= 0) {
+      if (beg_pos != reader.beg_pos()) {
+        fail(data, "Wrong error start position: Expected %i, found %i\n",
+             beg_pos, reader.beg_pos());
+      }
+    }
+    if (end_pos >= 0) {
+      if (end_pos != reader.end_pos()) {
+        fail(data, "Wrong error end position: Expected %i, found %i\n",
+             end_pos, reader.end_pos());
+      }
+    }
+  } else if (reader.throws()) {
+    const char* message = reader.message();
+    fail(data, "Throws unexpectedly with message: %s\n",
+         message);
+  }
+}
+
 int main(int argc, char* argv[]) {
   // Check for filename argument.
   if (argc < 2) {
-    fprintf(stderr, "ERROR: No filename on command line.\n");
-    fflush(stderr);
-    return EXIT_FAILURE;
+    fail(NULL, "ERROR: No filename on command line.\n");
   }
   const char* filename = argv[1];
 
+  // Parse expectations.
+  bool throws = false;
+  const char* throws_message = NULL;
+  int throws_beg_pos = -1;
+  int throws_end_pos = -1;
+  // Check for throws argument.
+  if (argc > 2) {
+    if (strncmp("throws", argv[2], 6)) {
+      fail(NULL, "ERROR: Extra arguments not prefixed by \"throws\".\n");
+    }
+    throws = true;
+    if (argc > 3) {
+      throws_message = argv[3];
+    }
+    if (argc > 4) {
+      throws_beg_pos = atoi(argv[4]);
+    }
+    if (argc > 5) {
+      throws_end_pos = atoi(argv[5]);
+    }
+  }
+
   // Open JS file.
   FILE* input = fopen(filename, "rb");
   if (input == NULL) {
@@ -151,19 +305,13 @@
 
   // Fail if stack overflow.
   if (data.stack_overflow()) {
-    fprintf(stderr, "ERROR: Stack overflow\n");
-    fflush(stderr);
-    return EXIT_FAILURE;
+    fail(&data, "ERROR: Stack overflow\n");
   }
 
-  // Print preparser data to stdout.
-  uint32_t size = data.size();
-  fprintf(stderr, "LOG: Success, data size: %u\n", size);
-  fflush(stderr);
-  if (!WriteBuffer(stdout, data.data(), size)) {
-    perror("ERROR: Writing data");
-    return EXIT_FAILURE;
-  }
+  // Check that the expected exception is thrown, if an exception is
+  // expected.
+  CheckException(&data, throws, throws_message,
+                 throws_beg_pos, throws_end_pos);
 
   return EXIT_SUCCESS;
 }
diff --git a/src/accessors.h b/src/accessors.h
index 14ccc8f..385536d 100644
--- a/src/accessors.h
+++ b/src/accessors.h
@@ -28,6 +28,8 @@
 #ifndef V8_ACCESSORS_H_
 #define V8_ACCESSORS_H_
 
+#include "allocation.h"
+
 namespace v8 {
 namespace internal {
 
diff --git a/src/api.cc b/src/api.cc
index 792e488..9194641 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -53,7 +53,6 @@
 
 #define LOG_API(isolate, expr) LOG(isolate, ApiEntryCall(expr))
 
-// TODO(isolates): avoid repeated TLS reads in function prologues.
 #ifdef ENABLE_VMSTATE_TRACKING
 #define ENTER_V8(isolate)                                        \
   ASSERT((isolate)->IsInitialized());                           \
@@ -290,6 +289,7 @@
   if (isolate != NULL) {
     if (isolate->IsInitialized()) return true;
   }
+  ASSERT(isolate == i::Isolate::Current());
   return ApiCheck(InitializeHelper(), location, "Error initializing V8");
 }
 
@@ -3255,6 +3255,74 @@
 }
 
 
+Local<v8::Value> Object::CallAsFunction(v8::Handle<v8::Object> recv, int argc,
+                                        v8::Handle<v8::Value> argv[]) {
+  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+  ON_BAILOUT(isolate, "v8::Object::CallAsFunction()",
+             return Local<v8::Value>());
+  LOG_API(isolate, "Object::CallAsFunction");
+  ENTER_V8(isolate);
+  i::HandleScope scope(isolate);
+  i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
+  i::Handle<i::Object> recv_obj = Utils::OpenHandle(*recv);
+  STATIC_ASSERT(sizeof(v8::Handle<v8::Value>) == sizeof(i::Object**));
+  i::Object*** args = reinterpret_cast<i::Object***>(argv);
+  i::Handle<i::JSFunction> fun = i::Handle<i::JSFunction>();
+  if (obj->IsJSFunction()) {
+    fun = i::Handle<i::JSFunction>::cast(obj);
+  } else {
+    EXCEPTION_PREAMBLE(isolate);
+    i::Handle<i::Object> delegate =
+        i::Execution::TryGetFunctionDelegate(obj, &has_pending_exception);
+    EXCEPTION_BAILOUT_CHECK(isolate, Local<Value>());
+    fun = i::Handle<i::JSFunction>::cast(delegate);
+    recv_obj = obj;
+  }
+  EXCEPTION_PREAMBLE(isolate);
+  i::Handle<i::Object> returned =
+      i::Execution::Call(fun, recv_obj, argc, args, &has_pending_exception);
+  EXCEPTION_BAILOUT_CHECK(isolate, Local<Value>());
+  return Utils::ToLocal(scope.CloseAndEscape(returned));
+}
+
+
+Local<v8::Value> Object::CallAsConstructor(int argc,
+                                           v8::Handle<v8::Value> argv[]) {
+  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+  ON_BAILOUT(isolate, "v8::Object::CallAsConstructor()",
+             return Local<v8::Object>());
+  LOG_API(isolate, "Object::CallAsConstructor");
+  ENTER_V8(isolate);
+  i::HandleScope scope(isolate);
+  i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
+  STATIC_ASSERT(sizeof(v8::Handle<v8::Value>) == sizeof(i::Object**));
+  i::Object*** args = reinterpret_cast<i::Object***>(argv);
+  if (obj->IsJSFunction()) {
+    i::Handle<i::JSFunction> fun = i::Handle<i::JSFunction>::cast(obj);
+    EXCEPTION_PREAMBLE(isolate);
+    i::Handle<i::Object> returned =
+        i::Execution::New(fun, argc, args, &has_pending_exception);
+    EXCEPTION_BAILOUT_CHECK(isolate, Local<v8::Object>());
+    return Utils::ToLocal(scope.CloseAndEscape(
+        i::Handle<i::JSObject>::cast(returned)));
+  }
+  EXCEPTION_PREAMBLE(isolate);
+  i::Handle<i::Object> delegate =
+      i::Execution::TryGetConstructorDelegate(obj, &has_pending_exception);
+  EXCEPTION_BAILOUT_CHECK(isolate, Local<v8::Object>());
+  if (!delegate->IsUndefined()) {
+    i::Handle<i::JSFunction> fun = i::Handle<i::JSFunction>::cast(delegate);
+    EXCEPTION_PREAMBLE(isolate);
+    i::Handle<i::Object> returned =
+        i::Execution::Call(fun, obj, argc, args, &has_pending_exception);
+    EXCEPTION_BAILOUT_CHECK(isolate, Local<v8::Object>());
+    ASSERT(!delegate->IsUndefined());
+    return Utils::ToLocal(scope.CloseAndEscape(returned));
+  }
+  return Local<v8::Object>();
+}
+
+
 Local<v8::Object> Function::NewInstance() const {
   return NewInstance(0, NULL);
 }
@@ -5708,9 +5776,8 @@
 
 
 char* HandleScopeImplementer::ArchiveThread(char* storage) {
-  Isolate* isolate = Isolate::Current();
   v8::ImplementationUtilities::HandleScopeData* current =
-      isolate->handle_scope_data();
+      isolate_->handle_scope_data();
   handle_scope_data_ = *current;
   memcpy(storage, this, sizeof(*this));
 
@@ -5728,7 +5795,7 @@
 
 char* HandleScopeImplementer::RestoreThread(char* storage) {
   memcpy(this, storage, sizeof(*this));
-  *Isolate::Current()->handle_scope_data() = handle_scope_data_;
+  *isolate_->handle_scope_data() = handle_scope_data_;
   return storage + ArchiveSpacePerThread();
 }
 
@@ -5754,7 +5821,7 @@
 
 void HandleScopeImplementer::Iterate(ObjectVisitor* v) {
   v8::ImplementationUtilities::HandleScopeData* current =
-      Isolate::Current()->handle_scope_data();
+      isolate_->handle_scope_data();
   handle_scope_data_ = *current;
   IterateThis(v);
 }
diff --git a/src/api.h b/src/api.h
index cd0205b..90cada7 100644
--- a/src/api.h
+++ b/src/api.h
@@ -399,8 +399,9 @@
 ISOLATED_CLASS HandleScopeImplementer {
  public:
 
-  HandleScopeImplementer()
-      : blocks_(0),
+  explicit HandleScopeImplementer(Isolate* isolate)
+      : isolate_(isolate),
+        blocks_(0),
         entered_contexts_(0),
         saved_contexts_(0),
         spare_(NULL),
@@ -466,6 +467,7 @@
     ASSERT(call_depth_ == 0);
   }
 
+  Isolate* isolate_;
   List<internal::Object**> blocks_;
   // Used as a stack to keep track of entered contexts.
   List<Handle<Object> > entered_contexts_;
diff --git a/src/arguments.h b/src/arguments.h
index a7a30e2..a080581 100644
--- a/src/arguments.h
+++ b/src/arguments.h
@@ -28,6 +28,8 @@
 #ifndef V8_ARGUMENTS_H_
 #define V8_ARGUMENTS_H_
 
+#include "allocation.h"
+
 namespace v8 {
 namespace internal {
 
diff --git a/src/arm/builtins-arm.cc b/src/arm/builtins-arm.cc
index e05ef51..3198092 100644
--- a/src/arm/builtins-arm.cc
+++ b/src/arm/builtins-arm.cc
@@ -1238,11 +1238,21 @@
 
     // Do not transform the receiver for strict mode functions.
     __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
-    __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kCompilerHintsOffset));
-    __ tst(r2, Operand(1 << (SharedFunctionInfo::kStrictModeFunction +
+    __ ldr(r3, FieldMemOperand(r2, SharedFunctionInfo::kCompilerHintsOffset));
+    __ tst(r3, Operand(1 << (SharedFunctionInfo::kStrictModeFunction +
                              kSmiTagSize)));
     __ b(ne, &shift_arguments);
 
+    // Do not transform the receiver for native (shared already in r2).
+    __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kScriptOffset));
+    __ LoadRoot(r3, Heap::kUndefinedValueRootIndex);
+    __ cmp(r2, r3);
+    __ b(eq, &shift_arguments);
+    __ ldr(r2, FieldMemOperand(r2, Script::kTypeOffset));
+    __ mov(r2, Operand(r2, ASR, kSmiTagSize));
+    __ cmp(r2, Operand(Script::TYPE_NATIVE));
+    __ b(eq, &shift_arguments);
+
     // Compute the receiver in non-strict mode.
     __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2));
     __ ldr(r2, MemOperand(r2, -kPointerSize));
@@ -1252,10 +1262,10 @@
     __ tst(r2, Operand(kSmiTagMask));
     __ b(eq, &convert_to_object);
 
-    __ LoadRoot(r3, Heap::kNullValueRootIndex);
+    // Heap::kUndefinedValueRootIndex is already in r3.
     __ cmp(r2, r3);
     __ b(eq, &use_global_receiver);
-    __ LoadRoot(r3, Heap::kUndefinedValueRootIndex);
+    __ LoadRoot(r3, Heap::kNullValueRootIndex);
     __ cmp(r2, r3);
     __ b(eq, &use_global_receiver);
 
@@ -1416,19 +1426,29 @@
   __ ldr(r0, MemOperand(fp, kRecvOffset));
 
   // Do not transform the receiver for strict mode functions.
-  __ ldr(r1, FieldMemOperand(r1, SharedFunctionInfo::kCompilerHintsOffset));
-  __ tst(r1, Operand(1 << (SharedFunctionInfo::kStrictModeFunction +
+  __ ldr(r2, FieldMemOperand(r1, SharedFunctionInfo::kCompilerHintsOffset));
+  __ tst(r2, Operand(1 << (SharedFunctionInfo::kStrictModeFunction +
                            kSmiTagSize)));
   __ b(ne, &push_receiver);
 
+  // Do not transform the receiver for native (shared already in r1).
+  __ ldr(r1, FieldMemOperand(r1, SharedFunctionInfo::kScriptOffset));
+  __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
+  __ cmp(r1, r2);
+  __ b(eq, &push_receiver);
+  __ ldr(r1, FieldMemOperand(r1, Script::kTypeOffset));
+  __ mov(r1, Operand(r1, ASR, kSmiTagSize));
+  __ cmp(r1, Operand(Script::TYPE_NATIVE));
+  __ b(eq, &push_receiver);
+
   // Compute the receiver in non-strict mode.
   __ tst(r0, Operand(kSmiTagMask));
   __ b(eq, &call_to_object);
   __ LoadRoot(r1, Heap::kNullValueRootIndex);
   __ cmp(r0, r1);
   __ b(eq, &use_global_receiver);
-  __ LoadRoot(r1, Heap::kUndefinedValueRootIndex);
-  __ cmp(r0, r1);
+  // Heap::kUndefinedValueRootIndex is already in r2.
+  __ cmp(r0, r2);
   __ b(eq, &use_global_receiver);
 
   // Check if the receiver is already a JavaScript object.
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
index 1179aac..10340b0 100644
--- a/src/arm/code-stubs-arm.cc
+++ b/src/arm/code-stubs-arm.cc
@@ -1568,13 +1568,22 @@
   __ JumpIfNonSmisNotBothSequentialAsciiStrings(lhs_, rhs_, r2, r3, &slow);
 
   __ IncrementCounter(isolate->counters()->string_compare_native(), 1, r2, r3);
-  StringCompareStub::GenerateCompareFlatAsciiStrings(masm,
+  if (cc_ == eq) {
+    StringCompareStub::GenerateFlatAsciiStringEquals(masm,
                                                      lhs_,
                                                      rhs_,
                                                      r2,
                                                      r3,
-                                                     r4,
-                                                     r5);
+                                                     r4);
+  } else {
+    StringCompareStub::GenerateCompareFlatAsciiStrings(masm,
+                                                       lhs_,
+                                                       rhs_,
+                                                       r2,
+                                                       r3,
+                                                       r4,
+                                                       r5);
+  }
   // Never falls through to here.
 
   __ bind(&slow);
@@ -5392,6 +5401,45 @@
 }
 
 
+void StringCompareStub::GenerateFlatAsciiStringEquals(MacroAssembler* masm,
+                                                      Register left,
+                                                      Register right,
+                                                      Register scratch1,
+                                                      Register scratch2,
+                                                      Register scratch3) {
+  Register length = scratch1;
+
+  // Compare lengths.
+  Label strings_not_equal, check_zero_length;
+  __ ldr(length, FieldMemOperand(left, String::kLengthOffset));
+  __ ldr(scratch2, FieldMemOperand(right, String::kLengthOffset));
+  __ cmp(length, scratch2);
+  __ b(eq, &check_zero_length);
+  __ bind(&strings_not_equal);
+  __ mov(r0, Operand(Smi::FromInt(NOT_EQUAL)));
+  __ Ret();
+
+  // Check if the length is zero.
+  Label compare_chars;
+  __ bind(&check_zero_length);
+  STATIC_ASSERT(kSmiTag == 0);
+  __ tst(length, Operand(length));
+  __ b(ne, &compare_chars);
+  __ mov(r0, Operand(Smi::FromInt(EQUAL)));
+  __ Ret();
+
+  // Compare characters.
+  __ bind(&compare_chars);
+  GenerateAsciiCharsCompareLoop(masm,
+                                left, right, length, scratch2, scratch3,
+                                &strings_not_equal);
+
+  // Characters are equal.
+  __ mov(r0, Operand(Smi::FromInt(EQUAL)));
+  __ Ret();
+}
+
+
 void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
                                                         Register left,
                                                         Register right,
@@ -5399,7 +5447,7 @@
                                                         Register scratch2,
                                                         Register scratch3,
                                                         Register scratch4) {
-  Label compare_lengths;
+  Label result_not_equal, compare_lengths;
   // Find minimum length and length difference.
   __ ldr(scratch1, FieldMemOperand(left, String::kLengthOffset));
   __ ldr(scratch2, FieldMemOperand(right, String::kLengthOffset));
@@ -5411,46 +5459,56 @@
   __ tst(min_length, Operand(min_length));
   __ b(eq, &compare_lengths);
 
-  // Untag smi.
-  __ mov(min_length, Operand(min_length, ASR, kSmiTagSize));
+  // Compare loop.
+  GenerateAsciiCharsCompareLoop(masm,
+                                left, right, min_length, scratch2, scratch4,
+                                &result_not_equal);
 
-  // Setup registers so that we only need to increment one register
-  // in the loop.
-  __ add(scratch2, min_length,
-         Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
-  __ add(left, left, Operand(scratch2));
-  __ add(right, right, Operand(scratch2));
-  // Registers left and right points to the min_length character of strings.
-  __ rsb(min_length, min_length, Operand(-1));
-  Register index = min_length;
-  // Index starts at -min_length.
-
-  {
-    // Compare loop.
-    Label loop;
-    __ bind(&loop);
-    // Compare characters.
-    __ add(index, index, Operand(1), SetCC);
-    __ ldrb(scratch2, MemOperand(left, index), ne);
-    __ ldrb(scratch4, MemOperand(right, index), ne);
-    // Skip to compare lengths with eq condition true.
-    __ b(eq, &compare_lengths);
-    __ cmp(scratch2, scratch4);
-    __ b(eq, &loop);
-    // Fallthrough with eq condition false.
-  }
-  // Compare lengths -  strings up to min-length are equal.
+  // Compare lengths - strings up to min-length are equal.
   __ bind(&compare_lengths);
   ASSERT(Smi::FromInt(EQUAL) == static_cast<Smi*>(0));
-  // Use zero length_delta as result.
-  __ mov(r0, Operand(length_delta), SetCC, eq);
-  // Fall through to here if characters compare not-equal.
+  // Use length_delta as result if it's zero.
+  __ mov(r0, Operand(length_delta), SetCC);
+  __ bind(&result_not_equal);
+  // Conditionally update the result based either on length_delta or
+  // the last comparion performed in the loop above.
   __ mov(r0, Operand(Smi::FromInt(GREATER)), LeaveCC, gt);
   __ mov(r0, Operand(Smi::FromInt(LESS)), LeaveCC, lt);
   __ Ret();
 }
 
 
+void StringCompareStub::GenerateAsciiCharsCompareLoop(
+    MacroAssembler* masm,
+    Register left,
+    Register right,
+    Register length,
+    Register scratch1,
+    Register scratch2,
+    Label* chars_not_equal) {
+  // Change index to run from -length to -1 by adding length to string
+  // start. This means that loop ends when index reaches zero, which
+  // doesn't need an additional compare.
+  __ SmiUntag(length);
+  __ add(scratch1, length,
+         Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
+  __ add(left, left, Operand(scratch1));
+  __ add(right, right, Operand(scratch1));
+  __ rsb(length, length, Operand(0));
+  Register index = length;  // index = -length;
+
+  // Compare loop.
+  Label loop;
+  __ bind(&loop);
+  __ ldrb(scratch1, MemOperand(left, index));
+  __ ldrb(scratch2, MemOperand(right, index));
+  __ cmp(scratch1, scratch2);
+  __ b(ne, chars_not_equal);
+  __ add(index, index, Operand(1), SetCC);
+  __ b(ne, &loop);
+}
+
+
 void StringCompareStub::Generate(MacroAssembler* masm) {
   Label runtime;
 
@@ -5903,6 +5961,71 @@
 }
 
 
+void ICCompareStub::GenerateStrings(MacroAssembler* masm) {
+  ASSERT(state_ == CompareIC::STRINGS);
+  Label miss;
+
+  // Registers containing left and right operands respectively.
+  Register left = r1;
+  Register right = r0;
+  Register tmp1 = r2;
+  Register tmp2 = r3;
+  Register tmp3 = r4;
+  Register tmp4 = r5;
+
+  // Check that both operands are heap objects.
+  __ JumpIfEitherSmi(left, right, &miss);
+
+  // Check that both operands are strings. This leaves the instance
+  // types loaded in tmp1 and tmp2.
+  __ ldr(tmp1, FieldMemOperand(left, HeapObject::kMapOffset));
+  __ ldr(tmp2, FieldMemOperand(right, HeapObject::kMapOffset));
+  __ ldrb(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset));
+  __ ldrb(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset));
+  STATIC_ASSERT(kNotStringTag != 0);
+  __ orr(tmp3, tmp1, tmp2);
+  __ tst(tmp3, Operand(kIsNotStringMask));
+  __ b(ne, &miss);
+
+  // Fast check for identical strings.
+  __ cmp(left, right);
+  STATIC_ASSERT(EQUAL == 0);
+  STATIC_ASSERT(kSmiTag == 0);
+  __ mov(r0, Operand(Smi::FromInt(EQUAL)), LeaveCC, eq);
+  __ Ret(eq);
+
+  // Handle not identical strings.
+
+  // Check that both strings are symbols. If they are, we're done
+  // because we already know they are not identical.
+  ASSERT(GetCondition() == eq);
+  STATIC_ASSERT(kSymbolTag != 0);
+  __ and_(tmp3, tmp1, Operand(tmp2));
+  __ tst(tmp3, Operand(kIsSymbolMask));
+  // Make sure r0 is non-zero. At this point input operands are
+  // guaranteed to be non-zero.
+  ASSERT(right.is(r0));
+  __ Ret(ne);
+
+  // Check that both strings are sequential ASCII.
+  Label runtime;
+  __ JumpIfBothInstanceTypesAreNotSequentialAscii(tmp1, tmp2, tmp3, tmp4,
+                                                  &runtime);
+
+  // Compare flat ASCII strings. Returns when done.
+  StringCompareStub::GenerateFlatAsciiStringEquals(
+      masm, left, right, tmp1, tmp2, tmp3);
+
+  // Handle more complex cases in runtime.
+  __ bind(&runtime);
+  __ Push(left, right);
+  __ TailCallRuntime(Runtime::kStringEquals, 2, 1);
+
+  __ bind(&miss);
+  GenerateMiss(masm);
+}
+
+
 void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
   ASSERT(state_ == CompareIC::OBJECTS);
   Label miss;
@@ -5973,6 +6096,236 @@
 }
 
 
+void StringDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
+                                                        Label* miss,
+                                                        Label* done,
+                                                        Register receiver,
+                                                        Register properties,
+                                                        String* name,
+                                                        Register scratch0) {
+  // If names of slots in range from 1 to kProbes - 1 for the hash value are
+  // not equal to the name and kProbes-th slot is not used (its name is the
+  // undefined value), it guarantees the hash table doesn't contain the
+  // property. It's true even if some slots represent deleted properties
+  // (their names are the null value).
+  for (int i = 0; i < kInlinedProbes; i++) {
+    // scratch0 points to properties hash.
+    // Compute the masked index: (hash + i + i * i) & mask.
+    Register index = scratch0;
+    // Capacity is smi 2^n.
+    __ ldr(index, FieldMemOperand(properties, kCapacityOffset));
+    __ sub(index, index, Operand(1));
+    __ and_(index, index, Operand(
+        Smi::FromInt(name->Hash() + StringDictionary::GetProbeOffset(i))));
+
+    // Scale the index by multiplying by the entry size.
+    ASSERT(StringDictionary::kEntrySize == 3);
+    __ add(index, index, Operand(index, LSL, 1));  // index *= 3.
+
+    Register entity_name = scratch0;
+    // Having undefined at this place means the name is not contained.
+    ASSERT_EQ(kSmiTagSize, 1);
+    Register tmp = properties;
+    __ add(tmp, properties, Operand(index, LSL, 1));
+    __ ldr(entity_name, FieldMemOperand(tmp, kElementsStartOffset));
+
+    ASSERT(!tmp.is(entity_name));
+    __ LoadRoot(tmp, Heap::kUndefinedValueRootIndex);
+    __ cmp(entity_name, tmp);
+    __ b(eq, done);
+
+    if (i != kInlinedProbes - 1) {
+      // Stop if found the property.
+      __ cmp(entity_name, Operand(Handle<String>(name)));
+      __ b(eq, miss);
+
+      // Check if the entry name is not a symbol.
+      __ ldr(entity_name, FieldMemOperand(entity_name, HeapObject::kMapOffset));
+      __ ldrb(entity_name,
+              FieldMemOperand(entity_name, Map::kInstanceTypeOffset));
+      __ tst(entity_name, Operand(kIsSymbolMask));
+      __ b(eq, miss);
+
+      // Restore the properties.
+      __ ldr(properties,
+             FieldMemOperand(receiver, JSObject::kPropertiesOffset));
+    }
+  }
+
+  const int spill_mask =
+      (lr.bit() | r6.bit() | r5.bit() | r4.bit() | r3.bit() |
+       r2.bit() | r1.bit() | r0.bit());
+
+  __ stm(db_w, sp, spill_mask);
+  __ ldr(r0, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
+  __ mov(r1, Operand(Handle<String>(name)));
+  StringDictionaryLookupStub stub(NEGATIVE_LOOKUP);
+  __ CallStub(&stub);
+  __ tst(r0, Operand(r0));
+  __ ldm(ia_w, sp, spill_mask);
+
+  __ b(eq, done);
+  __ b(ne, miss);
+}
+
+
+// Probe the string dictionary in the |elements| register. Jump to the
+// |done| label if a property with the given name is found. Jump to
+// the |miss| label otherwise.
+// If lookup was successful |scratch2| will be equal to elements + 4 * index.
+void StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
+                                                        Label* miss,
+                                                        Label* done,
+                                                        Register elements,
+                                                        Register name,
+                                                        Register scratch1,
+                                                        Register scratch2) {
+  // Assert that name contains a string.
+  if (FLAG_debug_code) __ AbortIfNotString(name);
+
+  // Compute the capacity mask.
+  __ ldr(scratch1, FieldMemOperand(elements, kCapacityOffset));
+  __ mov(scratch1, Operand(scratch1, ASR, kSmiTagSize));  // convert smi to int
+  __ sub(scratch1, scratch1, Operand(1));
+
+  // Generate an unrolled loop that performs a few probes before
+  // giving up. Measurements done on Gmail indicate that 2 probes
+  // cover ~93% of loads from dictionaries.
+  for (int i = 0; i < kInlinedProbes; i++) {
+    // Compute the masked index: (hash + i + i * i) & mask.
+    __ ldr(scratch2, FieldMemOperand(name, String::kHashFieldOffset));
+    if (i > 0) {
+      // Add the probe offset (i + i * i) left shifted to avoid right shifting
+      // the hash in a separate instruction. The value hash + i + i * i is right
+      // shifted in the following and instruction.
+      ASSERT(StringDictionary::GetProbeOffset(i) <
+             1 << (32 - String::kHashFieldOffset));
+      __ add(scratch2, scratch2, Operand(
+          StringDictionary::GetProbeOffset(i) << String::kHashShift));
+    }
+    __ and_(scratch2, scratch1, Operand(scratch2, LSR, String::kHashShift));
+
+    // Scale the index by multiplying by the element size.
+    ASSERT(StringDictionary::kEntrySize == 3);
+    // scratch2 = scratch2 * 3.
+    __ add(scratch2, scratch2, Operand(scratch2, LSL, 1));
+
+    // Check if the key is identical to the name.
+    __ add(scratch2, elements, Operand(scratch2, LSL, 2));
+    __ ldr(ip, FieldMemOperand(scratch2, kElementsStartOffset));
+    __ cmp(name, Operand(ip));
+    __ b(eq, done);
+  }
+
+  const int spill_mask =
+      (lr.bit() | r6.bit() | r5.bit() | r4.bit() |
+       r3.bit() | r2.bit() | r1.bit() | r0.bit()) &
+      ~(scratch1.bit() | scratch2.bit());
+
+  __ stm(db_w, sp, spill_mask);
+  __ Move(r0, elements);
+  __ Move(r1, name);
+  StringDictionaryLookupStub stub(POSITIVE_LOOKUP);
+  __ CallStub(&stub);
+  __ tst(r0, Operand(r0));
+  __ mov(scratch2, Operand(r2));
+  __ ldm(ia_w, sp, spill_mask);
+
+  __ b(ne, done);
+  __ b(eq, miss);
+}
+
+
+void StringDictionaryLookupStub::Generate(MacroAssembler* masm) {
+  // Registers:
+  //  result: StringDictionary to probe
+  //  r1: key
+  //  : StringDictionary to probe.
+  //  index_: will hold an index of entry if lookup is successful.
+  //          might alias with result_.
+  // Returns:
+  //  result_ is zero if lookup failed, non zero otherwise.
+
+  Register result = r0;
+  Register dictionary = r0;
+  Register key = r1;
+  Register index = r2;
+  Register mask = r3;
+  Register hash = r4;
+  Register undefined = r5;
+  Register entry_key = r6;
+
+  Label in_dictionary, maybe_in_dictionary, not_in_dictionary;
+
+  __ ldr(mask, FieldMemOperand(dictionary, kCapacityOffset));
+  __ mov(mask, Operand(mask, ASR, kSmiTagSize));
+  __ sub(mask, mask, Operand(1));
+
+  __ ldr(hash, FieldMemOperand(key, String::kHashFieldOffset));
+
+  __ LoadRoot(undefined, Heap::kUndefinedValueRootIndex);
+
+  for (int i = kInlinedProbes; i < kTotalProbes; i++) {
+    // Compute the masked index: (hash + i + i * i) & mask.
+    // Capacity is smi 2^n.
+    if (i > 0) {
+      // Add the probe offset (i + i * i) left shifted to avoid right shifting
+      // the hash in a separate instruction. The value hash + i + i * i is right
+      // shifted in the following and instruction.
+      ASSERT(StringDictionary::GetProbeOffset(i) <
+             1 << (32 - String::kHashFieldOffset));
+      __ add(index, hash, Operand(
+          StringDictionary::GetProbeOffset(i) << String::kHashShift));
+    } else {
+      __ mov(index, Operand(hash));
+    }
+    __ and_(index, mask, Operand(index, LSR, String::kHashShift));
+
+    // Scale the index by multiplying by the entry size.
+    ASSERT(StringDictionary::kEntrySize == 3);
+    __ add(index, index, Operand(index, LSL, 1));  // index *= 3.
+
+    ASSERT_EQ(kSmiTagSize, 1);
+    __ add(index, dictionary, Operand(index, LSL, 2));
+    __ ldr(entry_key, FieldMemOperand(index, kElementsStartOffset));
+
+    // Having undefined at this place means the name is not contained.
+    __ cmp(entry_key, Operand(undefined));
+    __ b(eq, &not_in_dictionary);
+
+    // Stop if found the property.
+    __ cmp(entry_key, Operand(key));
+    __ b(eq, &in_dictionary);
+
+    if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) {
+      // Check if the entry name is not a symbol.
+      __ ldr(entry_key, FieldMemOperand(entry_key, HeapObject::kMapOffset));
+      __ ldrb(entry_key,
+              FieldMemOperand(entry_key, Map::kInstanceTypeOffset));
+      __ tst(entry_key, Operand(kIsSymbolMask));
+      __ b(eq, &maybe_in_dictionary);
+    }
+  }
+
+  __ bind(&maybe_in_dictionary);
+  // If we are doing negative lookup then probing failure should be
+  // treated as a lookup success. For positive lookup probing failure
+  // should be treated as lookup failure.
+  if (mode_ == POSITIVE_LOOKUP) {
+    __ mov(result, Operand(0));
+    __ Ret();
+  }
+
+  __ bind(&in_dictionary);
+  __ mov(result, Operand(1));
+  __ Ret();
+
+  __ bind(&not_in_dictionary);
+  __ mov(result, Operand(0));
+  __ Ret();
+}
+
+
 #undef __
 
 } }  // namespace v8::internal
diff --git a/src/arm/code-stubs-arm.h b/src/arm/code-stubs-arm.h
index 2ca7b7a..112503f 100644
--- a/src/arm/code-stubs-arm.h
+++ b/src/arm/code-stubs-arm.h
@@ -327,8 +327,7 @@
  public:
   StringCompareStub() { }
 
-  // Compare two flat ASCII strings and returns result in r0.
-  // Does not use the stack.
+  // Compares two flat ASCII strings and returns result in r0.
   static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
                                               Register left,
                                               Register right,
@@ -337,11 +336,27 @@
                                               Register scratch3,
                                               Register scratch4);
 
- private:
-  Major MajorKey() { return StringCompare; }
-  int MinorKey() { return 0; }
+  // Compares two flat ASCII strings for equality and returns result
+  // in r0.
+  static void GenerateFlatAsciiStringEquals(MacroAssembler* masm,
+                                            Register left,
+                                            Register right,
+                                            Register scratch1,
+                                            Register scratch2,
+                                            Register scratch3);
 
-  void Generate(MacroAssembler* masm);
+ private:
+  virtual Major MajorKey() { return StringCompare; }
+  virtual int MinorKey() { return 0; }
+  virtual void Generate(MacroAssembler* masm);
+
+  static void GenerateAsciiCharsCompareLoop(MacroAssembler* masm,
+                                            Register left,
+                                            Register right,
+                                            Register length,
+                                            Register scratch1,
+                                            Register scratch2,
+                                            Label* chars_not_equal);
 };
 
 
@@ -597,6 +612,61 @@
 };
 
 
+class StringDictionaryLookupStub: public CodeStub {
+ public:
+  enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
+
+  explicit StringDictionaryLookupStub(LookupMode mode) : mode_(mode) { }
+
+  void Generate(MacroAssembler* masm);
+
+  static void GenerateNegativeLookup(MacroAssembler* masm,
+                                     Label* miss,
+                                     Label* done,
+                                     Register receiver,
+                                     Register properties,
+                                     String* name,
+                                     Register scratch0) ;
+
+  static void GeneratePositiveLookup(MacroAssembler* masm,
+                                     Label* miss,
+                                     Label* done,
+                                     Register elements,
+                                     Register name,
+                                     Register r0,
+                                     Register r1);
+
+ private:
+  static const int kInlinedProbes = 4;
+  static const int kTotalProbes = 20;
+
+  static const int kCapacityOffset =
+      StringDictionary::kHeaderSize +
+      StringDictionary::kCapacityIndex * kPointerSize;
+
+  static const int kElementsStartOffset =
+      StringDictionary::kHeaderSize +
+      StringDictionary::kElementsStartIndex * kPointerSize;
+
+
+#ifdef DEBUG
+  void Print() {
+    PrintF("StringDictionaryLookupStub\n");
+  }
+#endif
+
+  Major MajorKey() { return StringDictionaryNegativeLookup; }
+
+  int MinorKey() {
+    return LookupModeBits::encode(mode_);
+  }
+
+  class LookupModeBits: public BitField<LookupMode, 0, 1> {};
+
+  LookupMode mode_;
+};
+
+
 } }  // namespace v8::internal
 
 #endif  // V8_ARM_CODE_STUBS_ARM_H_
diff --git a/src/arm/ic-arm.cc b/src/arm/ic-arm.cc
index db04f33..731c471 100644
--- a/src/arm/ic-arm.cc
+++ b/src/arm/ic-arm.cc
@@ -105,65 +105,6 @@
 }
 
 
-// Probe the string dictionary in the |elements| register. Jump to the
-// |done| label if a property with the given name is found. Jump to
-// the |miss| label otherwise.
-static void GenerateStringDictionaryProbes(MacroAssembler* masm,
-                                           Label* miss,
-                                           Label* done,
-                                           Register elements,
-                                           Register name,
-                                           Register scratch1,
-                                           Register scratch2) {
-  // Assert that name contains a string.
-  if (FLAG_debug_code) __ AbortIfNotString(name);
-
-  // Compute the capacity mask.
-  const int kCapacityOffset = StringDictionary::kHeaderSize +
-      StringDictionary::kCapacityIndex * kPointerSize;
-  __ ldr(scratch1, FieldMemOperand(elements, kCapacityOffset));
-  __ mov(scratch1, Operand(scratch1, ASR, kSmiTagSize));  // convert smi to int
-  __ sub(scratch1, scratch1, Operand(1));
-
-  const int kElementsStartOffset = StringDictionary::kHeaderSize +
-      StringDictionary::kElementsStartIndex * kPointerSize;
-
-  // Generate an unrolled loop that performs a few probes before
-  // giving up. Measurements done on Gmail indicate that 2 probes
-  // cover ~93% of loads from dictionaries.
-  static const int kProbes = 4;
-  for (int i = 0; i < kProbes; i++) {
-    // Compute the masked index: (hash + i + i * i) & mask.
-    __ ldr(scratch2, FieldMemOperand(name, String::kHashFieldOffset));
-    if (i > 0) {
-      // Add the probe offset (i + i * i) left shifted to avoid right shifting
-      // the hash in a separate instruction. The value hash + i + i * i is right
-      // shifted in the following and instruction.
-      ASSERT(StringDictionary::GetProbeOffset(i) <
-             1 << (32 - String::kHashFieldOffset));
-      __ add(scratch2, scratch2, Operand(
-          StringDictionary::GetProbeOffset(i) << String::kHashShift));
-    }
-    __ and_(scratch2, scratch1, Operand(scratch2, LSR, String::kHashShift));
-
-    // Scale the index by multiplying by the element size.
-    ASSERT(StringDictionary::kEntrySize == 3);
-    // scratch2 = scratch2 * 3.
-    __ add(scratch2, scratch2, Operand(scratch2, LSL, 1));
-
-    // Check if the key is identical to the name.
-    __ add(scratch2, elements, Operand(scratch2, LSL, 2));
-    __ ldr(ip, FieldMemOperand(scratch2, kElementsStartOffset));
-    __ cmp(name, Operand(ip));
-    if (i != kProbes - 1) {
-      __ b(eq, done);
-    } else {
-      __ b(ne, miss);
-    }
-  }
-}
-
-
 // Helper function used from LoadIC/CallIC GenerateNormal.
 //
 // elements: Property dictionary. It is not clobbered if a jump to the miss
@@ -191,13 +132,13 @@
   Label done;
 
   // Probe the dictionary.
-  GenerateStringDictionaryProbes(masm,
-                                 miss,
-                                 &done,
-                                 elements,
-                                 name,
-                                 scratch1,
-                                 scratch2);
+  StringDictionaryLookupStub::GeneratePositiveLookup(masm,
+                                                     miss,
+                                                     &done,
+                                                     elements,
+                                                     name,
+                                                     scratch1,
+                                                     scratch2);
 
   // If probing finds an entry check that the value is a normal
   // property.
@@ -240,13 +181,13 @@
   Label done;
 
   // Probe the dictionary.
-  GenerateStringDictionaryProbes(masm,
-                                 miss,
-                                 &done,
-                                 elements,
-                                 name,
-                                 scratch1,
-                                 scratch2);
+  StringDictionaryLookupStub::GeneratePositiveLookup(masm,
+                                                     miss,
+                                                     &done,
+                                                     elements,
+                                                     name,
+                                                     scratch1,
+                                                     scratch2);
 
   // If probing finds an entry in the dictionary check that the value
   // is a normal property that is not read only.
diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc
index 71d8474..417927f 100644
--- a/src/arm/lithium-arm.cc
+++ b/src/arm/lithium-arm.cc
@@ -2127,7 +2127,7 @@
   HConstant* undefined = graph()->GetConstantUndefined();
   HEnvironment* inner = outer->CopyForInlining(instr->closure(),
                                                instr->function(),
-                                               false,
+                                               HEnvironment::LITHIUM,
                                                undefined);
   current_block_->UpdateEnvironment(inner);
   chunk_->AddInlinedClosure(instr->closure());
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index 33b6731..4b04538 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -2284,23 +2284,29 @@
 }
 
 
-void LCodeGen::EmitLoadField(Register result,
-                             Register object,
-                             Handle<Map> type,
-                             Handle<String> name) {
+void LCodeGen::EmitLoadFieldOrConstantFunction(Register result,
+                                               Register object,
+                                               Handle<Map> type,
+                                               Handle<String> name) {
   LookupResult lookup;
   type->LookupInDescriptors(NULL, *name, &lookup);
-  ASSERT(lookup.IsProperty() && lookup.type() == FIELD);
-  int index = lookup.GetLocalFieldIndexFromMap(*type);
-  int offset = index * kPointerSize;
-  if (index < 0) {
-    // Negative property indices are in-object properties, indexed
-    // from the end of the fixed part of the object.
-    __ ldr(result, FieldMemOperand(object, offset + type->instance_size()));
+  ASSERT(lookup.IsProperty() &&
+         (lookup.type() == FIELD || lookup.type() == CONSTANT_FUNCTION));
+  if (lookup.type() == FIELD) {
+    int index = lookup.GetLocalFieldIndexFromMap(*type);
+    int offset = index * kPointerSize;
+    if (index < 0) {
+      // Negative property indices are in-object properties, indexed
+      // from the end of the fixed part of the object.
+      __ ldr(result, FieldMemOperand(object, offset + type->instance_size()));
+    } else {
+      // Non-negative property indices are in the properties array.
+      __ ldr(result, FieldMemOperand(object, JSObject::kPropertiesOffset));
+      __ ldr(result, FieldMemOperand(result, offset + FixedArray::kHeaderSize));
+    }
   } else {
-    // Non-negative property indices are in the properties array.
-    __ ldr(result, FieldMemOperand(object, JSObject::kPropertiesOffset));
-    __ ldr(result, FieldMemOperand(result, offset + FixedArray::kHeaderSize));
+    Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*type));
+    LoadHeapObject(result, Handle<HeapObject>::cast(function));
   }
 }
 
@@ -2324,7 +2330,7 @@
       Label next;
       __ cmp(scratch, Operand(map));
       __ b(ne, &next);
-      EmitLoadField(result, object, map, name);
+      EmitLoadFieldOrConstantFunction(result, object, map, name);
       __ b(&done);
       __ bind(&next);
     }
@@ -2333,7 +2339,7 @@
     if (instr->hydrogen()->need_generic()) {
       Label generic;
       __ b(ne, &generic);
-      EmitLoadField(result, object, map, name);
+      EmitLoadFieldOrConstantFunction(result, object, map, name);
       __ b(&done);
       __ bind(&generic);
       __ mov(r2, Operand(name));
@@ -2341,7 +2347,7 @@
       CallCode(ic, RelocInfo::CODE_TARGET, instr);
     } else {
       DeoptimizeIf(ne, instr->environment());
-      EmitLoadField(result, object, map, name);
+      EmitLoadFieldOrConstantFunction(result, object, map, name);
     }
     __ bind(&done);
   }
diff --git a/src/arm/lithium-codegen-arm.h b/src/arm/lithium-codegen-arm.h
index 5dfb8e0..c219a6b 100644
--- a/src/arm/lithium-codegen-arm.h
+++ b/src/arm/lithium-codegen-arm.h
@@ -284,10 +284,10 @@
   // Caller should branch on equal condition.
   void EmitIsConstructCall(Register temp1, Register temp2);
 
-  void EmitLoadField(Register result,
-                     Register object,
-                     Handle<Map> type,
-                     Handle<String> name);
+  void EmitLoadFieldOrConstantFunction(Register result,
+                                       Register object,
+                                       Handle<Map> type,
+                                       Handle<String> name);
 
   LChunk* const chunk_;
   MacroAssembler* const masm_;
diff --git a/src/arm/simulator-arm.cc b/src/arm/simulator-arm.cc
index 68c2928..6af5355 100644
--- a/src/arm/simulator-arm.cc
+++ b/src/arm/simulator-arm.cc
@@ -719,20 +719,21 @@
 }
 
 
-void Simulator::Initialize() {
-  if (Isolate::Current()->simulator_initialized()) return;
-  Isolate::Current()->set_simulator_initialized(true);
-  ::v8::internal::ExternalReference::set_redirector(&RedirectExternalReference);
+void Simulator::Initialize(Isolate* isolate) {
+  if (isolate->simulator_initialized()) return;
+  isolate->set_simulator_initialized(true);
+  ::v8::internal::ExternalReference::set_redirector(isolate,
+                                                    &RedirectExternalReference);
 }
 
 
-Simulator::Simulator() : isolate_(Isolate::Current()) {
+Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
   i_cache_ = isolate_->simulator_i_cache();
   if (i_cache_ == NULL) {
     i_cache_ = new v8::internal::HashMap(&ICacheMatch);
     isolate_->set_simulator_i_cache(i_cache_);
   }
-  Initialize();
+  Initialize(isolate);
   // Setup simulator support first. Some of this information is needed to
   // setup the architecture state.
   size_t stack_size = 1 * 1024*1024;  // allocate 1MB for stack
@@ -848,17 +849,13 @@
 // Get the active Simulator for the current thread.
 Simulator* Simulator::current(Isolate* isolate) {
   v8::internal::Isolate::PerIsolateThreadData* isolate_data =
-      Isolate::CurrentPerIsolateThreadData();
-  if (isolate_data == NULL) {
-    Isolate::EnterDefaultIsolate();
-    isolate_data = Isolate::CurrentPerIsolateThreadData();
-  }
+      isolate->FindOrAllocatePerThreadDataForThisThread();
   ASSERT(isolate_data != NULL);
 
   Simulator* sim = isolate_data->simulator();
   if (sim == NULL) {
     // TODO(146): delete the simulator object when a thread/isolate goes away.
-    sim = new Simulator();
+    sim = new Simulator(isolate);
     isolate_data->set_simulator(sim);
   }
   return sim;
@@ -1018,13 +1015,13 @@
   } else {
     // We use a char buffer to get around the strict-aliasing rules which
     // otherwise allow the compiler to optimize away the copy.
-    char buffer[2 * sizeof(registers_[0])];
+    char buffer[sizeof(*x)];
     // Registers 0 and 1 -> x.
-    memcpy(buffer, registers_, sizeof(buffer));
-    memcpy(x, buffer, sizeof(buffer));
+    memcpy(buffer, registers_, sizeof(*x));
+    memcpy(x, buffer, sizeof(*x));
     // Registers 2 and 3 -> y.
-    memcpy(buffer, registers_ + 2, sizeof(buffer));
-    memcpy(y, buffer, sizeof(buffer));
+    memcpy(buffer, registers_ + 2, sizeof(*y));
+    memcpy(y, buffer, sizeof(*y));
   }
 }
 
@@ -1036,16 +1033,16 @@
   } else {
     // We use a char buffer to get around the strict-aliasing rules which
     // otherwise allow the compiler to optimize away the copy.
-    char buffer[2 * sizeof(registers_[0])];
+    char buffer[sizeof(*x)];
     // Registers 0 and 1 -> x.
-    memcpy(buffer, registers_, sizeof(buffer));
-    memcpy(x, buffer, sizeof(buffer));
+    memcpy(buffer, registers_, sizeof(*x));
+    memcpy(x, buffer, sizeof(*x));
   }
 }
 
 
-// For use in calls that take two double values, constructed either
-// from r0-r3 or d0 and d1.
+// For use in calls that take one double value constructed either
+// from r0 and r1 or d0 and one integer value.
 void Simulator::GetFpArgs(double* x, int32_t* y) {
   if (use_eabi_hardfloat()) {
     *x = vfp_register[0];
@@ -1053,13 +1050,13 @@
   } else {
     // We use a char buffer to get around the strict-aliasing rules which
     // otherwise allow the compiler to optimize away the copy.
-    char buffer[2 * sizeof(registers_[0])];
+    char buffer[sizeof(*x)];
     // Registers 0 and 1 -> x.
-    memcpy(buffer, registers_, sizeof(buffer));
-    memcpy(x, buffer, sizeof(buffer));
-    // Registers 2 and 3 -> y.
-    memcpy(buffer, registers_ + 2, sizeof(buffer));
-    memcpy(y, buffer, sizeof(buffer));
+    memcpy(buffer, registers_, sizeof(*x));
+    memcpy(x, buffer, sizeof(*x));
+    // Register 2 -> y.
+    memcpy(buffer, registers_ + 2, sizeof(*y));
+    memcpy(y, buffer, sizeof(*y));
   }
 }
 
diff --git a/src/arm/simulator-arm.h b/src/arm/simulator-arm.h
index 40c9d6d..391ef69 100644
--- a/src/arm/simulator-arm.h
+++ b/src/arm/simulator-arm.h
@@ -68,7 +68,9 @@
 // just use the C stack limit.
 class SimulatorStack : public v8::internal::AllStatic {
  public:
-  static inline uintptr_t JsLimitFromCLimit(uintptr_t c_limit) {
+  static inline uintptr_t JsLimitFromCLimit(v8::internal::Isolate* isolate,
+                                            uintptr_t c_limit) {
+    USE(isolate);
     return c_limit;
   }
 
@@ -143,7 +145,7 @@
     num_d_registers = 16
   };
 
-  Simulator();
+  explicit Simulator(Isolate* isolate);
   ~Simulator();
 
   // The currently executing Simulator instance. Potentially there can be one
@@ -179,7 +181,7 @@
   void Execute();
 
   // Call on program start.
-  static void Initialize();
+  static void Initialize(Isolate* isolate);
 
   // V8 generally calls into generated JS code with 5 parameters and into
   // generated RegExp code with 7 parameters. This is a convenience function,
@@ -408,8 +410,9 @@
 // trouble down the line.
 class SimulatorStack : public v8::internal::AllStatic {
  public:
-  static inline uintptr_t JsLimitFromCLimit(uintptr_t c_limit) {
-    return Simulator::current(Isolate::Current())->StackLimit();
+  static inline uintptr_t JsLimitFromCLimit(v8::internal::Isolate* isolate,
+                                            uintptr_t c_limit) {
+    return Simulator::current(isolate)->StackLimit();
   }
 
   static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc
index 97097c8..6fd5063 100644
--- a/src/arm/stub-cache-arm.cc
+++ b/src/arm/stub-cache-arm.cc
@@ -136,69 +136,15 @@
   // Restore the temporarily used register.
   __ ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
 
-  // Compute the capacity mask.
-  const int kCapacityOffset =
-      StringDictionary::kHeaderSize +
-      StringDictionary::kCapacityIndex * kPointerSize;
 
-  // Generate an unrolled loop that performs a few probes before
-  // giving up.
-  static const int kProbes = 4;
-  const int kElementsStartOffset =
-      StringDictionary::kHeaderSize +
-      StringDictionary::kElementsStartIndex * kPointerSize;
+  StringDictionaryLookupStub::GenerateNegativeLookup(masm,
+                                                     miss_label,
+                                                     &done,
+                                                     receiver,
+                                                     properties,
+                                                     name,
+                                                     scratch1);
 
-  // If names of slots in range from 1 to kProbes - 1 for the hash value are
-  // not equal to the name and kProbes-th slot is not used (its name is the
-  // undefined value), it guarantees the hash table doesn't contain the
-  // property. It's true even if some slots represent deleted properties
-  // (their names are the null value).
-  for (int i = 0; i < kProbes; i++) {
-    // scratch0 points to properties hash.
-    // Compute the masked index: (hash + i + i * i) & mask.
-    Register index = scratch1;
-    // Capacity is smi 2^n.
-    __ ldr(index, FieldMemOperand(properties, kCapacityOffset));
-    __ sub(index, index, Operand(1));
-    __ and_(index, index, Operand(
-        Smi::FromInt(name->Hash() + StringDictionary::GetProbeOffset(i))));
-
-    // Scale the index by multiplying by the entry size.
-    ASSERT(StringDictionary::kEntrySize == 3);
-    __ add(index, index, Operand(index, LSL, 1));  // index *= 3.
-
-    Register entity_name = scratch1;
-    // Having undefined at this place means the name is not contained.
-    ASSERT_EQ(kSmiTagSize, 1);
-    Register tmp = properties;
-    __ add(tmp, properties, Operand(index, LSL, 1));
-    __ ldr(entity_name, FieldMemOperand(tmp, kElementsStartOffset));
-
-    ASSERT(!tmp.is(entity_name));
-    __ LoadRoot(tmp, Heap::kUndefinedValueRootIndex);
-    __ cmp(entity_name, tmp);
-    if (i != kProbes - 1) {
-      __ b(eq, &done);
-
-      // Stop if found the property.
-      __ cmp(entity_name, Operand(Handle<String>(name)));
-      __ b(eq, miss_label);
-
-      // Check if the entry name is not a symbol.
-      __ ldr(entity_name, FieldMemOperand(entity_name, HeapObject::kMapOffset));
-      __ ldrb(entity_name,
-              FieldMemOperand(entity_name, Map::kInstanceTypeOffset));
-      __ tst(entity_name, Operand(kIsSymbolMask));
-      __ b(eq, miss_label);
-
-      // Restore the properties.
-      __ ldr(properties,
-             FieldMemOperand(receiver, JSObject::kPropertiesOffset));
-    } else {
-      // Give up probing if still not found the undefined value.
-      __ b(ne, miss_label);
-    }
-  }
   __ bind(&done);
   __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
 }
diff --git a/src/array.js b/src/array.js
index b062083..df080a7 100644
--- a/src/array.js
+++ b/src/array.js
@@ -397,6 +397,11 @@
 
 
 function ArrayJoin(separator) {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["Array.prototype.join"]);
+  }
+
   if (IS_UNDEFINED(separator)) {
     separator = ',';
   } else if (!IS_STRING(separator)) {
@@ -413,6 +418,11 @@
 // Removes the last element from the array and returns it. See
 // ECMA-262, section 15.4.4.6.
 function ArrayPop() {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["Array.prototype.pop"]);
+  }
+
   var n = TO_UINT32(this.length);
   if (n == 0) {
     this.length = n;
@@ -429,6 +439,11 @@
 // Appends the arguments to the end of the array and returns the new
 // length of the array. See ECMA-262, section 15.4.4.7.
 function ArrayPush() {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["Array.prototype.push"]);
+  }
+
   var n = TO_UINT32(this.length);
   var m = %_ArgumentsLength();
   for (var i = 0; i < m; i++) {
@@ -440,6 +455,11 @@
 
 
 function ArrayConcat(arg1) {  // length == 1
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["Array.prototype.concat"]);
+  }
+
   var arg_count = %_ArgumentsLength();
   var arrays = new InternalArray(1 + arg_count);
   arrays[0] = this;
@@ -496,6 +516,11 @@
 
 
 function ArrayReverse() {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["Array.prototype.reverse"]);
+  }
+
   var j = TO_UINT32(this.length) - 1;
 
   if (UseSparseVariant(this, j, IS_ARRAY(this))) {
@@ -527,6 +552,11 @@
 
 
 function ArrayShift() {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["Array.prototype.shift"]);
+  }
+
   var len = TO_UINT32(this.length);
 
   if (len === 0) {
@@ -548,6 +578,11 @@
 
 
 function ArrayUnshift(arg1) {  // length == 1
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["Array.prototype.unshift"]);
+  }
+
   var len = TO_UINT32(this.length);
   var num_arguments = %_ArgumentsLength();
 
@@ -567,6 +602,11 @@
 
 
 function ArraySlice(start, end) {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["Array.prototype.slice"]);
+  }
+
   var len = TO_UINT32(this.length);
   var start_i = TO_INTEGER(start);
   var end_i = len;
@@ -604,6 +644,11 @@
 
 
 function ArraySplice(start, delete_count) {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["Array.prototype.splice"]);
+  }
+
   var num_arguments = %_ArgumentsLength();
 
   var len = TO_UINT32(this.length);
@@ -675,6 +720,11 @@
 
 
 function ArraySort(comparefn) {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["Array.prototype.sort"]);
+  }
+
   // In-place QuickSort algorithm.
   // For short (length <= 22) arrays, insertion sort is used for efficiency.
 
@@ -936,6 +986,11 @@
 // preserving the semantics, since the calls to the receiver function can add
 // or delete elements from the array.
 function ArrayFilter(f, receiver) {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["Array.prototype.filter"]);
+  }
+
   if (!IS_FUNCTION(f)) {
     throw MakeTypeError('called_non_callable', [ f ]);
   }
@@ -957,6 +1012,11 @@
 
 
 function ArrayForEach(f, receiver) {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["Array.prototype.forEach"]);
+  }
+
   if (!IS_FUNCTION(f)) {
     throw MakeTypeError('called_non_callable', [ f ]);
   }
@@ -975,6 +1035,11 @@
 // Executes the function once for each element present in the
 // array until it finds one where callback returns true.
 function ArraySome(f, receiver) {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["Array.prototype.some"]);
+  }
+
   if (!IS_FUNCTION(f)) {
     throw MakeTypeError('called_non_callable', [ f ]);
   }
@@ -992,6 +1057,11 @@
 
 
 function ArrayEvery(f, receiver) {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["Array.prototype.every"]);
+  }
+
   if (!IS_FUNCTION(f)) {
     throw MakeTypeError('called_non_callable', [ f ]);
   }
@@ -1008,6 +1078,11 @@
 }
 
 function ArrayMap(f, receiver) {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["Array.prototype.map"]);
+  }
+
   if (!IS_FUNCTION(f)) {
     throw MakeTypeError('called_non_callable', [ f ]);
   }
@@ -1028,6 +1103,11 @@
 
 
 function ArrayIndexOf(element, index) {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["Array.prototype.indexOf"]);
+  }
+
   var length = TO_UINT32(this.length);
   if (length == 0) return -1;
   if (IS_UNDEFINED(index)) {
@@ -1085,6 +1165,11 @@
 
 
 function ArrayLastIndexOf(element, index) {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["Array.prototype.lastIndexOf"]);
+  }
+
   var length = TO_UINT32(this.length);
   if (length == 0) return -1;
   if (%_ArgumentsLength() < 2) {
@@ -1138,6 +1223,11 @@
 
 
 function ArrayReduce(callback, current) {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["Array.prototype.reduce"]);
+  }
+
   if (!IS_FUNCTION(callback)) {
     throw MakeTypeError('called_non_callable', [callback]);
   }
@@ -1167,6 +1257,11 @@
 }
 
 function ArrayReduceRight(callback, current) {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["Array.prototype.reduceRight"]);
+  }
+
   if (!IS_FUNCTION(callback)) {
     throw MakeTypeError('called_non_callable', [callback]);
   }
diff --git a/src/assembler.h b/src/assembler.h
index ef4ddc0..10d90a9 100644
--- a/src/assembler.h
+++ b/src/assembler.h
@@ -35,6 +35,7 @@
 #ifndef V8_ASSEMBLER_H_
 #define V8_ASSEMBLER_H_
 
+#include "allocation.h"
 #include "gdb-jit.h"
 #include "runtime.h"
 #include "token.h"
@@ -673,10 +674,11 @@
 
   // This lets you register a function that rewrites all external references.
   // Used by the ARM simulator to catch calls to external references.
-  static void set_redirector(ExternalReferenceRedirector* redirector) {
+  static void set_redirector(Isolate* isolate,
+                             ExternalReferenceRedirector* redirector) {
     // We can't stack them.
-    ASSERT(Isolate::Current()->external_reference_redirector() == NULL);
-    Isolate::Current()->set_external_reference_redirector(
+    ASSERT(isolate->external_reference_redirector() == NULL);
+    isolate->set_external_reference_redirector(
         reinterpret_cast<ExternalReferenceRedirectorPointer*>(redirector));
   }
 
diff --git a/src/ast.h b/src/ast.h
index b98b8e7..3de84bd 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -28,6 +28,7 @@
 #ifndef V8_AST_H_
 #define V8_AST_H_
 
+#include "allocation.h"
 #include "execution.h"
 #include "factory.h"
 #include "jsregexp.h"
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index 0800714..eb7a4ce 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -1253,8 +1253,7 @@
                      ? top_context->builtins()
                      : top_context->global());
   bool has_pending_exception;
-  Handle<Object> result =
-      Execution::Call(fun, receiver, 0, NULL, &has_pending_exception);
+  Execution::Call(fun, receiver, 0, NULL, &has_pending_exception);
   if (has_pending_exception) return false;
   return true;
 }
diff --git a/src/bootstrapper.h b/src/bootstrapper.h
index 018ceef..2f06608 100644
--- a/src/bootstrapper.h
+++ b/src/bootstrapper.h
@@ -29,6 +29,8 @@
 #ifndef V8_BOOTSTRAPPER_H_
 #define V8_BOOTSTRAPPER_H_
 
+#include "allocation.h"
+
 namespace v8 {
 namespace internal {
 
diff --git a/src/builtins.cc b/src/builtins.cc
index 377de05..f473559 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -1026,6 +1026,8 @@
                                 Object** argv,
                                 FunctionTemplateInfo* info) {
   Object* recv = argv[0];
+  // API calls are only supported with JSObject receivers.
+  if (!recv->IsJSObject()) return heap->null_value();
   Object* sig_obj = info->signature();
   if (sig_obj->IsUndefined()) return recv;
   SignatureInfo* sig = SignatureInfo::cast(sig_obj);
diff --git a/src/code-stubs.cc b/src/code-stubs.cc
index f680c60..954180c 100644
--- a/src/code-stubs.cc
+++ b/src/code-stubs.cc
@@ -197,6 +197,9 @@
     case CompareIC::HEAP_NUMBERS:
       GenerateHeapNumbers(masm);
       break;
+    case CompareIC::STRINGS:
+      GenerateStrings(masm);
+      break;
     case CompareIC::OBJECTS:
       GenerateObjects(masm);
       break;
diff --git a/src/code-stubs.h b/src/code-stubs.h
index d57d2be..4c5b2ff 100644
--- a/src/code-stubs.h
+++ b/src/code-stubs.h
@@ -28,6 +28,7 @@
 #ifndef V8_CODE_STUBS_H_
 #define V8_CODE_STUBS_H_
 
+#include "allocation.h"
 #include "globals.h"
 
 namespace v8 {
@@ -65,7 +66,8 @@
   V(NumberToString)                      \
   V(CEntry)                              \
   V(JSEntry)                             \
-  V(DebuggerStatement)
+  V(DebuggerStatement)                   \
+  V(StringDictionaryNegativeLookup)
 
 // List of code stubs only used on ARM platforms.
 #ifdef V8_TARGET_ARCH_ARM
@@ -424,6 +426,7 @@
 
   void GenerateSmis(MacroAssembler* masm);
   void GenerateHeapNumbers(MacroAssembler* masm);
+  void GenerateStrings(MacroAssembler* masm);
   void GenerateObjects(MacroAssembler* masm);
   void GenerateMiss(MacroAssembler* masm);
 
diff --git a/src/code.h b/src/code.h
index 072344b..766c932 100644
--- a/src/code.h
+++ b/src/code.h
@@ -28,6 +28,8 @@
 #ifndef V8_CODE_H_
 #define V8_CODE_H_
 
+#include "allocation.h"
+
 namespace v8 {
 namespace internal {
 
diff --git a/src/compiler.cc b/src/compiler.cc
index e9b48cb..985a951 100755
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -95,21 +95,13 @@
 
 
 void CompilationInfo::DisableOptimization() {
-  if (FLAG_optimize_closures) {
-    // If we allow closures optimizations and it's an optimizable closure
-    // mark it correspondingly.
-    bool is_closure = closure_.is_null() && !scope_->HasTrivialOuterContext();
-    if (is_closure) {
-      bool is_optimizable_closure =
-          !scope_->outer_scope_calls_eval() && !scope_->inside_with();
-      if (is_optimizable_closure) {
-        SetMode(BASE);
-        return;
-      }
-    }
-  }
-
-  SetMode(NONOPT);
+  bool is_optimizable_closure =
+    FLAG_optimize_closures &&
+    closure_.is_null() &&
+    !scope_->HasTrivialOuterContext() &&
+    !scope_->outer_scope_calls_eval() &&
+    !scope_->inside_with();
+  SetMode(is_optimizable_closure ? BASE : NONOPT);
 }
 
 
@@ -121,20 +113,23 @@
 // all. However crankshaft support recompilation of functions, so in this case
 // the full compiler need not be be used if a debugger is attached, but only if
 // break points has actually been set.
-static bool AlwaysFullCompiler() {
+static bool is_debugging_active() {
 #ifdef ENABLE_DEBUGGER_SUPPORT
   Isolate* isolate = Isolate::Current();
-  if (V8::UseCrankshaft()) {
-    return FLAG_always_full_compiler || isolate->debug()->has_break_points();
-  } else {
-    return FLAG_always_full_compiler || isolate->debugger()->IsDebuggerActive();
-  }
+  return V8::UseCrankshaft() ?
+    isolate->debug()->has_break_points() :
+    isolate->debugger()->IsDebuggerActive();
 #else
-  return FLAG_always_full_compiler;
+  return false;
 #endif
 }
 
 
+static bool AlwaysFullCompiler() {
+  return FLAG_always_full_compiler || is_debugging_active();
+}
+
+
 static void FinishOptimization(Handle<JSFunction> function, int64_t start) {
   int opt_count = function->shared()->opt_count();
   function->shared()->set_opt_count(opt_count + 1);
@@ -318,19 +313,18 @@
 }
 
 
+static bool GenerateCode(CompilationInfo* info) {
+  return V8::UseCrankshaft() ?
+    MakeCrankshaftCode(info) :
+    FullCodeGenerator::MakeCode(info);
+}
+
+
 static bool MakeCode(CompilationInfo* info) {
   // Precondition: code has been parsed.  Postcondition: the code field in
   // the compilation info is set if compilation succeeded.
   ASSERT(info->function() != NULL);
-
-  if (Rewriter::Rewrite(info) && Scope::Analyze(info)) {
-    if (V8::UseCrankshaft()) return MakeCrankshaftCode(info);
-    // If crankshaft is not supported fall back to full code generator
-    // for all compilation.
-    return FullCodeGenerator::MakeCode(info);
-  }
-
-  return false;
+  return Rewriter::Rewrite(info) && Scope::Analyze(info) && GenerateCode(info);
 }
 
 
diff --git a/src/compiler.h b/src/compiler.h
index e75e869..c19ceff 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -28,6 +28,7 @@
 #ifndef V8_COMPILER_H_
 #define V8_COMPILER_H_
 
+#include "allocation.h"
 #include "ast.h"
 #include "frame-element.h"
 #include "zone.h"
diff --git a/src/cpu-profiler.h b/src/cpu-profiler.h
index 4e39527..9481d3b 100644
--- a/src/cpu-profiler.h
+++ b/src/cpu-profiler.h
@@ -30,6 +30,7 @@
 
 #ifdef ENABLE_LOGGING_AND_PROFILING
 
+#include "allocation.h"
 #include "atomicops.h"
 #include "circular-queue.h"
 #include "unbound-queue.h"
diff --git a/src/cpu.h b/src/cpu.h
index e307302..2525484 100644
--- a/src/cpu.h
+++ b/src/cpu.h
@@ -36,6 +36,8 @@
 #ifndef V8_CPU_H_
 #define V8_CPU_H_
 
+#include "allocation.h"
+
 namespace v8 {
 namespace internal {
 
diff --git a/src/d8.h b/src/d8.h
index 6c973ad..dc02322 100644
--- a/src/d8.h
+++ b/src/d8.h
@@ -28,6 +28,7 @@
 #ifndef V8_D8_H_
 #define V8_D8_H_
 
+#include "allocation.h"
 #include "v8.h"
 #include "hashmap.h"
 
diff --git a/src/data-flow.h b/src/data-flow.h
index da92102..d69d6c7 100644
--- a/src/data-flow.h
+++ b/src/data-flow.h
@@ -30,6 +30,7 @@
 
 #include "v8.h"
 
+#include "allocation.h"
 #include "ast.h"
 #include "compiler.h"
 #include "zone-inl.h"
diff --git a/src/date.js b/src/date.js
index 242ab7b..5a2e9a2 100644
--- a/src/date.js
+++ b/src/date.js
@@ -684,7 +684,7 @@
 
 // ECMA 262 - 15.9.5.16
 function DateGetDay() {
-  var t = %_ValueOf(this);
+  var t = DATE_VALUE(this);
   if (NUMBER_IS_NAN(t)) return t;
   return WeekDay(LocalTimeNoCheck(t));
 }
@@ -692,7 +692,7 @@
 
 // ECMA 262 - 15.9.5.17
 function DateGetUTCDay() {
-  var t = %_ValueOf(this);
+  var t = DATE_VALUE(this);
   if (NUMBER_IS_NAN(t)) return t;
   return WeekDay(t);
 }
diff --git a/src/dateparser.h b/src/dateparser.h
index 9d29715..6e87c34 100644
--- a/src/dateparser.h
+++ b/src/dateparser.h
@@ -28,6 +28,7 @@
 #ifndef V8_DATEPARSER_H_
 #define V8_DATEPARSER_H_
 
+#include "allocation.h"
 #include "char-predicates-inl.h"
 #include "scanner-base.h"
 
diff --git a/src/debug.h b/src/debug.h
index dbaabe9..95dca72 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -28,6 +28,7 @@
 #ifndef V8_DEBUG_H_
 #define V8_DEBUG_H_
 
+#include "allocation.h"
 #include "arguments.h"
 #include "assembler.h"
 #include "debug-agent.h"
diff --git a/src/deoptimizer.h b/src/deoptimizer.h
index cb82f44..7c5dfb8 100644
--- a/src/deoptimizer.h
+++ b/src/deoptimizer.h
@@ -30,6 +30,7 @@
 
 #include "v8.h"
 
+#include "allocation.h"
 #include "macro-assembler.h"
 #include "zone-inl.h"
 
diff --git a/src/disassembler.h b/src/disassembler.h
index 68a338d..4a87dca 100644
--- a/src/disassembler.h
+++ b/src/disassembler.h
@@ -28,6 +28,8 @@
 #ifndef V8_DISASSEMBLER_H_
 #define V8_DISASSEMBLER_H_
 
+#include "allocation.h"
+
 namespace v8 {
 namespace internal {
 
diff --git a/src/execution.cc b/src/execution.cc
index eb26438..db74492 100644
--- a/src/execution.cc
+++ b/src/execution.cc
@@ -234,6 +234,30 @@
 }
 
 
+Handle<Object> Execution::TryGetFunctionDelegate(Handle<Object> object,
+                                                 bool* has_pending_exception) {
+  ASSERT(!object->IsJSFunction());
+  Isolate* isolate = Isolate::Current();
+
+  // Objects created through the API can have an instance-call handler
+  // that should be used when calling the object as a function.
+  if (object->IsHeapObject() &&
+      HeapObject::cast(*object)->map()->has_instance_call_handler()) {
+    return Handle<JSFunction>(
+        isolate->global_context()->call_as_function_delegate());
+  }
+
+  // If the Object doesn't have an instance-call handler we should
+  // throw a non-callable exception.
+  i::Handle<i::Object> error_obj = isolate->factory()->NewTypeError(
+      "called_non_callable", i::HandleVector<i::Object>(&object, 1));
+  isolate->Throw(*error_obj);
+  *has_pending_exception = true;
+
+  return isolate->factory()->undefined_value();
+}
+
+
 Handle<Object> Execution::GetConstructorDelegate(Handle<Object> object) {
   ASSERT(!object->IsJSFunction());
   Isolate* isolate = Isolate::Current();
@@ -253,6 +277,34 @@
 }
 
 
+Handle<Object> Execution::TryGetConstructorDelegate(
+    Handle<Object> object,
+    bool* has_pending_exception) {
+  ASSERT(!object->IsJSFunction());
+  Isolate* isolate = Isolate::Current();
+
+  // If you return a function from here, it will be called when an
+  // attempt is made to call the given object as a constructor.
+
+  // Objects created through the API can have an instance-call handler
+  // that should be used when calling the object as a function.
+  if (object->IsHeapObject() &&
+      HeapObject::cast(*object)->map()->has_instance_call_handler()) {
+    return Handle<JSFunction>(
+        isolate->global_context()->call_as_constructor_delegate());
+  }
+
+  // If the Object doesn't have an instance-call handler we should
+  // throw a non-callable exception.
+  i::Handle<i::Object> error_obj = isolate->factory()->NewTypeError(
+      "called_non_callable", i::HandleVector<i::Object>(&object, 1));
+  isolate->Throw(*error_obj);
+  *has_pending_exception = true;
+
+  return isolate->factory()->undefined_value();
+}
+
+
 bool StackGuard::IsStackOverflow() {
   ExecutionAccess access(isolate_);
   return (thread_local_.jslimit_ != kInterruptLimit &&
@@ -272,7 +324,7 @@
   ExecutionAccess access(isolate_);
   // If the current limits are special (eg due to a pending interrupt) then
   // leave them alone.
-  uintptr_t jslimit = SimulatorStack::JsLimitFromCLimit(limit);
+  uintptr_t jslimit = SimulatorStack::JsLimitFromCLimit(isolate_, limit);
   if (thread_local_.jslimit_ == thread_local_.real_jslimit_) {
     thread_local_.jslimit_ = jslimit;
   }
@@ -428,7 +480,7 @@
 }
 
 
-bool StackGuard::ThreadLocal::Initialize() {
+bool StackGuard::ThreadLocal::Initialize(Isolate* isolate) {
   bool should_set_stack_limits = false;
   if (real_climit_ == kIllegalLimit) {
     // Takes the address of the limit variable in order to find out where
@@ -436,8 +488,8 @@
     const uintptr_t kLimitSize = FLAG_stack_size * KB;
     uintptr_t limit = reinterpret_cast<uintptr_t>(&limit) - kLimitSize;
     ASSERT(reinterpret_cast<uintptr_t>(&limit) > kLimitSize);
-    real_jslimit_ = SimulatorStack::JsLimitFromCLimit(limit);
-    jslimit_ = SimulatorStack::JsLimitFromCLimit(limit);
+    real_jslimit_ = SimulatorStack::JsLimitFromCLimit(isolate, limit);
+    jslimit_ = SimulatorStack::JsLimitFromCLimit(isolate, limit);
     real_climit_ = limit;
     climit_ = limit;
     should_set_stack_limits = true;
@@ -456,9 +508,10 @@
 
 
 void StackGuard::InitThread(const ExecutionAccess& lock) {
-  if (thread_local_.Initialize()) isolate_->heap()->SetStackLimits();
-  uintptr_t stored_limit =
-      Isolate::CurrentPerIsolateThreadData()->stack_limit();
+  if (thread_local_.Initialize(isolate_)) isolate_->heap()->SetStackLimits();
+  Isolate::PerIsolateThreadData* per_thread =
+      isolate_->FindOrAllocatePerThreadDataForThisThread();
+  uintptr_t stored_limit = per_thread->stack_limit();
   // You should hold the ExecutionAccess lock when you call this.
   if (stored_limit != 0) {
     StackGuard::SetStackLimit(stored_limit);
@@ -681,13 +734,13 @@
     isolate->debug()->PreemptionWhileInDebugger();
   } else {
     // Perform preemption.
-    v8::Unlocker unlocker;
+    v8::Unlocker unlocker(reinterpret_cast<v8::Isolate*>(isolate));
     Thread::YieldCPU();
   }
 #else
   { // NOLINT
     // Perform preemption.
-    v8::Unlocker unlocker;
+    v8::Unlocker unlocker(reinterpret_cast<v8::Isolate*>(isolate));
     Thread::YieldCPU();
   }
 #endif
diff --git a/src/execution.h b/src/execution.h
index d4b80d2..7b6a48c 100644
--- a/src/execution.h
+++ b/src/execution.h
@@ -28,6 +28,8 @@
 #ifndef V8_EXECUTION_H_
 #define V8_EXECUTION_H_
 
+#include "allocation.h"
+
 namespace v8 {
 namespace internal {
 
@@ -138,10 +140,14 @@
   // Get a function delegate (or undefined) for the given non-function
   // object. Used for support calling objects as functions.
   static Handle<Object> GetFunctionDelegate(Handle<Object> object);
+  static Handle<Object> TryGetFunctionDelegate(Handle<Object> object,
+                                               bool* has_pending_exception);
 
   // Get a function delegate (or undefined) for the given non-function
   // object. Used for support calling objects as constructors.
   static Handle<Object> GetConstructorDelegate(Handle<Object> object);
+  static Handle<Object> TryGetConstructorDelegate(Handle<Object> object,
+                                                  bool* has_pending_exception);
 };
 
 
@@ -252,7 +258,7 @@
     void Clear();
 
     // Returns true if the heap's stack limits should be set, false if not.
-    bool Initialize();
+    bool Initialize(Isolate* isolate);
 
     // The stack limit is split into a JavaScript and a C++ stack limit. These
     // two are the same except when running on a simulator where the C++ and
diff --git a/src/extensions/experimental/experimental.gyp b/src/extensions/experimental/experimental.gyp
index d1194ce..2a7775e 100644
--- a/src/extensions/experimental/experimental.gyp
+++ b/src/extensions/experimental/experimental.gyp
@@ -45,6 +45,10 @@
         'i18n-extension.h',
         'i18n-locale.cc',
         'i18n-locale.h',
+        'i18n-utils.cc',
+        'i18n-utils.h',
+        'language-matcher.cc',
+        'language-matcher.h',
         '<(SHARED_INTERMEDIATE_DIR)/i18n-js.cc',
       ],
       'include_dirs': [
diff --git a/src/extensions/experimental/i18n-extension.cc b/src/extensions/experimental/i18n-extension.cc
index 56bea23..88c609e 100644
--- a/src/extensions/experimental/i18n-extension.cc
+++ b/src/extensions/experimental/i18n-extension.cc
@@ -55,20 +55,6 @@
     v8::Handle<v8::String> name) {
   if (name->Equals(v8::String::New("NativeJSLocale"))) {
     return v8::FunctionTemplate::New(I18NLocale::JSLocale);
-  } else if (name->Equals(v8::String::New("NativeJSAvailableLocales"))) {
-    return v8::FunctionTemplate::New(I18NLocale::JSAvailableLocales);
-  } else if (name->Equals(v8::String::New("NativeJSMaximizedLocale"))) {
-    return v8::FunctionTemplate::New(I18NLocale::JSMaximizedLocale);
-  } else if (name->Equals(v8::String::New("NativeJSMinimizedLocale"))) {
-    return v8::FunctionTemplate::New(I18NLocale::JSMinimizedLocale);
-  } else if (name->Equals(v8::String::New("NativeJSDisplayLanguage"))) {
-    return v8::FunctionTemplate::New(I18NLocale::JSDisplayLanguage);
-  } else if (name->Equals(v8::String::New("NativeJSDisplayScript"))) {
-    return v8::FunctionTemplate::New(I18NLocale::JSDisplayScript);
-  } else if (name->Equals(v8::String::New("NativeJSDisplayRegion"))) {
-    return v8::FunctionTemplate::New(I18NLocale::JSDisplayRegion);
-  } else if (name->Equals(v8::String::New("NativeJSDisplayName"))) {
-    return v8::FunctionTemplate::New(I18NLocale::JSDisplayName);
   } else if (name->Equals(v8::String::New("NativeJSBreakIterator"))) {
     return v8::FunctionTemplate::New(BreakIterator::JSBreakIterator);
   } else if (name->Equals(v8::String::New("NativeJSCollator"))) {
diff --git a/src/extensions/experimental/i18n-locale.cc b/src/extensions/experimental/i18n-locale.cc
index e5e1cf8..cf17812 100644
--- a/src/extensions/experimental/i18n-locale.cc
+++ b/src/extensions/experimental/i18n-locale.cc
@@ -27,146 +27,86 @@
 
 #include "i18n-locale.h"
 
-#include <algorithm>
-#include <string>
-
+#include "i18n-utils.h"
+#include "language-matcher.h"
 #include "unicode/locid.h"
 #include "unicode/uloc.h"
+#include "utils.h"
 
 namespace v8 {
 namespace internal {
 
+const char* const I18NLocale::kLocaleID = "localeID";
+const char* const I18NLocale::kRegionID = "regionID";
+const char* const I18NLocale::kICULocaleID = "icuLocaleID";
+
 v8::Handle<v8::Value> I18NLocale::JSLocale(const v8::Arguments& args) {
-  // TODO(cira): Fetch browser locale. Accept en-US as good default for now.
-  // We could possibly pass browser locale as a parameter in the constructor.
-  std::string locale_name("en-US");
-  if (args.Length() == 1 && args[0]->IsString()) {
-    locale_name = *v8::String::Utf8Value(args[0]->ToString());
-  }
+  v8::HandleScope handle_scope;
 
-  v8::Local<v8::Object> locale = v8::Object::New();
-  locale->Set(v8::String::New("locale"), v8::String::New(locale_name.c_str()));
-
-  icu::Locale icu_locale(locale_name.c_str());
-
-  const char* language = icu_locale.getLanguage();
-  locale->Set(v8::String::New("language"), v8::String::New(language));
-
-  const char* script = icu_locale.getScript();
-  if (strlen(script)) {
-    locale->Set(v8::String::New("script"), v8::String::New(script));
-  }
-
-  const char* region = icu_locale.getCountry();
-  if (strlen(region)) {
-    locale->Set(v8::String::New("region"), v8::String::New(region));
-  }
-
-  return locale;
-}
-
-// TODO(cira): Filter out locales that Chrome doesn't support.
-v8::Handle<v8::Value> I18NLocale::JSAvailableLocales(
-    const v8::Arguments& args) {
-  v8::Local<v8::Array> all_locales = v8::Array::New();
-
-  int count = 0;
-  const icu::Locale* icu_locales = icu::Locale::getAvailableLocales(count);
-  for (int i = 0; i < count; ++i) {
-    all_locales->Set(i, v8::String::New(icu_locales[i].getName()));
-  }
-
-  return all_locales;
-}
-
-// Use - as tag separator, not _ that ICU uses.
-static std::string NormalizeLocale(const std::string& locale) {
-  std::string result(locale);
-  // TODO(cira): remove STL dependency.
-  std::replace(result.begin(), result.end(), '_', '-');
-  return result;
-}
-
-v8::Handle<v8::Value> I18NLocale::JSMaximizedLocale(const v8::Arguments& args) {
-  if (!args.Length() || !args[0]->IsString()) {
+  if (args.Length() != 1 || !args[0]->IsObject()) {
     return v8::Undefined();
   }
 
-  UErrorCode status = U_ZERO_ERROR;
-  std::string locale_name = *v8::String::Utf8Value(args[0]->ToString());
-  char max_locale[ULOC_FULLNAME_CAPACITY];
-  uloc_addLikelySubtags(locale_name.c_str(), max_locale,
-                        sizeof(max_locale), &status);
-  if (U_FAILURE(status)) {
+  v8::Local<v8::Object> settings = args[0]->ToObject();
+
+  // Get best match for locale.
+  v8::TryCatch try_catch;
+  v8::Handle<v8::Value> locale_id = settings->Get(v8::String::New(kLocaleID));
+  if (try_catch.HasCaught()) {
     return v8::Undefined();
   }
 
-  return v8::String::New(NormalizeLocale(max_locale).c_str());
-}
-
-v8::Handle<v8::Value> I18NLocale::JSMinimizedLocale(const v8::Arguments& args) {
-  if (!args.Length() || !args[0]->IsString()) {
-    return v8::Undefined();
-  }
-
-  UErrorCode status = U_ZERO_ERROR;
-  std::string locale_name = *v8::String::Utf8Value(args[0]->ToString());
-  char min_locale[ULOC_FULLNAME_CAPACITY];
-  uloc_minimizeSubtags(locale_name.c_str(), min_locale,
-                       sizeof(min_locale), &status);
-  if (U_FAILURE(status)) {
-    return v8::Undefined();
-  }
-
-  return v8::String::New(NormalizeLocale(min_locale).c_str());
-}
-
-// Common code for JSDisplayXXX methods.
-static v8::Handle<v8::Value> GetDisplayItem(const v8::Arguments& args,
-                                            const std::string& item) {
-  if (args.Length() != 2 || !args[0]->IsString() || !args[1]->IsString()) {
-    return v8::Undefined();
-  }
-
-  std::string base_locale = *v8::String::Utf8Value(args[0]->ToString());
-  icu::Locale icu_locale(base_locale.c_str());
-  icu::Locale display_locale =
-      icu::Locale(*v8::String::Utf8Value(args[1]->ToString()));
-  icu::UnicodeString result;
-  if (item == "language") {
-    icu_locale.getDisplayLanguage(display_locale, result);
-  } else if (item == "script") {
-    icu_locale.getDisplayScript(display_locale, result);
-  } else if (item == "region") {
-    icu_locale.getDisplayCountry(display_locale, result);
-  } else if (item == "name") {
-    icu_locale.getDisplayName(display_locale, result);
+  LocaleIDMatch result;
+  if (locale_id->IsArray()) {
+    LanguageMatcher::GetBestMatchForPriorityList(
+        v8::Handle<v8::Array>::Cast(locale_id), &result);
+  } else if (locale_id->IsString()) {
+    LanguageMatcher::GetBestMatchForString(locale_id->ToString(), &result);
   } else {
+    LanguageMatcher::GetBestMatchForString(v8::String::New(""), &result);
+  }
+
+  // Get best match for region.
+  char region_id[ULOC_COUNTRY_CAPACITY];
+  I18NUtils::StrNCopy(region_id, ULOC_COUNTRY_CAPACITY, "");
+
+  v8::Handle<v8::Value> region = settings->Get(v8::String::New(kRegionID));
+  if (try_catch.HasCaught()) {
     return v8::Undefined();
   }
 
-  if (result.length()) {
-    return v8::String::New(
-        reinterpret_cast<const uint16_t*>(result.getBuffer()), result.length());
+  if (!GetBestMatchForRegionID(result.icu_id, region, region_id)) {
+    // Set region id to empty string because region couldn't be inferred.
+    I18NUtils::StrNCopy(region_id, ULOC_COUNTRY_CAPACITY, "");
   }
 
-  return v8::Undefined();
+  // Build JavaScript object that contains bcp and icu locale ID and region ID.
+  v8::Handle<v8::Object> locale = v8::Object::New();
+  locale->Set(v8::String::New(kLocaleID), v8::String::New(result.bcp47_id));
+  locale->Set(v8::String::New(kICULocaleID), v8::String::New(result.icu_id));
+  locale->Set(v8::String::New(kRegionID), v8::String::New(region_id));
+
+  return handle_scope.Close(locale);
 }
 
-v8::Handle<v8::Value> I18NLocale::JSDisplayLanguage(const v8::Arguments& args) {
-  return GetDisplayItem(args, "language");
-}
+bool I18NLocale::GetBestMatchForRegionID(
+    const char* locale_id, v8::Handle<v8::Value> region_id, char* result) {
+  if (region_id->IsString() && region_id->ToString()->Length() != 0) {
+    icu::Locale user_locale(
+        icu::Locale("und", *v8::String::Utf8Value(region_id->ToString())));
+    I18NUtils::StrNCopy(
+        result, ULOC_COUNTRY_CAPACITY, user_locale.getCountry());
+    return true;
+  }
+  // Maximize locale_id to infer the region (e.g. expand "de" to "de-Latn-DE"
+  // and grab "DE" from the result).
+  UErrorCode status = U_ZERO_ERROR;
+  char maximized_locale[ULOC_FULLNAME_CAPACITY];
+  uloc_addLikelySubtags(
+      locale_id, maximized_locale, ULOC_FULLNAME_CAPACITY, &status);
+  uloc_getCountry(maximized_locale, result, ULOC_COUNTRY_CAPACITY, &status);
 
-v8::Handle<v8::Value> I18NLocale::JSDisplayScript(const v8::Arguments& args) {
-  return GetDisplayItem(args, "script");
-}
-
-v8::Handle<v8::Value> I18NLocale::JSDisplayRegion(const v8::Arguments& args) {
-  return GetDisplayItem(args, "region");
-}
-
-v8::Handle<v8::Value> I18NLocale::JSDisplayName(const v8::Arguments& args) {
-  return GetDisplayItem(args, "name");
+  return !U_FAILURE(status);
 }
 
 } }  // namespace v8::internal
diff --git a/src/extensions/experimental/i18n-locale.h b/src/extensions/experimental/i18n-locale.h
index aa9adbe..053886b 100644
--- a/src/extensions/experimental/i18n-locale.h
+++ b/src/extensions/experimental/i18n-locale.h
@@ -39,13 +39,20 @@
 
   // Implementations of window.Locale methods.
   static v8::Handle<v8::Value> JSLocale(const v8::Arguments& args);
-  static v8::Handle<v8::Value> JSAvailableLocales(const v8::Arguments& args);
-  static v8::Handle<v8::Value> JSMaximizedLocale(const v8::Arguments& args);
-  static v8::Handle<v8::Value> JSMinimizedLocale(const v8::Arguments& args);
-  static v8::Handle<v8::Value> JSDisplayLanguage(const v8::Arguments& args);
-  static v8::Handle<v8::Value> JSDisplayScript(const v8::Arguments& args);
-  static v8::Handle<v8::Value> JSDisplayRegion(const v8::Arguments& args);
-  static v8::Handle<v8::Value> JSDisplayName(const v8::Arguments& args);
+
+  // Infers region id given the locale id, or uses user specified region id.
+  // Result is canonicalized.
+  // Returns status of ICU operation (maximizing locale or get region call).
+  static bool GetBestMatchForRegionID(
+      const char* locale_id, v8::Handle<v8::Value> regions, char* result);
+
+ private:
+  // Key name for localeID parameter.
+  static const char* const kLocaleID;
+  // Key name for regionID parameter.
+  static const char* const kRegionID;
+  // Key name for the icuLocaleID result.
+  static const char* const kICULocaleID;
 };
 
 } }  // namespace v8::internal
diff --git a/src/extensions/experimental/i18n.js b/src/extensions/experimental/i18n.js
index 5a74905..0fa7ae7 100644
--- a/src/extensions/experimental/i18n.js
+++ b/src/extensions/experimental/i18n.js
@@ -25,70 +25,71 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// TODO(cira): Remove v8 prefix from v8Locale once we have stable API.
-v8Locale = function(optLocale) {
+// TODO(cira): Rename v8Locale into LocaleInfo once we have stable API.
+/**
+ * LocaleInfo class is an aggregate class of all i18n API calls.
+ * @param {Object} settings - localeID and regionID to create LocaleInfo from.
+ *   {Array.<string>|string} settings.localeID -
+ *     Unicode identifier of the locale.
+ *     See http://unicode.org/reports/tr35/#BCP_47_Conformance
+ *   {string} settings.regionID - ISO3166 region ID with addition of
+ *     invalid, undefined and reserved region codes.
+ * @constructor
+ */
+v8Locale = function(settings) {
   native function NativeJSLocale();
-  var properties = NativeJSLocale(optLocale);
-  this.locale = properties.locale;
-  this.language = properties.language;
-  this.script = properties.script;
-  this.region = properties.region;
-};
 
-v8Locale.availableLocales = function() {
-  native function NativeJSAvailableLocales();
-  return NativeJSAvailableLocales();
-};
-
-v8Locale.prototype.maximizedLocale = function() {
-  native function NativeJSMaximizedLocale();
-  return new v8Locale(NativeJSMaximizedLocale(this.locale));
-};
-
-v8Locale.prototype.minimizedLocale = function() {
-  native function NativeJSMinimizedLocale();
-  return new v8Locale(NativeJSMinimizedLocale(this.locale));
-};
-
-v8Locale.prototype.displayLocale_ = function(displayLocale) {
-  var result = this.locale;
-  if (displayLocale !== undefined) {
-    result = displayLocale.locale;
+  // Assume user wanted to do v8Locale("sr");
+  if (typeof(settings) === "string") {
+    settings = {'localeID': settings};
   }
-  return result;
+
+  var properties = NativeJSLocale(
+      v8Locale.createSettingsOrDefault_(settings, {'localeID': 'root'}));
+
+  // Keep the resolved ICU locale ID around to avoid resolving localeID to
+  // ICU locale ID every time BreakIterator, Collator and so forth are called.
+  this.__icuLocaleID__ = properties.icuLocaleID;
+  this.options = {'localeID': properties.localeID,
+                  'regionID': properties.regionID};
 };
 
-v8Locale.prototype.displayLanguage = function(optDisplayLocale) {
-  var displayLocale = this.displayLocale_(optDisplayLocale);
-  native function NativeJSDisplayLanguage();
-  return NativeJSDisplayLanguage(this.locale, displayLocale);
+/**
+ * Clones existing locale with possible overrides for some of the options.
+ * @param {!Object} settings - overrides for current locale settings.
+ * @returns {Object} - new LocaleInfo object.
+ */
+v8Locale.prototype.derive = function(settings) {
+  return new v8Locale(
+      v8Locale.createSettingsOrDefault_(settings, this.options));
 };
 
-v8Locale.prototype.displayScript = function(optDisplayLocale) {
-  var displayLocale = this.displayLocale_(optDisplayLocale);
-  native function NativeJSDisplayScript();
-  return NativeJSDisplayScript(this.locale, displayLocale);
-};
-
-v8Locale.prototype.displayRegion = function(optDisplayLocale) {
-  var displayLocale = this.displayLocale_(optDisplayLocale);
-  native function NativeJSDisplayRegion();
-  return NativeJSDisplayRegion(this.locale, displayLocale);
-};
-
-v8Locale.prototype.displayName = function(optDisplayLocale) {
-  var displayLocale = this.displayLocale_(optDisplayLocale);
-  native function NativeJSDisplayName();
-  return NativeJSDisplayName(this.locale, displayLocale);
-};
-
+/**
+ * v8BreakIterator class implements locale aware segmenatation.
+ * It is not part of EcmaScript proposal.
+ * @param {Object} locale - locale object to pass to break
+ *   iterator implementation.
+ * @param {string} type - type of segmenatation:
+ *   - character
+ *   - word
+ *   - sentence
+ *   - line
+ * @constructor
+ */
 v8Locale.v8BreakIterator = function(locale, type) {
   native function NativeJSBreakIterator();
-  var iterator = NativeJSBreakIterator(locale, type);
+
+  locale = v8Locale.createLocaleOrDefault_(locale);
+  // BCP47 ID would work in this case, but we use ICU locale for consistency.
+  var iterator = NativeJSBreakIterator(locale.__icuLocaleID__, type);
   iterator.type = type;
   return iterator;
 };
 
+/**
+ * Type of the break we encountered during previous iteration.
+ * @type{Enum}
+ */
 v8Locale.v8BreakIterator.BreakType = {
   'unknown': -1,
   'none': 0,
@@ -98,19 +99,82 @@
   'ideo': 400
 };
 
+/**
+ * Creates new v8BreakIterator based on current locale.
+ * @param {string} - type of segmentation. See constructor.
+ * @returns {Object} - new v8BreakIterator object.
+ */
 v8Locale.prototype.v8CreateBreakIterator = function(type) {
-  return new v8Locale.v8BreakIterator(this.locale, type);
+  return new v8Locale.v8BreakIterator(this, type);
 };
 
 // TODO(jungshik): Set |collator.options| to actually recognized / resolved
 // values.
-v8Locale.Collator = function(locale, options) {
+/**
+ * Collator class implements locale-aware sort.
+ * @param {Object} locale - locale object to pass to collator implementation.
+ * @param {Object} settings - collation flags:
+ *   - ignoreCase
+ *   - ignoreAccents
+ *   - numeric
+ * @constructor
+ */
+v8Locale.Collator = function(locale, settings) {
   native function NativeJSCollator();
-  var collator = NativeJSCollator(locale,
-      options === undefined ? {} : options);
+
+  locale = v8Locale.createLocaleOrDefault_(locale);
+  var collator = NativeJSCollator(
+      locale.__icuLocaleID__, v8Locale.createSettingsOrDefault_(settings, {}));
   return collator;
 };
 
-v8Locale.prototype.createCollator = function(options) {
-  return new v8Locale.Collator(this.locale, options);
+/**
+ * Creates new Collator based on current locale.
+ * @param {Object} - collation flags. See constructor.
+ * @returns {Object} - new v8BreakIterator object.
+ */
+v8Locale.prototype.createCollator = function(settings) {
+  return new v8Locale.Collator(this, settings);
+};
+
+/**
+ * Merges user settings and defaults.
+ * Settings that are not of object type are rejected.
+ * Actual property values are not validated, but whitespace is trimmed if they
+ * are strings.
+ * @param {!Object} settings - user provided settings.
+ * @param {!Object} defaults - default values for this type of settings.
+ * @returns {Object} - valid settings object.
+ */
+v8Locale.createSettingsOrDefault_ = function(settings, defaults) {
+  if (!settings || typeof(settings) !== 'object' ) {
+    return defaults;
+  }
+  for (var key in defaults) {
+    if (!settings.hasOwnProperty(key)) {
+      settings[key] = defaults[key];
+    }
+  }
+  // Clean up values, like trimming whitespace.
+  for (var key in settings) {
+    if (typeof(settings[key]) === "string") {
+      settings[key] = settings[key].trim();
+    }
+  }
+
+  return settings;
+};
+
+/**
+ * If locale is valid (defined and of v8Locale type) we return it. If not
+ * we create default locale and return it.
+ * @param {!Object} locale - user provided locale.
+ * @returns {Object} - v8Locale object.
+ */
+v8Locale.createLocaleOrDefault_ = function(locale) {
+  if (!locale || !(locale instanceof v8Locale)) {
+    return new v8Locale();
+  } else {
+    return locale;
+  }
 };
diff --git a/src/frame-element.h b/src/frame-element.h
index 0c7d010..d2e41eb 100644
--- a/src/frame-element.h
+++ b/src/frame-element.h
@@ -28,6 +28,7 @@
 #ifndef V8_FRAME_ELEMENT_H_
 #define V8_FRAME_ELEMENT_H_
 
+#include "allocation.h"
 #include "type-info.h"
 #include "macro-assembler.h"
 #include "zone.h"
diff --git a/src/frames.h b/src/frames.h
index da9009b..27ba339 100644
--- a/src/frames.h
+++ b/src/frames.h
@@ -28,6 +28,7 @@
 #ifndef V8_FRAMES_H_
 #define V8_FRAMES_H_
 
+#include "allocation.h"
 #include "handles.h"
 #include "safepoint-table.h"
 
diff --git a/src/full-codegen.h b/src/full-codegen.h
index f5e819c..859c342 100644
--- a/src/full-codegen.h
+++ b/src/full-codegen.h
@@ -30,6 +30,7 @@
 
 #include "v8.h"
 
+#include "allocation.h"
 #include "ast.h"
 #include "code-stubs.h"
 #include "codegen.h"
diff --git a/src/gdb-jit.h b/src/gdb-jit.h
index de6928f..0c80fb6 100644
--- a/src/gdb-jit.h
+++ b/src/gdb-jit.h
@@ -28,6 +28,8 @@
 #ifndef V8_GDB_JIT_H_
 #define V8_GDB_JIT_H_
 
+#include "allocation.h"
+
 //
 // Basic implementation of GDB JIT Interface client.
 // GBD JIT Interface is supported in GDB 7.0 and above.
diff --git a/src/handles.h b/src/handles.h
index 3839f37..ed8a824 100644
--- a/src/handles.h
+++ b/src/handles.h
@@ -28,6 +28,7 @@
 #ifndef V8_HANDLES_H_
 #define V8_HANDLES_H_
 
+#include "allocation.h"
 #include "apiutils.h"
 
 namespace v8 {
diff --git a/src/heap-profiler.h b/src/heap-profiler.h
index 89a2e8a..c1e93c0 100644
--- a/src/heap-profiler.h
+++ b/src/heap-profiler.h
@@ -28,6 +28,7 @@
 #ifndef V8_HEAP_PROFILER_H_
 #define V8_HEAP_PROFILER_H_
 
+#include "allocation.h"
 #include "isolate.h"
 #include "zone-inl.h"
 
diff --git a/src/heap.h b/src/heap.h
index d0c1551..4f03572 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -30,6 +30,7 @@
 
 #include <math.h>
 
+#include "allocation.h"
 #include "globals.h"
 #include "list.h"
 #include "mark-compact.h"
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc
index ac509a7..caeebae 100644
--- a/src/hydrogen-instructions.cc
+++ b/src/hydrogen-instructions.cc
@@ -1206,13 +1206,23 @@
     Handle<Map> map = types->at(i);
     LookupResult lookup;
     map->LookupInDescriptors(NULL, *name, &lookup);
-    if (lookup.IsProperty() && lookup.type() == FIELD) {
-      types_.Add(types->at(i));
-      int index = lookup.GetLocalFieldIndexFromMap(*map);
-      if (index < 0) {
-        SetFlag(kDependsOnInobjectFields);
-      } else {
-        SetFlag(kDependsOnBackingStoreFields);
+    if (lookup.IsProperty()) {
+      switch (lookup.type()) {
+        case FIELD: {
+          int index = lookup.GetLocalFieldIndexFromMap(*map);
+          if (index < 0) {
+            SetFlag(kDependsOnInobjectFields);
+          } else {
+            SetFlag(kDependsOnBackingStoreFields);
+          }
+          types_.Add(types->at(i));
+          break;
+        }
+        case CONSTANT_FUNCTION:
+          types_.Add(types->at(i));
+          break;
+        default:
+          break;
       }
     }
   }
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index 82fdfa7..5a502e5 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -30,6 +30,7 @@
 
 #include "v8.h"
 
+#include "allocation.h"
 #include "code-stubs.h"
 #include "data-flow.h"
 #include "small-pointer-list.h"
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index 3b57f9f..a0d7837 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -4106,7 +4106,10 @@
 
   HConstant* undefined = graph()->GetConstantUndefined();
   HEnvironment* inner_env =
-      environment()->CopyForInlining(target, function, true, undefined);
+      environment()->CopyForInlining(target,
+                                     function,
+                                     HEnvironment::HYDROGEN,
+                                     undefined);
   HBasicBlock* body_entry = CreateBasicBlock(inner_env);
   current_block()->Goto(body_entry);
 
@@ -5735,7 +5738,7 @@
 
 HEnvironment* HEnvironment::CopyForInlining(Handle<JSFunction> target,
                                             FunctionLiteral* function,
-                                            bool is_speculative,
+                                            CompilationPhase compilation_phase,
                                             HConstant* undefined) const {
   // Outer environment is a copy of this one without the arguments.
   int arity = function->scope()->num_parameters();
@@ -5746,14 +5749,16 @@
   HEnvironment* inner =
       new(zone) HEnvironment(outer, function->scope(), target);
   // Get the argument values from the original environment.
-  if (is_speculative) {
+  if (compilation_phase == HYDROGEN) {
     for (int i = 0; i <= arity; ++i) {  // Include receiver.
       HValue* push = ExpressionStackAt(arity - i);
       inner->SetValueAt(i, push);
     }
   } else {
+    ASSERT(compilation_phase == LITHIUM);
     for (int i = 0; i <= arity; ++i) {  // Include receiver.
-      inner->SetValueAt(i, ExpressionStackAt(arity - i));
+      HValue* push = ExpressionStackAt(arity - i);
+      inner->SetValueAt(i, push);
     }
   }
 
diff --git a/src/hydrogen.h b/src/hydrogen.h
index 22b82d7..bd51dd1 100644
--- a/src/hydrogen.h
+++ b/src/hydrogen.h
@@ -30,6 +30,7 @@
 
 #include "v8.h"
 
+#include "allocation.h"
 #include "ast.h"
 #include "compiler.h"
 #include "hydrogen-instructions.h"
@@ -308,6 +309,8 @@
 
 class HEnvironment: public ZoneObject {
  public:
+  enum CompilationPhase { HYDROGEN, LITHIUM };
+
   HEnvironment(HEnvironment* outer,
                Scope* scope,
                Handle<JSFunction> closure);
@@ -384,7 +387,7 @@
   // instructions, otherwise they are the actual values.
   HEnvironment* CopyForInlining(Handle<JSFunction> target,
                                 FunctionLiteral* function,
-                                bool is_speculative,
+                                CompilationPhase compilation_phase,
                                 HConstant* undefined) const;
 
   void AddIncomingEdge(HBasicBlock* block, HEnvironment* other);
diff --git a/src/ia32/builtins-ia32.cc b/src/ia32/builtins-ia32.cc
index 29c67b5..0906897 100644
--- a/src/ia32/builtins-ia32.cc
+++ b/src/ia32/builtins-ia32.cc
@@ -599,6 +599,15 @@
               1 << SharedFunctionInfo::kStrictModeBitWithinByte);
     __ j(not_equal, &shift_arguments);
 
+    // Do not transform the receiver for natives (shared already in ebx).
+    __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kScriptOffset));
+    __ cmp(ebx, factory->undefined_value());
+    __ j(equal, &shift_arguments);
+    __ mov(ebx, FieldOperand(ebx, Script::kTypeOffset));
+    __ SmiUntag(ebx);
+    __ cmp(ebx, Script::TYPE_NATIVE);
+    __ j(equal, &shift_arguments);
+
     // Compute the receiver in non-strict mode.
     __ mov(ebx, Operand(esp, eax, times_4, 0));  // First argument.
     __ test(ebx, Immediate(kSmiTagMask));
@@ -755,10 +764,20 @@
             1 << SharedFunctionInfo::kStrictModeBitWithinByte);
   __ j(not_equal, &push_receiver);
 
+  Factory* factory = masm->isolate()->factory();
+
+  // Do not transform the receiver for natives (shared already in ecx).
+  __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kScriptOffset));
+  __ cmp(ecx, factory->undefined_value());
+  __ j(equal, &push_receiver);
+  __ mov(ecx, FieldOperand(ecx, Script::kTypeOffset));
+  __ SmiUntag(ecx);
+  __ cmp(ecx, Script::TYPE_NATIVE);
+  __ j(equal, &push_receiver);
+
   // Compute the receiver in non-strict mode.
   __ test(ebx, Immediate(kSmiTagMask));
   __ j(zero, &call_to_object);
-  Factory* factory = masm->isolate()->factory();
   __ cmp(ebx, factory->null_value());
   __ j(equal, &use_global_receiver);
   __ cmp(ebx, factory->undefined_value());
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index 7af000a..00fab7f 100644
--- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc
@@ -3901,12 +3901,20 @@
                                          &check_unequal_objects);
 
   // Inline comparison of ascii strings.
-  StringCompareStub::GenerateCompareFlatAsciiStrings(masm,
+  if (cc_ == equal) {
+    StringCompareStub::GenerateFlatAsciiStringEquals(masm,
                                                      edx,
                                                      eax,
                                                      ecx,
-                                                     ebx,
-                                                     edi);
+                                                     ebx);
+  } else {
+    StringCompareStub::GenerateCompareFlatAsciiStrings(masm,
+                                                       edx,
+                                                       eax,
+                                                       ecx,
+                                                       ebx,
+                                                       edi);
+  }
 #ifdef DEBUG
   __ Abort("Unexpected fall-through from string comparison");
 #endif
@@ -5602,16 +5610,48 @@
 }
 
 
+void StringCompareStub::GenerateFlatAsciiStringEquals(MacroAssembler* masm,
+                                                      Register left,
+                                                      Register right,
+                                                      Register scratch1,
+                                                      Register scratch2) {
+  Register length = scratch1;
+
+  // Compare lengths.
+  NearLabel strings_not_equal, check_zero_length;
+  __ mov(length, FieldOperand(left, String::kLengthOffset));
+  __ cmp(length, FieldOperand(right, String::kLengthOffset));
+  __ j(equal, &check_zero_length);
+  __ bind(&strings_not_equal);
+  __ Set(eax, Immediate(Smi::FromInt(NOT_EQUAL)));
+  __ ret(0);
+
+  // Check if the length is zero.
+  NearLabel compare_chars;
+  __ bind(&check_zero_length);
+  STATIC_ASSERT(kSmiTag == 0);
+  __ test(length, Operand(length));
+  __ j(not_zero, &compare_chars);
+  __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
+  __ ret(0);
+
+  // Compare characters.
+  __ bind(&compare_chars);
+  GenerateAsciiCharsCompareLoop(masm, left, right, length, scratch2,
+                                &strings_not_equal);
+
+  // Characters are equal.
+  __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
+  __ ret(0);
+}
+
+
 void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
                                                         Register left,
                                                         Register right,
                                                         Register scratch1,
                                                         Register scratch2,
                                                         Register scratch3) {
-  Label result_not_equal;
-  Label result_greater;
-  Label compare_lengths;
-
   Counters* counters = masm->isolate()->counters();
   __ IncrementCounter(counters->string_compare_native(), 1);
 
@@ -5631,36 +5671,14 @@
   Register min_length = scratch1;
 
   // If either length is zero, just compare lengths.
+  NearLabel compare_lengths;
   __ test(min_length, Operand(min_length));
   __ j(zero, &compare_lengths);
 
-  // Change index to run from -min_length to -1 by adding min_length
-  // to string start. This means that loop ends when index reaches zero,
-  // which doesn't need an additional compare.
-  __ SmiUntag(min_length);
-  __ lea(left,
-         FieldOperand(left,
-                      min_length, times_1,
-                      SeqAsciiString::kHeaderSize));
-  __ lea(right,
-         FieldOperand(right,
-                      min_length, times_1,
-                      SeqAsciiString::kHeaderSize));
-  __ neg(min_length);
-
-  Register index = min_length;  // index = -min_length;
-
-  {
-    // Compare loop.
-    NearLabel loop;
-    __ bind(&loop);
-    // Compare characters.
-    __ mov_b(scratch2, Operand(left, index, times_1, 0));
-    __ cmpb(scratch2, Operand(right, index, times_1, 0));
-    __ j(not_equal, &result_not_equal);
-    __ add(Operand(index), Immediate(1));
-    __ j(not_zero, &loop);
-  }
+  // Compare characters.
+  NearLabel result_not_equal;
+  GenerateAsciiCharsCompareLoop(masm, left, right, min_length, scratch2,
+                                &result_not_equal);
 
   // Compare lengths -  strings up to min-length are equal.
   __ bind(&compare_lengths);
@@ -5673,6 +5691,7 @@
   __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
   __ ret(0);
 
+  NearLabel result_greater;
   __ bind(&result_not_equal);
   __ j(greater, &result_greater);
 
@@ -5687,6 +5706,35 @@
 }
 
 
+void StringCompareStub::GenerateAsciiCharsCompareLoop(
+    MacroAssembler* masm,
+    Register left,
+    Register right,
+    Register length,
+    Register scratch,
+    NearLabel* chars_not_equal) {
+  // Change index to run from -length to -1 by adding length to string
+  // start. This means that loop ends when index reaches zero, which
+  // doesn't need an additional compare.
+  __ SmiUntag(length);
+  __ lea(left,
+         FieldOperand(left, length, times_1, SeqAsciiString::kHeaderSize));
+  __ lea(right,
+         FieldOperand(right, length, times_1, SeqAsciiString::kHeaderSize));
+  __ neg(length);
+  Register index = length;  // index = -length;
+
+  // Compare loop.
+  NearLabel loop;
+  __ bind(&loop);
+  __ mov_b(scratch, Operand(left, index, times_1, 0));
+  __ cmpb(scratch, Operand(right, index, times_1, 0));
+  __ j(not_equal, chars_not_equal);
+  __ add(Operand(index), Immediate(1));
+  __ j(not_zero, &loop);
+}
+
+
 void StringCompareStub::Generate(MacroAssembler* masm) {
   Label runtime;
 
@@ -5806,6 +5854,83 @@
 }
 
 
+void ICCompareStub::GenerateStrings(MacroAssembler* masm) {
+  ASSERT(state_ == CompareIC::STRINGS);
+  ASSERT(GetCondition() == equal);
+  Label miss;
+
+  // Registers containing left and right operands respectively.
+  Register left = edx;
+  Register right = eax;
+  Register tmp1 = ecx;
+  Register tmp2 = ebx;
+  Register tmp3 = edi;
+
+  // Check that both operands are heap objects.
+  __ mov(tmp1, Operand(left));
+  STATIC_ASSERT(kSmiTag == 0);
+  __ and_(tmp1, Operand(right));
+  __ test(tmp1, Immediate(kSmiTagMask));
+  __ j(zero, &miss);
+
+  // Check that both operands are strings. This leaves the instance
+  // types loaded in tmp1 and tmp2.
+  __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset));
+  __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset));
+  __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset));
+  __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
+  __ mov(tmp3, tmp1);
+  STATIC_ASSERT(kNotStringTag != 0);
+  __ or_(tmp3, Operand(tmp2));
+  __ test(tmp3, Immediate(kIsNotStringMask));
+  __ j(not_zero, &miss);
+
+  // Fast check for identical strings.
+  NearLabel not_same;
+  __ cmp(left, Operand(right));
+  __ j(not_equal, &not_same);
+  STATIC_ASSERT(EQUAL == 0);
+  STATIC_ASSERT(kSmiTag == 0);
+  __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
+  __ ret(0);
+
+  // Handle not identical strings.
+  __ bind(&not_same);
+
+  // Check that both strings are symbols. If they are, we're done
+  // because we already know they are not identical.
+  NearLabel do_compare;
+  STATIC_ASSERT(kSymbolTag != 0);
+  __ and_(tmp1, Operand(tmp2));
+  __ test(tmp1, Immediate(kIsSymbolMask));
+  __ j(zero, &do_compare);
+  // Make sure eax is non-zero. At this point input operands are
+  // guaranteed to be non-zero.
+  ASSERT(right.is(eax));
+  __ ret(0);
+
+  // Check that both strings are sequential ASCII.
+  Label runtime;
+  __ bind(&do_compare);
+  __ JumpIfNotBothSequentialAsciiStrings(left, right, tmp1, tmp2, &runtime);
+
+  // Compare flat ASCII strings. Returns when done.
+  StringCompareStub::GenerateFlatAsciiStringEquals(
+      masm, left, right, tmp1, tmp2);
+
+  // Handle more complex cases in runtime.
+  __ bind(&runtime);
+  __ pop(tmp1);  // Return address.
+  __ push(left);
+  __ push(right);
+  __ push(tmp1);
+  __ TailCallRuntime(Runtime::kStringEquals, 2, 1);
+
+  __ bind(&miss);
+  GenerateMiss(masm);
+}
+
+
 void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
   ASSERT(state_ == CompareIC::OBJECTS);
   NearLabel miss;
@@ -5859,6 +5984,215 @@
 }
 
 
+// Helper function used to check that the dictionary doesn't contain
+// the property. This function may return false negatives, so miss_label
+// must always call a backup property check that is complete.
+// This function is safe to call if the receiver has fast properties.
+// Name must be a symbol and receiver must be a heap object.
+void StringDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
+                                                        Label* miss,
+                                                        Label* done,
+                                                        Register properties,
+                                                        String* name,
+                                                        Register r0) {
+  ASSERT(name->IsSymbol());
+
+  // If names of slots in range from 1 to kProbes - 1 for the hash value are
+  // not equal to the name and kProbes-th slot is not used (its name is the
+  // undefined value), it guarantees the hash table doesn't contain the
+  // property. It's true even if some slots represent deleted properties
+  // (their names are the null value).
+  for (int i = 0; i < kInlinedProbes; i++) {
+    // Compute the masked index: (hash + i + i * i) & mask.
+    Register index = r0;
+    // Capacity is smi 2^n.
+    __ mov(index, FieldOperand(properties, kCapacityOffset));
+    __ dec(index);
+    __ and_(Operand(index),
+           Immediate(Smi::FromInt(name->Hash() +
+                                   StringDictionary::GetProbeOffset(i))));
+
+    // Scale the index by multiplying by the entry size.
+    ASSERT(StringDictionary::kEntrySize == 3);
+    __ lea(index, Operand(index, index, times_2, 0));  // index *= 3.
+    Register entity_name = r0;
+    // Having undefined at this place means the name is not contained.
+    ASSERT_EQ(kSmiTagSize, 1);
+    __ mov(entity_name, Operand(properties, index, times_half_pointer_size,
+                                kElementsStartOffset - kHeapObjectTag));
+    __ cmp(entity_name, masm->isolate()->factory()->undefined_value());
+    __ j(equal, done, taken);
+
+    // Stop if found the property.
+    __ cmp(entity_name, Handle<String>(name));
+    __ j(equal, miss, not_taken);
+
+    // Check if the entry name is not a symbol.
+    __ mov(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset));
+    __ test_b(FieldOperand(entity_name, Map::kInstanceTypeOffset),
+              kIsSymbolMask);
+    __ j(zero, miss, not_taken);
+  }
+
+  StringDictionaryLookupStub stub(properties,
+                                  r0,
+                                  r0,
+                                  StringDictionaryLookupStub::NEGATIVE_LOOKUP);
+  __ push(Immediate(Handle<Object>(name)));
+  __ push(Immediate(name->Hash()));
+  __ CallStub(&stub);
+  __ test(r0, Operand(r0));
+  __ j(not_zero, miss);
+  __ jmp(done);
+}
+
+
+// Probe the string dictionary in the |elements| register. Jump to the
+// |done| label if a property with the given name is found leaving the
+// index into the dictionary in |r0|. Jump to the |miss| label
+// otherwise.
+void StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
+                                                        Label* miss,
+                                                        Label* done,
+                                                        Register elements,
+                                                        Register name,
+                                                        Register r0,
+                                                        Register r1) {
+  // Assert that name contains a string.
+  if (FLAG_debug_code) __ AbortIfNotString(name);
+
+  __ mov(r1, FieldOperand(elements, kCapacityOffset));
+  __ shr(r1, kSmiTagSize);  // convert smi to int
+  __ dec(r1);
+
+  // Generate an unrolled loop that performs a few probes before
+  // giving up. Measurements done on Gmail indicate that 2 probes
+  // cover ~93% of loads from dictionaries.
+  for (int i = 0; i < kInlinedProbes; i++) {
+    // Compute the masked index: (hash + i + i * i) & mask.
+    __ mov(r0, FieldOperand(name, String::kHashFieldOffset));
+    __ shr(r0, String::kHashShift);
+    if (i > 0) {
+      __ add(Operand(r0), Immediate(StringDictionary::GetProbeOffset(i)));
+    }
+    __ and_(r0, Operand(r1));
+
+    // Scale the index by multiplying by the entry size.
+    ASSERT(StringDictionary::kEntrySize == 3);
+    __ lea(r0, Operand(r0, r0, times_2, 0));  // r0 = r0 * 3
+
+    // Check if the key is identical to the name.
+    __ cmp(name, Operand(elements,
+                         r0,
+                         times_4,
+                         kElementsStartOffset - kHeapObjectTag));
+    __ j(equal, done, taken);
+  }
+
+  StringDictionaryLookupStub stub(elements,
+                                  r1,
+                                  r0,
+                                  POSITIVE_LOOKUP);
+  __ push(name);
+  __ mov(r0, FieldOperand(name, String::kHashFieldOffset));
+  __ shr(r0, String::kHashShift);
+  __ push(r0);
+  __ CallStub(&stub);
+
+  __ test(r1, Operand(r1));
+  __ j(zero, miss);
+  __ jmp(done);
+}
+
+
+void StringDictionaryLookupStub::Generate(MacroAssembler* masm) {
+  // Stack frame on entry:
+  //  esp[0 * kPointerSize]: return address.
+  //  esp[1 * kPointerSize]: key's hash.
+  //  esp[2 * kPointerSize]: key.
+  // Registers:
+  //  dictionary_: StringDictionary to probe.
+  //  result_: used as scratch.
+  //  index_: will hold an index of entry if lookup is successful.
+  //          might alias with result_.
+  // Returns:
+  //  result_ is zero if lookup failed, non zero otherwise.
+
+  Label in_dictionary, maybe_in_dictionary, not_in_dictionary;
+
+  Register scratch = result_;
+
+  __ mov(scratch, FieldOperand(dictionary_, kCapacityOffset));
+  __ dec(scratch);
+  __ SmiUntag(scratch);
+  __ push(scratch);
+
+  // If names of slots in range from 1 to kProbes - 1 for the hash value are
+  // not equal to the name and kProbes-th slot is not used (its name is the
+  // undefined value), it guarantees the hash table doesn't contain the
+  // property. It's true even if some slots represent deleted properties
+  // (their names are the null value).
+  for (int i = kInlinedProbes; i < kTotalProbes; i++) {
+    // Compute the masked index: (hash + i + i * i) & mask.
+    __ mov(scratch, Operand(esp, 2 * kPointerSize));
+    if (i > 0) {
+      __ add(Operand(scratch),
+             Immediate(StringDictionary::GetProbeOffset(i)));
+    }
+    __ and_(scratch, Operand(esp, 0));
+
+    // Scale the index by multiplying by the entry size.
+    ASSERT(StringDictionary::kEntrySize == 3);
+    __ lea(index_, Operand(scratch, scratch, times_2, 0));  // index *= 3.
+
+    // Having undefined at this place means the name is not contained.
+    ASSERT_EQ(kSmiTagSize, 1);
+    __ mov(scratch, Operand(dictionary_,
+                            index_,
+                            times_pointer_size,
+                            kElementsStartOffset - kHeapObjectTag));
+    __ cmp(scratch, masm->isolate()->factory()->undefined_value());
+    __ j(equal, &not_in_dictionary);
+
+    // Stop if found the property.
+    __ cmp(scratch, Operand(esp, 3 * kPointerSize));
+    __ j(equal, &in_dictionary);
+
+    if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) {
+      // If we hit a non symbol key during negative lookup
+      // we have to bailout as this key might be equal to the
+      // key we are looking for.
+
+      // Check if the entry name is not a symbol.
+      __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
+      __ test_b(FieldOperand(scratch, Map::kInstanceTypeOffset),
+                kIsSymbolMask);
+      __ j(zero, &maybe_in_dictionary);
+    }
+  }
+
+  __ bind(&maybe_in_dictionary);
+  // If we are doing negative lookup then probing failure should be
+  // treated as a lookup success. For positive lookup probing failure
+  // should be treated as lookup failure.
+  if (mode_ == POSITIVE_LOOKUP) {
+    __ mov(result_, Immediate(0));
+    __ Drop(1);
+    __ ret(2 * kPointerSize);
+  }
+
+  __ bind(&in_dictionary);
+  __ mov(result_, Immediate(1));
+  __ Drop(1);
+  __ ret(2 * kPointerSize);
+
+  __ bind(&not_in_dictionary);
+  __ mov(result_, Immediate(0));
+  __ Drop(1);
+  __ ret(2 * kPointerSize);
+}
+
+
 #undef __
 
 } }  // namespace v8::internal
diff --git a/src/ia32/code-stubs-ia32.h b/src/ia32/code-stubs-ia32.h
index dcbcc61..768bfea 100644
--- a/src/ia32/code-stubs-ia32.h
+++ b/src/ia32/code-stubs-ia32.h
@@ -372,11 +372,9 @@
 
 class StringCompareStub: public CodeStub {
  public:
-  explicit StringCompareStub() {
-  }
+  StringCompareStub() { }
 
-  // Compare two flat ascii strings and returns result in eax after popping two
-  // arguments from the stack.
+  // Compares two flat ASCII strings and returns result in eax.
   static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
                                               Register left,
                                               Register right,
@@ -384,11 +382,25 @@
                                               Register scratch2,
                                               Register scratch3);
 
- private:
-  Major MajorKey() { return StringCompare; }
-  int MinorKey() { return 0; }
+  // Compares two flat ASCII strings for equality and returns result
+  // in eax.
+  static void GenerateFlatAsciiStringEquals(MacroAssembler* masm,
+                                            Register left,
+                                            Register right,
+                                            Register scratch1,
+                                            Register scratch2);
 
-  void Generate(MacroAssembler* masm);
+ private:
+  virtual Major MajorKey() { return StringCompare; }
+  virtual int MinorKey() { return 0; }
+  virtual void Generate(MacroAssembler* masm);
+
+  static void GenerateAsciiCharsCompareLoop(MacroAssembler* masm,
+                                            Register left,
+                                            Register right,
+                                            Register length,
+                                            Register scratch,
+                                            NearLabel* chars_not_equal);
 };
 
 
@@ -424,6 +436,74 @@
 #endif
 };
 
+
+class StringDictionaryLookupStub: public CodeStub {
+ public:
+  enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
+
+  StringDictionaryLookupStub(Register dictionary,
+                             Register result,
+                             Register index,
+                             LookupMode mode)
+      : dictionary_(dictionary), result_(result), index_(index), mode_(mode) { }
+
+  void Generate(MacroAssembler* masm);
+
+  static void GenerateNegativeLookup(MacroAssembler* masm,
+                                     Label* miss,
+                                     Label* done,
+                                     Register properties,
+                                     String* name,
+                                     Register r0);
+
+  static void GeneratePositiveLookup(MacroAssembler* masm,
+                                     Label* miss,
+                                     Label* done,
+                                     Register elements,
+                                     Register name,
+                                     Register r0,
+                                     Register r1);
+
+ private:
+  static const int kInlinedProbes = 4;
+  static const int kTotalProbes = 20;
+
+  static const int kCapacityOffset =
+      StringDictionary::kHeaderSize +
+      StringDictionary::kCapacityIndex * kPointerSize;
+
+  static const int kElementsStartOffset =
+      StringDictionary::kHeaderSize +
+      StringDictionary::kElementsStartIndex * kPointerSize;
+
+
+#ifdef DEBUG
+  void Print() {
+    PrintF("StringDictionaryLookupStub\n");
+  }
+#endif
+
+  Major MajorKey() { return StringDictionaryNegativeLookup; }
+
+  int MinorKey() {
+    return DictionaryBits::encode(dictionary_.code()) |
+        ResultBits::encode(result_.code()) |
+        IndexBits::encode(index_.code()) |
+        LookupModeBits::encode(mode_);
+  }
+
+  class DictionaryBits: public BitField<int, 0, 3> {};
+  class ResultBits: public BitField<int, 3, 3> {};
+  class IndexBits: public BitField<int, 6, 3> {};
+  class LookupModeBits: public BitField<LookupMode, 9, 1> {};
+
+  Register dictionary_;
+  Register result_;
+  Register index_;
+  LookupMode mode_;
+};
+
+
 } }  // namespace v8::internal
 
 #endif  // V8_IA32_CODE_STUBS_IA32_H_
diff --git a/src/ia32/ic-ia32.cc b/src/ia32/ic-ia32.cc
index 4106f01..1e77a78 100644
--- a/src/ia32/ic-ia32.cc
+++ b/src/ia32/ic-ia32.cc
@@ -97,60 +97,6 @@
 }
 
 
-// Probe the string dictionary in the |elements| register. Jump to the
-// |done| label if a property with the given name is found leaving the
-// index into the dictionary in |r0|. Jump to the |miss| label
-// otherwise.
-static void GenerateStringDictionaryProbes(MacroAssembler* masm,
-                                           Label* miss,
-                                           Label* done,
-                                           Register elements,
-                                           Register name,
-                                           Register r0,
-                                           Register r1) {
-  // Assert that name contains a string.
-  if (FLAG_debug_code) __ AbortIfNotString(name);
-
-  // Compute the capacity mask.
-  const int kCapacityOffset =
-      StringDictionary::kHeaderSize +
-      StringDictionary::kCapacityIndex * kPointerSize;
-  __ mov(r1, FieldOperand(elements, kCapacityOffset));
-  __ shr(r1, kSmiTagSize);  // convert smi to int
-  __ dec(r1);
-
-  // Generate an unrolled loop that performs a few probes before
-  // giving up. Measurements done on Gmail indicate that 2 probes
-  // cover ~93% of loads from dictionaries.
-  static const int kProbes = 4;
-  const int kElementsStartOffset =
-      StringDictionary::kHeaderSize +
-      StringDictionary::kElementsStartIndex * kPointerSize;
-  for (int i = 0; i < kProbes; i++) {
-    // Compute the masked index: (hash + i + i * i) & mask.
-    __ mov(r0, FieldOperand(name, String::kHashFieldOffset));
-    __ shr(r0, String::kHashShift);
-    if (i > 0) {
-      __ add(Operand(r0), Immediate(StringDictionary::GetProbeOffset(i)));
-    }
-    __ and_(r0, Operand(r1));
-
-    // Scale the index by multiplying by the entry size.
-    ASSERT(StringDictionary::kEntrySize == 3);
-    __ lea(r0, Operand(r0, r0, times_2, 0));  // r0 = r0 * 3
-
-    // Check if the key is identical to the name.
-    __ cmp(name, Operand(elements, r0, times_4,
-                         kElementsStartOffset - kHeapObjectTag));
-    if (i != kProbes - 1) {
-      __ j(equal, done, taken);
-    } else {
-      __ j(not_equal, miss, not_taken);
-    }
-  }
-}
-
-
 
 // Helper function used to load a property from a dictionary backing
 // storage. This function may fail to load a property even though it is
@@ -183,13 +129,13 @@
   Label done;
 
   // Probe the dictionary.
-  GenerateStringDictionaryProbes(masm,
-                                 miss_label,
-                                 &done,
-                                 elements,
-                                 name,
-                                 r0,
-                                 r1);
+  StringDictionaryLookupStub::GeneratePositiveLookup(masm,
+                                                     miss_label,
+                                                     &done,
+                                                     elements,
+                                                     name,
+                                                     r0,
+                                                     r1);
 
   // If probing finds an entry in the dictionary, r0 contains the
   // index into the dictionary. Check that the value is a normal
@@ -238,13 +184,13 @@
 
 
   // Probe the dictionary.
-  GenerateStringDictionaryProbes(masm,
-                                 miss_label,
-                                 &done,
-                                 elements,
-                                 name,
-                                 r0,
-                                 r1);
+  StringDictionaryLookupStub::GeneratePositiveLookup(masm,
+                                                     miss_label,
+                                                     &done,
+                                                     elements,
+                                                     name,
+                                                     r0,
+                                                     r1);
 
   // If probing finds an entry in the dictionary, r0 contains the
   // index into the dictionary. Check that the value is a normal
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index 25138df..b07a006 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -2200,23 +2200,29 @@
 }
 
 
-void LCodeGen::EmitLoadField(Register result,
-                             Register object,
-                             Handle<Map> type,
-                             Handle<String> name) {
+void LCodeGen::EmitLoadFieldOrConstantFunction(Register result,
+                                               Register object,
+                                               Handle<Map> type,
+                                               Handle<String> name) {
   LookupResult lookup;
   type->LookupInDescriptors(NULL, *name, &lookup);
-  ASSERT(lookup.IsProperty() && lookup.type() == FIELD);
-  int index = lookup.GetLocalFieldIndexFromMap(*type);
-  int offset = index * kPointerSize;
-  if (index < 0) {
-    // Negative property indices are in-object properties, indexed
-    // from the end of the fixed part of the object.
-    __ mov(result, FieldOperand(object, offset + type->instance_size()));
+  ASSERT(lookup.IsProperty() &&
+         (lookup.type() == FIELD || lookup.type() == CONSTANT_FUNCTION));
+  if (lookup.type() == FIELD) {
+    int index = lookup.GetLocalFieldIndexFromMap(*type);
+    int offset = index * kPointerSize;
+    if (index < 0) {
+      // Negative property indices are in-object properties, indexed
+      // from the end of the fixed part of the object.
+      __ mov(result, FieldOperand(object, offset + type->instance_size()));
+    } else {
+      // Non-negative property indices are in the properties array.
+      __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset));
+      __ mov(result, FieldOperand(result, offset + FixedArray::kHeaderSize));
+    }
   } else {
-    // Non-negative property indices are in the properties array.
-    __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset));
-    __ mov(result, FieldOperand(result, offset + FixedArray::kHeaderSize));
+    Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*type));
+    LoadHeapObject(result, Handle<HeapObject>::cast(function));
   }
 }
 
@@ -2239,7 +2245,7 @@
       NearLabel next;
       __ cmp(FieldOperand(object, HeapObject::kMapOffset), map);
       __ j(not_equal, &next);
-      EmitLoadField(result, object, map, name);
+      EmitLoadFieldOrConstantFunction(result, object, map, name);
       __ jmp(&done);
       __ bind(&next);
     }
@@ -2248,7 +2254,7 @@
     if (instr->hydrogen()->need_generic()) {
       NearLabel generic;
       __ j(not_equal, &generic);
-      EmitLoadField(result, object, map, name);
+      EmitLoadFieldOrConstantFunction(result, object, map, name);
       __ jmp(&done);
       __ bind(&generic);
       __ mov(ecx, name);
@@ -2256,7 +2262,7 @@
       CallCode(ic, RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT);
     } else {
       DeoptimizeIf(not_equal, instr->environment());
-      EmitLoadField(result, object, map, name);
+      EmitLoadFieldOrConstantFunction(result, object, map, name);
     }
     __ bind(&done);
   }
diff --git a/src/ia32/lithium-codegen-ia32.h b/src/ia32/lithium-codegen-ia32.h
index c7b96e7..bd2ed47 100644
--- a/src/ia32/lithium-codegen-ia32.h
+++ b/src/ia32/lithium-codegen-ia32.h
@@ -278,10 +278,10 @@
   // Caller should branch on equal condition.
   void EmitIsConstructCall(Register temp);
 
-  void EmitLoadField(Register result,
-                     Register object,
-                     Handle<Map> type,
-                     Handle<String> name);
+  void EmitLoadFieldOrConstantFunction(Register result,
+                                       Register object,
+                                       Handle<Map> type,
+                                       Handle<String> name);
 
   LChunk* const chunk_;
   MacroAssembler* const masm_;
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
index 18c6480..7329660 100644
--- a/src/ia32/lithium-ia32.cc
+++ b/src/ia32/lithium-ia32.cc
@@ -2190,7 +2190,7 @@
   HConstant* undefined = graph()->GetConstantUndefined();
   HEnvironment* inner = outer->CopyForInlining(instr->closure(),
                                                instr->function(),
-                                               false,
+                                               HEnvironment::LITHIUM,
                                                undefined);
   current_block_->UpdateEnvironment(inner);
   chunk_->AddInlinedClosure(instr->closure());
diff --git a/src/ia32/simulator-ia32.h b/src/ia32/simulator-ia32.h
index cb660cd..13ddf35 100644
--- a/src/ia32/simulator-ia32.h
+++ b/src/ia32/simulator-ia32.h
@@ -56,7 +56,9 @@
 // just use the C stack limit.
 class SimulatorStack : public v8::internal::AllStatic {
  public:
-  static inline uintptr_t JsLimitFromCLimit(uintptr_t c_limit) {
+  static inline uintptr_t JsLimitFromCLimit(Isolate* isolate,
+                                            uintptr_t c_limit) {
+    USE(isolate);
     return c_limit;
   }
 
diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc
index c625115..30e9dee 100644
--- a/src/ia32/stub-cache-ia32.cc
+++ b/src/ia32/stub-cache-ia32.cc
@@ -118,7 +118,6 @@
   __ IncrementCounter(counters->negative_lookups(), 1);
   __ IncrementCounter(counters->negative_lookups_miss(), 1);
 
-  Label done;
   __ mov(r0, FieldOperand(receiver, HeapObject::kMapOffset));
 
   const int kInterceptorOrAccessCheckNeededMask =
@@ -142,62 +141,13 @@
          Immediate(masm->isolate()->factory()->hash_table_map()));
   __ j(not_equal, miss_label);
 
-  // Compute the capacity mask.
-  const int kCapacityOffset =
-      StringDictionary::kHeaderSize +
-      StringDictionary::kCapacityIndex * kPointerSize;
-
-  // Generate an unrolled loop that performs a few probes before
-  // giving up.
-  static const int kProbes = 4;
-  const int kElementsStartOffset =
-      StringDictionary::kHeaderSize +
-      StringDictionary::kElementsStartIndex * kPointerSize;
-
-  // If names of slots in range from 1 to kProbes - 1 for the hash value are
-  // not equal to the name and kProbes-th slot is not used (its name is the
-  // undefined value), it guarantees the hash table doesn't contain the
-  // property. It's true even if some slots represent deleted properties
-  // (their names are the null value).
-  for (int i = 0; i < kProbes; i++) {
-    // r0 points to properties hash.
-    // Compute the masked index: (hash + i + i * i) & mask.
-    Register index = r1;
-    // Capacity is smi 2^n.
-    __ mov(index, FieldOperand(properties, kCapacityOffset));
-    __ dec(index);
-    __ and_(Operand(index),
-            Immediate(Smi::FromInt(name->Hash() +
-                                   StringDictionary::GetProbeOffset(i))));
-
-    // Scale the index by multiplying by the entry size.
-    ASSERT(StringDictionary::kEntrySize == 3);
-    __ lea(index, Operand(index, index, times_2, 0));  // index *= 3.
-
-    Register entity_name = r1;
-    // Having undefined at this place means the name is not contained.
-    ASSERT_EQ(kSmiTagSize, 1);
-    __ mov(entity_name, Operand(properties, index, times_half_pointer_size,
-                                kElementsStartOffset - kHeapObjectTag));
-    __ cmp(entity_name, masm->isolate()->factory()->undefined_value());
-    if (i != kProbes - 1) {
-      __ j(equal, &done, taken);
-
-      // Stop if found the property.
-      __ cmp(entity_name, Handle<String>(name));
-      __ j(equal, miss_label, not_taken);
-
-      // Check if the entry name is not a symbol.
-      __ mov(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset));
-      __ test_b(FieldOperand(entity_name, Map::kInstanceTypeOffset),
-                kIsSymbolMask);
-      __ j(zero, miss_label, not_taken);
-    } else {
-      // Give up probing if still not found the undefined value.
-      __ j(not_equal, miss_label, not_taken);
-    }
-  }
-
+  Label done;
+  StringDictionaryLookupStub::GenerateNegativeLookup(masm,
+                                                     miss_label,
+                                                     &done,
+                                                     properties,
+                                                     name,
+                                                     r1);
   __ bind(&done);
   __ DecrementCounter(counters->negative_lookups_miss(), 1);
 }
diff --git a/src/ic.cc b/src/ic.cc
index 9a1b55c..980dd08 100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -2141,6 +2141,7 @@
     case SMIS: return "SMIS";
     case HEAP_NUMBERS: return "HEAP_NUMBERS";
     case OBJECTS: return "OBJECTS";
+    case STRINGS: return "STRINGS";
     case GENERIC: return "GENERIC";
     default:
       UNREACHABLE();
@@ -2159,6 +2160,8 @@
       x->IsNumber() && y->IsNumber()) return HEAP_NUMBERS;
   if (op_ != Token::EQ && op_ != Token::EQ_STRICT) return GENERIC;
   if (state == UNINITIALIZED &&
+      x->IsString() && y->IsString()) return STRINGS;
+  if (state == UNINITIALIZED &&
       x->IsJSObject() && y->IsJSObject()) return OBJECTS;
   return GENERIC;
 }
diff --git a/src/ic.h b/src/ic.h
index c0f4d30..807b173 100644
--- a/src/ic.h
+++ b/src/ic.h
@@ -592,6 +592,7 @@
     UNINITIALIZED,
     SMIS,
     HEAP_NUMBERS,
+    STRINGS,
     OBJECTS,
     GENERIC
   };
diff --git a/src/isolate.cc b/src/isolate.cc
index 6fc671c..4871702 100644
--- a/src/isolate.cc
+++ b/src/isolate.cc
@@ -311,6 +311,17 @@
 }
 
 
+Isolate::PerIsolateThreadData* Isolate::FindPerThreadDataForThisThread() {
+  ThreadId thread_id = ThreadId::Current();
+  PerIsolateThreadData* per_thread = NULL;
+  {
+    ScopedLock lock(process_wide_mutex_);
+    per_thread = thread_data_table_->Lookup(this, thread_id);
+  }
+  return per_thread;
+}
+
+
 void Isolate::EnsureDefaultIsolate() {
   ScopedLock lock(process_wide_mutex_);
   if (default_isolate_ == NULL) {
@@ -322,7 +333,9 @@
   }
   // Can't use SetIsolateThreadLocals(default_isolate_, NULL) here
   // becase a non-null thread data may be already set.
-  Thread::SetThreadLocal(isolate_key_, default_isolate_);
+  if (Thread::GetThreadLocal(isolate_key_) == NULL) {
+    Thread::SetThreadLocal(isolate_key_, default_isolate_);
+  }
   CHECK(default_isolate_->PreInit());
 }
 
@@ -458,6 +471,11 @@
   zone_.isolate_ = this;
   stack_guard_.isolate_ = this;
 
+  // ThreadManager is initialized early to support locking an isolate
+  // before it is entered.
+  thread_manager_ = new ThreadManager();
+  thread_manager_->isolate_ = this;
+
 #if defined(V8_TARGET_ARCH_ARM) && !defined(__arm__) || \
     defined(V8_TARGET_ARCH_MIPS) && !defined(__mips__)
   simulator_initialized_ = false;
@@ -643,7 +661,6 @@
   TRACE_ISOLATE(preinit);
 
   ASSERT(Isolate::Current() == this);
-
 #ifdef ENABLE_DEBUGGER_SUPPORT
   debug_ = new Debug(this);
   debugger_ = new Debugger();
@@ -671,8 +688,6 @@
 
   string_tracker_ = new StringTracker();
   string_tracker_->isolate_ = this;
-  thread_manager_ = new ThreadManager();
-  thread_manager_->isolate_ = this;
   compilation_cache_ = new CompilationCache(this);
   transcendental_cache_ = new TranscendentalCache();
   keyed_lookup_cache_ = new KeyedLookupCache();
@@ -683,7 +698,7 @@
   write_input_buffer_ = new StringInputBuffer();
   global_handles_ = new GlobalHandles(this);
   bootstrapper_ = new Bootstrapper();
-  handle_scope_implementer_ = new HandleScopeImplementer();
+  handle_scope_implementer_ = new HandleScopeImplementer(this);
   stub_cache_ = new StubCache(this);
   ast_sentinels_ = new AstSentinels();
   regexp_stack_ = new RegExpStack();
@@ -700,6 +715,7 @@
 
 
 void Isolate::InitializeThreadLocal() {
+  thread_local_top_.isolate_ = this;
   thread_local_top_.Initialize();
   clear_pending_exception();
   clear_pending_message();
@@ -757,7 +773,7 @@
   // Initialize other runtime facilities
 #if defined(USE_SIMULATOR)
 #if defined(V8_TARGET_ARCH_ARM) || defined(V8_TARGET_ARCH_MIPS)
-  Simulator::Initialize();
+  Simulator::Initialize(this);
 #endif
 #endif
 
diff --git a/src/isolate.h b/src/isolate.h
index 44190c2..088c247 100644
--- a/src/isolate.h
+++ b/src/isolate.h
@@ -224,6 +224,7 @@
     ASSERT(try_catch_handler_address_ == NULL);
   }
 
+  Isolate* isolate_;
   // The context where the current execution method is created and for variable
   // lookups.
   Context* context_;
@@ -487,6 +488,10 @@
   // Safe to call multiple times.
   static void EnsureDefaultIsolate();
 
+  // Find the PerThread for this particular (isolate, thread) combination
+  // If one does not yet exist, return null.
+  PerIsolateThreadData* FindPerThreadDataForThisThread();
+
 #ifdef ENABLE_DEBUGGER_SUPPORT
   // Get the debugger from the default isolate. Preinitializes the
   // default isolate if needed.
@@ -1066,7 +1071,7 @@
   // If one does not yet exist, allocate a new one.
   PerIsolateThreadData* FindOrAllocatePerThreadDataForThisThread();
 
-  // PreInits and returns a default isolate. Needed when a new thread tries
+// PreInits and returns a default isolate. Needed when a new thread tries
   // to create a Locker for the first time (the lock itself is in the isolate).
   static Isolate* GetDefaultIsolateForLocking();
 
@@ -1198,9 +1203,13 @@
 
   friend class ExecutionAccess;
   friend class IsolateInitializer;
+  friend class ThreadManager;
+  friend class Simulator;
+  friend class StackGuard;
   friend class ThreadId;
   friend class v8::Isolate;
   friend class v8::Locker;
+  friend class v8::Unlocker;
 
   DISALLOW_COPY_AND_ASSIGN(Isolate);
 };
diff --git a/src/jsregexp.h b/src/jsregexp.h
index b9b2f60..e1892de 100644
--- a/src/jsregexp.h
+++ b/src/jsregexp.h
@@ -28,6 +28,7 @@
 #ifndef V8_JSREGEXP_H_
 #define V8_JSREGEXP_H_
 
+#include "allocation.h"
 #include "macro-assembler.h"
 #include "zone-inl.h"
 
diff --git a/src/lithium-allocator.h b/src/lithium-allocator.h
index 7fff294..d456558 100644
--- a/src/lithium-allocator.h
+++ b/src/lithium-allocator.h
@@ -30,6 +30,7 @@
 
 #include "v8.h"
 
+#include "allocation.h"
 #include "lithium.h"
 #include "zone.h"
 
diff --git a/src/lithium.h b/src/lithium.h
index d85a87c..c548684 100644
--- a/src/lithium.h
+++ b/src/lithium.h
@@ -28,6 +28,7 @@
 #ifndef V8_LITHIUM_H_
 #define V8_LITHIUM_H_
 
+#include "allocation.h"
 #include "hydrogen.h"
 #include "safepoint-table.h"
 
diff --git a/src/liveedit.h b/src/liveedit.h
index 36c2c76..60e6238 100644
--- a/src/liveedit.h
+++ b/src/liveedit.h
@@ -49,6 +49,7 @@
 // instantiate newly compiled functions.
 
 
+#include "allocation.h"
 #include "compiler.h"
 
 namespace v8 {
diff --git a/src/log-utils.h b/src/log-utils.h
index 0dbaa9f..81bbf77 100644
--- a/src/log-utils.h
+++ b/src/log-utils.h
@@ -28,6 +28,8 @@
 #ifndef V8_LOG_UTILS_H_
 #define V8_LOG_UTILS_H_
 
+#include "allocation.h"
+
 namespace v8 {
 namespace internal {
 
diff --git a/src/log.h b/src/log.h
index 980af1e..3434b73 100644
--- a/src/log.h
+++ b/src/log.h
@@ -28,6 +28,7 @@
 #ifndef V8_LOG_H_
 #define V8_LOG_H_
 
+#include "allocation.h"
 #include "platform.h"
 #include "log-utils.h"
 
diff --git a/src/messages.js b/src/messages.js
index fdeae7d..14cedec 100644
--- a/src/messages.js
+++ b/src/messages.js
@@ -207,6 +207,7 @@
       invalid_json:                 ["String '", "%0", "' is not valid JSON"],
       circular_structure:           ["Converting circular structure to JSON"],
       obj_ctor_property_non_object: ["Object.", "%0", " called on non-object"],
+      called_on_null_or_undefined:  ["%0", " called on null or undefined"],
       array_indexof_not_defined:    ["Array.getIndexOf: Argument undefined"],
       object_not_extensible:        ["Can't add property ", "%0", ", object is not extensible"],
       illegal_access:               ["Illegal access"],
@@ -1070,6 +1071,10 @@
 }
 
 function errorToString() {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["Error.prototype.toString"]);
+  }
   // This helper function is needed because access to properties on
   // the builtins object do not work inside of a catch clause.
   function isCyclicErrorMarker(o) { return o === cyclic_error_marker; }
diff --git a/src/mips/simulator-mips.cc b/src/mips/simulator-mips.cc
index 50ad7a1..803cd9e 100644
--- a/src/mips/simulator-mips.cc
+++ b/src/mips/simulator-mips.cc
@@ -738,20 +738,21 @@
 }
 
 
-void Simulator::Initialize() {
-  if (Isolate::Current()->simulator_initialized()) return;
-  Isolate::Current()->set_simulator_initialized(true);
-  ::v8::internal::ExternalReference::set_redirector(&RedirectExternalReference);
+void Simulator::Initialize(Isolate* isolate) {
+  if (isolate->simulator_initialized()) return;
+  isolate->set_simulator_initialized(true);
+  ::v8::internal::ExternalReference::set_redirector(isolate,
+                                                    &RedirectExternalReference);
 }
 
 
-Simulator::Simulator() : isolate_(Isolate::Current()) {
+Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
   i_cache_ = isolate_->simulator_i_cache();
   if (i_cache_ == NULL) {
     i_cache_ = new v8::internal::HashMap(&ICacheMatch);
     isolate_->set_simulator_i_cache(i_cache_);
   }
-  Initialize();
+  Initialize(isolate);
   // Setup simulator support first. Some of this information is needed to
   // setup the architecture state.
   stack_size_ = 1 * 1024*1024;  // allocate 1MB for stack
@@ -852,17 +853,14 @@
 // Get the active Simulator for the current thread.
 Simulator* Simulator::current(Isolate* isolate) {
   v8::internal::Isolate::PerIsolateThreadData* isolate_data =
-      Isolate::CurrentPerIsolateThreadData();
-  if (isolate_data == NULL) {
-    Isolate::EnterDefaultIsolate();
-    isolate_data = Isolate::CurrentPerIsolateThreadData();
-  }
+       isolate->FindOrAllocatePerThreadDataForThisThread();
+  ASSERT(isolate_data != NULL);
   ASSERT(isolate_data != NULL);
 
   Simulator* sim = isolate_data->simulator();
   if (sim == NULL) {
     // TODO(146): delete the simulator object when a thread/isolate goes away.
-    sim = new Simulator();
+    sim = new Simulator(isolate);
     isolate_data->set_simulator(sim);
   }
   return sim;
diff --git a/src/mips/simulator-mips.h b/src/mips/simulator-mips.h
index 0cd9bbe..b10eeab 100644
--- a/src/mips/simulator-mips.h
+++ b/src/mips/simulator-mips.h
@@ -68,7 +68,8 @@
 // just use the C stack limit.
 class SimulatorStack : public v8::internal::AllStatic {
  public:
-  static inline uintptr_t JsLimitFromCLimit(uintptr_t c_limit) {
+  static inline uintptr_t JsLimitFromCLimit(Isolate* isolate,
+                                            uintptr_t c_limit) {
     return c_limit;
   }
 
@@ -170,7 +171,7 @@
     kNumFPURegisters
   };
 
-  Simulator();
+  explicit Simulator(Isolate* isolate);
   ~Simulator();
 
   // The currently executing Simulator instance. Potentially there can be one
@@ -205,7 +206,7 @@
   void Execute();
 
   // Call on program start.
-  static void Initialize();
+  static void Initialize(Isolate* isolate);
 
   // V8 generally calls into generated JS code with 5 parameters and into
   // generated RegExp code with 7 parameters. This is a convenience function,
@@ -373,8 +374,9 @@
 // trouble down the line.
 class SimulatorStack : public v8::internal::AllStatic {
  public:
-  static inline uintptr_t JsLimitFromCLimit(uintptr_t c_limit) {
-    return Simulator::current(Isolate::Current())->StackLimit();
+  static inline uintptr_t JsLimitFromCLimit(Isolate* isolate,
+                                            uintptr_t c_limit) {
+    return Simulator::current(isolate)->StackLimit();
   }
 
   static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
diff --git a/src/objects-visiting.h b/src/objects-visiting.h
index da955da..d06140c 100644
--- a/src/objects-visiting.h
+++ b/src/objects-visiting.h
@@ -28,6 +28,8 @@
 #ifndef V8_OBJECTS_VISITING_H_
 #define V8_OBJECTS_VISITING_H_
 
+#include "allocation.h"
+
 // This file provides base classes and auxiliary methods for defining
 // static object visitors used during GC.
 // Visiting HeapObject body with a normal ObjectVisitor requires performing
diff --git a/src/objects.cc b/src/objects.cc
index f42be65..519909c 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -4957,8 +4957,7 @@
 
 
 // Archive statics that are thread local.
-char* Relocatable::ArchiveState(char* to) {
-  Isolate* isolate = Isolate::Current();
+char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
   *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
   isolate->set_relocatable_top(NULL);
   return to + ArchiveSpacePerThread();
@@ -4966,8 +4965,7 @@
 
 
 // Restore statics that are thread local.
-char* Relocatable::RestoreState(char* from) {
-  Isolate* isolate = Isolate::Current();
+char* Relocatable::RestoreState(Isolate* isolate, char* from) {
   isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
   return from + ArchiveSpacePerThread();
 }
diff --git a/src/objects.h b/src/objects.h
index 556aaa2..77aab24 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -28,6 +28,7 @@
 #ifndef V8_OBJECTS_H_
 #define V8_OBJECTS_H_
 
+#include "allocation.h"
 #include "builtins.h"
 #include "smart-pointer.h"
 #include "unicode-inl.h"
@@ -5924,8 +5925,8 @@
 
   static void PostGarbageCollectionProcessing();
   static int ArchiveSpacePerThread();
-  static char* ArchiveState(char* to);
-  static char* RestoreState(char* from);
+  static char* ArchiveState(Isolate* isolate, char* to);
+  static char* RestoreState(Isolate* isolate, char* from);
   static void Iterate(ObjectVisitor* v);
   static void Iterate(ObjectVisitor* v, Relocatable* top);
   static char* Iterate(ObjectVisitor* v, char* t);
diff --git a/src/parser.cc b/src/parser.cc
index f983437..9e4031a 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -3543,9 +3543,9 @@
     //    '(' (Identifier)*[','] ')'
     Expect(Token::LPAREN, CHECK_OK);
     start_pos = scanner().location().beg_pos;
-    Scanner::Location name_loc = Scanner::NoLocation();
-    Scanner::Location dupe_loc = Scanner::NoLocation();
-    Scanner::Location reserved_loc = Scanner::NoLocation();
+    Scanner::Location name_loc = Scanner::Location::invalid();
+    Scanner::Location dupe_loc = Scanner::Location::invalid();
+    Scanner::Location reserved_loc = Scanner::Location::invalid();
 
     bool done = (peek() == Token::RPAREN);
     while (!done) {
@@ -3864,12 +3864,14 @@
 }
 
 
-// Checks whether octal literal last seen is between beg_pos and end_pos.
-// If so, reports an error.
+// Checks whether an octal literal was last seen between beg_pos and end_pos.
+// If so, reports an error. Only called for strict mode.
 void Parser::CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) {
-  int octal = scanner().octal_position();
-  if (beg_pos <= octal && octal <= end_pos) {
-    ReportMessageAt(Scanner::Location(octal, octal + 1), "strict_octal_literal",
+  Scanner::Location octal = scanner().octal_position();
+  if (octal.IsValid() &&
+      beg_pos <= octal.beg_pos &&
+      octal.end_pos <= end_pos) {
+    ReportMessageAt(octal, "strict_octal_literal",
                     Vector<const char*>::empty());
     scanner().clear_octal_position();
     *ok = false;
diff --git a/src/parser.h b/src/parser.h
index a63651a..f50e2e3 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -32,6 +32,7 @@
 #include "ast.h"
 #include "scanner.h"
 #include "scopes.h"
+#include "preparse-data-format.h"
 #include "preparse-data.h"
 
 namespace v8 {
diff --git a/src/platform-freebsd.cc b/src/platform-freebsd.cc
index 8b83f2b..99264d2 100644
--- a/src/platform-freebsd.cc
+++ b/src/platform-freebsd.cc
@@ -52,6 +52,7 @@
 #undef MAP_TYPE
 
 #include "v8.h"
+#include "v8threads.h"
 
 #include "platform.h"
 #include "vm-state-inl.h"
@@ -397,31 +398,6 @@
 };
 
 
-ThreadHandle::ThreadHandle(Kind kind) {
-  data_ = new PlatformData(kind);
-}
-
-
-void ThreadHandle::Initialize(ThreadHandle::Kind kind) {
-  data_->Initialize(kind);
-}
-
-
-ThreadHandle::~ThreadHandle() {
-  delete data_;
-}
-
-
-bool ThreadHandle::IsSelf() const {
-  return pthread_equal(data_->thread_, pthread_self());
-}
-
-
-bool ThreadHandle::IsValid() const {
-  return data_->thread_ != kNoThread;
-}
-
-
 Thread::Thread(Isolate* isolate, const Options& options)
     : data_(new PlatformData),
       isolate_(isolate),
@@ -448,8 +424,8 @@
   // This is also initialized by the first argument to pthread_create() but we
   // don't know which thread will run first (the original thread or the new
   // one) so we initialize it here too.
-  thread_->data_->thread_ = pthread_self();
-  ASSERT(thread->IsValid());
+  thread->data()->thread_ = pthread_self();
+  ASSERT(thread->data()->thread_ != kNoThread);
   Thread::SetThreadLocal(Isolate::isolate_key(), thread->isolate());
   thread->Run();
   return NULL;
@@ -470,13 +446,13 @@
     pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
     attr_ptr = &attr;
   }
-  pthread_create(&thread_handle_data()->thread_, attr_ptr, ThreadEntry, this);
-  ASSERT(IsValid());
+  pthread_create(&data_->thread_, attr_ptr, ThreadEntry, this);
+  ASSERT(data_->thread_ != kNoThread);
 }
 
 
 void Thread::Join() {
-  pthread_join(thread_handle_data()->thread_, NULL);
+  pthread_join(data_->thread_, NULL);
 }
 
 
diff --git a/src/platform-linux.cc b/src/platform-linux.cc
index 606e607..26de12f 100644
--- a/src/platform-linux.cc
+++ b/src/platform-linux.cc
@@ -205,7 +205,7 @@
   asm("mov r2, #255");
   asm("lsl r1, r1, #8");
   asm("orr r1, r1, r2");
-  asm("lsl r1, r1, #16");
+  asm("lsl r1, r1, #20");
   // For vmov d0, r0, r1 use ARM mode.
 #ifdef __thumb__
   asm volatile(
diff --git a/src/preparse-data.cc b/src/preparse-data.cc
index 5cb0a88..e65734b 100644
--- a/src/preparse-data.cc
+++ b/src/preparse-data.cc
@@ -27,6 +27,7 @@
 
 #include "../include/v8stdint.h"
 
+#include "preparse-data-format.h"
 #include "preparse-data.h"
 
 #include "checks.h"
diff --git a/src/preparse-data.h b/src/preparse-data.h
index e12203a..551d2e8 100644
--- a/src/preparse-data.h
+++ b/src/preparse-data.h
@@ -25,41 +25,16 @@
 // (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_PREPARSER_DATA_H_
-#define V8_PREPARSER_DATA_H_
+#ifndef V8_PREPARSE_DATA_H_
+#define V8_PREPARSE_DATA_H_
 
+#include "allocation.h"
 #include "hashmap.h"
 #include "utils-inl.h"
 
 namespace v8 {
 namespace internal {
 
-// Generic and general data used by preparse data recorders and readers.
-
-class PreparseDataConstants : public AllStatic {
- public:
-  // Layout and constants of the preparse data exchange format.
-  static const unsigned kMagicNumber = 0xBadDead;
-  static const unsigned kCurrentVersion = 6;
-
-  static const int kMagicOffset = 0;
-  static const int kVersionOffset = 1;
-  static const int kHasErrorOffset = 2;
-  static const int kFunctionsSizeOffset = 3;
-  static const int kSymbolCountOffset = 4;
-  static const int kSizeOffset = 5;
-  static const int kHeaderSize = 6;
-
-  // If encoding a message, the following positions are fixed.
-  static const int kMessageStartPos = 0;
-  static const int kMessageEndPos = 1;
-  static const int kMessageArgCountPos = 2;
-  static const int kMessageTextPos = 3;
-
-  static const byte kNumberTerminator = 0x80u;
-};
-
-
 // ----------------------------------------------------------------------------
 // ParserRecorder - Logging of preparser data.
 
@@ -247,4 +222,4 @@
 
 } }  // namespace v8::internal.
 
-#endif  // V8_PREPARSER_DATA_H_
+#endif  // V8_PREPARSE_DATA_H_
diff --git a/src/preparser-api.cc b/src/preparser-api.cc
index 9646eb6..a0d13ed 100644
--- a/src/preparser-api.cc
+++ b/src/preparser-api.cc
@@ -33,6 +33,7 @@
 #include "utils.h"
 #include "list.h"
 #include "scanner-base.h"
+#include "preparse-data-format.h"
 #include "preparse-data.h"
 #include "preparser.h"
 
diff --git a/src/preparser.cc b/src/preparser.cc
index fec1567..5bd9906 100644
--- a/src/preparser.cc
+++ b/src/preparser.cc
@@ -34,6 +34,7 @@
 #include "list.h"
 
 #include "scanner-base.h"
+#include "preparse-data-format.h"
 #include "preparse-data.h"
 #include "preparser.h"
 
@@ -94,13 +95,33 @@
 }
 
 
+// Checks whether octal literal last seen is between beg_pos and end_pos.
+// If so, reports an error.
+void PreParser::CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) {
+  i::Scanner::Location octal = scanner_->octal_position();
+  if (beg_pos <= octal.beg_pos && octal.end_pos <= end_pos) {
+    ReportMessageAt(octal.beg_pos, octal.end_pos, "strict_octal_literal", NULL);
+    scanner_->clear_octal_position();
+    *ok = false;
+  }
+}
+
+
 PreParser::SourceElements PreParser::ParseSourceElements(int end_token,
                                                          bool* ok) {
   // SourceElements ::
   //   (Statement)* <end_token>
 
+  bool allow_directive_prologue = true;
   while (peek() != end_token) {
-    ParseStatement(CHECK_OK);
+    Statement statement = ParseStatement(CHECK_OK);
+    if (allow_directive_prologue) {
+      if (statement == kUseStrictExpressionStatement) {
+        set_strict_mode();
+      } else if (statement != kStringLiteralExpressionStatement) {
+        allow_directive_prologue = false;
+      }
+    }
   }
   return kUnknownSourceElements;
 }
@@ -299,10 +320,17 @@
   Expression expr = ParseExpression(true, CHECK_OK);
   if (peek() == i::Token::COLON && expr == kIdentifierExpression) {
     Consume(i::Token::COLON);
-    return ParseStatement(ok);
+    ParseStatement(ok);
+    return kUnknownStatement;
   }
   // Parsed expression statement.
   ExpectSemicolon(CHECK_OK);
+  if (expr == kStringLiteralExpression) {
+    return kStringLiteralExpressionStatement;
+  }
+  if (expr == kUseStrictString) {
+    return kUseStrictExpressionStatement;
+  }
   return kUnknownStatement;
 }
 
@@ -1057,10 +1085,10 @@
   ScopeType outer_scope_type = scope_->type();
   bool inside_with = scope_->IsInsideWith();
   Scope function_scope(&scope_, kFunctionScope);
-
   //  FormalParameterList ::
   //    '(' (Identifier)*[','] ')'
   Expect(i::Token::LPAREN, CHECK_OK);
+  int start_position = scanner_->location().beg_pos;
   bool done = (peek() == i::Token::RPAREN);
   while (!done) {
     ParseIdentifier(CHECK_OK);
@@ -1099,6 +1127,12 @@
     ParseSourceElements(i::Token::RBRACE, CHECK_OK);
     Expect(i::Token::RBRACE, CHECK_OK);
   }
+
+  if (scope_->is_strict()) {
+    int end_position = scanner_->location().end_pos;
+    CheckOctalLiteral(start_position, end_position, CHECK_OK);
+  }
+
   return kUnknownExpression;
 }
 
@@ -1149,8 +1183,17 @@
 
 
 PreParser::Expression PreParser::GetStringSymbol() {
+  const int kUseStrictLength = 10;
+  const char* kUseStrictChars = "use strict";
   LogSymbol();
-  return kUnknownExpression;
+  if (scanner_->is_literal_ascii() &&
+      scanner_->literal_length() == kUseStrictLength &&
+      !scanner_->literal_contains_escapes() &&
+      !strncmp(scanner_->literal_ascii_string().start(), kUseStrictChars,
+               kUseStrictLength)) {
+    return kUseStrictString;
+  }
+  return kStringLiteralExpression;
 }
 
 
diff --git a/src/preparser.h b/src/preparser.h
index b7fa6c7..93a8a42 100644
--- a/src/preparser.h
+++ b/src/preparser.h
@@ -33,7 +33,7 @@
 
 // Preparsing checks a JavaScript program and emits preparse-data that helps
 // a later parsing to be faster.
-// See preparse-data.h for the data.
+// See preparse-data-format.h for the data format.
 
 // The PreParser checks that the syntax follows the grammar for JavaScript,
 // and collects some information about the program along the way.
@@ -80,14 +80,18 @@
   // simple this-property assignments.
 
   enum StatementType {
-    kUnknownStatement
+    kUnknownStatement,
+    kStringLiteralExpressionStatement,
+    kUseStrictExpressionStatement
   };
 
   enum ExpressionType {
     kUnknownExpression,
     kIdentifierExpression,  // Used to detect labels.
     kThisExpression,
-    kThisPropertyExpression
+    kThisPropertyExpression,
+    kStringLiteralExpression,
+    kUseStrictString
   };
 
   enum IdentifierType {
@@ -95,7 +99,9 @@
   };
 
   enum SourceElementTypes {
-    kUnknownSourceElements
+    kUnknownSourceElements,
+    kDirectivePrologue,
+    kUseStrictDirective
   };
 
   typedef int SourceElements;
@@ -112,7 +118,8 @@
           type_(type),
           materialized_literal_count_(0),
           expected_properties_(0),
-          with_nesting_count_(0) {
+          with_nesting_count_(0),
+          strict_((prev_ != NULL) && prev_->is_strict()) {
       *variable = this;
     }
     ~Scope() { *variable_ = prev_; }
@@ -122,6 +129,8 @@
     int expected_properties() { return expected_properties_; }
     int materialized_literal_count() { return materialized_literal_count_; }
     bool IsInsideWith() { return with_nesting_count_ != 0; }
+    bool is_strict() { return strict_; }
+    void set_strict() { strict_ = true; }
     void EnterWith() { with_nesting_count_++; }
     void LeaveWith() { with_nesting_count_--; }
 
@@ -132,6 +141,7 @@
     int materialized_literal_count_;
     int expected_properties_;
     int with_nesting_count_;
+    bool strict_;
   };
 
   // Private constructor only used in PreParseProgram.
@@ -152,10 +162,13 @@
   PreParseResult PreParse() {
     Scope top_scope(&scope_, kTopLevelScope);
     bool ok = true;
+    int start_position = scanner_->peek_location().beg_pos;
     ParseSourceElements(i::Token::EOS, &ok);
     if (stack_overflow_) return kPreParseStackOverflow;
     if (!ok) {
       ReportUnexpectedToken(scanner_->current_token());
+    } else if (scope_->is_strict()) {
+      CheckOctalLiteral(start_position, scanner_->location().end_pos, &ok);
     }
     return kPreParseSuccess;
   }
@@ -169,6 +182,8 @@
     log_->LogMessage(start_pos, end_pos, type, name_opt);
   }
 
+  void CheckOctalLiteral(int beg_pos, int end_pos, bool* ok);
+
   // All ParseXXX functions take as the last argument an *ok parameter
   // which is set to false if parsing failed; it is unchanged otherwise.
   // By making the 'exception handling' explicit, we are forced to check
@@ -245,6 +260,12 @@
 
   bool peek_any_identifier();
 
+  void set_strict_mode() {
+    scope_->set_strict();
+  }
+
+  bool is_strict_mode() { return scope_->is_strict(); }
+
   void Consume(i::Token::Value token) { Next(); }
 
   void Expect(i::Token::Value token, bool* ok) {
diff --git a/src/prettyprinter.h b/src/prettyprinter.h
index 451b17e..080081d 100644
--- a/src/prettyprinter.h
+++ b/src/prettyprinter.h
@@ -28,6 +28,7 @@
 #ifndef V8_PRETTYPRINTER_H_
 #define V8_PRETTYPRINTER_H_
 
+#include "allocation.h"
 #include "ast.h"
 
 namespace v8 {
diff --git a/src/profile-generator.h b/src/profile-generator.h
index bbc9efc..5b789ac 100644
--- a/src/profile-generator.h
+++ b/src/profile-generator.h
@@ -30,6 +30,7 @@
 
 #ifdef ENABLE_LOGGING_AND_PROFILING
 
+#include "allocation.h"
 #include "hashmap.h"
 #include "../include/v8-profiler.h"
 
diff --git a/src/property.h b/src/property.h
index ee95ca2..5cd3c66 100644
--- a/src/property.h
+++ b/src/property.h
@@ -28,6 +28,8 @@
 #ifndef V8_PROPERTY_H_
 #define V8_PROPERTY_H_
 
+#include "allocation.h"
+
 namespace v8 {
 namespace internal {
 
diff --git a/src/runtime.cc b/src/runtime.cc
index 6738213..b32ae8a 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -7554,6 +7554,29 @@
 }
 
 
+RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
+  HandleScope scope(isolate);
+  ASSERT(args.length() == 1);
+  if (!V8::UseCrankshaft()) {
+    return Smi::FromInt(4);  // 4 == "never".
+  }
+  if (FLAG_always_opt) {
+    return Smi::FromInt(3);  // 3 == "always".
+  }
+  CONVERT_ARG_CHECKED(JSFunction, function, 0);
+  return function->IsOptimized() ? Smi::FromInt(1)   // 1 == "yes".
+                                 : Smi::FromInt(2);  // 2 == "no".
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
+  HandleScope scope(isolate);
+  ASSERT(args.length() == 1);
+  CONVERT_ARG_CHECKED(JSFunction, function, 0);
+  return Smi::FromInt(function->shared()->opt_count());
+}
+
+
 RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
   HandleScope scope(isolate);
   ASSERT(args.length() == 1);
diff --git a/src/runtime.h b/src/runtime.h
index f9a9cad..0641abd 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -28,6 +28,7 @@
 #ifndef V8_RUNTIME_H_
 #define V8_RUNTIME_H_
 
+#include "allocation.h"
 #include "zone.h"
 
 namespace v8 {
@@ -86,6 +87,8 @@
   F(NotifyOSR, 0, 1) \
   F(DeoptimizeFunction, 1, 1) \
   F(OptimizeFunctionOnNextCall, 1, 1) \
+  F(GetOptimizationStatus, 1, 1) \
+  F(GetOptimizationCount, 1, 1) \
   F(CompileForOnStackReplacement, 1, 1) \
   F(SetNewFunctionAttributes, 1, 1) \
   F(AllocateInNewSpace, 1, 1) \
diff --git a/src/safepoint-table.h b/src/safepoint-table.h
index 084a0b4..de537f9 100644
--- a/src/safepoint-table.h
+++ b/src/safepoint-table.h
@@ -28,6 +28,7 @@
 #ifndef V8_SAFEPOINT_TABLE_H_
 #define V8_SAFEPOINT_TABLE_H_
 
+#include "allocation.h"
 #include "heap.h"
 #include "v8memory.h"
 #include "zone.h"
diff --git a/src/scanner-base.cc b/src/scanner-base.cc
index 9715ca9..e15ef41 100644
--- a/src/scanner-base.cc
+++ b/src/scanner-base.cc
@@ -38,8 +38,7 @@
 // Scanner
 
 Scanner::Scanner(UnicodeCache* unicode_cache)
-    : unicode_cache_(unicode_cache),
-      octal_pos_(kNoOctalLocation) { }
+    : unicode_cache_(unicode_cache) { }
 
 
 uc32 Scanner::ScanHexEscape(uc32 c, int length) {
@@ -70,34 +69,12 @@
 }
 
 
-// Octal escapes of the forms '\0xx' and '\xxx' are not a part of
-// ECMA-262. Other JS VMs support them.
-uc32 Scanner::ScanOctalEscape(uc32 c, int length) {
-  uc32 x = c - '0';
-  int i = 0;
-  for (; i < length; i++) {
-    int d = c0_ - '0';
-    if (d < 0 || d > 7) break;
-    int nx = x * 8 + d;
-    if (nx >= 256) break;
-    x = nx;
-    Advance();
-  }
-  // Anything excelt '\0' is an octal escape sequence, illegal in strict mode.
-  // Remember the position of octal escape sequences so that better error
-  // can be reported later (in strict mode).
-  if (c != '0' || i > 0) {
-    octal_pos_ = source_pos() - i - 1;     // Already advanced
-  }
-  return x;
-}
-
 
 // ----------------------------------------------------------------------------
 // JavaScriptScanner
 
 JavaScriptScanner::JavaScriptScanner(UnicodeCache* scanner_contants)
-    : Scanner(scanner_contants) { }
+  : Scanner(scanner_contants), octal_pos_(Location::invalid()) { }
 
 
 Token::Value JavaScriptScanner::Next() {
@@ -518,6 +495,31 @@
 }
 
 
+// Octal escapes of the forms '\0xx' and '\xxx' are not a part of
+// ECMA-262. Other JS VMs support them.
+uc32 JavaScriptScanner::ScanOctalEscape(uc32 c, int length) {
+  uc32 x = c - '0';
+  int i = 0;
+  for (; i < length; i++) {
+    int d = c0_ - '0';
+    if (d < 0 || d > 7) break;
+    int nx = x * 8 + d;
+    if (nx >= 256) break;
+    x = nx;
+    Advance();
+  }
+  // Anything except '\0' is an octal escape sequence, illegal in strict mode.
+  // Remember the position of octal escape sequences so that an error
+  // can be reported later (in strict mode).
+  // We don't report the error immediately, because the octal escape can
+  // occur before the "use strict" directive.
+  if (c != '0' || i > 0) {
+    octal_pos_ = Location(source_pos() - i - 1, source_pos() - 1);
+  }
+  return x;
+}
+
+
 Token::Value JavaScriptScanner::ScanString() {
   uc32 quote = c0_;
   Advance();  // consume quote
@@ -562,6 +564,7 @@
   } else {
     // if the first character is '0' we must check for octals and hex
     if (c0_ == '0') {
+      int start_pos = source_pos();  // For reporting octal positions.
       AddLiteralCharAdvance();
 
       // either 0, 0exxx, 0Exxx, 0.xxx, an octal number, or a hex number
@@ -586,7 +589,7 @@
           }
           if (c0_  < '0' || '7'  < c0_) {
             // Octal literal finished.
-            octal_pos_ = next_.location.beg_pos;
+            octal_pos_ = Location(start_pos, source_pos());
             break;
           }
           AddLiteralCharAdvance();
@@ -729,6 +732,9 @@
       // worrying whether the following characters are part of the escape
       // or not, since any '/', '\\' or '[' is guaranteed to not be part
       // of the escape sequence.
+
+      // TODO(896): At some point, parse RegExps more throughly to capture
+      // octal esacpes in strict mode.
     } else {  // Unescaped character.
       if (c0_ == '[') in_character_class = true;
       if (c0_ == ']') in_character_class = false;
diff --git a/src/scanner-base.h b/src/scanner-base.h
index a2fbd82..02566dd 100644
--- a/src/scanner-base.h
+++ b/src/scanner-base.h
@@ -286,23 +286,17 @@
       return beg_pos >= 0 && end_pos >= beg_pos;
     }
 
+    static Location invalid() { return Location(-1, -1); }
+
     int beg_pos;
     int end_pos;
   };
 
-  static Location NoLocation() {
-    return Location(-1, -1);
-  }
-
   // Returns the location information for the current token
   // (the token returned by Next()).
   Location location() const { return current_.location; }
   Location peek_location() const { return next_.location; }
 
-  // Returns the location of the last seen octal literal
-  int octal_position() const { return octal_pos_; }
-  void clear_octal_position() { octal_pos_ = -1; }
-
   // Returns the literal string, if any, for the current token (the
   // token returned by Next()). The string is 0-terminated and in
   // UTF-8 format; they may contain 0-characters. Literal strings are
@@ -326,6 +320,16 @@
     return current_.literal_chars->length();
   }
 
+  bool literal_contains_escapes() const {
+    Location location = current_.location;
+    int source_length = (location.end_pos - location.beg_pos);
+    if (current_.token == Token::STRING) {
+      // Subtract delimiters.
+      source_length -= 2;
+    }
+    return current_.literal_chars->length() != source_length;
+  }
+
   // Returns the literal string for the next token (the token that
   // would be returned if Next() were called).
   bool is_next_literal_ascii() {
@@ -417,9 +421,6 @@
 
   uc32 ScanHexEscape(uc32 c, int length);
 
-  // Scans octal escape sequence. Also accepts "\0" decimal escape sequence.
-  uc32 ScanOctalEscape(uc32 c, int length);
-
   // Return the current source position.
   int source_pos() {
     return source_->pos() - kCharacterLookaheadBufferSize;
@@ -437,9 +438,6 @@
   // Input stream. Must be initialized to an UC16CharacterStream.
   UC16CharacterStream* source_;
 
-  // Start position of the octal literal last scanned.
-  int octal_pos_;
-
   // One Unicode character look-ahead; c0_ < 0 at the end of the input.
   uc32 c0_;
 };
@@ -492,6 +490,13 @@
   // Used for checking if a property name is an identifier.
   static bool IsIdentifier(unibrow::CharacterStream* buffer);
 
+  // Scans octal escape sequence. Also accepts "\0" decimal escape sequence.
+  uc32 ScanOctalEscape(uc32 c, int length);
+
+  // Returns the location of the last seen octal literal
+  Location octal_position() const { return octal_pos_; }
+  void clear_octal_position() { octal_pos_ = Location::invalid(); }
+
   // Seek forward to the given position.  This operation does not
   // work in general, for instance when there are pushed back
   // characters, but works for seeking forward until simple delimiter
@@ -521,6 +526,9 @@
   // If the escape sequence cannot be decoded the result is kBadChar.
   uc32 ScanIdentifierUnicodeEscape();
 
+  // Start position of the octal literal last scanned.
+  Location octal_pos_;
+
   bool has_line_terminator_before_next_;
 };
 
diff --git a/src/scopeinfo.h b/src/scopeinfo.h
index 2552af2..9e607fe 100644
--- a/src/scopeinfo.h
+++ b/src/scopeinfo.h
@@ -28,6 +28,7 @@
 #ifndef V8_SCOPEINFO_H_
 #define V8_SCOPEINFO_H_
 
+#include "allocation.h"
 #include "variables.h"
 #include "zone-inl.h"
 
diff --git a/src/spaces.h b/src/spaces.h
index 8269ea6..4024387 100644
--- a/src/spaces.h
+++ b/src/spaces.h
@@ -28,6 +28,7 @@
 #ifndef V8_SPACES_H_
 #define V8_SPACES_H_
 
+#include "allocation.h"
 #include "list.h"
 #include "log.h"
 
diff --git a/src/splay-tree.h b/src/splay-tree.h
index c265276..0cb9ea8 100644
--- a/src/splay-tree.h
+++ b/src/splay-tree.h
@@ -28,6 +28,8 @@
 #ifndef V8_SPLAY_TREE_H_
 #define V8_SPLAY_TREE_H_
 
+#include "allocation.h"
+
 namespace v8 {
 namespace internal {
 
diff --git a/src/string.js b/src/string.js
index d8d402c..bed211a 100644
--- a/src/string.js
+++ b/src/string.js
@@ -62,6 +62,10 @@
 
 // ECMA-262, section 15.5.4.4
 function StringCharAt(pos) {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["String.prototype.charAt"]);
+  }
   var result = %_StringCharAt(this, pos);
   if (%_IsSmi(result)) {
     result = %_StringCharAt(TO_STRING_INLINE(this), TO_INTEGER(pos));
@@ -72,6 +76,10 @@
 
 // ECMA-262 section 15.5.4.5
 function StringCharCodeAt(pos) {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["String.prototype.charCodeAt"]);
+  }
   var result = %_StringCharCodeAt(this, pos);
   if (!%_IsSmi(result)) {
     result = %_StringCharCodeAt(TO_STRING_INLINE(this), TO_INTEGER(pos));
@@ -82,6 +90,9 @@
 
 // ECMA-262, section 15.5.4.6
 function StringConcat() {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined", ["String.prototype.concat"]);
+  }
   var len = %_ArgumentsLength();
   var this_as_string = TO_STRING_INLINE(this);
   if (len === 1) {
@@ -102,6 +113,10 @@
 
 // ECMA-262 section 15.5.4.7
 function StringIndexOf(pattern /* position */) {  // length == 1
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["String.prototype.indexOf"]);
+  }
   var subject = TO_STRING_INLINE(this);
   pattern = TO_STRING_INLINE(pattern);
   var index = 0;
@@ -117,6 +132,10 @@
 
 // ECMA-262 section 15.5.4.8
 function StringLastIndexOf(pat /* position */) {  // length == 1
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["String.prototype.lastIndexOf"]);
+  }
   var sub = TO_STRING_INLINE(this);
   var subLength = sub.length;
   var pat = TO_STRING_INLINE(pat);
@@ -146,6 +165,10 @@
 // This function is implementation specific.  For now, we do not
 // do anything locale specific.
 function StringLocaleCompare(other) {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["String.prototype.localeCompare"]);
+  }
   if (%_ArgumentsLength() === 0) return 0;
   return %StringLocaleCompare(TO_STRING_INLINE(this), 
                               TO_STRING_INLINE(other));
@@ -154,6 +177,10 @@
 
 // ECMA-262 section 15.5.4.10
 function StringMatch(regexp) {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["String.prototype.match"]);
+  }
   var subject = TO_STRING_INLINE(this);
   if (IS_REGEXP(regexp)) {
     if (!regexp.global) return RegExpExecNoTests(regexp, subject, 0);
@@ -187,6 +214,10 @@
 
 // ECMA-262, section 15.5.4.11
 function StringReplace(search, replace) {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["String.prototype.replace"]);
+  }
   var subject = TO_STRING_INLINE(this);
 
   // Delegate to one of the regular expression variants if necessary.
@@ -467,6 +498,10 @@
 
 // ECMA-262 section 15.5.4.12
 function StringSearch(re) {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["String.prototype.search"]);
+  }
   var regexp;
   if (IS_STRING(re)) {
     regexp = %_GetFromCache(STRING_TO_REGEXP_CACHE_ID, re);
@@ -485,6 +520,10 @@
 
 // ECMA-262 section 15.5.4.13
 function StringSlice(start, end) {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["String.prototype.slice"]);
+  }
   var s = TO_STRING_INLINE(this);
   var s_len = s.length;
   var start_i = TO_INTEGER(start);
@@ -520,6 +559,10 @@
 
 // ECMA-262 section 15.5.4.14
 function StringSplit(separator, limit) {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["String.prototype.split"]);
+  }
   var subject = TO_STRING_INLINE(this);
   limit = (IS_UNDEFINED(limit)) ? 0xffffffff : TO_UINT32(limit);
   if (limit === 0) return [];
@@ -613,6 +656,10 @@
 
 // ECMA-262 section 15.5.4.15
 function StringSubstring(start, end) {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["String.prototype.subString"]);
+  }
   var s = TO_STRING_INLINE(this);
   var s_len = s.length;
 
@@ -646,6 +693,10 @@
 
 // This is not a part of ECMA-262.
 function StringSubstr(start, n) {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["String.prototype.substr"]);
+  }
   var s = TO_STRING_INLINE(this);
   var len;
 
@@ -686,37 +737,65 @@
 
 // ECMA-262, 15.5.4.16
 function StringToLowerCase() {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["String.prototype.toLowerCase"]);
+  }
   return %StringToLowerCase(TO_STRING_INLINE(this));
 }
 
 
 // ECMA-262, 15.5.4.17
 function StringToLocaleLowerCase() {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["String.prototype.toLocaleLowerCase"]);
+  }
   return %StringToLowerCase(TO_STRING_INLINE(this));
 }
 
 
 // ECMA-262, 15.5.4.18
 function StringToUpperCase() {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["String.prototype.toUpperCase"]);
+  }
   return %StringToUpperCase(TO_STRING_INLINE(this));
 }
 
 
 // ECMA-262, 15.5.4.19
 function StringToLocaleUpperCase() {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["String.prototype.toLocaleUpperCase"]);
+  }
   return %StringToUpperCase(TO_STRING_INLINE(this));
 }
 
 // ES5, 15.5.4.20
 function StringTrim() {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["String.prototype.trim"]);
+  }
   return %StringTrim(TO_STRING_INLINE(this), true, true);
 }
 
 function StringTrimLeft() {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["String.prototype.trimLeft"]);
+  }
   return %StringTrim(TO_STRING_INLINE(this), true, false);
 }
 
 function StringTrimRight() {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["String.prototype.trimRight"]);
+  }
   return %StringTrim(TO_STRING_INLINE(this), false, true);
 }
 
diff --git a/src/stub-cache.h b/src/stub-cache.h
index c5dcf36..358f205 100644
--- a/src/stub-cache.h
+++ b/src/stub-cache.h
@@ -28,6 +28,7 @@
 #ifndef V8_STUB_CACHE_H_
 #define V8_STUB_CACHE_H_
 
+#include "allocation.h"
 #include "arguments.h"
 #include "macro-assembler.h"
 #include "zone-inl.h"
diff --git a/src/top.cc b/src/top.cc
index f44de7a..6d68231 100644
--- a/src/top.cc
+++ b/src/top.cc
@@ -77,9 +77,9 @@
   InitializeInternal();
 #ifdef USE_SIMULATOR
 #ifdef V8_TARGET_ARCH_ARM
-  simulator_ = Simulator::current(Isolate::Current());
+  simulator_ = Simulator::current(isolate_);
 #elif V8_TARGET_ARCH_MIPS
-  simulator_ = Simulator::current(Isolate::Current());
+  simulator_ = Simulator::current(isolate_);
 #endif
 #endif
   thread_id_ = ThreadId::Current();
diff --git a/src/type-info.h b/src/type-info.h
index a715bc7..5bfd4cd 100644
--- a/src/type-info.h
+++ b/src/type-info.h
@@ -28,6 +28,7 @@
 #ifndef V8_TYPE_INFO_H_
 #define V8_TYPE_INFO_H_
 
+#include "allocation.h"
 #include "globals.h"
 #include "zone.h"
 #include "zone-inl.h"
diff --git a/src/unbound-queue.h b/src/unbound-queue.h
index 443d5ce..59a426b 100644
--- a/src/unbound-queue.h
+++ b/src/unbound-queue.h
@@ -28,6 +28,8 @@
 #ifndef V8_UNBOUND_QUEUE_
 #define V8_UNBOUND_QUEUE_
 
+#include "allocation.h"
+
 namespace v8 {
 namespace internal {
 
diff --git a/src/v8natives.js b/src/v8natives.js
index 4fcf0ac..7a4be27 100644
--- a/src/v8natives.js
+++ b/src/v8natives.js
@@ -208,12 +208,20 @@
 
 // ECMA-262 - 15.2.4.2
 function ObjectToString() {
+  if (IS_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    return '[object Undefined]';
+  }
+  if (IS_NULL(this)) return  '[object Null]';
   return "[object " + %_ClassOf(ToObject(this)) + "]";
 }
 
 
 // ECMA-262 - 15.2.4.3
 function ObjectToLocaleString() {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["Object.prototype.toLocaleString"]);
+  }
   return this.toString();
 }
 
@@ -232,6 +240,10 @@
 
 // ECMA-262 - 15.2.4.6
 function ObjectIsPrototypeOf(V) {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["Object.prototype.isPrototypeOf"]);
+  }
   if (!IS_SPEC_OBJECT(V)) return false;
   return %IsInPrototypeChain(this, V);
 }
@@ -1062,6 +1074,10 @@
 
 // ECMA-262 section 15.7.4.3
 function NumberToLocaleString() {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["Number.prototype.toLocaleString"]);
+  }
   return this.toString();
 }
 
@@ -1082,6 +1098,10 @@
   if (f < 0 || f > 20) {
     throw new $RangeError("toFixed() digits argument must be between 0 and 20");
   }
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["Number.prototype.toFixed"]);
+  }
   var x = ToNumber(this);
   return %NumberToFixed(x, f);
 }
@@ -1096,6 +1116,10 @@
       throw new $RangeError("toExponential() argument must be between 0 and 20");
     }
   }
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["Number.prototype.toExponential"]);
+  }
   var x = ToNumber(this);
   return %NumberToExponential(x, f);
 }
@@ -1103,6 +1127,10 @@
 
 // ECMA-262 section 15.7.4.7
 function NumberToPrecision(precision) {
+  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+    throw MakeTypeError("called_on_null_or_undefined",
+                        ["Number.prototype.toPrecision"]);
+  }
   if (IS_UNDEFINED(precision)) return ToString(%_ValueOf(this));
   var p = TO_INTEGER(precision);
   if (p < 1 || p > 21) {
diff --git a/src/v8threads.cc b/src/v8threads.cc
index 4b033fc..26169b5 100644
--- a/src/v8threads.cc
+++ b/src/v8threads.cc
@@ -43,90 +43,94 @@
 
 
 // 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) {
-  // TODO(isolates): When Locker has Isolate parameter and it is provided, grab
-  // that one instead of using the current one.
-  // We pull default isolate for Locker constructor w/o p[arameter.
-  // A thread should not enter an isolate before acquiring a lock,
-  // in cases which mandate using Lockers.
-  // So getting a lock is the first thing threads do in a scenario where
-  // multple threads share an isolate. Hence, we need to access
-  // 'locking isolate' before we can actually enter into default isolate.
-  internal::Isolate* isolate = internal::Isolate::GetDefaultIsolateForLocking();
-  ASSERT(isolate != NULL);
-
+// current thread will be guaranteed to have the lock for a given isolate.
+Locker::Locker(v8::Isolate* isolate)
+  : has_lock_(false),
+    top_level_(false),
+    isolate_(reinterpret_cast<i::Isolate*>(isolate)) {
+  if (isolate_ == NULL) {
+    isolate_ = i::Isolate::GetDefaultIsolateForLocking();
+  }
   // Record that the Locker has been used at least once.
   active_ = true;
   // Get the big lock if necessary.
-  if (!isolate->thread_manager()->IsLockedByCurrentThread()) {
-    isolate->thread_manager()->Lock();
+  if (!isolate_->thread_manager()->IsLockedByCurrentThread()) {
+    isolate_->thread_manager()->Lock();
     has_lock_ = true;
 
-    if (isolate->IsDefaultIsolate()) {
-      // This only enters if not yet entered.
-      internal::Isolate::EnterDefaultIsolate();
-    }
-
-    ASSERT(internal::Thread::HasThreadLocal(
-        internal::Isolate::thread_id_key()));
-
     // Make sure that V8 is initialized.  Archiving of threads interferes
     // with deserialization by adding additional root pointers, so we must
     // initialize here, before anyone can call ~Locker() or Unlocker().
-    if (!isolate->IsInitialized()) {
+    if (!isolate_->IsInitialized()) {
+      isolate_->Enter();
       V8::Initialize();
+      isolate_->Exit();
     }
+
     // This may be a locker within an unlocker in which case we have to
     // get the saved state for this thread and restore it.
-    if (isolate->thread_manager()->RestoreThread()) {
+    if (isolate_->thread_manager()->RestoreThread()) {
       top_level_ = false;
     } else {
-      internal::ExecutionAccess access(isolate);
-      isolate->stack_guard()->ClearThread(access);
-      isolate->stack_guard()->InitThread(access);
+      internal::ExecutionAccess access(isolate_);
+      isolate_->stack_guard()->ClearThread(access);
+      isolate_->stack_guard()->InitThread(access);
+    }
+    if (isolate_->IsDefaultIsolate()) {
+      // This only enters if not yet entered.
+      internal::Isolate::EnterDefaultIsolate();
     }
   }
-  ASSERT(isolate->thread_manager()->IsLockedByCurrentThread());
+  ASSERT(isolate_->thread_manager()->IsLockedByCurrentThread());
 }
 
 
-bool Locker::IsLocked() {
-  return internal::Isolate::Current()->thread_manager()->
-      IsLockedByCurrentThread();
+bool Locker::IsLocked(v8::Isolate* isolate) {
+  i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
+  if (internal_isolate == NULL) {
+    internal_isolate = i::Isolate::GetDefaultIsolateForLocking();
+  }
+  return internal_isolate->thread_manager()->IsLockedByCurrentThread();
 }
 
 
 Locker::~Locker() {
-  // TODO(isolate): this should use a field storing the isolate it
-  // locked instead.
-  internal::Isolate* isolate = internal::Isolate::Current();
-  ASSERT(isolate->thread_manager()->IsLockedByCurrentThread());
+  ASSERT(isolate_->thread_manager()->IsLockedByCurrentThread());
   if (has_lock_) {
-    if (top_level_) {
-      isolate->thread_manager()->FreeThreadResources();
-    } else {
-      isolate->thread_manager()->ArchiveThread();
+    if (isolate_->IsDefaultIsolate()) {
+      isolate_->Exit();
     }
-    isolate->thread_manager()->Unlock();
+    if (top_level_) {
+      isolate_->thread_manager()->FreeThreadResources();
+    } else {
+      isolate_->thread_manager()->ArchiveThread();
+    }
+    isolate_->thread_manager()->Unlock();
   }
 }
 
 
-Unlocker::Unlocker() {
-  internal::Isolate* isolate = internal::Isolate::Current();
-  ASSERT(isolate->thread_manager()->IsLockedByCurrentThread());
-  isolate->thread_manager()->ArchiveThread();
-  isolate->thread_manager()->Unlock();
+Unlocker::Unlocker(v8::Isolate* isolate)
+  : isolate_(reinterpret_cast<i::Isolate*>(isolate)) {
+  if (isolate_ == NULL) {
+    isolate_ = i::Isolate::GetDefaultIsolateForLocking();
+  }
+  ASSERT(isolate_->thread_manager()->IsLockedByCurrentThread());
+  if (isolate_->IsDefaultIsolate()) {
+    isolate_->Exit();
+  }
+  isolate_->thread_manager()->ArchiveThread();
+  isolate_->thread_manager()->Unlock();
 }
 
 
 Unlocker::~Unlocker() {
-  // TODO(isolates): check it's the isolate we unlocked.
-  internal::Isolate* isolate = internal::Isolate::Current();
-  ASSERT(!isolate->thread_manager()->IsLockedByCurrentThread());
-  isolate->thread_manager()->Lock();
-  isolate->thread_manager()->RestoreThread();
+  ASSERT(!isolate_->thread_manager()->IsLockedByCurrentThread());
+  isolate_->thread_manager()->Lock();
+  isolate_->thread_manager()->RestoreThread();
+  if (isolate_->IsDefaultIsolate()) {
+    isolate_->Enter();
+  }
 }
 
 
@@ -144,17 +148,20 @@
 
 
 bool ThreadManager::RestoreThread() {
+  ASSERT(IsLockedByCurrentThread());
   // First check whether the current thread has been 'lazily archived', ie
   // not archived at all.  If that is the case we put the state storage we
   // had prepared back in the free list, since we didn't need it after all.
   if (lazily_archived_thread_.Equals(ThreadId::Current())) {
     lazily_archived_thread_ = ThreadId::Invalid();
-    ASSERT(Isolate::CurrentPerIsolateThreadData()->thread_state() ==
-           lazily_archived_thread_state_);
+    Isolate::PerIsolateThreadData* per_thread =
+        isolate_->FindPerThreadDataForThisThread();
+    ASSERT(per_thread != NULL);
+    ASSERT(per_thread->thread_state() == lazily_archived_thread_state_);
     lazily_archived_thread_state_->set_id(ThreadId::Invalid());
     lazily_archived_thread_state_->LinkInto(ThreadState::FREE_LIST);
     lazily_archived_thread_state_ = NULL;
-    Isolate::CurrentPerIsolateThreadData()->set_thread_state(NULL);
+    per_thread->set_thread_state(NULL);
     return true;
   }
 
@@ -168,7 +175,7 @@
     EagerlyArchiveThread();
   }
   Isolate::PerIsolateThreadData* per_thread =
-      Isolate::CurrentPerIsolateThreadData();
+      isolate_->FindPerThreadDataForThisThread();
   if (per_thread == NULL || per_thread->thread_state() == NULL) {
     // This is a new thread.
     isolate_->stack_guard()->InitThread(access);
@@ -178,7 +185,7 @@
   char* from = state->data();
   from = isolate_->handle_scope_implementer()->RestoreThread(from);
   from = isolate_->RestoreThread(from);
-  from = Relocatable::RestoreState(from);
+  from = Relocatable::RestoreState(isolate_, from);
 #ifdef ENABLE_DEBUGGER_SUPPORT
   from = isolate_->debug()->RestoreDebug(from);
 #endif
@@ -300,9 +307,12 @@
 void ThreadManager::ArchiveThread() {
   ASSERT(lazily_archived_thread_.Equals(ThreadId::Invalid()));
   ASSERT(!IsArchived());
+  ASSERT(IsLockedByCurrentThread());
   ThreadState* state = GetFreeThreadState();
   state->Unlink();
-  Isolate::CurrentPerIsolateThreadData()->set_thread_state(state);
+  Isolate::PerIsolateThreadData* per_thread =
+      isolate_->FindOrAllocatePerThreadDataForThisThread();
+  per_thread->set_thread_state(state);
   lazily_archived_thread_ = ThreadId::Current();
   lazily_archived_thread_state_ = state;
   ASSERT(state->id().Equals(ThreadId::Invalid()));
@@ -312,6 +322,7 @@
 
 
 void ThreadManager::EagerlyArchiveThread() {
+  ASSERT(IsLockedByCurrentThread());
   ThreadState* state = lazily_archived_thread_state_;
   state->LinkInto(ThreadState::IN_USE_LIST);
   char* to = state->data();
@@ -319,7 +330,7 @@
   // in ThreadManager::Iterate(ObjectVisitor*).
   to = isolate_->handle_scope_implementer()->ArchiveThread(to);
   to = isolate_->ArchiveThread(to);
-  to = Relocatable::ArchiveState(to);
+  to = Relocatable::ArchiveState(isolate_, to);
 #ifdef ENABLE_DEBUGGER_SUPPORT
   to = isolate_->debug()->ArchiveDebug(to);
 #endif
@@ -344,11 +355,11 @@
 
 
 bool ThreadManager::IsArchived() {
-  Isolate::PerIsolateThreadData* data = Isolate::CurrentPerIsolateThreadData();
+  Isolate::PerIsolateThreadData* data =
+      isolate_->FindPerThreadDataForThisThread();
   return data != NULL && data->thread_state() != NULL;
 }
 
-
 void ThreadManager::Iterate(ObjectVisitor* v) {
   // Expecting no threads during serialization/deserialization
   for (ThreadState* state = FirstThreadStateInUse();
diff --git a/src/version.cc b/src/version.cc
index 168f779..5cc81ac 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,7 +34,7 @@
 // cannot be changed without changing the SCons build script.
 #define MAJOR_VERSION     3
 #define MINOR_VERSION     3
-#define BUILD_NUMBER      4
+#define BUILD_NUMBER      5
 #define PATCH_LEVEL       0
 // Use 1 for candidates and 0 otherwise.
 // (Boolean macro values are not supported by all preprocessors.)
diff --git a/src/vm-state.h b/src/vm-state.h
index 11fc6d6..2062340 100644
--- a/src/vm-state.h
+++ b/src/vm-state.h
@@ -28,6 +28,7 @@
 #ifndef V8_VM_STATE_H_
 #define V8_VM_STATE_H_
 
+#include "allocation.h"
 #include "isolate.h"
 
 namespace v8 {
diff --git a/src/x64/builtins-x64.cc b/src/x64/builtins-x64.cc
index a549633..023e581 100644
--- a/src/x64/builtins-x64.cc
+++ b/src/x64/builtins-x64.cc
@@ -658,6 +658,15 @@
              Immediate(1 << SharedFunctionInfo::kStrictModeBitWithinByte));
     __ j(not_equal, &shift_arguments);
 
+    // Do not transform the receiver for natives.
+    // SharedFunctionInfo is already loaded into rbx.
+    __ movq(rbx, FieldOperand(rbx, SharedFunctionInfo::kScriptOffset));
+    __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex);
+    __ j(equal, &shift_arguments);
+    __ SmiCompare(FieldOperand(rbx, Script::kTypeOffset),
+               Smi::FromInt(Script::TYPE_NATIVE));
+    __ j(equal, &shift_arguments);
+
     // Compute the receiver in non-strict mode.
     __ movq(rbx, Operand(rsp, rax, times_pointer_size, 0));
     __ JumpIfSmi(rbx, &convert_to_object);
@@ -822,6 +831,15 @@
            Immediate(1 << SharedFunctionInfo::kStrictModeBitWithinByte));
   __ j(not_equal, &push_receiver);
 
+  // Do not transform the receiver for natives.
+  // SharedFunctionInfo is already loaded into rdx.
+  __ movq(rdx, FieldOperand(rdx, SharedFunctionInfo::kScriptOffset));
+  __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex);
+  __ j(equal, &push_receiver);
+  __ SmiCompare(FieldOperand(rdx, Script::kTypeOffset),
+             Smi::FromInt(Script::TYPE_NATIVE));
+  __ j(equal, &push_receiver);
+
   // Compute the receiver in non-strict mode.
   __ JumpIfSmi(rbx, &call_to_object);
   __ CompareRoot(rbx, Heap::kNullValueRootIndex);
diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
index ec1c185..5f0a84d 100644
--- a/src/x64/code-stubs-x64.cc
+++ b/src/x64/code-stubs-x64.cc
@@ -976,7 +976,7 @@
         // already loaded heap_number_map.
         __ AllocateInNewSpace(HeapNumber::kSize,
                               rax,
-                              rcx,
+                              rdx,
                               no_reg,
                               &allocation_failed,
                               TAG_OBJECT);
@@ -2835,13 +2835,21 @@
       rdx, rax, rcx, rbx, &check_unequal_objects);
 
   // Inline comparison of ascii strings.
-  StringCompareStub::GenerateCompareFlatAsciiStrings(masm,
+  if (cc_ == equal) {
+    StringCompareStub::GenerateFlatAsciiStringEquals(masm,
                                                      rdx,
                                                      rax,
                                                      rcx,
-                                                     rbx,
-                                                     rdi,
-                                                     r8);
+                                                     rbx);
+  } else {
+    StringCompareStub::GenerateCompareFlatAsciiStrings(masm,
+                                                       rdx,
+                                                       rax,
+                                                       rcx,
+                                                       rbx,
+                                                       rdi,
+                                                       r8);
+  }
 
 #ifdef DEBUG
   __ Abort("Unexpected fall-through from string comparison");
@@ -4489,6 +4497,47 @@
 }
 
 
+void StringCompareStub::GenerateFlatAsciiStringEquals(MacroAssembler* masm,
+                                                      Register left,
+                                                      Register right,
+                                                      Register scratch1,
+                                                      Register scratch2) {
+  Register length = scratch1;
+
+  // Compare lengths.
+  NearLabel check_zero_length;
+  __ movq(length, FieldOperand(left, String::kLengthOffset));
+  __ SmiCompare(length, FieldOperand(right, String::kLengthOffset));
+  __ j(equal, &check_zero_length);
+  __ Move(rax, Smi::FromInt(NOT_EQUAL));
+  __ ret(0);
+
+  // Check if the length is zero.
+  NearLabel compare_chars;
+  __ bind(&check_zero_length);
+  STATIC_ASSERT(kSmiTag == 0);
+  __ SmiTest(length);
+  __ j(not_zero, &compare_chars);
+  __ Move(rax, Smi::FromInt(EQUAL));
+  __ ret(0);
+
+  // Compare characters.
+  __ bind(&compare_chars);
+  NearLabel strings_not_equal;
+  GenerateAsciiCharsCompareLoop(masm, left, right, length, scratch2,
+                                &strings_not_equal);
+
+  // Characters are equal.
+  __ Move(rax, Smi::FromInt(EQUAL));
+  __ ret(0);
+
+  // Characters are not equal.
+  __ bind(&strings_not_equal);
+  __ Move(rax, Smi::FromInt(NOT_EQUAL));
+  __ ret(0);
+}
+
+
 void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
                                                         Register left,
                                                         Register right,
@@ -4523,35 +4572,11 @@
   __ SmiTest(min_length);
   __ j(zero, &compare_lengths);
 
-  __ SmiToInteger32(min_length, min_length);
-
-  // Registers scratch2 and scratch3 are free.
+  // Compare loop.
   NearLabel result_not_equal;
-  Label loop;
-  {
-    // Check characters 0 .. min_length - 1 in a loop.
-    // Use scratch3 as loop index, min_length as limit and scratch2
-    // for computation.
-    const Register index = scratch3;
-    __ Set(index, 0);  // Index into strings.
-    __ bind(&loop);
-    // Compare characters.
-    // TODO(lrn): Could we load more than one character at a time?
-    __ movb(scratch2, FieldOperand(left,
-                                   index,
-                                   times_1,
-                                   SeqAsciiString::kHeaderSize));
-    // Increment index and use -1 modifier on next load to give
-    // the previous load extra time to complete.
-    __ addl(index, Immediate(1));
-    __ cmpb(scratch2, FieldOperand(right,
-                                   index,
-                                   times_1,
-                                   SeqAsciiString::kHeaderSize - 1));
-    __ j(not_equal, &result_not_equal);
-    __ cmpl(index, min_length);
-    __ j(not_equal, &loop);
-  }
+  GenerateAsciiCharsCompareLoop(masm, left, right, min_length, scratch2,
+                                &result_not_equal);
+
   // Completed loop without finding different characters.
   // Compare lengths (precomputed).
   __ bind(&compare_lengths);
@@ -4578,6 +4603,35 @@
 }
 
 
+void StringCompareStub::GenerateAsciiCharsCompareLoop(
+    MacroAssembler* masm,
+    Register left,
+    Register right,
+    Register length,
+    Register scratch,
+    NearLabel* chars_not_equal) {
+  // Change index to run from -length to -1 by adding length to string
+  // start. This means that loop ends when index reaches zero, which
+  // doesn't need an additional compare.
+  __ SmiToInteger32(length, length);
+  __ lea(left,
+         FieldOperand(left, length, times_1, SeqAsciiString::kHeaderSize));
+  __ lea(right,
+         FieldOperand(right, length, times_1, SeqAsciiString::kHeaderSize));
+  __ neg(length);
+  Register index = length;  // index = -length;
+
+  // Compare loop.
+  NearLabel loop;
+  __ bind(&loop);
+  __ movb(scratch, Operand(left, index, times_1, 0));
+  __ cmpb(scratch, Operand(right, index, times_1, 0));
+  __ j(not_equal, chars_not_equal);
+  __ addq(index, Immediate(1));
+  __ j(not_zero, &loop);
+}
+
+
 void StringCompareStub::Generate(MacroAssembler* masm) {
   Label runtime;
 
@@ -4685,6 +4739,80 @@
 }
 
 
+void ICCompareStub::GenerateStrings(MacroAssembler* masm) {
+  ASSERT(state_ == CompareIC::STRINGS);
+  ASSERT(GetCondition() == equal);
+  Label miss;
+
+  // Registers containing left and right operands respectively.
+  Register left = rdx;
+  Register right = rax;
+  Register tmp1 = rcx;
+  Register tmp2 = rbx;
+  Register tmp3 = rdi;
+
+  // Check that both operands are heap objects.
+  Condition cond = masm->CheckEitherSmi(left, right, tmp1);
+  __ j(cond, &miss);
+
+  // Check that both operands are strings. This leaves the instance
+  // types loaded in tmp1 and tmp2.
+  __ movq(tmp1, FieldOperand(left, HeapObject::kMapOffset));
+  __ movq(tmp2, FieldOperand(right, HeapObject::kMapOffset));
+  __ movzxbq(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset));
+  __ movzxbq(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
+  __ movq(tmp3, tmp1);
+  STATIC_ASSERT(kNotStringTag != 0);
+  __ or_(tmp3, tmp2);
+  __ testl(tmp3, Immediate(kIsNotStringMask));
+  __ j(not_zero, &miss);
+
+  // Fast check for identical strings.
+  NearLabel not_same;
+  __ cmpq(left, right);
+  __ j(not_equal, &not_same);
+  STATIC_ASSERT(EQUAL == 0);
+  STATIC_ASSERT(kSmiTag == 0);
+  __ Move(rax, Smi::FromInt(EQUAL));
+  __ ret(0);
+
+  // Handle not identical strings.
+  __ bind(&not_same);
+
+  // Check that both strings are symbols. If they are, we're done
+  // because we already know they are not identical.
+  NearLabel do_compare;
+  STATIC_ASSERT(kSymbolTag != 0);
+  __ and_(tmp1, tmp2);
+  __ testl(tmp1, Immediate(kIsSymbolMask));
+  __ j(zero, &do_compare);
+  // Make sure rax is non-zero. At this point input operands are
+  // guaranteed to be non-zero.
+  ASSERT(right.is(rax));
+  __ ret(0);
+
+  // Check that both strings are sequential ASCII.
+  Label runtime;
+  __ bind(&do_compare);
+  __ JumpIfNotBothSequentialAsciiStrings(left, right, tmp1, tmp2, &runtime);
+
+  // Compare flat ASCII strings. Returns when done.
+  StringCompareStub::GenerateFlatAsciiStringEquals(
+      masm, left, right, tmp1, tmp2);
+
+  // Handle more complex cases in runtime.
+  __ bind(&runtime);
+  __ pop(tmp1);  // Return address.
+  __ push(left);
+  __ push(right);
+  __ push(tmp1);
+  __ TailCallRuntime(Runtime::kStringEquals, 2, 1);
+
+  __ bind(&miss);
+  GenerateMiss(masm);
+}
+
+
 void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
   ASSERT(state_ == CompareIC::OBJECTS);
   NearLabel miss;
@@ -4736,6 +4864,203 @@
 }
 
 
+void StringDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
+                                                        Label* miss,
+                                                        Label* done,
+                                                        Register properties,
+                                                        String* name,
+                                                        Register r0) {
+  // If names of slots in range from 1 to kProbes - 1 for the hash value are
+  // not equal to the name and kProbes-th slot is not used (its name is the
+  // undefined value), it guarantees the hash table doesn't contain the
+  // property. It's true even if some slots represent deleted properties
+  // (their names are the null value).
+  for (int i = 0; i < kInlinedProbes; i++) {
+    // r0 points to properties hash.
+    // Compute the masked index: (hash + i + i * i) & mask.
+    Register index = r0;
+    // Capacity is smi 2^n.
+    __ SmiToInteger32(index, FieldOperand(properties, kCapacityOffset));
+    __ decl(index);
+    __ and_(index,
+            Immediate(name->Hash() + StringDictionary::GetProbeOffset(i)));
+
+    // Scale the index by multiplying by the entry size.
+    ASSERT(StringDictionary::kEntrySize == 3);
+    __ lea(index, Operand(index, index, times_2, 0));  // index *= 3.
+
+    Register entity_name = r0;
+    // Having undefined at this place means the name is not contained.
+    ASSERT_EQ(kSmiTagSize, 1);
+    __ movq(entity_name, Operand(properties,
+                                 index,
+                                 times_pointer_size,
+                                 kElementsStartOffset - kHeapObjectTag));
+    __ Cmp(entity_name, masm->isolate()->factory()->undefined_value());
+    __ j(equal, done);
+
+    // Stop if found the property.
+    __ Cmp(entity_name, Handle<String>(name));
+    __ j(equal, miss);
+
+    // Check if the entry name is not a symbol.
+    __ movq(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset));
+    __ testb(FieldOperand(entity_name, Map::kInstanceTypeOffset),
+             Immediate(kIsSymbolMask));
+    __ j(zero, miss);
+  }
+
+  StringDictionaryLookupStub stub(properties,
+                                  r0,
+                                  r0,
+                                  StringDictionaryLookupStub::NEGATIVE_LOOKUP);
+  __ Push(Handle<Object>(name));
+  __ push(Immediate(name->Hash()));
+  __ CallStub(&stub);
+  __ testq(r0, r0);
+  __ j(not_zero, miss);
+  __ jmp(done);
+}
+
+
+// Probe the string dictionary in the |elements| register. Jump to the
+// |done| label if a property with the given name is found leaving the
+// index into the dictionary in |r1|. Jump to the |miss| label
+// otherwise.
+void StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
+                                                        Label* miss,
+                                                        Label* done,
+                                                        Register elements,
+                                                        Register name,
+                                                        Register r0,
+                                                        Register r1) {
+  // Assert that name contains a string.
+  if (FLAG_debug_code) __ AbortIfNotString(name);
+
+  __ SmiToInteger32(r0, FieldOperand(elements, kCapacityOffset));
+  __ decl(r0);
+
+  for (int i = 0; i < kInlinedProbes; i++) {
+    // Compute the masked index: (hash + i + i * i) & mask.
+    __ movl(r1, FieldOperand(name, String::kHashFieldOffset));
+    __ shrl(r1, Immediate(String::kHashShift));
+    if (i > 0) {
+      __ addl(r1, Immediate(StringDictionary::GetProbeOffset(i)));
+    }
+    __ and_(r1, r0);
+
+    // Scale the index by multiplying by the entry size.
+    ASSERT(StringDictionary::kEntrySize == 3);
+    __ lea(r1, Operand(r1, r1, times_2, 0));  // r1 = r1 * 3
+
+    // Check if the key is identical to the name.
+    __ cmpq(name, Operand(elements, r1, times_pointer_size,
+                          kElementsStartOffset - kHeapObjectTag));
+    __ j(equal, done);
+  }
+
+  StringDictionaryLookupStub stub(elements,
+                                  r0,
+                                  r1,
+                                  POSITIVE_LOOKUP);
+  __ push(name);
+  __ movl(r0, FieldOperand(name, String::kHashFieldOffset));
+  __ shrl(r0, Immediate(String::kHashShift));
+  __ push(r0);
+  __ CallStub(&stub);
+
+  __ testq(r0, r0);
+  __ j(zero, miss);
+  __ jmp(done);
+}
+
+
+void StringDictionaryLookupStub::Generate(MacroAssembler* masm) {
+  // Stack frame on entry:
+  //  esp[0 * kPointerSize]: return address.
+  //  esp[1 * kPointerSize]: key's hash.
+  //  esp[2 * kPointerSize]: key.
+  // Registers:
+  //  dictionary_: StringDictionary to probe.
+  //  result_: used as scratch.
+  //  index_: will hold an index of entry if lookup is successful.
+  //          might alias with result_.
+  // Returns:
+  //  result_ is zero if lookup failed, non zero otherwise.
+
+  Label in_dictionary, maybe_in_dictionary, not_in_dictionary;
+
+  Register scratch = result_;
+
+  __ SmiToInteger32(scratch, FieldOperand(dictionary_, kCapacityOffset));
+  __ decl(scratch);
+  __ push(scratch);
+
+  // If names of slots in range from 1 to kProbes - 1 for the hash value are
+  // not equal to the name and kProbes-th slot is not used (its name is the
+  // undefined value), it guarantees the hash table doesn't contain the
+  // property. It's true even if some slots represent deleted properties
+  // (their names are the null value).
+  for (int i = kInlinedProbes; i < kTotalProbes; i++) {
+    // Compute the masked index: (hash + i + i * i) & mask.
+    __ movq(scratch, Operand(rsp, 2 * kPointerSize));
+    if (i > 0) {
+      __ addl(scratch, Immediate(StringDictionary::GetProbeOffset(i)));
+    }
+    __ and_(scratch, Operand(rsp, 0));
+
+    // Scale the index by multiplying by the entry size.
+    ASSERT(StringDictionary::kEntrySize == 3);
+    __ lea(index_, Operand(scratch, scratch, times_2, 0));  // index *= 3.
+
+    // Having undefined at this place means the name is not contained.
+    __ movq(scratch, Operand(dictionary_,
+                             index_,
+                             times_pointer_size,
+                             kElementsStartOffset - kHeapObjectTag));
+
+    __ Cmp(scratch, masm->isolate()->factory()->undefined_value());
+    __ j(equal, &not_in_dictionary);
+
+    // Stop if found the property.
+    __ cmpq(scratch, Operand(rsp, 3 * kPointerSize));
+    __ j(equal, &in_dictionary);
+
+    if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) {
+      // If we hit a non symbol key during negative lookup
+      // we have to bailout as this key might be equal to the
+      // key we are looking for.
+
+      // Check if the entry name is not a symbol.
+      __ movq(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
+      __ testb(FieldOperand(scratch, Map::kInstanceTypeOffset),
+               Immediate(kIsSymbolMask));
+      __ j(zero, &maybe_in_dictionary);
+    }
+  }
+
+  __ bind(&maybe_in_dictionary);
+  // If we are doing negative lookup then probing failure should be
+  // treated as a lookup success. For positive lookup probing failure
+  // should be treated as lookup failure.
+  if (mode_ == POSITIVE_LOOKUP) {
+    __ movq(scratch, Immediate(0));
+    __ Drop(1);
+    __ ret(2 * kPointerSize);
+  }
+
+  __ bind(&in_dictionary);
+  __ movq(scratch, Immediate(1));
+  __ Drop(1);
+  __ ret(2 * kPointerSize);
+
+  __ bind(&not_in_dictionary);
+  __ movq(scratch, Immediate(0));
+  __ Drop(1);
+  __ ret(2 * kPointerSize);
+}
+
+
 #undef __
 
 } }  // namespace v8::internal
diff --git a/src/x64/code-stubs-x64.h b/src/x64/code-stubs-x64.h
index 5398452..44e2775 100644
--- a/src/x64/code-stubs-x64.h
+++ b/src/x64/code-stubs-x64.h
@@ -364,10 +364,9 @@
 
 class StringCompareStub: public CodeStub {
  public:
-  explicit StringCompareStub() {}
+  StringCompareStub() {}
 
-  // Compare two flat ascii strings and returns result in rax after popping two
-  // arguments from the stack.
+  // Compares two flat ASCII strings and returns result in rax.
   static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
                                               Register left,
                                               Register right,
@@ -376,11 +375,25 @@
                                               Register scratch3,
                                               Register scratch4);
 
- private:
-  Major MajorKey() { return StringCompare; }
-  int MinorKey() { return 0; }
+  // Compares two flat ASCII strings for equality and returns result
+  // in rax.
+  static void GenerateFlatAsciiStringEquals(MacroAssembler* masm,
+                                            Register left,
+                                            Register right,
+                                            Register scratch1,
+                                            Register scratch2);
 
-  void Generate(MacroAssembler* masm);
+ private:
+  virtual Major MajorKey() { return StringCompare; }
+  virtual int MinorKey() { return 0; }
+  virtual void Generate(MacroAssembler* masm);
+
+  static void GenerateAsciiCharsCompareLoop(MacroAssembler* masm,
+                                            Register left,
+                                            Register right,
+                                            Register length,
+                                            Register scratch,
+                                            NearLabel* chars_not_equal);
 };
 
 
@@ -421,6 +434,73 @@
 };
 
 
+class StringDictionaryLookupStub: public CodeStub {
+ public:
+  enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
+
+  StringDictionaryLookupStub(Register dictionary,
+                             Register result,
+                             Register index,
+                             LookupMode mode)
+      : dictionary_(dictionary), result_(result), index_(index), mode_(mode) { }
+
+  void Generate(MacroAssembler* masm);
+
+  static void GenerateNegativeLookup(MacroAssembler* masm,
+                                     Label* miss,
+                                     Label* done,
+                                     Register properties,
+                                     String* name,
+                                     Register r0);
+
+  static void GeneratePositiveLookup(MacroAssembler* masm,
+                                     Label* miss,
+                                     Label* done,
+                                     Register elements,
+                                     Register name,
+                                     Register r0,
+                                     Register r1);
+
+ private:
+  static const int kInlinedProbes = 4;
+  static const int kTotalProbes = 20;
+
+  static const int kCapacityOffset =
+      StringDictionary::kHeaderSize +
+      StringDictionary::kCapacityIndex * kPointerSize;
+
+  static const int kElementsStartOffset =
+      StringDictionary::kHeaderSize +
+      StringDictionary::kElementsStartIndex * kPointerSize;
+
+
+#ifdef DEBUG
+  void Print() {
+    PrintF("StringDictionaryLookupStub\n");
+  }
+#endif
+
+  Major MajorKey() { return StringDictionaryNegativeLookup; }
+
+  int MinorKey() {
+    return DictionaryBits::encode(dictionary_.code()) |
+        ResultBits::encode(result_.code()) |
+        IndexBits::encode(index_.code()) |
+        LookupModeBits::encode(mode_);
+  }
+
+  class DictionaryBits: public BitField<int, 0, 4> {};
+  class ResultBits: public BitField<int, 4, 4> {};
+  class IndexBits: public BitField<int, 8, 4> {};
+  class LookupModeBits: public BitField<LookupMode, 12, 1> {};
+
+  Register dictionary_;
+  Register result_;
+  Register index_;
+  LookupMode mode_;
+};
+
+
 } }  // namespace v8::internal
 
 #endif  // V8_X64_CODE_STUBS_X64_H_
diff --git a/src/x64/ic-x64.cc b/src/x64/ic-x64.cc
index 5ed89b5..05d8719 100644
--- a/src/x64/ic-x64.cc
+++ b/src/x64/ic-x64.cc
@@ -97,58 +97,6 @@
 }
 
 
-// Probe the string dictionary in the |elements| register. Jump to the
-// |done| label if a property with the given name is found leaving the
-// index into the dictionary in |r1|. Jump to the |miss| label
-// otherwise.
-static void GenerateStringDictionaryProbes(MacroAssembler* masm,
-                                           Label* miss,
-                                           Label* done,
-                                           Register elements,
-                                           Register name,
-                                           Register r0,
-                                           Register r1) {
-  // Assert that name contains a string.
-  if (FLAG_debug_code) __ AbortIfNotString(name);
-
-  // Compute the capacity mask.
-  const int kCapacityOffset =
-      StringDictionary::kHeaderSize +
-      StringDictionary::kCapacityIndex * kPointerSize;
-  __ SmiToInteger32(r0, FieldOperand(elements, kCapacityOffset));
-  __ decl(r0);
-
-  // Generate an unrolled loop that performs a few probes before
-  // giving up. Measurements done on Gmail indicate that 2 probes
-  // cover ~93% of loads from dictionaries.
-  static const int kProbes = 4;
-  const int kElementsStartOffset =
-      StringDictionary::kHeaderSize +
-      StringDictionary::kElementsStartIndex * kPointerSize;
-  for (int i = 0; i < kProbes; i++) {
-    // Compute the masked index: (hash + i + i * i) & mask.
-    __ movl(r1, FieldOperand(name, String::kHashFieldOffset));
-    __ shrl(r1, Immediate(String::kHashShift));
-    if (i > 0) {
-      __ addl(r1, Immediate(StringDictionary::GetProbeOffset(i)));
-    }
-    __ and_(r1, r0);
-
-    // Scale the index by multiplying by the entry size.
-    ASSERT(StringDictionary::kEntrySize == 3);
-    __ lea(r1, Operand(r1, r1, times_2, 0));  // r1 = r1 * 3
-
-    // Check if the key is identical to the name.
-    __ cmpq(name, Operand(elements, r1, times_pointer_size,
-                          kElementsStartOffset - kHeapObjectTag));
-    if (i != kProbes - 1) {
-      __ j(equal, done);
-    } else {
-      __ j(not_equal, miss);
-    }
-  }
-}
-
 
 // Helper function used to load a property from a dictionary backing storage.
 // This function may return false negatives, so miss_label
@@ -179,13 +127,13 @@
   Label done;
 
   // Probe the dictionary.
-  GenerateStringDictionaryProbes(masm,
-                                 miss_label,
-                                 &done,
-                                 elements,
-                                 name,
-                                 r0,
-                                 r1);
+  StringDictionaryLookupStub::GeneratePositiveLookup(masm,
+                                                     miss_label,
+                                                     &done,
+                                                     elements,
+                                                     name,
+                                                     r0,
+                                                     r1);
 
   // If probing finds an entry in the dictionary, r0 contains the
   // index into the dictionary. Check that the value is a normal
@@ -237,13 +185,13 @@
   Label done;
 
   // Probe the dictionary.
-  GenerateStringDictionaryProbes(masm,
-                                 miss_label,
-                                 &done,
-                                 elements,
-                                 name,
-                                 scratch0,
-                                 scratch1);
+  StringDictionaryLookupStub::GeneratePositiveLookup(masm,
+                                                     miss_label,
+                                                     &done,
+                                                     elements,
+                                                     name,
+                                                     scratch0,
+                                                     scratch1);
 
   // If probing finds an entry in the dictionary, scratch0 contains the
   // index into the dictionary. Check that the value is a normal
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index 5b45b13..47c77b7 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -2208,23 +2208,29 @@
 }
 
 
-void LCodeGen::EmitLoadField(Register result,
-                             Register object,
-                             Handle<Map> type,
-                             Handle<String> name) {
+void LCodeGen::EmitLoadFieldOrConstantFunction(Register result,
+                                               Register object,
+                                               Handle<Map> type,
+                                               Handle<String> name) {
   LookupResult lookup;
   type->LookupInDescriptors(NULL, *name, &lookup);
-  ASSERT(lookup.IsProperty() && lookup.type() == FIELD);
-  int index = lookup.GetLocalFieldIndexFromMap(*type);
-  int offset = index * kPointerSize;
-  if (index < 0) {
-    // Negative property indices are in-object properties, indexed
-    // from the end of the fixed part of the object.
-    __ movq(result, FieldOperand(object, offset + type->instance_size()));
+  ASSERT(lookup.IsProperty() &&
+         (lookup.type() == FIELD || lookup.type() == CONSTANT_FUNCTION));
+  if (lookup.type() == FIELD) {
+    int index = lookup.GetLocalFieldIndexFromMap(*type);
+    int offset = index * kPointerSize;
+    if (index < 0) {
+      // Negative property indices are in-object properties, indexed
+      // from the end of the fixed part of the object.
+      __ movq(result, FieldOperand(object, offset + type->instance_size()));
+    } else {
+      // Non-negative property indices are in the properties array.
+      __ movq(result, FieldOperand(object, JSObject::kPropertiesOffset));
+      __ movq(result, FieldOperand(result, offset + FixedArray::kHeaderSize));
+    }
   } else {
-    // Non-negative property indices are in the properties array.
-    __ movq(result, FieldOperand(object, JSObject::kPropertiesOffset));
-    __ movq(result, FieldOperand(result, offset + FixedArray::kHeaderSize));
+    Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*type));
+    LoadHeapObject(result, Handle<HeapObject>::cast(function));
   }
 }
 
@@ -2248,7 +2254,7 @@
       NearLabel next;
       __ Cmp(FieldOperand(object, HeapObject::kMapOffset), map);
       __ j(not_equal, &next);
-      EmitLoadField(result, object, map, name);
+      EmitLoadFieldOrConstantFunction(result, object, map, name);
       __ jmp(&done);
       __ bind(&next);
     }
@@ -2257,7 +2263,7 @@
     if (instr->hydrogen()->need_generic()) {
       NearLabel generic;
       __ j(not_equal, &generic);
-      EmitLoadField(result, object, map, name);
+      EmitLoadFieldOrConstantFunction(result, object, map, name);
       __ jmp(&done);
       __ bind(&generic);
       __ Move(rcx, instr->hydrogen()->name());
@@ -2265,7 +2271,7 @@
       CallCode(ic, RelocInfo::CODE_TARGET, instr);
     } else {
       DeoptimizeIf(not_equal, instr->environment());
-      EmitLoadField(result, object, map, name);
+      EmitLoadFieldOrConstantFunction(result, object, map, name);
     }
     __ bind(&done);
   }
diff --git a/src/x64/lithium-codegen-x64.h b/src/x64/lithium-codegen-x64.h
index 17c1289..76abfa1 100644
--- a/src/x64/lithium-codegen-x64.h
+++ b/src/x64/lithium-codegen-x64.h
@@ -264,10 +264,10 @@
   // Caller should branch on equal condition.
   void EmitIsConstructCall(Register temp);
 
-  void EmitLoadField(Register result,
-                     Register object,
-                     Handle<Map> type,
-                     Handle<String> name);
+  void EmitLoadFieldOrConstantFunction(Register result,
+                                       Register object,
+                                       Handle<Map> type,
+                                       Handle<String> name);
 
   // Emits code for pushing either a tagged constant, a (non-double)
   // register, or a stack slot operand.
diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc
index 94cdd04..7ca7c05 100644
--- a/src/x64/lithium-x64.cc
+++ b/src/x64/lithium-x64.cc
@@ -2122,7 +2122,7 @@
   HConstant* undefined = graph()->GetConstantUndefined();
   HEnvironment* inner = outer->CopyForInlining(instr->closure(),
                                                instr->function(),
-                                               false,
+                                               HEnvironment::LITHIUM,
                                                undefined);
   current_block_->UpdateEnvironment(inner);
   chunk_->AddInlinedClosure(instr->closure());
diff --git a/src/x64/simulator-x64.h b/src/x64/simulator-x64.h
index cfaa5b8..df8423a 100644
--- a/src/x64/simulator-x64.h
+++ b/src/x64/simulator-x64.h
@@ -55,7 +55,8 @@
 // just use the C stack limit.
 class SimulatorStack : public v8::internal::AllStatic {
  public:
-  static inline uintptr_t JsLimitFromCLimit(uintptr_t c_limit) {
+  static inline uintptr_t JsLimitFromCLimit(Isolate* isolate,
+                                            uintptr_t c_limit) {
     return c_limit;
   }
 
diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc
index ef6f758..6c83606 100644
--- a/src/x64/stub-cache-x64.cc
+++ b/src/x64/stub-cache-x64.cc
@@ -93,7 +93,6 @@
   __ IncrementCounter(counters->negative_lookups(), 1);
   __ IncrementCounter(counters->negative_lookups_miss(), 1);
 
-  Label done;
   __ movq(r0, FieldOperand(receiver, HeapObject::kMapOffset));
 
   const int kInterceptorOrAccessCheckNeededMask =
@@ -117,62 +116,13 @@
                  Heap::kHashTableMapRootIndex);
   __ j(not_equal, miss_label);
 
-  // Compute the capacity mask.
-  const int kCapacityOffset =
-      StringDictionary::kHeaderSize +
-      StringDictionary::kCapacityIndex * kPointerSize;
-
-  // Generate an unrolled loop that performs a few probes before
-  // giving up.
-  static const int kProbes = 4;
-  const int kElementsStartOffset =
-      StringDictionary::kHeaderSize +
-      StringDictionary::kElementsStartIndex * kPointerSize;
-
-  // If names of slots in range from 1 to kProbes - 1 for the hash value are
-  // not equal to the name and kProbes-th slot is not used (its name is the
-  // undefined value), it guarantees the hash table doesn't contain the
-  // property. It's true even if some slots represent deleted properties
-  // (their names are the null value).
-  for (int i = 0; i < kProbes; i++) {
-    // r0 points to properties hash.
-    // Compute the masked index: (hash + i + i * i) & mask.
-    Register index = r1;
-    // Capacity is smi 2^n.
-    __ SmiToInteger32(index, FieldOperand(properties, kCapacityOffset));
-    __ decl(index);
-    __ and_(index,
-            Immediate(name->Hash() + StringDictionary::GetProbeOffset(i)));
-
-    // Scale the index by multiplying by the entry size.
-    ASSERT(StringDictionary::kEntrySize == 3);
-    __ lea(index, Operand(index, index, times_2, 0));  // index *= 3.
-
-    Register entity_name = r1;
-    // Having undefined at this place means the name is not contained.
-    ASSERT_EQ(kSmiTagSize, 1);
-    __ movq(entity_name, Operand(properties, index, times_pointer_size,
-                                 kElementsStartOffset - kHeapObjectTag));
-    __ Cmp(entity_name, masm->isolate()->factory()->undefined_value());
-    // __ jmp(miss_label);
-    if (i != kProbes - 1) {
-      __ j(equal, &done);
-
-      // Stop if found the property.
-      __ Cmp(entity_name, Handle<String>(name));
-      __ j(equal, miss_label);
-
-      // Check if the entry name is not a symbol.
-      __ movq(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset));
-      __ testb(FieldOperand(entity_name, Map::kInstanceTypeOffset),
-               Immediate(kIsSymbolMask));
-      __ j(zero, miss_label);
-    } else {
-      // Give up probing if still not found the undefined value.
-      __ j(not_equal, miss_label);
-    }
-  }
-
+  Label done;
+  StringDictionaryLookupStub::GenerateNegativeLookup(masm,
+                                                     miss_label,
+                                                     &done,
+                                                     properties,
+                                                     name,
+                                                     r1);
   __ bind(&done);
   __ DecrementCounter(counters->negative_lookups_miss(), 1);
 }
diff --git a/src/zone.h b/src/zone.h
index 9efe4f5..94a6241 100644
--- a/src/zone.h
+++ b/src/zone.h
@@ -28,6 +28,8 @@
 #ifndef V8_ZONE_H_
 #define V8_ZONE_H_
 
+#include "allocation.h"
+
 namespace v8 {
 namespace internal {
 
diff --git a/test/cctest/SConscript b/test/cctest/SConscript
index f4cb4a9..e2b0fc9 100644
--- a/test/cctest/SConscript
+++ b/test/cctest/SConscript
@@ -64,6 +64,7 @@
     'test-list.cc',
     'test-liveedit.cc',
     'test-lock.cc',
+    'test-lockers.cc',
     'test-log-utils.cc',
     'test-log.cc',
     'test-mark-compact.cc',
diff --git a/test/cctest/cctest.gyp b/test/cctest/cctest.gyp
index aa2b355..51a5fc7 100644
--- a/test/cctest/cctest.gyp
+++ b/test/cctest/cctest.gyp
@@ -93,6 +93,7 @@
         'test-list.cc',
         'test-liveedit.cc',
         'test-lock.cc',
+        'test-lockers.cc',
         'test-log.cc',
         'test-log-utils.cc',
         'test-mark-compact.cc',
diff --git a/test/cctest/cctest.h b/test/cctest/cctest.h
index 277593c..e4052d6 100644
--- a/test/cctest/cctest.h
+++ b/test/cctest/cctest.h
@@ -98,7 +98,11 @@
   // The ApiTestFuzzer is also a Thread, so it has a Run method.
   virtual void Run();
 
-  enum PartOfTest { FIRST_PART, SECOND_PART };
+  enum PartOfTest { FIRST_PART,
+                    SECOND_PART,
+                    THIRD_PART,
+                    FOURTH_PART,
+                    LAST_PART = FOURTH_PART };
 
   static void Setup(PartOfTest part);
   static void RunAllTests();
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index e2a7fb1..ab94085 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -30,6 +30,7 @@
 #include "v8.h"
 
 #include "api.h"
+#include "isolate.h"
 #include "compilation-cache.h"
 #include "execution.h"
 #include "snapshot.h"
@@ -6746,6 +6747,200 @@
   CHECK(value->BooleanValue());
 }
 
+
+static Handle<Value> ConstructorCallback(const Arguments& args) {
+  ApiTestFuzzer::Fuzz();
+  Local<Object> This;
+
+  if (args.IsConstructCall()) {
+    Local<Object> Holder = args.Holder();
+    This = Object::New();
+    Local<Value> proto = Holder->GetPrototype();
+    if (proto->IsObject()) {
+      This->SetPrototype(proto);
+    }
+  } else {
+    This = args.This();
+  }
+
+  This->Set(v8_str("a"), args[0]);
+  return This;
+}
+
+
+static Handle<Value> FakeConstructorCallback(const Arguments& args) {
+  ApiTestFuzzer::Fuzz();
+  return args[0];
+}
+
+
+THREADED_TEST(ConstructorForObject) {
+  v8::HandleScope handle_scope;
+  LocalContext context;
+
+  { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
+    instance_template->SetCallAsFunctionHandler(ConstructorCallback);
+    Local<Object> instance = instance_template->NewInstance();
+    context->Global()->Set(v8_str("obj"), instance);
+    v8::TryCatch try_catch;
+    Local<Value> value;
+    CHECK(!try_catch.HasCaught());
+
+    // Call the Object's constructor with a 32-bit signed integer.
+    value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
+    CHECK(!try_catch.HasCaught());
+    CHECK(value->IsInt32());
+    CHECK_EQ(28, value->Int32Value());
+
+    Local<Value> args1[] = { v8_num(28) };
+    Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
+    CHECK(value_obj1->IsObject());
+    Local<Object> object1 = Local<Object>::Cast(value_obj1);
+    value = object1->Get(v8_str("a"));
+    CHECK(value->IsInt32());
+    CHECK(!try_catch.HasCaught());
+    CHECK_EQ(28, value->Int32Value());
+
+    // Call the Object's constructor with a String.
+    value = CompileRun(
+        "(function() { var o = new obj('tipli'); return o.a; })()");
+    CHECK(!try_catch.HasCaught());
+    CHECK(value->IsString());
+    String::AsciiValue string_value1(value->ToString());
+    CHECK_EQ("tipli", *string_value1);
+
+    Local<Value> args2[] = { v8_str("tipli") };
+    Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
+    CHECK(value_obj2->IsObject());
+    Local<Object> object2 = Local<Object>::Cast(value_obj2);
+    value = object2->Get(v8_str("a"));
+    CHECK(!try_catch.HasCaught());
+    CHECK(value->IsString());
+    String::AsciiValue string_value2(value->ToString());
+    CHECK_EQ("tipli", *string_value2);
+
+    // Call the Object's constructor with a Boolean.
+    value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
+    CHECK(!try_catch.HasCaught());
+    CHECK(value->IsBoolean());
+    CHECK_EQ(true, value->BooleanValue());
+
+    Handle<Value> args3[] = { v8::Boolean::New(true) };
+    Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
+    CHECK(value_obj3->IsObject());
+    Local<Object> object3 = Local<Object>::Cast(value_obj3);
+    value = object3->Get(v8_str("a"));
+    CHECK(!try_catch.HasCaught());
+    CHECK(value->IsBoolean());
+    CHECK_EQ(true, value->BooleanValue());
+
+    // Call the Object's constructor with undefined.
+    Handle<Value> args4[] = { v8::Undefined() };
+    Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
+    CHECK(value_obj4->IsObject());
+    Local<Object> object4 = Local<Object>::Cast(value_obj4);
+    value = object4->Get(v8_str("a"));
+    CHECK(!try_catch.HasCaught());
+    CHECK(value->IsUndefined());
+
+    // Call the Object's constructor with null.
+    Handle<Value> args5[] = { v8::Null() };
+    Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
+    CHECK(value_obj5->IsObject());
+    Local<Object> object5 = Local<Object>::Cast(value_obj5);
+    value = object5->Get(v8_str("a"));
+    CHECK(!try_catch.HasCaught());
+    CHECK(value->IsNull());
+  }
+
+  // Check exception handling when there is no constructor set for the Object.
+  { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
+    Local<Object> instance = instance_template->NewInstance();
+    context->Global()->Set(v8_str("obj2"), instance);
+    v8::TryCatch try_catch;
+    Local<Value> value;
+    CHECK(!try_catch.HasCaught());
+
+    value = CompileRun("new obj2(28)");
+    CHECK(try_catch.HasCaught());
+    String::AsciiValue exception_value1(try_catch.Exception());
+    CHECK_EQ("TypeError: object is not a function", *exception_value1);
+    try_catch.Reset();
+
+    Local<Value> args[] = { v8_num(29) };
+    value = instance->CallAsConstructor(1, args);
+    CHECK(try_catch.HasCaught());
+    String::AsciiValue exception_value2(try_catch.Exception());
+    CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
+    try_catch.Reset();
+  }
+
+  // Check the case when constructor throws exception.
+  { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
+    instance_template->SetCallAsFunctionHandler(ThrowValue);
+    Local<Object> instance = instance_template->NewInstance();
+    context->Global()->Set(v8_str("obj3"), instance);
+    v8::TryCatch try_catch;
+    Local<Value> value;
+    CHECK(!try_catch.HasCaught());
+
+    value = CompileRun("new obj3(22)");
+    CHECK(try_catch.HasCaught());
+    String::AsciiValue exception_value1(try_catch.Exception());
+    CHECK_EQ("22", *exception_value1);
+    try_catch.Reset();
+
+    Local<Value> args[] = { v8_num(23) };
+    value = instance->CallAsConstructor(1, args);
+    CHECK(try_catch.HasCaught());
+    String::AsciiValue exception_value2(try_catch.Exception());
+    CHECK_EQ("23", *exception_value2);
+    try_catch.Reset();
+  }
+
+  // Check whether constructor returns with an object or non-object.
+  { Local<FunctionTemplate> function_template =
+        FunctionTemplate::New(FakeConstructorCallback);
+    Local<Function> function = function_template->GetFunction();
+    Local<Object> instance1 = function;
+    context->Global()->Set(v8_str("obj4"), instance1);
+    v8::TryCatch try_catch;
+    Local<Value> value;
+    CHECK(!try_catch.HasCaught());
+
+    CHECK(instance1->IsObject());
+    CHECK(instance1->IsFunction());
+
+    value = CompileRun("new obj4(28)");
+    CHECK(!try_catch.HasCaught());
+    CHECK(value->IsObject());
+
+    Local<Value> args1[] = { v8_num(28) };
+    value = instance1->CallAsConstructor(1, args1);
+    CHECK(!try_catch.HasCaught());
+    CHECK(value->IsObject());
+
+    Local<ObjectTemplate> instance_template = ObjectTemplate::New();
+    instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
+    Local<Object> instance2 = instance_template->NewInstance();
+    context->Global()->Set(v8_str("obj5"), instance2);
+    CHECK(!try_catch.HasCaught());
+
+    CHECK(instance2->IsObject());
+    CHECK(!instance2->IsFunction());
+
+    value = CompileRun("new obj5(28)");
+    CHECK(!try_catch.HasCaught());
+    CHECK(!value->IsObject());
+
+    Local<Value> args2[] = { v8_num(28) };
+    value = instance2->CallAsConstructor(1, args2);
+    CHECK(!try_catch.HasCaught());
+    CHECK(!value->IsObject());
+  }
+}
+
+
 THREADED_TEST(FunctionDescriptorException) {
   v8::HandleScope handle_scope;
   LocalContext context;
@@ -6962,50 +7157,110 @@
   v8::HandleScope scope;
   LocalContext context;
 
-  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
-  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
-  instance_template->SetCallAsFunctionHandler(call_as_function);
-  Local<v8::Object> instance = t->GetFunction()->NewInstance();
-  context->Global()->Set(v8_str("obj"), instance);
-  v8::TryCatch try_catch;
-  Local<Value> value;
-  CHECK(!try_catch.HasCaught());
+  { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
+    Local<ObjectTemplate> instance_template = t->InstanceTemplate();
+    instance_template->SetCallAsFunctionHandler(call_as_function);
+    Local<v8::Object> instance = t->GetFunction()->NewInstance();
+    context->Global()->Set(v8_str("obj"), instance);
+    v8::TryCatch try_catch;
+    Local<Value> value;
+    CHECK(!try_catch.HasCaught());
 
-  value = CompileRun("obj(42)");
-  CHECK(!try_catch.HasCaught());
-  CHECK_EQ(42, value->Int32Value());
+    value = CompileRun("obj(42)");
+    CHECK(!try_catch.HasCaught());
+    CHECK_EQ(42, value->Int32Value());
 
-  value = CompileRun("(function(o){return o(49)})(obj)");
-  CHECK(!try_catch.HasCaught());
-  CHECK_EQ(49, value->Int32Value());
+    value = CompileRun("(function(o){return o(49)})(obj)");
+    CHECK(!try_catch.HasCaught());
+    CHECK_EQ(49, value->Int32Value());
 
-  // test special case of call as function
-  value = CompileRun("[obj]['0'](45)");
-  CHECK(!try_catch.HasCaught());
-  CHECK_EQ(45, value->Int32Value());
+    // test special case of call as function
+    value = CompileRun("[obj]['0'](45)");
+    CHECK(!try_catch.HasCaught());
+    CHECK_EQ(45, value->Int32Value());
 
-  value = CompileRun("obj.call = Function.prototype.call;"
-                     "obj.call(null, 87)");
-  CHECK(!try_catch.HasCaught());
-  CHECK_EQ(87, value->Int32Value());
+    value = CompileRun("obj.call = Function.prototype.call;"
+                       "obj.call(null, 87)");
+    CHECK(!try_catch.HasCaught());
+    CHECK_EQ(87, value->Int32Value());
 
-  // Regression tests for bug #1116356: Calling call through call/apply
-  // must work for non-function receivers.
-  const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
-  value = CompileRun(apply_99);
-  CHECK(!try_catch.HasCaught());
-  CHECK_EQ(99, value->Int32Value());
+    // Regression tests for bug #1116356: Calling call through call/apply
+    // must work for non-function receivers.
+    const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
+    value = CompileRun(apply_99);
+    CHECK(!try_catch.HasCaught());
+    CHECK_EQ(99, value->Int32Value());
 
-  const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
-  value = CompileRun(call_17);
-  CHECK(!try_catch.HasCaught());
-  CHECK_EQ(17, value->Int32Value());
+    const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
+    value = CompileRun(call_17);
+    CHECK(!try_catch.HasCaught());
+    CHECK_EQ(17, value->Int32Value());
 
-  // Check that the call-as-function handler can be called through
-  // new.
-  value = CompileRun("new obj(43)");
-  CHECK(!try_catch.HasCaught());
-  CHECK_EQ(-43, value->Int32Value());
+    // Check that the call-as-function handler can be called through
+    // new.
+    value = CompileRun("new obj(43)");
+    CHECK(!try_catch.HasCaught());
+    CHECK_EQ(-43, value->Int32Value());
+
+    // Check that the call-as-function handler can be called through
+    // the API.
+    v8::Handle<Value> args[] = { v8_num(28) };
+    value = instance->CallAsFunction(instance, 1, args);
+    CHECK(!try_catch.HasCaught());
+    CHECK_EQ(28, value->Int32Value());
+  }
+
+  { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
+    Local<ObjectTemplate> instance_template = t->InstanceTemplate();
+    Local<v8::Object> instance = t->GetFunction()->NewInstance();
+    context->Global()->Set(v8_str("obj2"), instance);
+    v8::TryCatch try_catch;
+    Local<Value> value;
+    CHECK(!try_catch.HasCaught());
+
+    // Call an object without call-as-function handler through the JS
+    value = CompileRun("obj2(28)");
+    CHECK(value.IsEmpty());
+    CHECK(try_catch.HasCaught());
+    String::AsciiValue exception_value1(try_catch.Exception());
+    CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function",
+             *exception_value1);
+    try_catch.Reset();
+
+    // Call an object without call-as-function handler through the API
+    value = CompileRun("obj2(28)");
+    v8::Handle<Value> args[] = { v8_num(28) };
+    value = instance->CallAsFunction(instance, 1, args);
+    CHECK(value.IsEmpty());
+    CHECK(try_catch.HasCaught());
+    String::AsciiValue exception_value2(try_catch.Exception());
+    CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
+    try_catch.Reset();
+  }
+
+  { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
+    Local<ObjectTemplate> instance_template = t->InstanceTemplate();
+    instance_template->SetCallAsFunctionHandler(ThrowValue);
+    Local<v8::Object> instance = t->GetFunction()->NewInstance();
+    context->Global()->Set(v8_str("obj3"), instance);
+    v8::TryCatch try_catch;
+    Local<Value> value;
+    CHECK(!try_catch.HasCaught());
+
+    // Catch the exception which is thrown by call-as-function handler
+    value = CompileRun("obj3(22)");
+    CHECK(try_catch.HasCaught());
+    String::AsciiValue exception_value1(try_catch.Exception());
+    CHECK_EQ("22", *exception_value1);
+    try_catch.Reset();
+
+    v8::Handle<Value> args[] = { v8_num(23) };
+    value = instance->CallAsFunction(instance, 1, args);
+    CHECK(try_catch.HasCaught());
+    String::AsciiValue exception_value2(try_catch.Exception());
+    CHECK_EQ("23", *exception_value2);
+    try_catch.Reset();
+  }
 }
 
 
@@ -8946,11 +9201,10 @@
 void ApiTestFuzzer::Setup(PartOfTest part) {
   linear_congruential_generator = i::FLAG_testing_prng_seed;
   fuzzing_ = true;
-  int start = (part == FIRST_PART) ? 0 : (RegisterThreadedTest::count() >> 1);
-  int end = (part == FIRST_PART)
-      ? (RegisterThreadedTest::count() >> 1)
-      : RegisterThreadedTest::count();
-  active_tests_ = tests_being_run_ = end - start;
+  int count = RegisterThreadedTest::count();
+  int start =  count * part / (LAST_PART + 1);
+  int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
+  active_tests_ = tests_being_run_ = end - start + 1;
   for (int i = 0; i < tests_being_run_; i++) {
     RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(
         i::Isolate::Current(), i + start);
@@ -9020,6 +9274,17 @@
   ApiTestFuzzer::TearDown();
 }
 
+TEST(Threading3) {
+  ApiTestFuzzer::Setup(ApiTestFuzzer::THIRD_PART);
+  ApiTestFuzzer::RunAllTests();
+  ApiTestFuzzer::TearDown();
+}
+
+TEST(Threading4) {
+  ApiTestFuzzer::Setup(ApiTestFuzzer::FOURTH_PART);
+  ApiTestFuzzer::RunAllTests();
+  ApiTestFuzzer::TearDown();
+}
 
 void ApiTestFuzzer::CallTest() {
   if (kLogThreading)
@@ -13388,6 +13653,28 @@
   isolate2->Dispose();
 }
 
+TEST(IsolateDifferentContexts) {
+  v8::Isolate* isolate = v8::Isolate::New();
+  Persistent<v8::Context> context;
+  {
+    v8::Isolate::Scope isolate_scope(isolate);
+    v8::HandleScope handle_scope;
+    context = v8::Context::New();
+    v8::Context::Scope context_scope(context);
+    Local<Value> v = CompileRun("2");
+    CHECK(v->IsNumber());
+    CHECK_EQ(2, static_cast<int>(v->NumberValue()));
+  }
+  {
+    v8::Isolate::Scope isolate_scope(isolate);
+    v8::HandleScope handle_scope;
+    context = v8::Context::New();
+    v8::Context::Scope context_scope(context);
+    Local<Value> v = CompileRun("22");
+    CHECK(v->IsNumber());
+    CHECK_EQ(22, static_cast<int>(v->NumberValue()));
+  }
+}
 
 class InitDefaultIsolateThread : public v8::internal::Thread {
  public:
@@ -14104,3 +14391,20 @@
   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
   CheckCodeGenerationDisallowed();
 }
+
+
+static v8::Handle<Value> NonObjectThis(const v8::Arguments& args) {
+  return v8::Undefined();
+}
+
+
+THREADED_TEST(CallAPIFunctionOnNonObject) {
+  v8::HandleScope scope;
+  LocalContext context;
+  Handle<FunctionTemplate> templ = v8::FunctionTemplate::New(NonObjectThis);
+  Handle<Function> function = templ->GetFunction();
+  context->Global()->Set(v8_str("f"), function);
+  TryCatch try_catch;
+  CompileRun("f.call(2)");
+  CHECK(try_catch.HasCaught());
+}
diff --git a/test/cctest/test-thread-termination.cc b/test/cctest/test-thread-termination.cc
index 5635b17..1e8a627 100644
--- a/test/cctest/test-thread-termination.cc
+++ b/test/cctest/test-thread-termination.cc
@@ -221,29 +221,37 @@
 };
 
 
-// Test that multiple threads using V8 can be terminated from another
-// thread when using Lockers and preemption.
-TEST(TerminateMultipleV8Threads) {
+// Test that multiple threads using default isolate can be terminated
+// from another thread when using Lockers and preemption.
+TEST(TerminateMultipleV8ThreadsDefaultIsolate) {
   {
     v8::Locker locker;
     v8::V8::Initialize();
     v8::Locker::StartPreemption(1);
     semaphore = v8::internal::OS::CreateSemaphore(0);
   }
-  LoopingThread thread1(i::Isolate::Current());
-  thread1.Start();
-  LoopingThread thread2(i::Isolate::Current());
-  thread2.Start();
-  // Wait until both threads have signaled the semaphore.
-  semaphore->Wait();
-  semaphore->Wait();
+  const int kThreads = 2;
+  i::List<LoopingThread*> threads(kThreads);
+  for (int i = 0; i < kThreads; i++) {
+    threads.Add(new LoopingThread(i::Isolate::Current()));
+  }
+  for (int i = 0; i < kThreads; i++) {
+    threads[i]->Start();
+  }
+  // Wait until all threads have signaled the semaphore.
+  for (int i = 0; i < kThreads; i++) {
+    semaphore->Wait();
+  }
   {
     v8::Locker locker;
-    v8::V8::TerminateExecution(thread1.GetV8ThreadId());
-    v8::V8::TerminateExecution(thread2.GetV8ThreadId());
+    for (int i = 0; i < kThreads; i++) {
+      v8::V8::TerminateExecution(threads[i]->GetV8ThreadId());
+    }
   }
-  thread1.Join();
-  thread2.Join();
+  for (int i = 0; i < kThreads; i++) {
+    threads[i]->Join();
+    delete threads[i];
+  }
 
   delete semaphore;
   semaphore = NULL;
diff --git a/test/es5conform/es5conform.status b/test/es5conform/es5conform.status
index 1dc90d3..55712ba 100644
--- a/test/es5conform/es5conform.status
+++ b/test/es5conform/es5conform.status
@@ -172,14 +172,6 @@
 # SUBSETFAIL
 chapter15/15.2/15.2.3/15.2.3.4/15.2.3.4-4-35: FAIL_OK
 
-# Bad test - the spec does not say anything about throwing errors
-# on calling Array.prototype.indexOf with undefined as argument.
-chapter15/15.4/15.4.4/15.4.4.14/15.4.4.14-1-1: FAIL_OK
-
-# Bad test - the spec does not say anything about throwing errors
-# on calling Array.prototype.indexOf with null as argument.
-chapter15/15.4/15.4.4/15.4.4.14/15.4.4.14-1-2: FAIL_OK
-
 # Bad test - the test at the end should be "i === true".
 chapter15/15.4/15.4.4/15.4.4.17/15.4.4.17-8-10: FAIL_OK
 
@@ -204,10 +196,6 @@
 # have no effect on the actual array on which reduceRight is called.
 chapter15/15.4/15.4.4/15.4.4.22/15.4.4.22-9-7: FAIL_OK
 
-# We do not implement trim correctly on null and undefined.
-chapter15/15.5/15.5.4/15.5.4.20/15.5.4.20-1-1: FAIL
-chapter15/15.5/15.5.4/15.5.4.20/15.5.4.20-1-2: FAIL
-
 # We do not correctly recognize \uFEFF as whitespace
 chapter15/15.5/15.5.4/15.5.4.20/15.5.4.20-4-10: FAIL
 chapter15/15.5/15.5.4/15.5.4.20/15.5.4.20-4-18: FAIL
diff --git a/test/mjsunit/compiler/regress-1085.js b/test/mjsunit/compiler/regress-1085.js
index 5d787a4..cea587f 100644
--- a/test/mjsunit/compiler/regress-1085.js
+++ b/test/mjsunit/compiler/regress-1085.js
@@ -25,11 +25,14 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+// Flags: --allow-natives-syntax
 
 // Test correct checks for negative zero.
 // This test relies on specific type feedback for Math.min.
 function f(x) { return 1 / Math.min(1, x); }
 
-for (var i=0; i<1000000; i++) f(1);
+for (var i = 0; i < 5; ++i) f(1);
+%OptimizeFunctionOnNextCall(f);
+%OptimizeFunctionOnNextCall(Math.min);
 
 assertEquals(-Infinity, f(-0));
diff --git a/test/mjsunit/regress/regress-1210.js b/test/mjsunit/regress/regress-1210.js
index 7d4735a..43500e7 100644
--- a/test/mjsunit/regress/regress-1210.js
+++ b/test/mjsunit/regress/regress-1210.js
@@ -44,7 +44,7 @@
 }
 
 // Run enough to optimize assuming global 'a' is a smi.
-for (var i = 0; i < 1000000; ++i) test(0);
+for (var i = 0; i < 10; ++i) test(0);
 %OptimizeFunctionOnNextCall(test);
 test(0);
 
diff --git a/test/mjsunit/regress/regress-485.js b/test/mjsunit/regress/regress-485.js
index 62c6fb9..e5182b3 100755
--- a/test/mjsunit/regress/regress-485.js
+++ b/test/mjsunit/regress/regress-485.js
@@ -38,19 +38,6 @@
 
 assertEquals(global, builtin(), "Direct call to builtin");
 
-assertEquals(global, builtin.call(), "call() to builtin");
-assertEquals(global, builtin.call(null), "call(null) to builtin");
-assertEquals(global, builtin.call(undefined), "call(undefined) to builtin");
-
-assertEquals(global, builtin.apply(), "apply() to builtin");
-assertEquals(global, builtin.apply(null), "apply(null) to builtin");
-assertEquals(global, builtin.apply(undefined), "apply(undefined) to builtin");
-
-assertEquals(global, builtin.call.call(builtin), "call.call() to builtin");
-assertEquals(global, builtin.call.apply(builtin), "call.apply() to builtin");
-assertEquals(global, builtin.apply.call(builtin), "apply.call() to builtin");
-assertEquals(global, builtin.apply.apply(builtin), "apply.apply() to builtin");
-
 
 // Builtin that depends on value of this to compute result.
 var builtin2 = Object.prototype.toString;
diff --git a/test/mozilla/mozilla.status b/test/mozilla/mozilla.status
index b9528bd..e281e67 100644
--- a/test/mozilla/mozilla.status
+++ b/test/mozilla/mozilla.status
@@ -610,6 +610,9 @@
 # We fail on out of memory.  The important thing is not to crash.
 js1_5/Regress/regress-303213: FAIL || TIMEOUT if $mode == debug
 
+# This test fails since we now throw in String.prototype.match when apply
+# is given null or undefined as this argument (and so does firefox nightly).
+js1_5/Regress/regress-295052: FAIL
 
 # Bug 1202592: New ecma_3/String/15.5.4.11 is failing.
 ecma_3/String/15.5.4.11: FAIL
diff --git a/test/preparser/testcfg.py b/test/preparser/testcfg.py
index c78d03b..afe3d7d 100644
--- a/test/preparser/testcfg.py
+++ b/test/preparser/testcfg.py
@@ -30,14 +30,15 @@
 from os.path import join, dirname, exists
 import platform
 import utils
-
+import re
 
 class PreparserTestCase(test.TestCase):
 
-  def __init__(self, root, path, executable, mode, context):
+  def __init__(self, root, path, executable, mode, throws, context):
     super(PreparserTestCase, self).__init__(context, path, mode)
     self.executable = executable
     self.root = root
+    self.throws = throws
 
   def GetLabel(self):
     return "%s %s %s" % (self.mode, self.path[-2], self.path[-1])
@@ -48,6 +49,8 @@
   def BuildCommand(self, path):
     testfile = join(self.root, self.GetName()) + ".js"
     result = [self.executable, testfile]
+    if (self.throws):
+      result += ['throws'] + self.throws
     return result
 
   def GetCommand(self):
@@ -65,19 +68,41 @@
   def GetBuildRequirements(self):
     return ['preparser']
 
+  def GetExpectations(self):
+    expects_file = join(self.root, 'preparser.expectation')
+    map = {}
+    if exists(expects_file):
+      rule_regex = re.compile("^([\w\-]+)(?::([\w\-]+))?(?::(\d+),(\d+))?$")
+      for line in utils.ReadLinesFrom(expects_file):
+        if (line[0] == '#'): continue
+        rule_match = rule_regex.match(line)
+        if rule_match:
+          expects = []
+          if (rule_match.group(2)):
+            expects = expects + [rule_match.group(2)]
+            if (rule_match.group(3)):
+              expects = expects + [rule_match.group(3), rule_match.group(4)]
+          map[rule_match.group(1)] = expects
+    return map;
+
+
   def ListTests(self, current_path, path, mode, variant_flags):
     executable = join('obj', 'preparser', mode, 'preparser')
     if utils.IsWindows():
       executable += '.exe'
     executable = join(self.context.buildspace, executable)
+    expectations = self.GetExpectations()
     # Find all .js files in tests/preparser directory.
     filenames = [f[:-3] for f in os.listdir(self.root) if f.endswith(".js")]
     filenames.sort()
     result = []
     for file in filenames:
+      throws = None;
+      if (file in expectations):
+        throws = expectations[file]
       result.append(PreparserTestCase(self.root,
                                       current_path + [file], executable,
-                                      mode, self.context))
+                                      mode, throws, self.context))
     return result
 
   def GetTestStatus(self, sections, defs):
@@ -85,6 +110,9 @@
     if exists(status_file):
       test.ReadConfigurationInto(status_file, sections, defs)
 
+  def VariantFlags(self):
+    return [[]];
+
 
 def GetConfiguration(context, root):
   return PreparserTestConfiguration(context, root)
diff --git a/test/sputnik/sputnik.status b/test/sputnik/sputnik.status
index 6da87ea..f322840 100644
--- a/test/sputnik/sputnik.status
+++ b/test/sputnik/sputnik.status
@@ -179,7 +179,6 @@
 S9.9_A1: FAIL_OK
 S9.9_A2: FAIL_OK
 
-
 ##################### SKIPPED TESTS #####################
 
 # These tests take a looong time to run in debug mode.
@@ -189,26 +188,6 @@
 # V8 Bug: http://code.google.com/p/v8/issues/detail?id=1196
 S8.7_A5_T2: FAIL
 
-# V8 bugs: http://code.google.com/p/v8/issues/detail?id=1198
-# V8 should not wrap this when calling builtin functions
-S15.2.4.3_A12: FAIL
-S15.2.4.7_A13: FAIL
-# Object.prototype.toString
-S15.2.4.2_A12: FAIL
-S15.2.4.2_A13: FAIL
-# Object.prototype.toLocaleString
-S15.2.4.3_A13: FAIL
-S15.2.4.4_A13: FAIL
-S15.2.4.4_A12: FAIL
-# Object.prototype.propertyIsEnumerable
-S15.2.4.7_A12: FAIL
-# Object.prototype.hasOwnProperty
-S15.2.4.5_A12: FAIL
-S15.2.4.5_A13: FAIL
-# Object.prototype.isPrototypeOf
-S15.2.4.6_A13: FAIL
-S15.2.4.6_A12: FAIL
-
 # Invalid test case (recent change adding var changes semantics)
 S8.3_A1_T1: FAIL
 # Test bug: http://code.google.com/p/sputniktests/issues/detail?id=35
@@ -270,6 +249,7 @@
 S15.10.7_A3_T2: FAIL_OK
 S15.10.7_A3_T1: FAIL_OK
 
+
 [ $arch == arm ]
 
 # BUG(3251225): Tests that timeout with --nocrankshaft.
diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp
index 0108b12..7fea189 100644
--- a/tools/gyp/v8.gyp
+++ b/tools/gyp/v8.gyp
@@ -526,6 +526,7 @@
             '../../src/platform-tls-win32.h',
             '../../src/platform-tls.h',
             '../../src/platform.h',
+            '../../src/preparse-data-format.h',
             '../../src/preparse-data.cc',
             '../../src/preparse-data.h',
             '../../src/preparser.cc',
@@ -591,7 +592,7 @@
             '../../src/unicode-inl.h',
             '../../src/unicode.cc',
             '../../src/unicode.h',
-	    '../../src/utils-inl.h',
+            '../../src/utils-inl.h',
             '../../src/utils.cc',
             '../../src/utils.h',
             '../../src/v8-counters.cc',
diff --git a/tools/test.py b/tools/test.py
index c1840bb..cb2428c 100755
--- a/tools/test.py
+++ b/tools/test.py
@@ -392,7 +392,7 @@
       result = self.RunCommand(self.GetCommand())
     except:
       self.terminate = True
-      raise BreakNowException("Used pressed CTRL+C or IO went wrong")
+      raise BreakNowException("User pressed CTRL+C or IO went wrong")
     finally:
       self.AfterRun(result)
     return result
@@ -566,6 +566,13 @@
     return (path[0], path[1:])
 
 
+# Use this to run several variants of the tests, e.g.:
+# VARIANT_FLAGS = [[], ['--always_compact', '--noflush_code']]
+VARIANT_FLAGS = [[],
+                 ['--stress-opt', '--always-opt'],
+                 ['--nocrankshaft']]
+
+
 class TestConfiguration(object):
 
   def __init__(self, context, root):
@@ -583,6 +590,11 @@
   def GetTestStatus(self, sections, defs):
     pass
 
+  def VariantFlags(self):
+    return VARIANT_FLAGS
+
+
+
 
 class TestSuite(object):
 
@@ -593,13 +605,6 @@
     return self.name
 
 
-# Use this to run several variants of the tests, e.g.:
-# VARIANT_FLAGS = [[], ['--always_compact', '--noflush_code']]
-VARIANT_FLAGS = [[],
-                 ['--stress-opt', '--always-opt'],
-                 ['--nocrankshaft']]
-
-
 class TestRepository(TestSuite):
 
   def __init__(self, path):
@@ -627,12 +632,11 @@
     return self.GetConfiguration(context).GetBuildRequirements()
 
   def AddTestsToList(self, result, current_path, path, context, mode):
-    for v in VARIANT_FLAGS:
+    for v in self.GetConfiguration(context).VariantFlags():
       tests = self.GetConfiguration(context).ListTests(current_path, path, mode, v)
       for t in tests: t.variant_flags = v
       result += tests
 
-
   def GetTestStatus(self, context, sections, defs):
     self.GetConfiguration(context).GetTestStatus(sections, defs)