Upgrade V8 to 2.1.3
authorRyan Dahl <ry@tinyclouds.org>
Wed, 10 Mar 2010 18:50:46 +0000 (10:50 -0800)
committerRyan Dahl <ry@tinyclouds.org>
Wed, 10 Mar 2010 18:50:46 +0000 (10:50 -0800)
194 files changed:
deps/v8/ChangeLog
deps/v8/SConstruct
deps/v8/include/v8.h
deps/v8/src/SConscript
deps/v8/src/accessors.cc
deps/v8/src/api.cc
deps/v8/src/arm/assembler-arm.cc
deps/v8/src/arm/assembler-arm.h
deps/v8/src/arm/builtins-arm.cc
deps/v8/src/arm/codegen-arm.cc
deps/v8/src/arm/codegen-arm.h
deps/v8/src/arm/fast-codegen-arm.cc
deps/v8/src/arm/full-codegen-arm.cc
deps/v8/src/arm/ic-arm.cc
deps/v8/src/arm/macro-assembler-arm.cc
deps/v8/src/arm/macro-assembler-arm.h
deps/v8/src/arm/regexp-macro-assembler-arm.cc
deps/v8/src/arm/stub-cache-arm.cc
deps/v8/src/arm/virtual-frame-arm.cc
deps/v8/src/arm/virtual-frame-arm.h
deps/v8/src/array.js
deps/v8/src/assembler.cc
deps/v8/src/assembler.h
deps/v8/src/ast.cc
deps/v8/src/ast.h
deps/v8/src/bootstrapper.cc
deps/v8/src/builtins.cc
deps/v8/src/code-stubs.cc
deps/v8/src/code-stubs.h
deps/v8/src/codegen.cc
deps/v8/src/compilation-cache.cc
deps/v8/src/compiler.cc
deps/v8/src/compiler.h
deps/v8/src/contexts.h
deps/v8/src/conversions-inl.h
deps/v8/src/conversions.h
deps/v8/src/data-flow.cc
deps/v8/src/data-flow.h
deps/v8/src/date-delay.js
deps/v8/src/debug-delay.js
deps/v8/src/debug.cc
deps/v8/src/debug.h
deps/v8/src/factory.h
deps/v8/src/fast-codegen.h
deps/v8/src/flag-definitions.h
deps/v8/src/frame-element.cc
deps/v8/src/frame-element.h
deps/v8/src/frames.cc
deps/v8/src/globals.h
deps/v8/src/handles.cc
deps/v8/src/handles.h
deps/v8/src/heap-inl.h
deps/v8/src/heap-profiler.cc
deps/v8/src/heap-profiler.h
deps/v8/src/heap.cc
deps/v8/src/heap.h
deps/v8/src/ia32/assembler-ia32.cc
deps/v8/src/ia32/assembler-ia32.h
deps/v8/src/ia32/builtins-ia32.cc
deps/v8/src/ia32/codegen-ia32.cc
deps/v8/src/ia32/codegen-ia32.h
deps/v8/src/ia32/debug-ia32.cc
deps/v8/src/ia32/disasm-ia32.cc
deps/v8/src/ia32/fast-codegen-ia32.cc
deps/v8/src/ia32/full-codegen-ia32.cc
deps/v8/src/ia32/ic-ia32.cc
deps/v8/src/ia32/macro-assembler-ia32.cc
deps/v8/src/ia32/macro-assembler-ia32.h
deps/v8/src/ia32/regexp-macro-assembler-ia32.cc
deps/v8/src/ia32/regexp-macro-assembler-ia32.h
deps/v8/src/ia32/register-allocator-ia32.cc
deps/v8/src/ia32/stub-cache-ia32.cc
deps/v8/src/ia32/virtual-frame-ia32.cc
deps/v8/src/ia32/virtual-frame-ia32.h
deps/v8/src/ic.cc
deps/v8/src/ic.h
deps/v8/src/jsregexp.h
deps/v8/src/jump-target-inl.h
deps/v8/src/jump-target.cc
deps/v8/src/jump-target.h
deps/v8/src/liveedit-delay.js [new file with mode: 0644]
deps/v8/src/liveedit.cc
deps/v8/src/liveedit.h
deps/v8/src/log.cc
deps/v8/src/log.h
deps/v8/src/macros.py
deps/v8/src/math.js
deps/v8/src/messages.cc
deps/v8/src/messages.js
deps/v8/src/mips/codegen-mips.cc
deps/v8/src/mips/codegen-mips.h
deps/v8/src/mips/fast-codegen-mips.cc
deps/v8/src/mips/full-codegen-mips.cc
deps/v8/src/mips/ic-mips.cc
deps/v8/src/mips/jump-target-mips.cc
deps/v8/src/mips/macro-assembler-mips.cc
deps/v8/src/mips/macro-assembler-mips.h
deps/v8/src/mips/stub-cache-mips.cc
deps/v8/src/mips/virtual-frame-mips.cc
deps/v8/src/mips/virtual-frame-mips.h
deps/v8/src/number-info.h
deps/v8/src/objects-debug.cc
deps/v8/src/objects-inl.h
deps/v8/src/objects.cc
deps/v8/src/objects.h
deps/v8/src/parser.cc
deps/v8/src/platform-freebsd.cc
deps/v8/src/platform-linux.cc
deps/v8/src/platform-macos.cc
deps/v8/src/platform-win32.cc
deps/v8/src/prettyprinter.cc
deps/v8/src/regexp-delay.js
deps/v8/src/register-allocator-inl.h
deps/v8/src/register-allocator.cc
deps/v8/src/register-allocator.h
deps/v8/src/rewriter.cc
deps/v8/src/runtime.cc
deps/v8/src/runtime.h
deps/v8/src/runtime.js
deps/v8/src/scanner.cc
deps/v8/src/scanner.h
deps/v8/src/scopeinfo.cc
deps/v8/src/scopeinfo.h
deps/v8/src/scopes.cc
deps/v8/src/serialize.cc
deps/v8/src/spaces.cc
deps/v8/src/splay-tree-inl.h [new file with mode: 0644]
deps/v8/src/splay-tree.h [new file with mode: 0644]
deps/v8/src/string.js
deps/v8/src/top.cc
deps/v8/src/usage-analyzer.cc [deleted file]
deps/v8/src/utils.h
deps/v8/src/v8-counters.h
deps/v8/src/v8.h
deps/v8/src/variables.cc
deps/v8/src/variables.h
deps/v8/src/version.cc
deps/v8/src/virtual-frame-inl.h
deps/v8/src/virtual-frame.cc
deps/v8/src/x64/builtins-x64.cc
deps/v8/src/x64/codegen-x64.cc
deps/v8/src/x64/codegen-x64.h
deps/v8/src/x64/fast-codegen-x64.cc
deps/v8/src/x64/full-codegen-x64.cc
deps/v8/src/x64/ic-x64.cc
deps/v8/src/x64/macro-assembler-x64.cc
deps/v8/src/x64/macro-assembler-x64.h
deps/v8/src/x64/regexp-macro-assembler-x64.cc
deps/v8/src/x64/stub-cache-x64.cc
deps/v8/src/x64/virtual-frame-x64.cc
deps/v8/src/x64/virtual-frame-x64.h
deps/v8/src/zone-inl.h
deps/v8/src/zone.cc
deps/v8/src/zone.h
deps/v8/test/cctest/SConscript
deps/v8/test/cctest/cctest.status
deps/v8/test/cctest/test-api.cc
deps/v8/test/cctest/test-dataflow.cc [new file with mode: 0644]
deps/v8/test/cctest/test-debug.cc
deps/v8/test/cctest/test-disasm-ia32.cc
deps/v8/test/cctest/test-heap-profiler.cc
deps/v8/test/cctest/test-heap.cc
deps/v8/test/cctest/test-log.cc
deps/v8/test/cctest/test-serialize.cc
deps/v8/test/mjsunit/array-elements-from-array-prototype-chain.js [new file with mode: 0644]
deps/v8/test/mjsunit/array-elements-from-array-prototype.js [new file with mode: 0644]
deps/v8/test/mjsunit/array-elements-from-object-prototype.js [new file with mode: 0644]
deps/v8/test/mjsunit/array-length.js
deps/v8/test/mjsunit/array-slice.js
deps/v8/test/mjsunit/array-splice.js
deps/v8/test/mjsunit/array-unshift.js
deps/v8/test/mjsunit/bugs/bug-618.js [new file with mode: 0644]
deps/v8/test/mjsunit/date.js
deps/v8/test/mjsunit/debug-liveedit-1.js [new file with mode: 0644]
deps/v8/test/mjsunit/debug-liveedit-2.js [new file with mode: 0644]
deps/v8/test/mjsunit/debug-liveedit-check-stack.js [new file with mode: 0644]
deps/v8/test/mjsunit/debug-scopes.js
deps/v8/test/mjsunit/debug-script.js
deps/v8/test/mjsunit/fuzz-natives.js
deps/v8/test/mjsunit/math-sqrt.js [new file with mode: 0644]
deps/v8/test/mjsunit/regress/regress-634.js [new file with mode: 0644]
deps/v8/test/mjsunit/regress/regress-636.js [moved from deps/v8/src/usage-analyzer.h with 81% similarity]
deps/v8/test/mjsunit/string-charat.js
deps/v8/test/mjsunit/string-index.js
deps/v8/test/mjsunit/string-split-cache.js [new file with mode: 0644]
deps/v8/test/mjsunit/undeletable-functions.js
deps/v8/tools/gyp/v8.gyp
deps/v8/tools/visual_studio/js2c.cmd
deps/v8/tools/visual_studio/v8.vcproj
deps/v8/tools/visual_studio/v8_arm.vcproj
deps/v8/tools/visual_studio/v8_base.vcproj
deps/v8/tools/visual_studio/v8_base_arm.vcproj
deps/v8/tools/visual_studio/v8_base_x64.vcproj
deps/v8/tools/visual_studio/v8_x64.vcproj

index 339fd18..4363b19 100644 (file)
@@ -1,3 +1,21 @@
+2010-03-10: Version 2.1.3
+
+        Added API method for context-disposal notifications.
+
+        Added API method for accessing elements by integer index.
+
+        Added missing implementation of Uint32::Value and Value::IsUint32
+        API methods.
+
+        Added IsExecutionTerminating API method.
+
+        Disabled strict aliasing for GCC 4.4.
+
+        Fixed string-concatenation bug (issue 636).
+
+        Performance improvements on all platforms.
+
+
 2010-02-23: Version 2.1.2
 
         Fix a crash bug caused by wrong assert.
@@ -6,6 +24,7 @@
 
         Performance improvements on all platforms.
 
+
 2010-02-19: Version 2.1.1
 
         [ES5] Implemented Object.defineProperty.
index 5483663..f7638e0 100644 (file)
@@ -46,8 +46,8 @@ if ANDROID_TOP is None:
 # on linux we need these compiler flags to avoid crashes in the v8 test suite
 # and avoid dtoa.c strict aliasing issues
 if os.environ.get('GCC_VERSION') == '44':
-    GCC_EXTRA_CCFLAGS = ['-fno-tree-vrp']
-    GCC_DTOA_EXTRA_CCFLAGS = ['-fno-strict-aliasing']
+    GCC_EXTRA_CCFLAGS = ['-fno-tree-vrp', '-fno-strict-aliasing']
+    GCC_DTOA_EXTRA_CCFLAGS = []
 else:
     GCC_EXTRA_CCFLAGS = []
     GCC_DTOA_EXTRA_CCFLAGS = []
@@ -255,8 +255,16 @@ LIBRARY_FLAGS = {
       },
       'msvcltcg:on': {
         'CCFLAGS':      ['/GL'],
-        'LINKFLAGS':    ['/LTCG'],
         'ARFLAGS':      ['/LTCG'],
+        'pgo:off': {
+          'LINKFLAGS':    ['/LTCG'],
+        },
+        'pgo:instrument': {
+          'LINKFLAGS':    ['/LTCG:PGI']
+        },
+        'pgo:optimize': {
+          'LINKFLAGS':    ['/LTCG:PGO']
+        }
       }
     }
   }
@@ -267,6 +275,7 @@ V8_EXTRA_FLAGS = {
   'gcc': {
     'all': {
       'WARNINGFLAGS': ['-Wall',
+                       '-Werror',
                        '-W',
                        '-Wno-unused-parameter',
                        '-Wnon-virtual-dtor']
@@ -526,7 +535,15 @@ SAMPLE_FLAGS = {
       },
       'msvcltcg:on': {
         'CCFLAGS':      ['/GL'],
-        'LINKFLAGS':    ['/LTCG'],
+        'pgo:off': {
+          'LINKFLAGS':    ['/LTCG'],
+        },
+      },
+      'pgo:instrument': {
+        'LINKFLAGS':    ['/LTCG:PGI']
+      },
+      'pgo:optimize': {
+        'LINKFLAGS':    ['/LTCG:PGO']
       }
     },
     'arch:ia32': {
@@ -710,6 +727,11 @@ SIMPLE_OPTIONS = {
     'values': ['arm', 'thumb2', 'none'],
     'default': 'none',
     'help': 'generate thumb2 instructions instead of arm instructions (default)'
+  },
+  'pgo': {
+    'values': ['off', 'instrument', 'optimize'],
+    'default': 'off',
+    'help': 'select profile guided optimization variant',
   }
 }
 
@@ -797,6 +819,8 @@ def VerifyOptions(env):
     Abort("Shared Object soname not applicable for Windows.")
   if env['soname'] == 'on' and env['library'] == 'static':
     Abort("Shared Object soname not applicable for static library.")
+  if env['os'] != 'win32' and env['pgo'] != 'off':
+    Abort("Profile guided optimization only supported on Windows.")
   for (name, option) in SIMPLE_OPTIONS.iteritems():
     if (not option.get('default')) and (name not in ARGUMENTS):
       message = ("A value for option %s must be specified (%s)." %
@@ -882,7 +906,7 @@ class BuildContext(object):
       env['ENV'] = self.env_overrides
 
 
-def PostprocessOptions(options):
+def PostprocessOptions(options, os):
   # Adjust architecture if the simulator option has been set
   if (options['simulator'] != 'none') and (options['arch'] != options['simulator']):
     if 'arch' in ARGUMENTS:
@@ -893,6 +917,10 @@ def PostprocessOptions(options):
     # Print a warning if profiling is enabled without profiling support
     print "Warning: forcing profilingsupport on when prof is on"
     options['profilingsupport'] = 'on'
+  if os == 'win32' and options['pgo'] != 'off' and options['msvcltcg'] == 'off':
+    if 'msvcltcg' in ARGUMENTS:
+      print "Warning: forcing msvcltcg on as it is required for pgo (%s)" % options['pgo']
+    options['msvcltcg'] = 'on'
   if (options['armvariant'] == 'none' and options['arch'] == 'arm'):
     options['armvariant'] = 'arm'
   if (options['armvariant'] != 'none' and options['arch'] != 'arm'):
@@ -923,7 +951,7 @@ def BuildSpecific(env, mode, env_overrides):
   options = {'mode': mode}
   for option in SIMPLE_OPTIONS:
     options[option] = env[option]
-  PostprocessOptions(options)
+  PostprocessOptions(options, env['os'])
 
   context = BuildContext(options, env_overrides, samples=SplitList(env['sample']))
 
index 69b93c6..882eedd 100644 (file)
@@ -261,6 +261,10 @@ template <class T> class V8EXPORT_INLINE Handle {
     return Handle<T>(T::Cast(*that));
   }
 
+  template <class S> inline Handle<S> As() {
+    return Handle<S>::Cast(*this);
+  }
+
  private:
   T* val_;
 };
@@ -295,6 +299,10 @@ template <class T> class V8EXPORT_INLINE Local : public Handle<T> {
     return Local<T>(T::Cast(*that));
   }
 
+  template <class S> inline Local<S> As() {
+    return Local<S>::Cast(*this);
+  }
+
   /** Create a local handle for the content of another handle.
    *  The referee is kept alive by the local handle even when
    *  the original handle is destroyed/disposed.
@@ -368,6 +376,10 @@ template <class T> class V8EXPORT_INLINE Persistent : public Handle<T> {
     return Persistent<T>(T::Cast(*that));
   }
 
+  template <class S> inline Persistent<S> As() {
+    return Persistent<S>::Cast(*this);
+  }
+
   /**
    * Creates a new persistent handle for an existing local or
    * persistent handle.
@@ -538,13 +550,13 @@ class V8EXPORT Script {
    * Compiles the specified script (context-independent).
    *
    * \param source Script source code.
-   * \param origin Script origin, owned by caller, no references are kept 
+   * \param origin Script origin, owned by caller, no references are kept
    *   when New() returns
    * \param pre_data Pre-parsing data, as obtained by ScriptData::PreCompile()
    *   using pre_data speeds compilation if it's done multiple times.
    *   Owned by caller, no references are kept when New() returns.
    * \param script_data Arbitrary data associated with script. Using
-   *   this has same effect as calling SetData(), but allows data to be 
+   *   this has same effect as calling SetData(), but allows data to be
    *   available to compile event handlers.
    * \return Compiled script object (context independent; when run it
    *   will use the currently entered context).
@@ -559,7 +571,7 @@ class V8EXPORT Script {
    * object (typically a string) as the script's origin.
    *
    * \param source Script source code.
-   * \patam file_name file name object (typically a string) to be used 
+   * \param file_name file name object (typically a string) to be used
    *   as the script's origin.
    * \return Compiled script object (context independent; when run it
    *   will use the currently entered context).
@@ -571,7 +583,7 @@ class V8EXPORT Script {
    * Compiles the specified script (bound to current context).
    *
    * \param source Script source code.
-   * \param origin Script origin, owned by caller, no references are kept 
+   * \param origin Script origin, owned by caller, no references are kept
    *   when Compile() returns
    * \param pre_data Pre-parsing data, as obtained by ScriptData::PreCompile()
    *   using pre_data speeds compilation if it's done multiple times.
@@ -755,6 +767,11 @@ class V8EXPORT Value : public Data {
   bool IsInt32() const;
 
   /**
+   * Returns true if this value is a 32-bit signed integer.
+   */
+  bool IsUint32() const;
+
+  /**
    * Returns true if this value is a Date.
    */
   bool IsDate() const;
@@ -1178,6 +1195,9 @@ class V8EXPORT Object : public Value {
            Handle<Value> value,
            PropertyAttribute attribs = None);
 
+  bool Set(uint32_t index,
+           Handle<Value> value);
+
   // Sets a local property on this object bypassing interceptors and
   // overriding accessors or read-only properties.
   //
@@ -1192,6 +1212,8 @@ class V8EXPORT Object : public Value {
 
   Local<Value> Get(Handle<Value> key);
 
+  Local<Value> Get(uint32_t index);
+
   // TODO(1245389): Replace the type-specific versions of these
   // functions with generic ones that accept a Handle<Value> key.
   bool Has(Handle<String> key);
@@ -2485,9 +2507,11 @@ class V8EXPORT V8 {
 
   /**
    * Optional notification that a context has been disposed. V8 uses
-   * these notifications to guide the garbage collection heuristic.
+   * these notifications to guide the GC heuristic. Returns the number
+   * of context disposals - including this one - since the last time
+   * V8 had a chance to clean up.
    */
-  static void ContextDisposedNotification();
+  static int ContextDisposedNotification();
 
  private:
   V8();
index 73de193..d61da3e 100755 (executable)
@@ -97,7 +97,6 @@ SOURCES = {
     token.cc
     top.cc
     unicode.cc
-    usage-analyzer.cc
     utils.cc
     v8-counters.cc
     v8.cc
@@ -249,6 +248,7 @@ math.js
 messages.js
 apinatives.js
 debug-delay.js
+liveedit-delay.js
 mirror-delay.js
 date-delay.js
 regexp-delay.js
index b05719e..e41db94 100644 (file)
@@ -32,7 +32,6 @@
 #include "factory.h"
 #include "scopeinfo.h"
 #include "top.h"
-#include "zone-inl.h"
 
 namespace v8 {
 namespace internal {
index 22d2f4b..93fce79 100644 (file)
 #include "debug.h"
 #include "execution.h"
 #include "global-handles.h"
+#include "messages.h"
 #include "platform.h"
 #include "serialize.h"
 #include "snapshot.h"
+#include "top.h"
 #include "utils.h"
 #include "v8threads.h"
 #include "version.h"
@@ -1569,6 +1571,18 @@ bool Value::IsInt32() const {
 }
 
 
+bool Value::IsUint32() const {
+  if (IsDeadCheck("v8::Value::IsUint32()")) return false;
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  if (obj->IsSmi()) return i::Smi::cast(*obj)->value() >= 0;
+  if (obj->IsNumber()) {
+    double value = obj->Number();
+    return i::FastUI2D(i::FastD2UI(value)) == value;
+  }
+  return false;
+}
+
+
 bool Value::IsDate() const {
   if (IsDeadCheck("v8::Value::IsDate()")) return false;
   i::Handle<i::Object> obj = Utils::OpenHandle(this);
@@ -1974,6 +1988,23 @@ bool v8::Object::Set(v8::Handle<Value> key, v8::Handle<Value> value,
 }
 
 
+bool v8::Object::Set(uint32_t index, v8::Handle<Value> value) {
+  ON_BAILOUT("v8::Object::Set()", return false);
+  ENTER_V8;
+  HandleScope scope;
+  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
+  i::Handle<i::Object> value_obj = Utils::OpenHandle(*value);
+  EXCEPTION_PREAMBLE();
+  i::Handle<i::Object> obj = i::SetElement(
+      self,
+      index,
+      value_obj);
+  has_pending_exception = obj.is_null();
+  EXCEPTION_BAILOUT_CHECK(false);
+  return true;
+}
+
+
 bool v8::Object::ForceSet(v8::Handle<Value> key,
                           v8::Handle<Value> value,
                           v8::PropertyAttribute attribs) {
@@ -2022,6 +2053,18 @@ Local<Value> v8::Object::Get(v8::Handle<Value> key) {
 }
 
 
+Local<Value> v8::Object::Get(uint32_t index) {
+  ON_BAILOUT("v8::Object::Get()", return Local<v8::Value>());
+  ENTER_V8;
+  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
+  EXCEPTION_PREAMBLE();
+  i::Handle<i::Object> result = i::GetElement(self, index);
+  has_pending_exception = result.is_null();
+  EXCEPTION_BAILOUT_CHECK(Local<Value>());
+  return Utils::ToLocal(result);
+}
+
+
 Local<Value> v8::Object::GetPrototype() {
   ON_BAILOUT("v8::Object::GetPrototype()", return Local<v8::Value>());
   ENTER_V8;
@@ -2614,7 +2657,7 @@ int String::WriteAscii(char* buffer, int start, int length) const {
   StringTracker::RecordWrite(str);
   // Flatten the string for efficiency.  This applies whether we are
   // using StringInputBuffer or Get(i) to access the characters.
-  str->TryFlattenIfNotFlat();
+  str->TryFlatten();
   int end = length;
   if ( (length == -1) || (length > str->length() - start) )
     end = str->length() - start;
@@ -2727,6 +2770,17 @@ int32_t Int32::Value() const {
 }
 
 
+uint32_t Uint32::Value() const {
+  if (IsDeadCheck("v8::Uint32::Value()")) return 0;
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  if (obj->IsSmi()) {
+    return i::Smi::cast(*obj)->value();
+  } else {
+    return static_cast<uint32_t>(obj->Number());
+  }
+}
+
+
 int v8::Object::InternalFieldCount() {
   if (IsDeadCheck("v8::Object::InternalFieldCount()")) return 0;
   i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
@@ -2820,9 +2874,9 @@ void v8::V8::LowMemoryNotification() {
 }
 
 
-void v8::V8::ContextDisposedNotification() {
-  if (!i::V8::IsRunning()) return;
-  i::Heap::NotifyContextDisposed();
+int v8::V8::ContextDisposedNotification() {
+  if (!i::V8::IsRunning()) return 0;
+  return i::Heap::NotifyContextDisposed();
 }
 
 
index c79aac6..6b226fd 100644 (file)
@@ -81,100 +81,6 @@ void CpuFeatures::Probe() {
 
 
 // -----------------------------------------------------------------------------
-// Implementation of Register and CRegister
-
-Register no_reg = { -1 };
-
-Register r0  = {  0 };
-Register r1  = {  1 };
-Register r2  = {  2 };
-Register r3  = {  3 };
-Register r4  = {  4 };
-Register r5  = {  5 };
-Register r6  = {  6 };
-Register r7  = {  7 };
-Register r8  = {  8 };  // Used as context register.
-Register r9  = {  9 };
-Register r10 = { 10 };  // Used as roots register.
-Register fp  = { 11 };
-Register ip  = { 12 };
-Register sp  = { 13 };
-Register lr  = { 14 };
-Register pc  = { 15 };
-
-
-CRegister no_creg = { -1 };
-
-CRegister cr0  = {  0 };
-CRegister cr1  = {  1 };
-CRegister cr2  = {  2 };
-CRegister cr3  = {  3 };
-CRegister cr4  = {  4 };
-CRegister cr5  = {  5 };
-CRegister cr6  = {  6 };
-CRegister cr7  = {  7 };
-CRegister cr8  = {  8 };
-CRegister cr9  = {  9 };
-CRegister cr10 = { 10 };
-CRegister cr11 = { 11 };
-CRegister cr12 = { 12 };
-CRegister cr13 = { 13 };
-CRegister cr14 = { 14 };
-CRegister cr15 = { 15 };
-
-// Support for the VFP registers s0 to s31 (d0 to d15).
-// Note that "sN:sM" is the same as "dN/2".
-SwVfpRegister s0  = {  0 };
-SwVfpRegister s1  = {  1 };
-SwVfpRegister s2  = {  2 };
-SwVfpRegister s3  = {  3 };
-SwVfpRegister s4  = {  4 };
-SwVfpRegister s5  = {  5 };
-SwVfpRegister s6  = {  6 };
-SwVfpRegister s7  = {  7 };
-SwVfpRegister s8  = {  8 };
-SwVfpRegister s9  = {  9 };
-SwVfpRegister s10 = { 10 };
-SwVfpRegister s11 = { 11 };
-SwVfpRegister s12 = { 12 };
-SwVfpRegister s13 = { 13 };
-SwVfpRegister s14 = { 14 };
-SwVfpRegister s15 = { 15 };
-SwVfpRegister s16 = { 16 };
-SwVfpRegister s17 = { 17 };
-SwVfpRegister s18 = { 18 };
-SwVfpRegister s19 = { 19 };
-SwVfpRegister s20 = { 20 };
-SwVfpRegister s21 = { 21 };
-SwVfpRegister s22 = { 22 };
-SwVfpRegister s23 = { 23 };
-SwVfpRegister s24 = { 24 };
-SwVfpRegister s25 = { 25 };
-SwVfpRegister s26 = { 26 };
-SwVfpRegister s27 = { 27 };
-SwVfpRegister s28 = { 28 };
-SwVfpRegister s29 = { 29 };
-SwVfpRegister s30 = { 30 };
-SwVfpRegister s31 = { 31 };
-
-DwVfpRegister d0  = {  0 };
-DwVfpRegister d1  = {  1 };
-DwVfpRegister d2  = {  2 };
-DwVfpRegister d3  = {  3 };
-DwVfpRegister d4  = {  4 };
-DwVfpRegister d5  = {  5 };
-DwVfpRegister d6  = {  6 };
-DwVfpRegister d7  = {  7 };
-DwVfpRegister d8  = {  8 };
-DwVfpRegister d9  = {  9 };
-DwVfpRegister d10 = { 10 };
-DwVfpRegister d11 = { 11 };
-DwVfpRegister d12 = { 12 };
-DwVfpRegister d13 = { 13 };
-DwVfpRegister d14 = { 14 };
-DwVfpRegister d15 = { 15 };
-
-// -----------------------------------------------------------------------------
 // Implementation of RelocInfo
 
 const int RelocInfo::kApplyMask = 0;
index f6b7a06..c972c57 100644 (file)
@@ -84,25 +84,24 @@ struct Register {
   int code_;
 };
 
-
-extern Register no_reg;
-extern Register r0;
-extern Register r1;
-extern Register r2;
-extern Register r3;
-extern Register r4;
-extern Register r5;
-extern Register r6;
-extern Register r7;
-extern Register r8;
-extern Register r9;
-extern Register r10;
-extern Register fp;
-extern Register ip;
-extern Register sp;
-extern Register lr;
-extern Register pc;
-
+const Register no_reg = { -1 };
+
+const Register r0  = {  0 };
+const Register r1  = {  1 };
+const Register r2  = {  2 };
+const Register r3  = {  3 };
+const Register r4  = {  4 };
+const Register r5  = {  5 };
+const Register r6  = {  6 };
+const Register r7  = {  7 };
+const Register r8  = {  8 };  // Used as context register.
+const Register r9  = {  9 };
+const Register r10 = { 10 };  // Used as roots register.
+const Register fp  = { 11 };
+const Register ip  = { 12 };
+const Register sp  = { 13 };
+const Register lr  = { 14 };
+const Register pc  = { 15 };
 
 // Single word VFP register.
 struct SwVfpRegister {
@@ -139,57 +138,57 @@ struct DwVfpRegister {
 };
 
 
-// Support for VFP registers s0 to s31 (d0 to d15).
+// Support for the VFP registers s0 to s31 (d0 to d15).
 // Note that "s(N):s(N+1)" is the same as "d(N/2)".
-extern SwVfpRegister s0;
-extern SwVfpRegister s1;
-extern SwVfpRegister s2;
-extern SwVfpRegister s3;
-extern SwVfpRegister s4;
-extern SwVfpRegister s5;
-extern SwVfpRegister s6;
-extern SwVfpRegister s7;
-extern SwVfpRegister s8;
-extern SwVfpRegister s9;
-extern SwVfpRegister s10;
-extern SwVfpRegister s11;
-extern SwVfpRegister s12;
-extern SwVfpRegister s13;
-extern SwVfpRegister s14;
-extern SwVfpRegister s15;
-extern SwVfpRegister s16;
-extern SwVfpRegister s17;
-extern SwVfpRegister s18;
-extern SwVfpRegister s19;
-extern SwVfpRegister s20;
-extern SwVfpRegister s21;
-extern SwVfpRegister s22;
-extern SwVfpRegister s23;
-extern SwVfpRegister s24;
-extern SwVfpRegister s25;
-extern SwVfpRegister s26;
-extern SwVfpRegister s27;
-extern SwVfpRegister s28;
-extern SwVfpRegister s29;
-extern SwVfpRegister s30;
-extern SwVfpRegister s31;
-
-extern DwVfpRegister d0;
-extern DwVfpRegister d1;
-extern DwVfpRegister d2;
-extern DwVfpRegister d3;
-extern DwVfpRegister d4;
-extern DwVfpRegister d5;
-extern DwVfpRegister d6;
-extern DwVfpRegister d7;
-extern DwVfpRegister d8;
-extern DwVfpRegister d9;
-extern DwVfpRegister d10;
-extern DwVfpRegister d11;
-extern DwVfpRegister d12;
-extern DwVfpRegister d13;
-extern DwVfpRegister d14;
-extern DwVfpRegister d15;
+const SwVfpRegister s0  = {  0 };
+const SwVfpRegister s1  = {  1 };
+const SwVfpRegister s2  = {  2 };
+const SwVfpRegister s3  = {  3 };
+const SwVfpRegister s4  = {  4 };
+const SwVfpRegister s5  = {  5 };
+const SwVfpRegister s6  = {  6 };
+const SwVfpRegister s7  = {  7 };
+const SwVfpRegister s8  = {  8 };
+const SwVfpRegister s9  = {  9 };
+const SwVfpRegister s10 = { 10 };
+const SwVfpRegister s11 = { 11 };
+const SwVfpRegister s12 = { 12 };
+const SwVfpRegister s13 = { 13 };
+const SwVfpRegister s14 = { 14 };
+const SwVfpRegister s15 = { 15 };
+const SwVfpRegister s16 = { 16 };
+const SwVfpRegister s17 = { 17 };
+const SwVfpRegister s18 = { 18 };
+const SwVfpRegister s19 = { 19 };
+const SwVfpRegister s20 = { 20 };
+const SwVfpRegister s21 = { 21 };
+const SwVfpRegister s22 = { 22 };
+const SwVfpRegister s23 = { 23 };
+const SwVfpRegister s24 = { 24 };
+const SwVfpRegister s25 = { 25 };
+const SwVfpRegister s26 = { 26 };
+const SwVfpRegister s27 = { 27 };
+const SwVfpRegister s28 = { 28 };
+const SwVfpRegister s29 = { 29 };
+const SwVfpRegister s30 = { 30 };
+const SwVfpRegister s31 = { 31 };
+
+const DwVfpRegister d0  = {  0 };
+const DwVfpRegister d1  = {  1 };
+const DwVfpRegister d2  = {  2 };
+const DwVfpRegister d3  = {  3 };
+const DwVfpRegister d4  = {  4 };
+const DwVfpRegister d5  = {  5 };
+const DwVfpRegister d6  = {  6 };
+const DwVfpRegister d7  = {  7 };
+const DwVfpRegister d8  = {  8 };
+const DwVfpRegister d9  = {  9 };
+const DwVfpRegister d10 = { 10 };
+const DwVfpRegister d11 = { 11 };
+const DwVfpRegister d12 = { 12 };
+const DwVfpRegister d13 = { 13 };
+const DwVfpRegister d14 = { 14 };
+const DwVfpRegister d15 = { 15 };
 
 
 // Coprocessor register
@@ -210,23 +209,24 @@ struct CRegister {
 };
 
 
-extern CRegister no_creg;
-extern CRegister cr0;
-extern CRegister cr1;
-extern CRegister cr2;
-extern CRegister cr3;
-extern CRegister cr4;
-extern CRegister cr5;
-extern CRegister cr6;
-extern CRegister cr7;
-extern CRegister cr8;
-extern CRegister cr9;
-extern CRegister cr10;
-extern CRegister cr11;
-extern CRegister cr12;
-extern CRegister cr13;
-extern CRegister cr14;
-extern CRegister cr15;
+const CRegister no_creg = { -1 };
+
+const CRegister cr0  = {  0 };
+const CRegister cr1  = {  1 };
+const CRegister cr2  = {  2 };
+const CRegister cr3  = {  3 };
+const CRegister cr4  = {  4 };
+const CRegister cr5  = {  5 };
+const CRegister cr6  = {  6 };
+const CRegister cr7  = {  7 };
+const CRegister cr8  = {  8 };
+const CRegister cr9  = {  9 };
+const CRegister cr10 = { 10 };
+const CRegister cr11 = { 11 };
+const CRegister cr12 = { 12 };
+const CRegister cr13 = { 13 };
+const CRegister cr14 = { 14 };
+const CRegister cr15 = { 15 };
 
 
 // Coprocessor number
index edb1b0a..91e896d 100644 (file)
@@ -61,10 +61,10 @@ void Builtins::Generate_Adaptor(MacroAssembler* masm,
     ASSERT(extra_args == NO_EXTRA_ARGUMENTS);
   }
 
-  // JumpToRuntime expects r0 to contain the number of arguments
+  // JumpToExternalReference expects r0 to contain the number of arguments
   // including the receiver and the extra arguments.
   __ add(r0, r0, Operand(num_extra_args + 1));
-  __ JumpToRuntime(ExternalReference(id));
+  __ JumpToExternalReference(ExternalReference(id));
 }
 
 
index 6644d02..9e59582 100644 (file)
@@ -31,6 +31,7 @@
 #include "codegen-inl.h"
 #include "compiler.h"
 #include "debug.h"
+#include "ic-inl.h"
 #include "parser.h"
 #include "register-allocator-inl.h"
 #include "runtime.h"
@@ -142,6 +143,7 @@ CodeGenerator::CodeGenerator(MacroAssembler* masm)
 void CodeGenerator::Generate(CompilationInfo* info) {
   // Record the position for debugging purposes.
   CodeForFunctionPosition(info->function());
+  Comment cmnt(masm_, "[ function compiled by virtual frame code generator");
 
   // Initialize state.
   info_ = info;
@@ -3321,6 +3323,25 @@ void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) {
 }
 
 
+// Generates the Math.pow method - currently just calls runtime.
+void CodeGenerator::GenerateMathPow(ZoneList<Expression*>* args) {
+  ASSERT(args->length() == 2);
+  Load(args->at(0));
+  Load(args->at(1));
+  frame_->CallRuntime(Runtime::kMath_pow, 2);
+  frame_->EmitPush(r0);
+}
+
+
+// Generates the Math.sqrt method - currently just calls runtime.
+void CodeGenerator::GenerateMathSqrt(ZoneList<Expression*>* args) {
+  ASSERT(args->length() == 1);
+  Load(args->at(0));
+  frame_->CallRuntime(Runtime::kMath_sqrt, 1);
+  frame_->EmitPush(r0);
+}
+
+
 // This should generate code that performs a charCodeAt() call or returns
 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt.
 // It is not yet implemented on ARM, so it always goes to the slow case.
@@ -3404,6 +3425,44 @@ void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
 }
 
 
+void CodeGenerator::GenerateCharFromCode(ZoneList<Expression*>* args) {
+  Comment(masm_, "[ GenerateCharFromCode");
+  ASSERT(args->length() == 1);
+
+  LoadAndSpill(args->at(0));
+  frame_->EmitPop(r0);
+
+  JumpTarget slow_case;
+  JumpTarget exit;
+
+  // Fast case of Heap::LookupSingleCharacterStringFromCode.
+  ASSERT(kSmiTag == 0);
+  ASSERT(kSmiShiftSize == 0);
+  ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1));
+  __ tst(r0, Operand(kSmiTagMask |
+                     ((~String::kMaxAsciiCharCode) << kSmiTagSize)));
+  slow_case.Branch(nz);
+
+  ASSERT(kSmiTag == 0);
+  __ mov(r1, Operand(Factory::single_character_string_cache()));
+  __ add(r1, r1, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize));
+  __ ldr(r1, MemOperand(r1, FixedArray::kHeaderSize - kHeapObjectTag));
+  __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
+  __ cmp(r1, ip);
+  slow_case.Branch(eq);
+
+  frame_->EmitPush(r1);
+  exit.Jump();
+
+  slow_case.Bind();
+  frame_->EmitPush(r0);
+  frame_->CallRuntime(Runtime::kCharFromCode, 1);
+  frame_->EmitPush(r0);
+
+  exit.Bind();
+}
+
+
 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
   VirtualFrame::SpilledScope spilled_scope;
   ASSERT(args->length() == 1);
@@ -3625,6 +3684,24 @@ void CodeGenerator::GenerateNumberToString(ZoneList<Expression*>* args) {
 }
 
 
+void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) {
+  ASSERT_EQ(args->length(), 1);
+  // Load the argument on the stack and jump to the runtime.
+  Load(args->at(0));
+  frame_->CallRuntime(Runtime::kMath_sin, 1);
+  frame_->EmitPush(r0);
+}
+
+
+void CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) {
+  ASSERT_EQ(args->length(), 1);
+  // Load the argument on the stack and jump to the runtime.
+  Load(args->at(0));
+  frame_->CallRuntime(Runtime::kMath_cos, 1);
+  frame_->EmitPush(r0);
+}
+
+
 void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) {
   VirtualFrame::SpilledScope spilled_scope;
   ASSERT(args->length() == 2);
@@ -4489,7 +4566,7 @@ void FastNewClosureStub::Generate(MacroAssembler* masm) {
   __ bind(&gc);
   __ push(cp);
   __ push(r3);
-  __ TailCallRuntime(ExternalReference(Runtime::kNewClosure), 2, 1);
+  __ TailCallRuntime(Runtime::kNewClosure, 2, 1);
 }
 
 
@@ -4539,7 +4616,7 @@ void FastNewContextStub::Generate(MacroAssembler* masm) {
 
   // Need to collect. Call into runtime system.
   __ bind(&gc);
-  __ TailCallRuntime(ExternalReference(Runtime::kNewContext), 1, 1);
+  __ TailCallRuntime(Runtime::kNewContext, 1, 1);
 }
 
 
@@ -4601,8 +4678,7 @@ void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) {
   __ Ret();
 
   __ bind(&slow_case);
-  ExternalReference runtime(Runtime::kCreateArrayLiteralShallow);
-  __ TailCallRuntime(runtime, 3, 1);
+  __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1);
 }
 
 
@@ -6170,12 +6246,17 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
 }
 
 
+Handle<Code> GetBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info) {
+  return Handle<Code>::null();
+}
+
+
 void StackCheckStub::Generate(MacroAssembler* masm) {
   // Do tail-call to runtime routine.  Runtime routines expect at least one
   // argument, so give it a Smi.
   __ mov(r0, Operand(Smi::FromInt(0)));
   __ push(r0);
-  __ TailCallRuntime(ExternalReference(Runtime::kStackGuard), 1, 1);
+  __ TailCallRuntime(Runtime::kStackGuard, 1, 1);
 
   __ StubReturn(1);
 }
@@ -6784,7 +6865,7 @@ void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
   // by calling the runtime system.
   __ bind(&slow);
   __ push(r1);
-  __ TailCallRuntime(ExternalReference(Runtime::kGetArgumentsProperty), 1, 1);
+  __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1);
 }
 
 
@@ -6887,7 +6968,7 @@ void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) {
 
   // Do the runtime call to allocate the arguments object.
   __ bind(&runtime);
-  __ TailCallRuntime(ExternalReference(Runtime::kNewArgumentsFast), 3, 1);
+  __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1);
 }
 
 
@@ -7178,6 +7259,170 @@ void StringStubBase::GenerateCopyCharactersLong(MacroAssembler* masm,
 }
 
 
+void StringStubBase::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
+                                                          Register c1,
+                                                          Register c2,
+                                                          Register scratch1,
+                                                          Register scratch2,
+                                                          Register scratch3,
+                                                          Register scratch4,
+                                                          Register scratch5,
+                                                          Label* not_found) {
+  // Register scratch3 is the general scratch register in this function.
+  Register scratch = scratch3;
+
+  // Make sure that both characters are not digits as such strings has a
+  // different hash algorithm. Don't try to look for these in the symbol table.
+  Label not_array_index;
+  __ sub(scratch, c1, Operand(static_cast<int>('0')));
+  __ cmp(scratch, Operand(static_cast<int>('9' - '0')));
+  __ b(hi, &not_array_index);
+  __ sub(scratch, c2, Operand(static_cast<int>('0')));
+  __ cmp(scratch, Operand(static_cast<int>('9' - '0')));
+
+  // If check failed combine both characters into single halfword.
+  // This is required by the contract of the method: code at the
+  // not_found branch expects this combination in c1 register
+  __ orr(c1, c1, Operand(c2, LSL, kBitsPerByte), LeaveCC, ls);
+  __ b(ls, not_found);
+
+  __ bind(&not_array_index);
+  // Calculate the two character string hash.
+  Register hash = scratch1;
+  GenerateHashInit(masm, hash, c1);
+  GenerateHashAddCharacter(masm, hash, c2);
+  GenerateHashGetHash(masm, hash);
+
+  // Collect the two characters in a register.
+  Register chars = c1;
+  __ orr(chars, chars, Operand(c2, LSL, kBitsPerByte));
+
+  // chars: two character string, char 1 in byte 0 and char 2 in byte 1.
+  // hash:  hash of two character string.
+
+  // Load symbol table
+  // Load address of first element of the symbol table.
+  Register symbol_table = c2;
+  __ LoadRoot(symbol_table, Heap::kSymbolTableRootIndex);
+
+  // Load undefined value
+  Register undefined = scratch4;
+  __ LoadRoot(undefined, Heap::kUndefinedValueRootIndex);
+
+  // Calculate capacity mask from the symbol table capacity.
+  Register mask = scratch2;
+  __ ldr(mask, FieldMemOperand(symbol_table, SymbolTable::kCapacityOffset));
+  __ mov(mask, Operand(mask, ASR, 1));
+  __ sub(mask, mask, Operand(1));
+
+  // Calculate untagged address of the first element of the symbol table.
+  Register first_symbol_table_element = symbol_table;
+  __ add(first_symbol_table_element, symbol_table,
+         Operand(SymbolTable::kElementsStartOffset - kHeapObjectTag));
+
+  // Registers
+  // chars: two character string, char 1 in byte 0 and char 2 in byte 1.
+  // hash:  hash of two character string
+  // mask:  capacity mask
+  // first_symbol_table_element: address of the first element of
+  //                             the symbol table
+  // scratch: -
+
+  // Perform a number of probes in the symbol table.
+  static const int kProbes = 4;
+  Label found_in_symbol_table;
+  Label next_probe[kProbes];
+  for (int i = 0; i < kProbes; i++) {
+    Register candidate = scratch5;  // Scratch register contains candidate.
+
+    // Calculate entry in symbol table.
+    if (i > 0) {
+      __ add(candidate, hash, Operand(SymbolTable::GetProbeOffset(i)));
+    } else {
+      __ mov(candidate, hash);
+    }
+
+    __ and_(candidate, candidate, Operand(mask));
+
+    // Load the entry from the symble table.
+    ASSERT_EQ(1, SymbolTable::kEntrySize);
+    __ ldr(candidate,
+           MemOperand(first_symbol_table_element,
+                      candidate,
+                      LSL,
+                      kPointerSizeLog2));
+
+    // If entry is undefined no string with this hash can be found.
+    __ cmp(candidate, undefined);
+    __ b(eq, not_found);
+
+    // If length is not 2 the string is not a candidate.
+    __ ldr(scratch, FieldMemOperand(candidate, String::kLengthOffset));
+    __ cmp(scratch, Operand(2));
+    __ b(ne, &next_probe[i]);
+
+    // Check that the candidate is a non-external ascii string.
+    __ ldr(scratch, FieldMemOperand(candidate, HeapObject::kMapOffset));
+    __ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
+    __ JumpIfInstanceTypeIsNotSequentialAscii(scratch, scratch,
+                                              &next_probe[i]);
+
+    // Check if the two characters match.
+    // Assumes that word load is little endian.
+    __ ldrh(scratch, FieldMemOperand(candidate, SeqAsciiString::kHeaderSize));
+    __ cmp(chars, scratch);
+    __ b(eq, &found_in_symbol_table);
+    __ bind(&next_probe[i]);
+  }
+
+  // No matching 2 character string found by probing.
+  __ jmp(not_found);
+
+  // Scratch register contains result when we fall through to here.
+  Register result = scratch;
+  __ bind(&found_in_symbol_table);
+  if (!result.is(r0)) {
+    __ mov(r0, result);
+  }
+}
+
+
+void StringStubBase::GenerateHashInit(MacroAssembler* masm,
+                                      Register hash,
+                                      Register character) {
+  // hash = character + (character << 10);
+  __ add(hash, character, Operand(character, LSL, 10));
+  // hash ^= hash >> 6;
+  __ eor(hash, hash, Operand(hash, ASR, 6));
+}
+
+
+void StringStubBase::GenerateHashAddCharacter(MacroAssembler* masm,
+                                              Register hash,
+                                              Register character) {
+  // hash += character;
+  __ add(hash, hash, Operand(character));
+  // hash += hash << 10;
+  __ add(hash, hash, Operand(hash, LSL, 10));
+  // hash ^= hash >> 6;
+  __ eor(hash, hash, Operand(hash, ASR, 6));
+}
+
+
+void StringStubBase::GenerateHashGetHash(MacroAssembler* masm,
+                                         Register hash) {
+  // hash += hash << 3;
+  __ add(hash, hash, Operand(hash, LSL, 3));
+  // hash ^= hash >> 11;
+  __ eor(hash, hash, Operand(hash, ASR, 11));
+  // hash += hash << 15;
+  __ add(hash, hash, Operand(hash, LSL, 15), SetCC);
+
+  // if (hash == 0) hash = 27;
+  __ mov(hash, Operand(27), LeaveCC, nz);
+}
+
+
 void SubStringStub::Generate(MacroAssembler* masm) {
   Label runtime;
 
@@ -7213,11 +7458,14 @@ void SubStringStub::Generate(MacroAssembler* masm) {
 
   __ sub(r2, r2, Operand(r3), SetCC);
   __ b(mi, &runtime);  // Fail if from > to.
-  // Handle sub-strings of length 2 and less in the runtime system.
+  // Special handling of sub-strings of length 1 and 2. One character strings
+  // are handled in the runtime system (looked up in the single character
+  // cache). Two character strings are looked for in the symbol cache.
   __ cmp(r2, Operand(2));
-  __ b(le, &runtime);
+  __ b(lt, &runtime);
 
   // r2: length
+  // r3: from index (untaged smi)
   // r6: from (smi)
   // r7: to (smi)
 
@@ -7231,6 +7479,7 @@ void SubStringStub::Generate(MacroAssembler* masm) {
 
   // r1: instance type
   // r2: length
+  // r3: from index (untaged smi)
   // r5: string
   // r6: from (smi)
   // r7: to (smi)
@@ -7257,6 +7506,7 @@ void SubStringStub::Generate(MacroAssembler* masm) {
 
   // r1: instance type.
   // r2: length
+  // r3: from index (untaged smi)
   // r5: string
   // r6: from (smi)
   // r7: to (smi)
@@ -7266,6 +7516,7 @@ void SubStringStub::Generate(MacroAssembler* masm) {
 
   // r1: instance type.
   // r2: result string length.
+  // r3: from index (untaged smi)
   // r5: string.
   // r6: from offset (smi)
   // Check for flat ascii string.
@@ -7274,6 +7525,35 @@ void SubStringStub::Generate(MacroAssembler* masm) {
   ASSERT_EQ(0, kTwoByteStringTag);
   __ b(eq, &non_ascii_flat);
 
+  Label result_longer_than_two;
+  __ cmp(r2, Operand(2));
+  __ b(gt, &result_longer_than_two);
+
+  // Sub string of length 2 requested.
+  // Get the two characters forming the sub string.
+  __ add(r5, r5, Operand(r3));
+  __ ldrb(r3, FieldMemOperand(r5, SeqAsciiString::kHeaderSize));
+  __ ldrb(r4, FieldMemOperand(r5, SeqAsciiString::kHeaderSize + 1));
+
+  // Try to lookup two character string in symbol table.
+  Label make_two_character_string;
+  GenerateTwoCharacterSymbolTableProbe(masm, r3, r4, r1, r5, r6, r7, r9,
+                                       &make_two_character_string);
+  __ IncrementCounter(&Counters::sub_string_native, 1, r3, r4);
+  __ add(sp, sp, Operand(3 * kPointerSize));
+  __ Ret();
+
+  // r2: result string length.
+  // r3: two characters combined into halfword in little endian byte order.
+  __ bind(&make_two_character_string);
+  __ AllocateAsciiString(r0, r2, r4, r5, r9, &runtime);
+  __ strh(r3, FieldMemOperand(r0, SeqAsciiString::kHeaderSize));
+  __ IncrementCounter(&Counters::sub_string_native, 1, r3, r4);
+  __ add(sp, sp, Operand(3 * kPointerSize));
+  __ Ret();
+
+  __ bind(&result_longer_than_two);
+
   // Allocate the result.
   __ AllocateAsciiString(r0, r2, r3, r4, r1, &runtime);
 
@@ -7331,7 +7611,7 @@ void SubStringStub::Generate(MacroAssembler* masm) {
 
   // Just jump to runtime to create the sub string.
   __ bind(&runtime);
-  __ TailCallRuntime(ExternalReference(Runtime::kSubString), 3, 1);
+  __ TailCallRuntime(Runtime::kSubString, 3, 1);
 }
 
 
@@ -7422,7 +7702,7 @@ void StringCompareStub::Generate(MacroAssembler* masm) {
   // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
   // tagged as a small integer.
   __ bind(&runtime);
-  __ TailCallRuntime(ExternalReference(Runtime::kStringCompare), 2, 1);
+  __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
 }
 
 
@@ -7482,14 +7762,52 @@ void StringAddStub::Generate(MacroAssembler* masm) {
   // r4: first string instance type (if string_check_)
   // r5: second string instance type (if string_check_)
   // Look at the length of the result of adding the two strings.
-  Label string_add_flat_result;
+  Label string_add_flat_result, longer_than_two;
   // Adding two lengths can't overflow.
   ASSERT(String::kMaxLength * 2 > String::kMaxLength);
   __ add(r6, r2, Operand(r3));
   // Use the runtime system when adding two one character strings, as it
   // contains optimizations for this specific case using the symbol table.
   __ cmp(r6, Operand(2));
-  __ b(eq, &string_add_runtime);
+  __ b(ne, &longer_than_two);
+
+  // Check that both strings are non-external ascii strings.
+  if (!string_check_) {
+    __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset));
+    __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset));
+    __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset));
+    __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset));
+  }
+  __ JumpIfBothInstanceTypesAreNotSequentialAscii(r4, r5, r6, r7,
+                                                  &string_add_runtime);
+
+  // Get the two characters forming the sub string.
+  __ ldrb(r2, FieldMemOperand(r0, SeqAsciiString::kHeaderSize));
+  __ ldrb(r3, FieldMemOperand(r1, SeqAsciiString::kHeaderSize));
+
+  // Try to lookup two character string in symbol table. If it is not found
+  // just allocate a new one.
+  Label make_two_character_string;
+  GenerateTwoCharacterSymbolTableProbe(masm, r2, r3, r6, r7, r4, r5, r9,
+                                       &make_two_character_string);
+  __ IncrementCounter(&Counters::string_add_native, 1, r2, r3);
+  __ add(sp, sp, Operand(2 * kPointerSize));
+  __ Ret();
+
+  __ bind(&make_two_character_string);
+  // Resulting string has length 2 and first chars of two strings
+  // are combined into single halfword in r2 register.
+  // So we can fill resulting string without two loops by a single
+  // halfword store instruction (which assumes that processor is
+  // in a little endian mode)
+  __ mov(r6, Operand(2));
+  __ AllocateAsciiString(r0, r6, r4, r5, r9, &string_add_runtime);
+  __ strh(r2, FieldMemOperand(r0, SeqAsciiString::kHeaderSize));
+  __ IncrementCounter(&Counters::string_add_native, 1, r2, r3);
+  __ add(sp, sp, Operand(2 * kPointerSize));
+  __ Ret();
+
+  __ bind(&longer_than_two);
   // Check if resulting string will be flat.
   __ cmp(r6, Operand(String::kMinNonFlatLength));
   __ b(lt, &string_add_flat_result);
@@ -7568,6 +7886,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
 
   // Both strings are sequential ASCII strings. We also know that they are
   // short (since the sum of the lengths is less than kMinNonFlatLength).
+  // r6: length of resulting flat string
   __ AllocateAsciiString(r7, r6, r4, r5, r9, &string_add_runtime);
   // Locate first character of result.
   __ add(r6, r7, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
@@ -7636,7 +7955,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
 
   // Just jump to runtime to add the two strings.
   __ bind(&string_add_runtime);
-  __ TailCallRuntime(ExternalReference(Runtime::kStringAdd), 2, 1);
+  __ TailCallRuntime(Runtime::kStringAdd, 2, 1);
 }
 
 
index 2bc482e..bea98b6 100644 (file)
@@ -370,6 +370,9 @@ class CodeGenerator: public AstVisitor {
   // Fast support for charCodeAt(n).
   void GenerateFastCharCodeAt(ZoneList<Expression*>* args);
 
+  // Fast support for string.charAt(n) and string[n].
+  void GenerateCharFromCode(ZoneList<Expression*>* args);
+
   // Fast support for object equality testing.
   void GenerateObjectEquals(ZoneList<Expression*>* args);
 
@@ -393,6 +396,16 @@ class CodeGenerator: public AstVisitor {
   // Fast support for number to string.
   void GenerateNumberToString(ZoneList<Expression*>* args);
 
+  // Fast support for Math.pow().
+  void GenerateMathPow(ZoneList<Expression*>* args);
+
+  // Fast call to sine function.
+  void GenerateMathSin(ZoneList<Expression*>* args);
+  void GenerateMathCos(ZoneList<Expression*>* args);
+
+  // Fast support for Math.pow().
+  void GenerateMathSqrt(ZoneList<Expression*>* args);
+
   // Simple condition analysis.
   enum ConditionAnalysis {
     ALWAYS_TRUE,
@@ -554,6 +567,36 @@ class StringStubBase: public CodeStub {
                                   Register scratch4,
                                   Register scratch5,
                                   int flags);
+
+
+  // Probe the symbol table for a two character string. If the string is
+  // not found by probing a jump to the label not_found is performed. This jump
+  // does not guarantee that the string is not in the symbol table. If the
+  // string is found the code falls through with the string in register r0.
+  // Contents of both c1 and c2 registers are modified. At the exit c1 is
+  // guaranteed to contain halfword with low and high bytes equal to
+  // initial contents of c1 and c2 respectively.
+  void GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
+                                            Register c1,
+                                            Register c2,
+                                            Register scratch1,
+                                            Register scratch2,
+                                            Register scratch3,
+                                            Register scratch4,
+                                            Register scratch5,
+                                            Label* not_found);
+
+  // Generate string hash.
+  void GenerateHashInit(MacroAssembler* masm,
+                        Register hash,
+                        Register character);
+
+  void GenerateHashAddCharacter(MacroAssembler* masm,
+                                Register hash,
+                                Register character);
+
+  void GenerateHashGetHash(MacroAssembler* masm,
+                           Register hash);
 };
 
 
index 0d322d1..5dedc29 100644 (file)
@@ -40,6 +40,7 @@ Register FastCodeGenerator::accumulator0() { return r0; }
 Register FastCodeGenerator::accumulator1() { return r1; }
 Register FastCodeGenerator::scratch0() { return r3; }
 Register FastCodeGenerator::scratch1() { return r4; }
+Register FastCodeGenerator::scratch2() { return r5; }
 Register FastCodeGenerator::receiver_reg() { return r2; }
 Register FastCodeGenerator::context_reg() { return cp; }
 
@@ -100,7 +101,7 @@ void FastCodeGenerator::EmitThisPropertyStore(Handle<String> name) {
 
   if (needs_write_barrier) {
     __ mov(scratch1(), Operand(offset));
-    __ RecordWrite(scratch0(), scratch1(), ip);
+    __ RecordWrite(scratch0(), scratch1(), scratch2());
   }
 
   if (destination().is(accumulator1())) {
@@ -180,6 +181,7 @@ void FastCodeGenerator::EmitBitOr() {
 void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
   ASSERT(info_ == NULL);
   info_ = compilation_info;
+  Comment cmnt(masm_, "[ function compiled by fast code generator");
 
   // Save the caller's frame pointer and set up our own.
   Comment prologue_cmnt(masm(), ";; Prologue");
index c37e29f..230818f 100644 (file)
@@ -57,6 +57,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info, Mode mode) {
   ASSERT(info_ == NULL);
   info_ = info;
   SetFunctionPosition(function());
+  Comment cmnt(masm_, "[ function compiled by full code generator");
 
   if (mode == PRIMARY) {
     int locals_count = scope()->num_stack_slots();
index 7ddb338..e68a77a 100644 (file)
@@ -494,7 +494,8 @@ void LoadIC::GenerateMiss(MacroAssembler* masm) {
   __ stm(db_w, sp, r2.bit() | r3.bit());
 
   // Perform tail call to the entry.
-  __ TailCallRuntime(ExternalReference(IC_Utility(kLoadIC_Miss)), 2, 1);
+  ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss));
+  __ TailCallExternalReference(ref, 2, 1);
 }
 
 
@@ -531,7 +532,8 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
   __ ldm(ia, sp, r2.bit() | r3.bit());
   __ stm(db_w, sp, r2.bit() | r3.bit());
 
-  __ TailCallRuntime(ExternalReference(IC_Utility(kKeyedLoadIC_Miss)), 2, 1);
+  ExternalReference ref = ExternalReference(IC_Utility(kKeyedLoadIC_Miss));
+  __ TailCallExternalReference(ref, 2, 1);
 }
 
 
@@ -545,7 +547,7 @@ void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
   __ ldm(ia, sp, r2.bit() | r3.bit());
   __ stm(db_w, sp, r2.bit() | r3.bit());
 
-  __ TailCallRuntime(ExternalReference(Runtime::kGetProperty), 2, 1);
+  __ TailCallRuntime(Runtime::kGetProperty, 2, 1);
 }
 
 
@@ -662,7 +664,7 @@ void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
   __ push(r0);  // key
 
   // Perform tail call to the entry.
-  __ TailCallRuntime(ExternalReference(
+  __ TailCallExternalReference(ExternalReference(
         IC_Utility(kKeyedLoadPropertyWithInterceptor)), 2, 1);
 
   __ bind(&slow);
@@ -681,7 +683,8 @@ void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
   __ ldm(ia, sp, r2.bit() | r3.bit());
   __ stm(db_w, sp, r0.bit() | r2.bit() | r3.bit());
 
-  __ TailCallRuntime(ExternalReference(IC_Utility(kKeyedStoreIC_Miss)), 3, 1);
+  ExternalReference ref = ExternalReference(IC_Utility(kKeyedStoreIC_Miss));
+  __ TailCallExternalReference(ref, 3, 1);
 }
 
 
@@ -695,7 +698,7 @@ void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm) {
   __ ldm(ia, sp, r1.bit() | r3.bit());  // r0 == value, r1 == key, r3 == object
   __ stm(db_w, sp, r0.bit() | r1.bit() | r3.bit());
 
-  __ TailCallRuntime(ExternalReference(Runtime::kSetProperty), 3, 1);
+  __ TailCallRuntime(Runtime::kSetProperty, 3, 1);
 }
 
 
@@ -854,7 +857,8 @@ void StoreIC::GenerateMiss(MacroAssembler* masm) {
   __ stm(db_w, sp, r2.bit() | r0.bit());
 
   // Perform tail call to the entry.
-  __ TailCallRuntime(ExternalReference(IC_Utility(kStoreIC_Miss)), 3, 1);
+  ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_Miss));
+  __ TailCallExternalReference(ref, 3, 1);
 }
 
 
@@ -897,7 +901,8 @@ void StoreIC::GenerateArrayLength(MacroAssembler* masm) {
   __ push(receiver);
   __ push(value);
 
-  __ TailCallRuntime(ExternalReference(IC_Utility(kStoreIC_ArrayLength)), 2, 1);
+  ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_ArrayLength));
+  __ TailCallExternalReference(ref, 2, 1);
 
   __ bind(&miss);
 
index b249d69..36bebdf 100644 (file)
@@ -220,7 +220,7 @@ void MacroAssembler::RecordWrite(Register object, Register offset,
   // remembered set bits in the new space.
   // object: heap object pointer (with tag)
   // offset: offset to store location from the object
-  and_(scratch, object, Operand(Heap::NewSpaceMask()));
+  and_(scratch, object, Operand(ExternalReference::new_space_mask()));
   cmp(scratch, Operand(ExternalReference::new_space_start()));
   b(eq, &done);
 
@@ -1234,19 +1234,26 @@ void MacroAssembler::CallExternalReference(const ExternalReference& ext,
 }
 
 
-void MacroAssembler::TailCallRuntime(const ExternalReference& ext,
-                                     int num_arguments,
-                                     int result_size) {
+void MacroAssembler::TailCallExternalReference(const ExternalReference& ext,
+                                               int num_arguments,
+                                               int result_size) {
   // TODO(1236192): Most runtime routines don't need the number of
   // arguments passed in because it is constant. At some point we
   // should remove this need and make the runtime routine entry code
   // smarter.
   mov(r0, Operand(num_arguments));
-  JumpToRuntime(ext);
+  JumpToExternalReference(ext);
+}
+
+
+void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid,
+                                     int num_arguments,
+                                     int result_size) {
+  TailCallExternalReference(ExternalReference(fid), num_arguments, result_size);
 }
 
 
-void MacroAssembler::JumpToRuntime(const ExternalReference& builtin) {
+void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin) {
 #if defined(__thumb__)
   // Thumb mode builtin.
   ASSERT((reinterpret_cast<intptr_t>(builtin.address()) & 1) == 1);
@@ -1410,15 +1417,12 @@ void MacroAssembler::JumpIfNonSmisNotBothSequentialAsciiStrings(
   ldr(scratch2, FieldMemOperand(second, HeapObject::kMapOffset));
   ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
   ldrb(scratch2, FieldMemOperand(scratch2, Map::kInstanceTypeOffset));
-  int kFlatAsciiStringMask =
-      kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask;
-  int kFlatAsciiStringTag = ASCII_STRING_TYPE;
-  and_(scratch1, scratch1, Operand(kFlatAsciiStringMask));
-  and_(scratch2, scratch2, Operand(kFlatAsciiStringMask));
-  cmp(scratch1, Operand(kFlatAsciiStringTag));
-  // Ignore second test if first test failed.
-  cmp(scratch2, Operand(kFlatAsciiStringTag), eq);
-  b(ne, failure);
+
+  JumpIfBothInstanceTypesAreNotSequentialAscii(scratch1,
+                                               scratch2,
+                                               scratch1,
+                                               scratch2,
+                                               failure);
 }
 
 void MacroAssembler::JumpIfNotBothSequentialAsciiStrings(Register first,
@@ -1439,6 +1443,36 @@ void MacroAssembler::JumpIfNotBothSequentialAsciiStrings(Register first,
 }
 
 
+void MacroAssembler::JumpIfBothInstanceTypesAreNotSequentialAscii(
+    Register first,
+    Register second,
+    Register scratch1,
+    Register scratch2,
+    Label* failure) {
+  int kFlatAsciiStringMask =
+      kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask;
+  int kFlatAsciiStringTag = ASCII_STRING_TYPE;
+  and_(scratch1, first, Operand(kFlatAsciiStringMask));
+  and_(scratch2, second, Operand(kFlatAsciiStringMask));
+  cmp(scratch1, Operand(kFlatAsciiStringTag));
+  // Ignore second test if first test failed.
+  cmp(scratch2, Operand(kFlatAsciiStringTag), eq);
+  b(ne, failure);
+}
+
+
+void MacroAssembler::JumpIfInstanceTypeIsNotSequentialAscii(Register type,
+                                                            Register scratch,
+                                                            Label* failure) {
+  int kFlatAsciiStringMask =
+      kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask;
+  int kFlatAsciiStringTag = ASCII_STRING_TYPE;
+  and_(scratch, type, Operand(kFlatAsciiStringMask));
+  cmp(scratch, Operand(kFlatAsciiStringTag));
+  b(ne, failure);
+}
+
+
 #ifdef ENABLE_DEBUGGER_SUPPORT
 CodePatcher::CodePatcher(byte* address, int instructions)
     : address_(address),
index 98cea16..5d9e513 100644 (file)
@@ -333,7 +333,6 @@ class MacroAssembler: public Assembler {
   void StubReturn(int argc);
 
   // Call a runtime routine.
-  // Eventually this should be used for all C calls.
   void CallRuntime(Runtime::Function* f, int num_arguments);
 
   // Convenience function: Same as above, but takes the fid instead.
@@ -344,14 +343,19 @@ class MacroAssembler: public Assembler {
                              int num_arguments);
 
   // Tail call of a runtime routine (jump).
-  // Like JumpToRuntime, but also takes care of passing the number
+  // Like JumpToExternalReference, but also takes care of passing the number
   // of parameters.
-  void TailCallRuntime(const ExternalReference& ext,
+  void TailCallExternalReference(const ExternalReference& ext,
+                                 int num_arguments,
+                                 int result_size);
+
+  // Convenience function: tail call a runtime routine (jump).
+  void TailCallRuntime(Runtime::FunctionId fid,
                        int num_arguments,
                        int result_size);
 
   // Jump to a runtime routine.
-  void JumpToRuntime(const ExternalReference& builtin);
+  void JumpToExternalReference(const ExternalReference& builtin);
 
   // Invoke specified builtin JavaScript function. Adds an entry to
   // the unresolved list if the name does not resolve.
@@ -421,6 +425,22 @@ class MacroAssembler: public Assembler {
                                            Register scratch2,
                                            Label* not_flat_ascii_strings);
 
+  // Checks if both instance types are sequential ASCII strings and jumps to
+  // label if either is not.
+  void JumpIfBothInstanceTypesAreNotSequentialAscii(
+      Register first_object_instance_type,
+      Register second_object_instance_type,
+      Register scratch1,
+      Register scratch2,
+      Label* failure);
+
+  // Check if instance type is sequential ASCII string and jump to label if
+  // it is not.
+  void JumpIfInstanceTypeIsNotSequentialAscii(Register type,
+                                              Register scratch,
+                                              Label* failure);
+
+
  private:
   void Jump(intptr_t target, RelocInfo::Mode rmode, Condition cond = al);
   void Call(intptr_t target, RelocInfo::Mode rmode, Condition cond = al);
index 9dd3b93..f621be4 100644 (file)
@@ -765,7 +765,7 @@ Handle<Object> RegExpMacroAssemblerARM::GetCode(Handle<String> source) {
     Label grow_failed;
 
     // Call GrowStack(backtrack_stackpointer())
-    int num_arguments = 2;
+    static const int num_arguments = 2;
     FrameAlign(num_arguments, r0);
     __ mov(r0, backtrack_stackpointer());
     __ add(r1, frame_pointer(), Operand(kStackHighEnd));
@@ -966,7 +966,7 @@ void RegExpMacroAssemblerARM::WriteStackPointerToRegister(int reg) {
 // Private methods:
 
 void RegExpMacroAssemblerARM::CallCheckStackGuardState(Register scratch) {
-  int num_arguments = 3;
+  static const int num_arguments = 3;
   FrameAlign(num_arguments, scratch);
   // RegExp code frame pointer.
   __ mov(r2, frame_pointer());
index da73942..5d5b2a5 100644 (file)
@@ -297,7 +297,7 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
     __ push(receiver_reg);
     __ mov(r2, Operand(Handle<Map>(transition)));
     __ stm(db_w, sp, r2.bit() | r0.bit());
-    __ TailCallRuntime(
+    __ TailCallExternalReference(
            ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage)),
            3, 1);
     return;
@@ -529,7 +529,7 @@ class LoadInterceptorCompiler BASE_EMBEDDED {
 
       ExternalReference ref =
           ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
-      __ TailCallRuntime(ref, 5, 1);
+      __ TailCallExternalReference(ref, 5, 1);
 
       __ bind(&cleanup);
       __ pop(scratch1);
@@ -549,7 +549,7 @@ class LoadInterceptorCompiler BASE_EMBEDDED {
 
     ExternalReference ref = ExternalReference(
         IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
-    __ TailCallRuntime(ref, 5, 1);
+    __ TailCallExternalReference(ref, 5, 1);
   }
 
  private:
@@ -719,7 +719,7 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object,
   // Do tail-call to the runtime system.
   ExternalReference load_callback_property =
       ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
-  __ TailCallRuntime(load_callback_property, 5, 1);
+  __ TailCallExternalReference(load_callback_property, 5, 1);
 
   return true;
 }
@@ -1204,7 +1204,7 @@ Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
   // Do tail-call to the runtime system.
   ExternalReference store_callback_property =
       ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
-  __ TailCallRuntime(store_callback_property, 4, 1);
+  __ TailCallExternalReference(store_callback_property, 4, 1);
 
   // Handle store cache miss.
   __ bind(&miss);
@@ -1251,7 +1251,7 @@ Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
   // Do tail-call to the runtime system.
   ExternalReference store_ic_property =
       ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
-  __ TailCallRuntime(store_ic_property, 3, 1);
+  __ TailCallExternalReference(store_ic_property, 3, 1);
 
   // Handle store cache miss.
   __ bind(&miss);
index 6e1a47f..ab6e5f8 100644 (file)
 namespace v8 {
 namespace internal {
 
-// -------------------------------------------------------------------------
-// VirtualFrame implementation.
-
 #define __ ACCESS_MASM(masm())
 
-
-// On entry to a function, the virtual frame already contains the
-// receiver and the parameters.  All initial frame elements are in
-// memory.
-VirtualFrame::VirtualFrame()
-    : elements_(parameter_count() + local_count() + kPreallocatedElements),
-      stack_pointer_(parameter_count()) {  // 0-based index of TOS.
-  for (int i = 0; i <= stack_pointer_; i++) {
-    elements_.Add(FrameElement::MemoryElement(NumberInfo::kUnknown));
-  }
-  for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
-    register_locations_[i] = kIllegalIndex;
-  }
-}
-
-
 void VirtualFrame::SyncElementBelowStackPointer(int index) {
   UNREACHABLE();
 }
@@ -314,7 +295,7 @@ void VirtualFrame::EmitPop(Register reg) {
 
 void VirtualFrame::EmitPush(Register reg) {
   ASSERT(stack_pointer_ == element_count() - 1);
-  elements_.Add(FrameElement::MemoryElement(NumberInfo::kUnknown));
+  elements_.Add(FrameElement::MemoryElement(NumberInfo::Unknown()));
   stack_pointer_++;
   __ push(reg);
 }
index f69bddf..6eb0811 100644 (file)
@@ -59,7 +59,7 @@ class VirtualFrame : public ZoneObject {
   static const int kIllegalIndex = -1;
 
   // Construct an initial virtual frame on entry to a JS function.
-  VirtualFrame();
+  inline VirtualFrame();
 
   // Construct a virtual frame as a clone of an existing one.
   explicit inline VirtualFrame(VirtualFrame* original);
@@ -69,7 +69,7 @@ class VirtualFrame : public ZoneObject {
 
   // Create a duplicate of an existing valid frame element.
   FrameElement CopyElementAt(int index,
-                             NumberInfo::Type info = NumberInfo::kUnknown);
+                             NumberInfo info = NumberInfo::Unknown());
 
   // The number of elements on the virtual frame.
   int element_count() { return elements_.length(); }
@@ -344,7 +344,7 @@ class VirtualFrame : public ZoneObject {
   void EmitPushMultiple(int count, int src_regs);
 
   // Push an element on the virtual frame.
-  inline void Push(Register reg, NumberInfo::Type info = NumberInfo::kUnknown);
+  inline void Push(Register reg, NumberInfo info = NumberInfo::Unknown());
   inline void Push(Handle<Object> value);
   inline void Push(Smi* value);
 
index c28a662..e33c280 100644 (file)
@@ -1149,6 +1149,8 @@ function SetupArray() {
     ArrayReduce: 1,
     ArrayReduceRight: 1
   });
+
+  %FinishArrayPrototypeSetup($Array.prototype);
 }
 
 
index 96d516f..aaf10ef 100644 (file)
@@ -579,6 +579,11 @@ ExternalReference ExternalReference::random_positive_smi_function() {
 }
 
 
+ExternalReference ExternalReference::transcendental_cache_array_address() {
+  return ExternalReference(TranscendentalCache::cache_array_address());
+}
+
+
 ExternalReference ExternalReference::keyed_lookup_cache_keys() {
   return ExternalReference(KeyedLookupCache::keys_address());
 }
@@ -619,6 +624,11 @@ ExternalReference ExternalReference::new_space_start() {
 }
 
 
+ExternalReference ExternalReference::new_space_mask() {
+  return ExternalReference(reinterpret_cast<Address>(Heap::NewSpaceMask()));
+}
+
+
 ExternalReference ExternalReference::new_space_allocation_top_address() {
   return ExternalReference(Heap::NewSpaceAllocationTopAddress());
 }
index f401306..cde7d69 100644 (file)
@@ -37,7 +37,6 @@
 
 #include "runtime.h"
 #include "top.h"
-#include "zone-inl.h"
 #include "token.h"
 
 namespace v8 {
@@ -400,6 +399,7 @@ class ExternalReference BASE_EMBEDDED {
 
   static ExternalReference perform_gc_function();
   static ExternalReference random_positive_smi_function();
+  static ExternalReference transcendental_cache_array_address();
 
   // Static data in the keyed lookup cache.
   static ExternalReference keyed_lookup_cache_keys();
@@ -427,6 +427,7 @@ class ExternalReference BASE_EMBEDDED {
 
   // Static variable Heap::NewSpaceStart()
   static ExternalReference new_space_start();
+  static ExternalReference new_space_mask();
   static ExternalReference heap_always_allocate_scope_depth();
 
   // Used for fast allocation in generated code.
index 7cb5578..062a5c6 100644 (file)
@@ -67,8 +67,6 @@ VariableProxy::VariableProxy(Handle<String> name,
     inside_with_(inside_with) {
   // names must be canonicalized for fast equality checks
   ASSERT(name->IsSymbol());
-  // at least one access, otherwise no need for a VariableProxy
-  var_uses_.RecordRead(1);
 }
 
 
@@ -87,8 +85,7 @@ void VariableProxy::BindTo(Variable* var) {
   // eval() etc.  Const-ness and variable declarations are a complete mess
   // in JS. Sigh...
   var_ = var;
-  var->var_uses()->RecordUses(&var_uses_);
-  var->obj_uses()->RecordUses(&obj_uses_);
+  var->set_is_used(true);
 }
 
 
index f2171cc..13502dc 100644 (file)
@@ -117,6 +117,9 @@ typedef ZoneList<Handle<Object> > ZoneObjectList;
 
 class AstNode: public ZoneObject {
  public:
+  static const int kNoNumber = -1;
+
+  AstNode() : num_(kNoNumber) {}
   virtual ~AstNode() { }
   virtual void Accept(AstVisitor* v) = 0;
 
@@ -141,6 +144,13 @@ class AstNode: public ZoneObject {
   virtual ObjectLiteral* AsObjectLiteral() { return NULL; }
   virtual ArrayLiteral* AsArrayLiteral() { return NULL; }
   virtual CompareOperation* AsCompareOperation() { return NULL; }
+
+  int num() { return num_; }
+  void set_num(int n) { num_ = n; }
+
+ private:
+  // Support for ast node numbering.
+  int num_;
 };
 
 
@@ -181,9 +191,10 @@ class Expression: public AstNode {
     kTestValue
   };
 
-  static const int kNoLabel = -1;
-
-  Expression() : num_(kNoLabel), def_(NULL), defined_vars_(NULL) {}
+  Expression()
+      : bitfields_(0),
+        def_(NULL),
+        defined_vars_(NULL) {}
 
   virtual Expression* AsExpression()  { return this; }
 
@@ -211,11 +222,6 @@ class Expression: public AstNode {
   // Static type information for this expression.
   StaticType* type() { return &type_; }
 
-  int num() { return num_; }
-
-  // AST node numbering ordered by evaluation order.
-  void set_num(int n) { num_ = n; }
-
   // Data flow information.
   DefinitionInfo* var_def() { return def_; }
   void set_var_def(DefinitionInfo* def) { def_ = def; }
@@ -225,11 +231,36 @@ class Expression: public AstNode {
     defined_vars_ = defined_vars;
   }
 
+  // AST analysis results
+
+  // True if the expression rooted at this node can be compiled by the
+  // side-effect free compiler.
+  bool side_effect_free() { return SideEffectFreeField::decode(bitfields_); }
+  void set_side_effect_free(bool is_side_effect_free) {
+    bitfields_ &= ~SideEffectFreeField::mask();
+    bitfields_ |= SideEffectFreeField::encode(is_side_effect_free);
+  }
+
+  // Will ToInt32 (ECMA 262-3 9.5) or ToUint32 (ECMA 262-3 9.6)
+  // be applied to the value of this expression?
+  // If so, we may be able to optimize the calculation of the value.
+  bool to_int32() { return ToInt32Field::decode(bitfields_); }
+  void set_to_int32(bool to_int32) {
+    bitfields_ &= ~ToInt32Field::mask();
+    bitfields_ |= ToInt32Field::encode(to_int32);
+  }
+
+
  private:
+  uint32_t bitfields_;
   StaticType type_;
-  int num_;
+
   DefinitionInfo* def_;
   ZoneList<DefinitionInfo*>* defined_vars_;
+
+  // Using template BitField<type, start, size>.
+  class SideEffectFreeField : public BitField<bool, 0, 1> {};
+  class ToInt32Field : public BitField<bool, 1, 1> {};
 };
 
 
@@ -931,6 +962,10 @@ class VariableProxy: public Expression {
     return var()->is_global() || var()->rewrite()->IsLeaf();
   }
 
+  // Reading from a mutable variable is a side effect, but 'this' is
+  // immutable.
+  virtual bool IsTrivial() { return is_this(); }
+
   bool IsVariable(Handle<String> n) {
     return !is_this() && name().is_identical_to(n);
   }
@@ -942,8 +977,6 @@ class VariableProxy: public Expression {
 
   Handle<String> name() const  { return name_; }
   Variable* var() const  { return var_; }
-  UseCount* var_uses()  { return &var_uses_; }
-  UseCount* obj_uses()  { return &obj_uses_; }
   bool is_this() const  { return is_this_; }
   bool inside_with() const  { return inside_with_; }
 
@@ -956,10 +989,6 @@ class VariableProxy: public Expression {
   bool is_this_;
   bool inside_with_;
 
-  // VariableProxy usage info.
-  UseCount var_uses_;  // uses of the variable value
-  UseCount obj_uses_;  // uses of the object the variable points to
-
   VariableProxy(Handle<String> name, bool is_this, bool inside_with);
   explicit VariableProxy(bool is_this);
 
@@ -1018,6 +1047,8 @@ class Slot: public Expression {
 
   virtual bool IsLeaf() { return true; }
 
+  bool IsStackAllocated() { return type_ == PARAMETER || type_ == LOCAL; }
+
   // Accessors
   Variable* var() const { return var_; }
   Type type() const { return type_; }
index a7cf421..12efbc1 100644 (file)
@@ -1050,6 +1050,19 @@ bool Genesis::InstallNatives() {
     script->set_type(Smi::FromInt(Script::TYPE_NATIVE));
     global_context()->set_empty_script(*script);
   }
+  {
+    // Builtin function for OpaqueReference -- a JSValue-based object,
+    // that keeps its field isolated from JavaScript code. It may store
+    // objects, that JavaScript code may not access.
+    Handle<JSFunction> opaque_reference_fun =
+        InstallFunction(builtins, "OpaqueReference", JS_VALUE_TYPE,
+                        JSValue::kSize, Top::initial_object_prototype(),
+                        Builtins::Illegal, false);
+    Handle<JSObject> prototype =
+        Factory::NewJSObject(Top::object_function(), TENURED);
+    SetPrototype(opaque_reference_fun, prototype);
+    global_context()->set_opaque_reference_function(*opaque_reference_fun);
+  }
 
   if (FLAG_natives_file == NULL) {
     // Without natives file, install default natives.
index 8e88c28..a8ba818 100644 (file)
@@ -242,6 +242,109 @@ BUILTIN(ArrayCodeGeneric) {
 }
 
 
+static Object* AllocateJSArray() {
+  JSFunction* array_function =
+      Top::context()->global_context()->array_function();
+  Object* result = Heap::AllocateJSObject(array_function);
+  if (result->IsFailure()) return result;
+  return result;
+}
+
+
+static Object* AllocateEmptyJSArray() {
+  Object* result = AllocateJSArray();
+  if (result->IsFailure()) return result;
+  JSArray* result_array = JSArray::cast(result);
+  result_array->set_length(Smi::FromInt(0));
+  result_array->set_elements(Heap::empty_fixed_array());
+  return result_array;
+}
+
+
+static void CopyElements(AssertNoAllocation* no_gc,
+                         FixedArray* dst,
+                         int dst_index,
+                         FixedArray* src,
+                         int src_index,
+                         int len) {
+  ASSERT(dst != src);  // Use MoveElements instead.
+  memcpy(dst->data_start() + dst_index,
+         src->data_start() + src_index,
+         len * kPointerSize);
+  WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc);
+  if (mode == UPDATE_WRITE_BARRIER) {
+    Heap::RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
+  }
+}
+
+
+static void MoveElements(AssertNoAllocation* no_gc,
+                         FixedArray* dst,
+                         int dst_index,
+                         FixedArray* src,
+                         int src_index,
+                         int len) {
+  memmove(dst->data_start() + dst_index,
+          src->data_start() + src_index,
+          len * kPointerSize);
+  WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc);
+  if (mode == UPDATE_WRITE_BARRIER) {
+    Heap::RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
+  }
+}
+
+
+static void FillWithHoles(FixedArray* dst, int from, int to) {
+  MemsetPointer(dst->data_start() + from, Heap::the_hole_value(), to - from);
+}
+
+
+static bool ArrayPrototypeHasNoElements() {
+  // This method depends on non writability of Object and Array prototype
+  // fields.
+  Context* global_context = Top::context()->global_context();
+  // Array.prototype
+  JSObject* proto =
+      JSObject::cast(global_context->array_function()->prototype());
+  if (proto->elements() != Heap::empty_fixed_array()) return false;
+  // Hidden prototype
+  proto = JSObject::cast(proto->GetPrototype());
+  ASSERT(proto->elements() == Heap::empty_fixed_array());
+  // Object.prototype
+  proto = JSObject::cast(proto->GetPrototype());
+  if (proto != global_context->initial_object_prototype()) return false;
+  if (proto->elements() != Heap::empty_fixed_array()) return false;
+  ASSERT(proto->GetPrototype()->IsNull());
+  return true;
+}
+
+
+static Object* CallJsBuiltin(const char* name,
+                             BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
+  HandleScope handleScope;
+
+  Handle<Object> js_builtin =
+      GetProperty(Handle<JSObject>(Top::global_context()->builtins()),
+                  name);
+  ASSERT(js_builtin->IsJSFunction());
+  Handle<JSFunction> function(Handle<JSFunction>::cast(js_builtin));
+  Vector<Object**> argv(Vector<Object**>::New(args.length() - 1));
+  int n_args = args.length() - 1;
+  for (int i = 0; i < n_args; i++) {
+    argv[i] = &args[i + 1];
+  }
+  bool pending_exception = false;
+  Handle<Object> result = Execution::Call(function,
+                                          args.receiver(),
+                                          n_args,
+                                          argv.start(),
+                                          &pending_exception);
+  argv.Dispose();
+  if (pending_exception) return Failure::Exception();
+  return *result;
+}
+
+
 BUILTIN(ArrayPush) {
   JSArray* array = JSArray::cast(*args.receiver());
   ASSERT(array->HasFastElements());
@@ -261,22 +364,21 @@ BUILTIN(ArrayPush) {
   if (new_length > elms->length()) {
     // New backing storage is needed.
     int capacity = new_length + (new_length >> 1) + 16;
-    Object* obj = Heap::AllocateFixedArrayWithHoles(capacity);
+    Object* obj = Heap::AllocateUninitializedFixedArray(capacity);
     if (obj->IsFailure()) return obj;
+    FixedArray* new_elms = FixedArray::cast(obj);
 
     AssertNoAllocation no_gc;
-    FixedArray* new_elms = FixedArray::cast(obj);
-    WriteBarrierMode mode = new_elms->GetWriteBarrierMode(no_gc);
-    // Fill out the new array with old elements.
-    for (int i = 0; i < len; i++) new_elms->set(i, elms->get(i), mode);
+    CopyElements(&no_gc, new_elms, 0, elms, 0, len);
+    FillWithHoles(new_elms, new_length, capacity);
+
     elms = new_elms;
     array->set_elements(elms);
   }
 
+  // Add the provided values.
   AssertNoAllocation no_gc;
   WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
-
-  // Add the provided values.
   for (int index = 0; index < to_add; index++) {
     elms->set(index + len, args[index + 1], mode);
   }
@@ -290,10 +392,9 @@ BUILTIN(ArrayPush) {
 BUILTIN(ArrayPop) {
   JSArray* array = JSArray::cast(*args.receiver());
   ASSERT(array->HasFastElements());
-  Object* undefined = Heap::undefined_value();
 
   int len = Smi::cast(array->length())->value();
-  if (len == 0) return undefined;
+  if (len == 0) return Heap::undefined_value();
 
   // Get top element
   FixedArray* elms = FixedArray::cast(array->elements());
@@ -318,41 +419,28 @@ BUILTIN(ArrayPop) {
 }
 
 
-static Object* GetElementToMove(uint32_t index,
-                                FixedArray* elms,
-                                JSObject* prototype) {
-  Object* e = elms->get(index);
-  if (e->IsTheHole() && prototype->HasElement(index)) {
-    e = prototype->GetElement(index);
+BUILTIN(ArrayShift) {
+  if (!ArrayPrototypeHasNoElements()) {
+    return CallJsBuiltin("ArrayShift", args);
   }
-  return e;
-}
 
-
-BUILTIN(ArrayShift) {
   JSArray* array = JSArray::cast(*args.receiver());
   ASSERT(array->HasFastElements());
 
   int len = Smi::cast(array->length())->value();
   if (len == 0) return Heap::undefined_value();
 
-  // Fetch the prototype.
-  JSFunction* array_function =
-      Top::context()->global_context()->array_function();
-  JSObject* prototype = JSObject::cast(array_function->prototype());
-
   FixedArray* elms = FixedArray::cast(array->elements());
 
   // Get first element
   Object* first = elms->get(0);
   if (first->IsTheHole()) {
-    first = prototype->GetElement(0);
+    first = Heap::undefined_value();
   }
 
   // Shift the elements.
-  for (int i = 0; i < len - 1; i++) {
-    elms->set(i, GetElementToMove(i + 1, elms, prototype));
-  }
+  AssertNoAllocation no_gc;
+  MoveElements(&no_gc, elms, 0, elms, 1, len - 1);
   elms->set(len - 1, Heap::the_hole_value());
 
   // Set the length.
@@ -363,6 +451,10 @@ BUILTIN(ArrayShift) {
 
 
 BUILTIN(ArrayUnshift) {
+  if (!ArrayPrototypeHasNoElements()) {
+    return CallJsBuiltin("ArrayUnshift", args);
+  }
+
   JSArray* array = JSArray::cast(*args.receiver());
   ASSERT(array->HasFastElements());
 
@@ -379,38 +471,22 @@ BUILTIN(ArrayUnshift) {
 
   FixedArray* elms = FixedArray::cast(array->elements());
 
-  // Fetch the prototype.
-  JSFunction* array_function =
-      Top::context()->global_context()->array_function();
-  JSObject* prototype = JSObject::cast(array_function->prototype());
-
   if (new_length > elms->length()) {
     // New backing storage is needed.
     int capacity = new_length + (new_length >> 1) + 16;
-    Object* obj = Heap::AllocateFixedArrayWithHoles(capacity);
+    Object* obj = Heap::AllocateUninitializedFixedArray(capacity);
     if (obj->IsFailure()) return obj;
+    FixedArray* new_elms = FixedArray::cast(obj);
 
     AssertNoAllocation no_gc;
-    FixedArray* new_elms = FixedArray::cast(obj);
-    WriteBarrierMode mode = new_elms->GetWriteBarrierMode(no_gc);
-    // Fill out the new array with old elements.
-    for (int i = 0; i < len; i++)
-      new_elms->set(to_add + i,
-                    GetElementToMove(i, elms, prototype),
-                    mode);
+    CopyElements(&no_gc, new_elms, to_add, elms, 0, len);
+    FillWithHoles(new_elms, new_length, capacity);
 
     elms = new_elms;
     array->set_elements(elms);
   } else {
     AssertNoAllocation no_gc;
-    WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
-
-    // Move elements to the right
-    for (int i = 0; i < len; i++) {
-      elms->set(new_length - i - 1,
-                GetElementToMove(len - i - 1, elms, prototype),
-                mode);
-    }
+    MoveElements(&no_gc, elms, to_add, elms, 0, len);
   }
 
   // Add the provided values.
@@ -426,32 +502,11 @@ BUILTIN(ArrayUnshift) {
 }
 
 
-static Object* CallJsBuiltin(const char* name,
-                             BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
-  HandleScope handleScope;
-
-  Handle<Object> js_builtin =
-      GetProperty(Handle<JSObject>(Top::global_context()->builtins()),
-                  name);
-  ASSERT(js_builtin->IsJSFunction());
-  Handle<JSFunction> function(Handle<JSFunction>::cast(js_builtin));
-  Vector<Object**> argv(Vector<Object**>::New(args.length() - 1));
-  int n_args = args.length() - 1;
-  for (int i = 0; i < n_args; i++) {
-    argv[i] = &args[i + 1];
+BUILTIN(ArraySlice) {
+  if (!ArrayPrototypeHasNoElements()) {
+    return CallJsBuiltin("ArraySlice", args);
   }
-  bool pending_exception = false;
-  Handle<Object> result = Execution::Call(function,
-                                          args.receiver(),
-                                          n_args,
-                                          argv.start(),
-                                          &pending_exception);
-  if (pending_exception) return Failure::Exception();
-  return *result;
-}
-
 
-BUILTIN(ArraySlice) {
   JSArray* array = JSArray::cast(*args.receiver());
   ASSERT(array->HasFastElements());
 
@@ -460,21 +515,21 @@ BUILTIN(ArraySlice) {
   int n_arguments = args.length() - 1;
 
   // Note carefully choosen defaults---if argument is missing,
-  // it's undefined which gets converted to 0 for relativeStart
-  // and to len for relativeEnd.
-  int relativeStart = 0;
-  int relativeEnd = len;
+  // it's undefined which gets converted to 0 for relative_start
+  // and to len for relative_end.
+  int relative_start = 0;
+  int relative_end = len;
   if (n_arguments > 0) {
     Object* arg1 = args[1];
     if (arg1->IsSmi()) {
-      relativeStart = Smi::cast(arg1)->value();
+      relative_start = Smi::cast(arg1)->value();
     } else if (!arg1->IsUndefined()) {
       return CallJsBuiltin("ArraySlice", args);
     }
     if (n_arguments > 1) {
       Object* arg2 = args[2];
       if (arg2->IsSmi()) {
-        relativeEnd = Smi::cast(arg2)->value();
+        relative_end = Smi::cast(arg2)->value();
       } else if (!arg2->IsUndefined()) {
         return CallJsBuiltin("ArraySlice", args);
       }
@@ -482,43 +537,31 @@ BUILTIN(ArraySlice) {
   }
 
   // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6.
-  int k = (relativeStart < 0) ? Max(len + relativeStart, 0)
-                              : Min(relativeStart, len);
+  int k = (relative_start < 0) ? Max(len + relative_start, 0)
+                               : Min(relative_start, len);
 
   // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8.
-  int final = (relativeEnd < 0) ? Max(len + relativeEnd, 0)
-                                : Min(relativeEnd, len);
+  int final = (relative_end < 0) ? Max(len + relative_end, 0)
+                                 : Min(relative_end, len);
 
   // Calculate the length of result array.
   int result_len = final - k;
-  if (result_len < 0) {
-    result_len = 0;
+  if (result_len <= 0) {
+    return AllocateEmptyJSArray();
   }
 
-  JSFunction* array_function =
-      Top::context()->global_context()->array_function();
-  Object* result = Heap::AllocateJSObject(array_function);
+  Object* result = AllocateJSArray();
   if (result->IsFailure()) return result;
   JSArray* result_array = JSArray::cast(result);
 
-  result = Heap::AllocateFixedArrayWithHoles(result_len);
+  result = Heap::AllocateUninitializedFixedArray(result_len);
   if (result->IsFailure()) return result;
   FixedArray* result_elms = FixedArray::cast(result);
 
   FixedArray* elms = FixedArray::cast(array->elements());
 
-  // Fetch the prototype.
-  JSObject* prototype = JSObject::cast(array_function->prototype());
-
   AssertNoAllocation no_gc;
-  WriteBarrierMode mode = result_elms->GetWriteBarrierMode(no_gc);
-
-  // Fill newly created array.
-  for (int i = 0; i < result_len; i++) {
-    result_elms->set(i,
-                     GetElementToMove(k + i, elms, prototype),
-                     mode);
-  }
+  CopyElements(&no_gc, result_elms, 0, elms, k, result_len);
 
   // Set elements.
   result_array->set_elements(result_elms);
@@ -530,6 +573,10 @@ BUILTIN(ArraySlice) {
 
 
 BUILTIN(ArraySplice) {
+  if (!ArrayPrototypeHasNoElements()) {
+    return CallJsBuiltin("ArraySplice", args);
+  }
+
   JSArray* array = JSArray::cast(*args.receiver());
   ASSERT(array->HasFastElements());
 
@@ -546,118 +593,111 @@ BUILTIN(ArraySplice) {
     return Heap::undefined_value();
   }
 
-  int relativeStart = 0;
+  int relative_start = 0;
   Object* arg1 = args[1];
   if (arg1->IsSmi()) {
-    relativeStart = Smi::cast(arg1)->value();
+    relative_start = Smi::cast(arg1)->value();
   } else if (!arg1->IsUndefined()) {
     return CallJsBuiltin("ArraySplice", args);
   }
-  int actualStart = (relativeStart < 0) ? Max(len + relativeStart, 0)
-                                        : Min(relativeStart, len);
+  int actual_start = (relative_start < 0) ? Max(len + relative_start, 0)
+                                          : Min(relative_start, len);
 
   // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
   // given differently from when an undefined delete count is given.
   // This does not follow ECMA-262, but we do the same for
   // compatibility.
-  int deleteCount = len;
+  int delete_count = len;
   if (n_arguments > 1) {
     Object* arg2 = args[2];
     if (arg2->IsSmi()) {
-      deleteCount = Smi::cast(arg2)->value();
+      delete_count = Smi::cast(arg2)->value();
     } else {
       return CallJsBuiltin("ArraySplice", args);
     }
   }
-  int actualDeleteCount = Min(Max(deleteCount, 0), len - actualStart);
-
-  JSFunction* array_function =
-      Top::context()->global_context()->array_function();
-
-  // Allocate result array.
-  Object* result = Heap::AllocateJSObject(array_function);
-  if (result->IsFailure()) return result;
-  JSArray* result_array = JSArray::cast(result);
-
-  result = Heap::AllocateFixedArrayWithHoles(actualDeleteCount);
-  if (result->IsFailure()) return result;
-  FixedArray* result_elms = FixedArray::cast(result);
+  int actual_delete_count = Min(Max(delete_count, 0), len - actual_start);
 
   FixedArray* elms = FixedArray::cast(array->elements());
 
-  // Fetch the prototype.
-  JSObject* prototype = JSObject::cast(array_function->prototype());
+  JSArray* result_array = NULL;
+  if (actual_delete_count == 0) {
+    Object* result = AllocateEmptyJSArray();
+    if (result->IsFailure()) return result;
+    result_array = JSArray::cast(result);
+  } else {
+    // Allocate result array.
+    Object* result = AllocateJSArray();
+    if (result->IsFailure()) return result;
+    result_array = JSArray::cast(result);
 
-  AssertNoAllocation no_gc;
-  WriteBarrierMode mode = result_elms->GetWriteBarrierMode(no_gc);
+    result = Heap::AllocateUninitializedFixedArray(actual_delete_count);
+    if (result->IsFailure()) return result;
+    FixedArray* result_elms = FixedArray::cast(result);
 
-  // Fill newly created array.
-  for (int k = 0; k < actualDeleteCount; k++) {
-    result_elms->set(k,
-                     GetElementToMove(actualStart + k, elms, prototype),
-                     mode);
-  }
+    AssertNoAllocation no_gc;
+    // Fill newly created array.
+    CopyElements(&no_gc,
+                 result_elms, 0,
+                 elms, actual_start,
+                 actual_delete_count);
 
-  // Set elements.
-  result_array->set_elements(result_elms);
+    // Set elements.
+    result_array->set_elements(result_elms);
 
-  // Set the length.
-  result_array->set_length(Smi::FromInt(actualDeleteCount));
+    // Set the length.
+    result_array->set_length(Smi::FromInt(actual_delete_count));
+  }
 
-  int itemCount = (n_arguments > 1) ? (n_arguments - 2) : 0;
+  int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0;
 
-  int new_length = len - actualDeleteCount + itemCount;
+  int new_length = len - actual_delete_count + item_count;
 
-  mode = elms->GetWriteBarrierMode(no_gc);
-  if (itemCount < actualDeleteCount) {
+  if (item_count < actual_delete_count) {
     // Shrink the array.
-    for (int k = actualStart; k < (len - actualDeleteCount); k++) {
-      elms->set(k + itemCount,
-                GetElementToMove(k + actualDeleteCount, elms, prototype),
-                mode);
-    }
-
-    for (int k = len; k > new_length; k--) {
-      elms->set(k - 1, Heap::the_hole_value());
-    }
-  } else if (itemCount > actualDeleteCount) {
+    AssertNoAllocation no_gc;
+    MoveElements(&no_gc,
+                 elms, actual_start + item_count,
+                 elms, actual_start + actual_delete_count,
+                 (len - actual_delete_count - actual_start));
+    FillWithHoles(elms, new_length, len);
+  } else if (item_count > actual_delete_count) {
     // Currently fixed arrays cannot grow too big, so
     // we should never hit this case.
-    ASSERT((itemCount - actualDeleteCount) <= (Smi::kMaxValue - len));
-
-    FixedArray* source_elms = elms;
+    ASSERT((item_count - actual_delete_count) <= (Smi::kMaxValue - len));
 
     // Check if array need to grow.
     if (new_length > elms->length()) {
       // New backing storage is needed.
       int capacity = new_length + (new_length >> 1) + 16;
-      Object* obj = Heap::AllocateFixedArrayWithHoles(capacity);
+      Object* obj = Heap::AllocateUninitializedFixedArray(capacity);
       if (obj->IsFailure()) return obj;
-
       FixedArray* new_elms = FixedArray::cast(obj);
-      mode = new_elms->GetWriteBarrierMode(no_gc);
 
-      // Copy the part before actualStart as is.
-      for (int k = 0; k < actualStart; k++) {
-        new_elms->set(k, elms->get(k), mode);
-      }
+      AssertNoAllocation no_gc;
+      // Copy the part before actual_start as is.
+      CopyElements(&no_gc, new_elms, 0, elms, 0, actual_start);
+      CopyElements(&no_gc,
+                   new_elms, actual_start + item_count,
+                   elms, actual_start + actual_delete_count,
+                   (len - actual_delete_count - actual_start));
+      FillWithHoles(new_elms, new_length, capacity);
 
-      source_elms = elms;
       elms = new_elms;
       array->set_elements(elms);
-    }
-
-    for (int k = len - actualDeleteCount; k > actualStart; k--) {
-      elms->set(k + itemCount - 1,
-                GetElementToMove(k + actualDeleteCount - 1,
-                                 source_elms,
-                                 prototype),
-                mode);
+    } else {
+      AssertNoAllocation no_gc;
+      MoveElements(&no_gc,
+                   elms, actual_start + item_count,
+                   elms, actual_start + actual_delete_count,
+                   (len - actual_delete_count - actual_start));
     }
   }
 
-  for (int k = actualStart; k < actualStart + itemCount; k++) {
-    elms->set(k, args[3 + k - actualStart], mode);
+  AssertNoAllocation no_gc;
+  WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
+  for (int k = actual_start; k < actual_start + item_count; k++) {
+    elms->set(k, args[3 + k - actual_start], mode);
   }
 
   // Set the length.
index 4d0fd29..e42f758 100644 (file)
@@ -83,6 +83,11 @@ void CodeStub::RecordCodeGeneration(Code* code, MacroAssembler* masm) {
 }
 
 
+int CodeStub::GetCodeKind() {
+  return Code::STUB;
+}
+
+
 Handle<Code> CodeStub::GetCode() {
   Code* code;
   if (!FindCodeInCache(&code)) {
@@ -97,7 +102,10 @@ Handle<Code> CodeStub::GetCode() {
     masm.GetCode(&desc);
 
     // Copy the generated code into a heap object.
-    Code::Flags flags = Code::ComputeFlags(Code::STUB, InLoop());
+    Code::Flags flags = Code::ComputeFlags(
+        static_cast<Code::Kind>(GetCodeKind()),
+        InLoop(),
+        GetICState());
     Handle<Code> new_object =
         Factory::NewCode(desc, NULL, flags, masm.CodeObject());
     RecordCodeGeneration(*new_object, &masm);
@@ -132,7 +140,10 @@ Object* CodeStub::TryGetCode() {
     masm.GetCode(&desc);
 
     // Try to copy the generated code into a heap object.
-    Code::Flags flags = Code::ComputeFlags(Code::STUB, InLoop());
+    Code::Flags flags = Code::ComputeFlags(
+        static_cast<Code::Kind>(GetCodeKind()),
+        InLoop(),
+        GetICState());
     Object* new_object =
         Heap::CreateCode(desc, NULL, flags, masm.CodeObject());
     if (new_object->IsFailure()) return new_object;
index 3901a64..de2ad56 100644 (file)
@@ -28,6 +28,8 @@
 #ifndef V8_CODE_STUBS_H_
 #define V8_CODE_STUBS_H_
 
+#include "globals.h"
+
 namespace v8 {
 namespace internal {
 
@@ -48,6 +50,7 @@ namespace internal {
   V(FastNewClosure)                      \
   V(FastNewContext)                      \
   V(FastCloneShallowArray)               \
+  V(TranscendentalCache)                 \
   V(GenericUnaryOp)                      \
   V(RevertToNumber)                      \
   V(ToBoolean)                           \
@@ -138,6 +141,14 @@ class CodeStub BASE_EMBEDDED {
   // lazily generated function should be fully optimized or not.
   virtual InLoopFlag InLoop() { return NOT_IN_LOOP; }
 
+  // GenericBinaryOpStub needs to override this.
+  virtual int GetCodeKind();
+
+  // GenericBinaryOpStub needs to override this.
+  virtual InlineCacheState GetICState() {
+    return UNINITIALIZED;
+  }
+
   // Returns a name for logging/debugging purposes.
   virtual const char* GetName() { return MajorName(MajorKey(), false); }
 
index 5e25f69..6841c21 100644 (file)
@@ -369,6 +369,7 @@ CodeGenerator::InlineRuntimeLUT CodeGenerator::kInlineRuntimeLUT[] = {
   {&CodeGenerator::GenerateValueOf, "_ValueOf"},
   {&CodeGenerator::GenerateSetValueOf, "_SetValueOf"},
   {&CodeGenerator::GenerateFastCharCodeAt, "_FastCharCodeAt"},
+  {&CodeGenerator::GenerateCharFromCode, "_CharFromCode"},
   {&CodeGenerator::GenerateObjectEquals, "_ObjectEquals"},
   {&CodeGenerator::GenerateLog, "_Log"},
   {&CodeGenerator::GenerateRandomPositiveSmi, "_RandomPositiveSmi"},
@@ -380,6 +381,10 @@ CodeGenerator::InlineRuntimeLUT CodeGenerator::kInlineRuntimeLUT[] = {
   {&CodeGenerator::GenerateStringCompare, "_StringCompare"},
   {&CodeGenerator::GenerateRegExpExec, "_RegExpExec"},
   {&CodeGenerator::GenerateNumberToString, "_NumberToString"},
+  {&CodeGenerator::GenerateMathPow, "_Math_pow"},
+  {&CodeGenerator::GenerateMathSin, "_Math_sin"},
+  {&CodeGenerator::GenerateMathCos, "_Math_cos"},
+  {&CodeGenerator::GenerateMathSqrt, "_Math_sqrt"},
 };
 
 
index 5427367..9dcbeb5 100644 (file)
 namespace v8 {
 namespace internal {
 
-
 // The number of sub caches covering the different types to cache.
 static const int kSubCacheCount = 4;
 
 // The number of generations for each sub cache.
-#if defined(ANDROID)
-static const int kScriptGenerations = 1;
-static const int kEvalGlobalGenerations = 1;
-static const int kEvalContextualGenerations = 1;
-static const int kRegExpGenerations = 1;
-#else
 // The number of ScriptGenerations is carefully chosen based on histograms.
 // See issue 458: http://code.google.com/p/v8/issues/detail?id=458
 static const int kScriptGenerations = 5;
 static const int kEvalGlobalGenerations = 2;
 static const int kEvalContextualGenerations = 2;
 static const int kRegExpGenerations = 2;
-#endif
 
 // Initial size of each compilation cache table allocated.
 static const int kInitialCacheSize = 64;
 
+// Index for the first generation in the cache.
+static const int kFirstGeneration = 0;
+
 // The compilation cache consists of several generational sub-caches which uses
 // this class as a base class. A sub-cache contains a compilation cache tables
 // for each generation of the sub-cache. Since the same source code string has
@@ -70,6 +65,15 @@ class CompilationSubCache {
   // Get the compilation cache tables for a specific generation.
   Handle<CompilationCacheTable> GetTable(int generation);
 
+  // Accessors for first generation.
+  Handle<CompilationCacheTable> GetFirstTable() {
+    return GetTable(kFirstGeneration);
+  }
+  void SetFirstTable(Handle<CompilationCacheTable> value) {
+    ASSERT(kFirstGeneration < generations_);
+    tables_[kFirstGeneration] = *value;
+  }
+
   // Age the sub-cache by evicting the oldest generation and creating a new
   // young generation.
   void Age();
@@ -104,6 +108,10 @@ class CompilationCacheScript : public CompilationSubCache {
   void Put(Handle<String> source, Handle<JSFunction> boilerplate);
 
  private:
+  // Note: Returns a new hash table if operation results in expansion.
+  Handle<CompilationCacheTable> TablePut(Handle<String> source,
+                                         Handle<JSFunction> boilerplate);
+
   bool HasOrigin(Handle<JSFunction> boilerplate,
                  Handle<Object> name,
                  int line_offset,
@@ -125,6 +133,12 @@ class CompilationCacheEval: public CompilationSubCache {
            Handle<Context> context,
            Handle<JSFunction> boilerplate);
 
+ private:
+  // Note: Returns a new hash table if operation results in expansion.
+  Handle<CompilationCacheTable> TablePut(Handle<String> source,
+                                         Handle<Context> context,
+                                         Handle<JSFunction> boilerplate);
+
   DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationCacheEval);
 };
 
@@ -140,6 +154,11 @@ class CompilationCacheRegExp: public CompilationSubCache {
   void Put(Handle<String> source,
            JSRegExp::Flags flags,
            Handle<FixedArray> data);
+ private:
+  // Note: Returns a new hash table if operation results in expansion.
+  Handle<CompilationCacheTable> TablePut(Handle<String> source,
+                                         JSRegExp::Flags flags,
+                                         Handle<FixedArray> data);
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationCacheRegExp);
 };
@@ -287,12 +306,19 @@ Handle<JSFunction> CompilationCacheScript::Lookup(Handle<String> source,
 }
 
 
+Handle<CompilationCacheTable> CompilationCacheScript::TablePut(
+    Handle<String> source,
+    Handle<JSFunction> boilerplate) {
+  CALL_HEAP_FUNCTION(GetFirstTable()->Put(*source, *boilerplate),
+                     CompilationCacheTable);
+}
+
+
 void CompilationCacheScript::Put(Handle<String> source,
                                  Handle<JSFunction> boilerplate) {
   HandleScope scope;
   ASSERT(boilerplate->IsBoilerplate());
-  Handle<CompilationCacheTable> table = GetTable(0);
-  CALL_HEAP_FUNCTION_VOID(table->Put(*source, *boilerplate));
+  SetFirstTable(TablePut(source, boilerplate));
 }
 
 
@@ -326,13 +352,21 @@ Handle<JSFunction> CompilationCacheEval::Lookup(Handle<String> source,
 }
 
 
+Handle<CompilationCacheTable> CompilationCacheEval::TablePut(
+    Handle<String> source,
+    Handle<Context> context,
+    Handle<JSFunction> boilerplate) {
+  CALL_HEAP_FUNCTION(GetFirstTable()->PutEval(*source, *context, *boilerplate),
+                     CompilationCacheTable);
+}
+
+
 void CompilationCacheEval::Put(Handle<String> source,
                                Handle<Context> context,
                                Handle<JSFunction> boilerplate) {
   HandleScope scope;
   ASSERT(boilerplate->IsBoilerplate());
-  Handle<CompilationCacheTable> table = GetTable(0);
-  CALL_HEAP_FUNCTION_VOID(table->PutEval(*source, *context, *boilerplate));
+  SetFirstTable(TablePut(source, context, boilerplate));
 }
 
 
@@ -366,12 +400,20 @@ Handle<FixedArray> CompilationCacheRegExp::Lookup(Handle<String> source,
 }
 
 
+Handle<CompilationCacheTable> CompilationCacheRegExp::TablePut(
+    Handle<String> source,
+    JSRegExp::Flags flags,
+    Handle<FixedArray> data) {
+  CALL_HEAP_FUNCTION(GetFirstTable()->PutRegExp(*source, flags, *data),
+                     CompilationCacheTable);
+}
+
+
 void CompilationCacheRegExp::Put(Handle<String> source,
                                  JSRegExp::Flags flags,
                                  Handle<FixedArray> data) {
   HandleScope scope;
-  Handle<CompilationCacheTable> table = GetTable(0);
-  CALL_HEAP_FUNCTION_VOID(table->PutRegExp(*source, flags, *data));
+  SetFirstTable(TablePut(source, flags, data));
 }
 
 
index 557a91e..ebb62f1 100755 (executable)
 #include "codegen-inl.h"
 #include "compilation-cache.h"
 #include "compiler.h"
+#include "data-flow.h"
 #include "debug.h"
 #include "fast-codegen.h"
 #include "full-codegen.h"
+#include "liveedit.h"
 #include "oprofile-agent.h"
 #include "rewriter.h"
 #include "scopes.h"
-#include "usage-analyzer.h"
-#include "liveedit.h"
 
 namespace v8 {
 namespace internal {
@@ -48,7 +48,7 @@ static Handle<Code> MakeCode(Handle<Context> context, CompilationInfo* info) {
   FunctionLiteral* function = info->function();
   ASSERT(function != NULL);
   // Rewrite the AST by introducing .result assignments where needed.
-  if (!Rewriter::Process(function) || !AnalyzeVariableUsage(function)) {
+  if (!Rewriter::Process(function)) {
     // Signal a stack overflow by returning a null handle.  The stack
     // overflow exception will be thrown by the caller.
     return Handle<Code>::null();
@@ -79,6 +79,17 @@ static Handle<Code> MakeCode(Handle<Context> context, CompilationInfo* info) {
     return Handle<Code>::null();
   }
 
+  if (FLAG_use_flow_graph) {
+    FlowGraphBuilder builder;
+    builder.Build(function);
+
+#ifdef DEBUG
+    if (FLAG_print_graph_text) {
+      builder.graph()->PrintText(builder.postorder());
+    }
+#endif
+  }
+
   // Generate code and return it.  Code generator selection is governed by
   // which backends are enabled and whether the function is considered
   // run-once code or not:
@@ -117,6 +128,14 @@ static Handle<Code> MakeCode(Handle<Context> context, CompilationInfo* info) {
 }
 
 
+#ifdef ENABLE_DEBUGGER_SUPPORT
+Handle<Code> MakeCodeForLiveEdit(CompilationInfo* info) {
+  Handle<Context> context = Handle<Context>::null();
+  return MakeCode(context, info);
+}
+#endif
+
+
 static Handle<JSFunction> MakeFunction(bool is_global,
                                        bool is_eval,
                                        Compiler::ValidationState validate,
@@ -224,7 +243,7 @@ static Handle<JSFunction> MakeFunction(bool is_global,
 
 #ifdef ENABLE_DEBUGGER_SUPPORT
   // Notify debugger
-  Debugger::OnAfterCompile(script, fun);
+  Debugger::OnAfterCompile(script, Debugger::NO_AFTER_COMPILE_FLAGS);
 #endif
 
   return fun;
@@ -444,6 +463,17 @@ Handle<JSFunction> Compiler::BuildBoilerplate(FunctionLiteral* literal,
       return Handle<JSFunction>::null();
     }
 
+    if (FLAG_use_flow_graph) {
+      FlowGraphBuilder builder;
+      builder.Build(literal);
+
+#ifdef DEBUG
+      if (FLAG_print_graph_text) {
+        builder.graph()->PrintText(builder.postorder());
+      }
+#endif
+    }
+
     // Generate code and return it.  The way that the compilation mode
     // is controlled by the command-line flags is described in
     // the static helper function MakeCode.
index f01889d..8e220e6 100644 (file)
@@ -276,6 +276,13 @@ class Compiler : public AllStatic {
 };
 
 
+#ifdef ENABLE_DEBUGGER_SUPPORT
+
+Handle<Code> MakeCodeForLiveEdit(CompilationInfo* info);
+
+#endif
+
+
 // During compilation we need a global list of handles to constants
 // for frame elements.  When the zone gets deleted, we make sure to
 // clear this list of handles as well.
index 9baf072..98ebc47 100644 (file)
@@ -95,6 +95,7 @@ enum ContextLookupFlags {
     call_as_constructor_delegate) \
   V(EMPTY_SCRIPT_INDEX, Script, empty_script) \
   V(SCRIPT_FUNCTION_INDEX, JSFunction, script_function) \
+  V(OPAQUE_REFERENCE_FUNCTION_INDEX, JSFunction, opaque_reference_function) \
   V(CONTEXT_EXTENSION_FUNCTION_INDEX, JSFunction, context_extension_function) \
   V(OUT_OF_MEMORY_INDEX, Object, out_of_memory) \
   V(MAP_CACHE_INDEX, Object, map_cache) \
@@ -216,6 +217,7 @@ class Context: public FixedArray {
     CALL_AS_CONSTRUCTOR_DELEGATE_INDEX,
     EMPTY_SCRIPT_INDEX,
     SCRIPT_FUNCTION_INDEX,
+    OPAQUE_REFERENCE_FUNCTION_INDEX,
     CONTEXT_EXTENSION_FUNCTION_INDEX,
     OUT_OF_MEMORY_INDEX,
     MAP_CACHE_INDEX,
index ba7220a..f7210d5 100644 (file)
@@ -59,6 +59,32 @@ static inline int FastD2I(double x) {
 }
 
 
+// The fast double-to-unsigned-int conversion routine does not guarantee
+// rounding towards zero.
+static inline unsigned int FastD2UI(double x) {
+  // There is no unsigned version of lrint, so there is no fast path
+  // in this function as there is in FastD2I. Using lrint doesn't work
+  // for values of 2^31 and above.
+
+  // Convert "small enough" doubles to uint32_t by fixing the 32
+  // least significant non-fractional bits in the low 32 bits of the
+  // double, and reading them from there.
+  const double k2Pow52 = 4503599627370496.0;
+  bool negative = x < 0;
+  if (negative) {
+    x = -x;
+  }
+  if (x < k2Pow52) {
+    x += k2Pow52;
+    uint32_t result;
+    memcpy(&result, &x, sizeof(result));  // Copy low 32 bits.
+    return negative ? ~result + 1 : result;
+  }
+  // Large number (outside uint32 range), Infinity or NaN.
+  return 0x80000000u;  // Return integer indefinite.
+}
+
+
 static inline double DoubleToInteger(double x) {
   if (isnan(x)) return 0;
   if (!isfinite(x) || x == 0) return x;
index 67f7d53..bdc7e44 100644 (file)
@@ -32,11 +32,12 @@ namespace v8 {
 namespace internal {
 
 
-// The fast double-to-int conversion routine does not guarantee
+// The fast double-to-(unsigned-)int conversion routine does not guarantee
 // rounding towards zero.
 // The result is unspecified if x is infinite or NaN, or if the rounded
 // integer value is outside the range of type int.
 static inline int FastD2I(double x);
+static inline unsigned int FastD2UI(double x);
 
 
 static inline double FastI2D(int x) {
index 5e9d217..6b45da0 100644 (file)
@@ -33,6 +33,540 @@ namespace v8 {
 namespace internal {
 
 
+void FlowGraph::AppendInstruction(AstNode* instruction) {
+  ASSERT(instruction != NULL);
+  if (is_empty() || !exit()->IsBlockNode()) {
+    AppendNode(new BlockNode());
+  }
+  BlockNode::cast(exit())->AddInstruction(instruction);
+}
+
+
+void FlowGraph::AppendNode(Node* node) {
+  ASSERT(node != NULL);
+  if (is_empty()) {
+    entry_ = exit_ = node;
+  } else {
+    exit()->AddSuccessor(node);
+    node->AddPredecessor(exit());
+    exit_ = node;
+  }
+}
+
+
+void FlowGraph::AppendGraph(FlowGraph* graph) {
+  ASSERT(!graph->is_empty());
+  if (is_empty()) {
+    entry_ = graph->entry();
+    exit_ = graph->exit();
+  } else {
+    exit()->AddSuccessor(graph->entry());
+    graph->entry()->AddPredecessor(exit());
+    exit_ = graph->exit();
+  }
+}
+
+
+void FlowGraph::Split(BranchNode* branch,
+                      FlowGraph* left,
+                      FlowGraph* right,
+                      JoinNode* merge) {
+  // Graphs are in edge split form.  Add empty blocks if necessary.
+  if (left->is_empty()) left->AppendNode(new BlockNode());
+  if (right->is_empty()) right->AppendNode(new BlockNode());
+
+  // Add the branch, left flowgraph and merge.
+  AppendNode(branch);
+  AppendGraph(left);
+  AppendNode(merge);
+
+  // Splice in the right flowgraph.
+  right->AppendNode(merge);
+  branch->AddSuccessor(right->entry());
+  right->entry()->AddPredecessor(branch);
+}
+
+
+void FlowGraph::Loop(JoinNode* merge,
+                     FlowGraph* condition,
+                     BranchNode* branch,
+                     FlowGraph* body) {
+  // Add the merge, condition and branch.  Add merge's predecessors in
+  // left-to-right order.
+  AppendNode(merge);
+  body->AppendNode(merge);
+  AppendGraph(condition);
+  AppendNode(branch);
+
+  // Splice in the body flowgraph.
+  branch->AddSuccessor(body->entry());
+  body->entry()->AddPredecessor(branch);
+}
+
+
+void EntryNode::Traverse(bool mark,
+                         ZoneList<Node*>* preorder,
+                         ZoneList<Node*>* postorder) {
+  ASSERT(successor_ != NULL);
+  preorder->Add(this);
+  if (!successor_->IsMarkedWith(mark)) {
+    successor_->MarkWith(mark);
+    successor_->Traverse(mark, preorder, postorder);
+  }
+  postorder->Add(this);
+}
+
+
+void ExitNode::Traverse(bool mark,
+                        ZoneList<Node*>* preorder,
+                        ZoneList<Node*>* postorder) {
+  preorder->Add(this);
+  postorder->Add(this);
+}
+
+
+void BlockNode::Traverse(bool mark,
+                         ZoneList<Node*>* preorder,
+                         ZoneList<Node*>* postorder) {
+  ASSERT(successor_ != NULL);
+  preorder->Add(this);
+  if (!successor_->IsMarkedWith(mark)) {
+    successor_->MarkWith(mark);
+    successor_->Traverse(mark, preorder, postorder);
+  }
+  postorder->Add(this);
+}
+
+
+void BranchNode::Traverse(bool mark,
+                          ZoneList<Node*>* preorder,
+                          ZoneList<Node*>* postorder) {
+  ASSERT(successor0_ != NULL && successor1_ != NULL);
+  preorder->Add(this);
+  if (!successor0_->IsMarkedWith(mark)) {
+    successor0_->MarkWith(mark);
+    successor0_->Traverse(mark, preorder, postorder);
+  }
+  if (!successor1_->IsMarkedWith(mark)) {
+    successor1_->MarkWith(mark);
+    successor1_->Traverse(mark, preorder, postorder);
+  }
+  postorder->Add(this);
+}
+
+
+void JoinNode::Traverse(bool mark,
+                        ZoneList<Node*>* preorder,
+                        ZoneList<Node*>* postorder) {
+  ASSERT(successor_ != NULL);
+  preorder->Add(this);
+  if (!successor_->IsMarkedWith(mark)) {
+    successor_->MarkWith(mark);
+    successor_->Traverse(mark, preorder, postorder);
+  }
+  postorder->Add(this);
+}
+
+
+void FlowGraphBuilder::Build(FunctionLiteral* lit) {
+  graph_ = FlowGraph::Empty();
+  graph_.AppendNode(new EntryNode());
+  global_exit_ = new ExitNode();
+  VisitStatements(lit->body());
+
+  if (HasStackOverflow()) {
+    graph_ = FlowGraph::Empty();
+    return;
+  }
+
+  graph_.AppendNode(global_exit_);
+
+  // Build preorder and postorder traversal orders.  All the nodes in
+  // the graph have the same mark flag.  For the traversal, use that
+  // flag's negation.  Traversal will flip all the flags.
+  bool mark = graph_.entry()->IsMarkedWith(false);
+  graph_.entry()->MarkWith(mark);
+  graph_.entry()->Traverse(mark, &preorder_, &postorder_);
+}
+
+
+void FlowGraphBuilder::VisitDeclaration(Declaration* decl) {
+  UNREACHABLE();
+}
+
+
+void FlowGraphBuilder::VisitBlock(Block* stmt) {
+  VisitStatements(stmt->statements());
+}
+
+
+void FlowGraphBuilder::VisitExpressionStatement(ExpressionStatement* stmt) {
+  Visit(stmt->expression());
+}
+
+
+void FlowGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) {
+  // Nothing to do.
+}
+
+
+void FlowGraphBuilder::VisitIfStatement(IfStatement* stmt) {
+  Visit(stmt->condition());
+
+  BranchNode* branch = new BranchNode();
+  FlowGraph original = graph_;
+  graph_ = FlowGraph::Empty();
+  Visit(stmt->then_statement());
+
+  FlowGraph left = graph_;
+  graph_ = FlowGraph::Empty();
+  Visit(stmt->else_statement());
+
+  JoinNode* join = new JoinNode();
+  original.Split(branch, &left, &graph_, join);
+  graph_ = original;
+}
+
+
+void FlowGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) {
+  SetStackOverflow();
+}
+
+
+void FlowGraphBuilder::VisitBreakStatement(BreakStatement* stmt) {
+  SetStackOverflow();
+}
+
+
+void FlowGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
+  Visit(stmt->expression());
+  graph_.AppendInstruction(stmt);
+  graph_.AppendNode(global_exit());
+}
+
+
+void FlowGraphBuilder::VisitWithEnterStatement(WithEnterStatement* stmt) {
+  Visit(stmt->expression());
+  graph_.AppendInstruction(stmt);
+}
+
+
+void FlowGraphBuilder::VisitWithExitStatement(WithExitStatement* stmt) {
+  graph_.AppendInstruction(stmt);
+}
+
+
+void FlowGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
+  SetStackOverflow();
+}
+
+
+void FlowGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) {
+  JoinNode* join = new JoinNode();
+  FlowGraph original = graph_;
+  graph_ = FlowGraph::Empty();
+  Visit(stmt->body());
+
+  FlowGraph body = graph_;
+  graph_ = FlowGraph::Empty();
+  Visit(stmt->cond());
+
+  BranchNode* branch = new BranchNode();
+
+  // Add body, condition and branch.
+  original.AppendNode(join);
+  original.AppendGraph(&body);
+  original.AppendGraph(&graph_);  // The condition.
+  original.AppendNode(branch);
+
+  // Tie the knot.
+  branch->AddSuccessor(join);
+  join->AddPredecessor(branch);
+
+  graph_ = original;
+}
+
+
+void FlowGraphBuilder::VisitWhileStatement(WhileStatement* stmt) {
+  JoinNode* join = new JoinNode();
+  FlowGraph original = graph_;
+  graph_ = FlowGraph::Empty();
+  Visit(stmt->cond());
+
+  BranchNode* branch = new BranchNode();
+  FlowGraph condition = graph_;
+  graph_ = FlowGraph::Empty();
+  Visit(stmt->body());
+
+  original.Loop(join, &condition, branch, &graph_);
+  graph_ = original;
+}
+
+
+void FlowGraphBuilder::VisitForStatement(ForStatement* stmt) {
+  if (stmt->init() != NULL) Visit(stmt->init());
+
+  JoinNode* join = new JoinNode();
+  FlowGraph original = graph_;
+  graph_ = FlowGraph::Empty();
+  if (stmt->cond() != NULL) Visit(stmt->cond());
+
+  BranchNode* branch = new BranchNode();
+  FlowGraph condition = graph_;
+  graph_ = FlowGraph::Empty();
+  Visit(stmt->body());
+
+  if (stmt->next() != NULL) Visit(stmt->next());
+
+  original.Loop(join, &condition, branch, &graph_);
+  graph_ = original;
+}
+
+
+void FlowGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
+  Visit(stmt->enumerable());
+
+  JoinNode* join = new JoinNode();
+  FlowGraph empty;
+  BranchNode* branch = new BranchNode();
+  FlowGraph original = graph_;
+  graph_ = FlowGraph::Empty();
+  Visit(stmt->body());
+
+  original.Loop(join, &empty, branch, &graph_);
+  graph_ = original;
+}
+
+
+void FlowGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) {
+  SetStackOverflow();
+}
+
+
+void FlowGraphBuilder::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
+  SetStackOverflow();
+}
+
+
+void FlowGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) {
+  graph_.AppendInstruction(stmt);
+}
+
+
+void FlowGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) {
+  graph_.AppendInstruction(expr);
+}
+
+
+void FlowGraphBuilder::VisitFunctionBoilerplateLiteral(
+    FunctionBoilerplateLiteral* expr) {
+  graph_.AppendInstruction(expr);
+}
+
+
+void FlowGraphBuilder::VisitConditional(Conditional* expr) {
+  Visit(expr->condition());
+
+  BranchNode* branch = new BranchNode();
+  FlowGraph original = graph_;
+  graph_ = FlowGraph::Empty();
+  Visit(expr->then_expression());
+
+  FlowGraph left = graph_;
+  graph_ = FlowGraph::Empty();
+  Visit(expr->else_expression());
+
+  JoinNode* join = new JoinNode();
+  original.Split(branch, &left, &graph_, join);
+  graph_ = original;
+}
+
+
+void FlowGraphBuilder::VisitSlot(Slot* expr) {
+  UNREACHABLE();
+}
+
+
+void FlowGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
+  graph_.AppendInstruction(expr);
+}
+
+
+void FlowGraphBuilder::VisitLiteral(Literal* expr) {
+  graph_.AppendInstruction(expr);
+}
+
+
+void FlowGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
+  graph_.AppendInstruction(expr);
+}
+
+
+void FlowGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
+  ZoneList<ObjectLiteral::Property*>* properties = expr->properties();
+  for (int i = 0, len = properties->length(); i < len; i++) {
+    Visit(properties->at(i)->value());
+  }
+  graph_.AppendInstruction(expr);
+}
+
+
+void FlowGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
+  ZoneList<Expression*>* values = expr->values();
+  for (int i = 0, len = values->length(); i < len; i++) {
+    Visit(values->at(i));
+  }
+  graph_.AppendInstruction(expr);
+}
+
+
+void FlowGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) {
+  graph_.AppendInstruction(expr);
+}
+
+
+void FlowGraphBuilder::VisitAssignment(Assignment* expr) {
+  Variable* var = expr->target()->AsVariableProxy()->AsVariable();
+  Property* prop = expr->target()->AsProperty();
+  // Left-hand side can be a variable or property (or reference error) but
+  // not both.
+  ASSERT(var == NULL || prop == NULL);
+  if (var != NULL) {
+    Visit(expr->value());
+    if (var->IsStackAllocated()) definitions_.Add(expr);
+
+  } else if (prop != NULL) {
+    Visit(prop->obj());
+    if (!prop->key()->IsPropertyName()) Visit(prop->key());
+    Visit(expr->value());
+  }
+  graph_.AppendInstruction(expr);
+}
+
+
+void FlowGraphBuilder::VisitThrow(Throw* expr) {
+  Visit(expr->exception());
+  graph_.AppendInstruction(expr);
+}
+
+
+void FlowGraphBuilder::VisitProperty(Property* expr) {
+  Visit(expr->obj());
+  if (!expr->key()->IsPropertyName()) Visit(expr->key());
+  graph_.AppendInstruction(expr);
+}
+
+
+void FlowGraphBuilder::VisitCall(Call* expr) {
+  Visit(expr->expression());
+  ZoneList<Expression*>* arguments = expr->arguments();
+  for (int i = 0, len = arguments->length(); i < len; i++) {
+    Visit(arguments->at(i));
+  }
+  graph_.AppendInstruction(expr);
+}
+
+
+void FlowGraphBuilder::VisitCallNew(CallNew* expr) {
+  Visit(expr->expression());
+  ZoneList<Expression*>* arguments = expr->arguments();
+  for (int i = 0, len = arguments->length(); i < len; i++) {
+    Visit(arguments->at(i));
+  }
+  graph_.AppendInstruction(expr);
+}
+
+
+void FlowGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
+  ZoneList<Expression*>* arguments = expr->arguments();
+  for (int i = 0, len = arguments->length(); i < len; i++) {
+    Visit(arguments->at(i));
+  }
+  graph_.AppendInstruction(expr);
+}
+
+
+void FlowGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
+  Visit(expr->expression());
+  graph_.AppendInstruction(expr);
+}
+
+
+void FlowGraphBuilder::VisitCountOperation(CountOperation* expr) {
+  Visit(expr->expression());
+  Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
+  if (var != NULL && var->IsStackAllocated()) {
+    definitions_.Add(expr);
+  }
+  graph_.AppendInstruction(expr);
+}
+
+
+void FlowGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
+  Visit(expr->left());
+
+  switch (expr->op()) {
+    case Token::COMMA:
+      Visit(expr->right());
+      break;
+
+    case Token::OR: {
+      BranchNode* branch = new BranchNode();
+      FlowGraph original = graph_;
+      graph_ = FlowGraph::Empty();
+      Visit(expr->right());
+      FlowGraph empty;
+      JoinNode* join = new JoinNode();
+      original.Split(branch, &empty, &graph_, join);
+      graph_ = original;
+      break;
+    }
+
+    case Token::AND: {
+      BranchNode* branch = new BranchNode();
+      FlowGraph original = graph_;
+      graph_ = FlowGraph::Empty();
+      Visit(expr->right());
+      FlowGraph empty;
+      JoinNode* join = new JoinNode();
+      original.Split(branch, &graph_, &empty, join);
+      graph_ = original;
+      break;
+    }
+
+    case Token::BIT_OR:
+    case Token::BIT_XOR:
+    case Token::BIT_AND:
+    case Token::SHL:
+    case Token::SAR:
+    case Token::SHR:
+    case Token::ADD:
+    case Token::SUB:
+    case Token::MUL:
+    case Token::DIV:
+    case Token::MOD:
+      Visit(expr->right());
+      graph_.AppendInstruction(expr);
+      break;
+
+    default:
+      UNREACHABLE();
+  }
+}
+
+
+void FlowGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
+  Visit(expr->left());
+  Visit(expr->right());
+  graph_.AppendInstruction(expr);
+}
+
+
+void FlowGraphBuilder::VisitThisFunction(ThisFunction* expr) {
+  graph_.AppendInstruction(expr);
+}
+
+
 void AstLabeler::Label(CompilationInfo* info) {
   info_ = info;
   VisitStatements(info_->function()->body());
@@ -204,6 +738,9 @@ void AstLabeler::VisitAssignment(Assignment* expr) {
   USE(proxy);
   ASSERT(proxy != NULL && proxy->var()->is_this());
   info()->set_has_this_properties(true);
+
+  prop->obj()->set_num(AstNode::kNoNumber);
+  prop->key()->set_num(AstNode::kNoNumber);
   Visit(expr->value());
   expr->set_num(next_number_++);
 }
@@ -220,6 +757,9 @@ void AstLabeler::VisitProperty(Property* expr) {
   USE(proxy);
   ASSERT(proxy != NULL && proxy->var()->is_this());
   info()->set_has_this_properties(true);
+
+  expr->obj()->set_num(AstNode::kNoNumber);
+  expr->key()->set_num(AstNode::kNoNumber);
   expr->set_num(next_number_++);
 }
 
@@ -558,4 +1098,370 @@ void LivenessAnalyzer::VisitThisFunction(ThisFunction* expr) {
 }
 
 
+#ifdef DEBUG
+
+// Print a textual representation of an instruction in a flow graph.  Using
+// the AstVisitor is overkill because there is no recursion here.  It is
+// only used for printing in debug mode.
+class TextInstructionPrinter: public AstVisitor {
+ public:
+  TextInstructionPrinter() {}
+
+ private:
+  // AST node visit functions.
+#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
+  AST_NODE_LIST(DECLARE_VISIT)
+#undef DECLARE_VISIT
+
+  DISALLOW_COPY_AND_ASSIGN(TextInstructionPrinter);
+};
+
+
+void TextInstructionPrinter::VisitDeclaration(Declaration* decl) {
+  UNREACHABLE();
+}
+
+
+void TextInstructionPrinter::VisitBlock(Block* stmt) {
+  PrintF("Block");
+}
+
+
+void TextInstructionPrinter::VisitExpressionStatement(
+    ExpressionStatement* stmt) {
+  PrintF("ExpressionStatement");
+}
+
+
+void TextInstructionPrinter::VisitEmptyStatement(EmptyStatement* stmt) {
+  PrintF("EmptyStatement");
+}
+
+
+void TextInstructionPrinter::VisitIfStatement(IfStatement* stmt) {
+  PrintF("IfStatement");
+}
+
+
+void TextInstructionPrinter::VisitContinueStatement(ContinueStatement* stmt) {
+  UNREACHABLE();
+}
+
+
+void TextInstructionPrinter::VisitBreakStatement(BreakStatement* stmt) {
+  UNREACHABLE();
+}
+
+
+void TextInstructionPrinter::VisitReturnStatement(ReturnStatement* stmt) {
+  PrintF("return @%d", stmt->expression()->num());
+}
+
+
+void TextInstructionPrinter::VisitWithEnterStatement(WithEnterStatement* stmt) {
+  PrintF("WithEnterStatement");
+}
+
+
+void TextInstructionPrinter::VisitWithExitStatement(WithExitStatement* stmt) {
+  PrintF("WithExitStatement");
+}
+
+
+void TextInstructionPrinter::VisitSwitchStatement(SwitchStatement* stmt) {
+  UNREACHABLE();
+}
+
+
+void TextInstructionPrinter::VisitDoWhileStatement(DoWhileStatement* stmt) {
+  PrintF("DoWhileStatement");
+}
+
+
+void TextInstructionPrinter::VisitWhileStatement(WhileStatement* stmt) {
+  PrintF("WhileStatement");
+}
+
+
+void TextInstructionPrinter::VisitForStatement(ForStatement* stmt) {
+  PrintF("ForStatement");
+}
+
+
+void TextInstructionPrinter::VisitForInStatement(ForInStatement* stmt) {
+  PrintF("ForInStatement");
+}
+
+
+void TextInstructionPrinter::VisitTryCatchStatement(TryCatchStatement* stmt) {
+  UNREACHABLE();
+}
+
+
+void TextInstructionPrinter::VisitTryFinallyStatement(
+    TryFinallyStatement* stmt) {
+  UNREACHABLE();
+}
+
+
+void TextInstructionPrinter::VisitDebuggerStatement(DebuggerStatement* stmt) {
+  PrintF("DebuggerStatement");
+}
+
+
+void TextInstructionPrinter::VisitFunctionLiteral(FunctionLiteral* expr) {
+  PrintF("FunctionLiteral");
+}
+
+
+void TextInstructionPrinter::VisitFunctionBoilerplateLiteral(
+    FunctionBoilerplateLiteral* expr) {
+  PrintF("FunctionBoilerplateLiteral");
+}
+
+
+void TextInstructionPrinter::VisitConditional(Conditional* expr) {
+  PrintF("Conditional");
+}
+
+
+void TextInstructionPrinter::VisitSlot(Slot* expr) {
+  UNREACHABLE();
+}
+
+
+void TextInstructionPrinter::VisitVariableProxy(VariableProxy* expr) {
+  Variable* var = expr->AsVariable();
+  if (var != NULL) {
+    SmartPointer<char> name = var->name()->ToCString();
+    PrintF("%s", *name);
+  } else {
+    ASSERT(expr->AsProperty() != NULL);
+    VisitProperty(expr->AsProperty());
+  }
+}
+
+
+void TextInstructionPrinter::VisitLiteral(Literal* expr) {
+  expr->handle()->ShortPrint();
+}
+
+
+void TextInstructionPrinter::VisitRegExpLiteral(RegExpLiteral* expr) {
+  PrintF("RegExpLiteral");
+}
+
+
+void TextInstructionPrinter::VisitObjectLiteral(ObjectLiteral* expr) {
+  PrintF("ObjectLiteral");
+}
+
+
+void TextInstructionPrinter::VisitArrayLiteral(ArrayLiteral* expr) {
+  PrintF("ArrayLiteral");
+}
+
+
+void TextInstructionPrinter::VisitCatchExtensionObject(
+    CatchExtensionObject* expr) {
+  PrintF("CatchExtensionObject");
+}
+
+
+void TextInstructionPrinter::VisitAssignment(Assignment* expr) {
+  Variable* var = expr->target()->AsVariableProxy()->AsVariable();
+  Property* prop = expr->target()->AsProperty();
+
+  if (var != NULL) {
+    SmartPointer<char> name = var->name()->ToCString();
+    PrintF("%s %s @%d",
+           *name,
+           Token::String(expr->op()),
+           expr->value()->num());
+  } else if (prop != NULL) {
+    if (prop->key()->IsPropertyName()) {
+      PrintF("@%d.", prop->obj()->num());
+      ASSERT(prop->key()->AsLiteral() != NULL);
+      prop->key()->AsLiteral()->handle()->Print();
+      PrintF(" %s @%d",
+             Token::String(expr->op()),
+             expr->value()->num());
+    } else {
+      PrintF("@%d[@%d] %s @%d",
+             prop->obj()->num(),
+             prop->key()->num(),
+             Token::String(expr->op()),
+             expr->value()->num());
+    }
+  } else {
+    // Throw reference error.
+    Visit(expr->target());
+  }
+}
+
+
+void TextInstructionPrinter::VisitThrow(Throw* expr) {
+  PrintF("throw @%d", expr->exception()->num());
+}
+
+
+void TextInstructionPrinter::VisitProperty(Property* expr) {
+  if (expr->key()->IsPropertyName()) {
+    PrintF("@%d.", expr->obj()->num());
+    ASSERT(expr->key()->AsLiteral() != NULL);
+    expr->key()->AsLiteral()->handle()->Print();
+  } else {
+    PrintF("@%d[@%d]", expr->obj()->num(), expr->key()->num());
+  }
+}
+
+
+void TextInstructionPrinter::VisitCall(Call* expr) {
+  PrintF("@%d(", expr->expression()->num());
+  ZoneList<Expression*>* arguments = expr->arguments();
+  for (int i = 0, len = arguments->length(); i < len; i++) {
+    if (i != 0) PrintF(", ");
+    PrintF("@%d", arguments->at(i)->num());
+  }
+  PrintF(")");
+}
+
+
+void TextInstructionPrinter::VisitCallNew(CallNew* expr) {
+  PrintF("new @%d(", expr->expression()->num());
+  ZoneList<Expression*>* arguments = expr->arguments();
+  for (int i = 0, len = arguments->length(); i < len; i++) {
+    if (i != 0) PrintF(", ");
+    PrintF("@%d", arguments->at(i)->num());
+  }
+  PrintF(")");
+}
+
+
+void TextInstructionPrinter::VisitCallRuntime(CallRuntime* expr) {
+  SmartPointer<char> name = expr->name()->ToCString();
+  PrintF("%s(", *name);
+  ZoneList<Expression*>* arguments = expr->arguments();
+  for (int i = 0, len = arguments->length(); i < len; i++) {
+    if (i != 0) PrintF(", ");
+    PrintF("@%d", arguments->at(i)->num());
+  }
+  PrintF(")");
+}
+
+
+void TextInstructionPrinter::VisitUnaryOperation(UnaryOperation* expr) {
+  PrintF("%s(@%d)", Token::String(expr->op()), expr->expression()->num());
+}
+
+
+void TextInstructionPrinter::VisitCountOperation(CountOperation* expr) {
+  if (expr->is_prefix()) {
+    PrintF("%s@%d", Token::String(expr->op()), expr->expression()->num());
+  } else {
+    PrintF("@%d%s", expr->expression()->num(), Token::String(expr->op()));
+  }
+}
+
+
+void TextInstructionPrinter::VisitBinaryOperation(BinaryOperation* expr) {
+  ASSERT(expr->op() != Token::COMMA);
+  ASSERT(expr->op() != Token::OR);
+  ASSERT(expr->op() != Token::AND);
+  PrintF("@%d %s @%d",
+         expr->left()->num(),
+         Token::String(expr->op()),
+         expr->right()->num());
+}
+
+
+void TextInstructionPrinter::VisitCompareOperation(CompareOperation* expr) {
+  PrintF("@%d %s @%d",
+         expr->left()->num(),
+         Token::String(expr->op()),
+         expr->right()->num());
+}
+
+
+void TextInstructionPrinter::VisitThisFunction(ThisFunction* expr) {
+  PrintF("ThisFunction");
+}
+
+
+static int node_count = 0;
+static int instruction_count = 0;
+
+
+void Node::AssignNumbers() {
+  set_number(node_count++);
+}
+
+
+void BlockNode::AssignNumbers() {
+  set_number(node_count++);
+  for (int i = 0, len = instructions_.length(); i < len; i++) {
+    instructions_[i]->set_num(instruction_count++);
+  }
+}
+
+
+void EntryNode::PrintText() {
+  PrintF("L%d: Entry\n", number());
+  PrintF("goto L%d\n\n", successor_->number());
+}
+
+void ExitNode::PrintText() {
+  PrintF("L%d: Exit\n\n", number());
+}
+
+
+void BlockNode::PrintText() {
+  // Print the instructions in the block.
+  PrintF("L%d: Block\n", number());
+  TextInstructionPrinter printer;
+  for (int i = 0, len = instructions_.length(); i < len; i++) {
+    PrintF("%d ", instructions_[i]->num());
+    printer.Visit(instructions_[i]);
+    PrintF("\n");
+  }
+  PrintF("goto L%d\n\n", successor_->number());
+}
+
+
+void BranchNode::PrintText() {
+  PrintF("L%d: Branch\n", number());
+  PrintF("goto (L%d, L%d)\n\n", successor0_->number(), successor1_->number());
+}
+
+
+void JoinNode::PrintText() {
+  PrintF("L%d: Join(", number());
+  for (int i = 0, len = predecessors_.length(); i < len; i++) {
+    if (i != 0) PrintF(", ");
+    PrintF("L%d", predecessors_[i]->number());
+  }
+  PrintF(")\ngoto L%d\n\n", successor_->number());
+}
+
+
+void FlowGraph::PrintText(ZoneList<Node*>* postorder) {
+  PrintF("\n========\n");
+
+  // Number nodes and instructions in reverse postorder.
+  node_count = 0;
+  instruction_count = 0;
+  for (int i = postorder->length() - 1; i >= 0; i--) {
+    postorder->at(i)->AssignNumbers();
+  }
+
+  // Print basic blocks in reverse postorder.
+  for (int i = postorder->length() - 1; i >= 0; i--) {
+    postorder->at(i)->PrintText();
+  }
+}
+
+
+#endif  // defined(DEBUG)
+
+
 } }  // namespace v8::internal
index 2331944..2dc2d73 100644 (file)
 #ifndef V8_DATAFLOW_H_
 #define V8_DATAFLOW_H_
 
+#include "v8.h"
+
 #include "ast.h"
 #include "compiler.h"
+#include "zone-inl.h"
 
 namespace v8 {
 namespace internal {
 
+class BitVector: public ZoneObject {
+ public:
+  explicit BitVector(int length)
+      : length_(length),
+        data_length_(SizeFor(length)),
+        data_(Zone::NewArray<uint32_t>(data_length_)) {
+    ASSERT(length > 0);
+    Clear();
+  }
+
+  BitVector(const BitVector& other)
+      : length_(other.length()),
+        data_length_(SizeFor(length_)),
+        data_(Zone::NewArray<uint32_t>(data_length_)) {
+    CopyFrom(other);
+  }
+
+  static int SizeFor(int length) {
+    return 1 + ((length - 1) / 32);
+  }
+
+  BitVector& operator=(const BitVector& rhs) {
+    if (this != &rhs) CopyFrom(rhs);
+    return *this;
+  }
+
+  void CopyFrom(const BitVector& other) {
+    ASSERT(other.length() == length());
+    for (int i = 0; i < data_length_; i++) {
+      data_[i] = other.data_[i];
+    }
+  }
+
+  bool Contains(int i) {
+    ASSERT(i >= 0 && i < length());
+    uint32_t block = data_[i / 32];
+    return (block & (1U << (i % 32))) != 0;
+  }
+
+  void Add(int i) {
+    ASSERT(i >= 0 && i < length());
+    data_[i / 32] |= (1U << (i % 32));
+  }
+
+  void Remove(int i) {
+    ASSERT(i >= 0 && i < length());
+    data_[i / 32] &= ~(1U << (i % 32));
+  }
+
+  void Union(const BitVector& other) {
+    ASSERT(other.length() == length());
+    for (int i = 0; i < data_length_; i++) {
+      data_[i] |= other.data_[i];
+    }
+  }
+
+  void Intersect(const BitVector& other) {
+    ASSERT(other.length() == length());
+    for (int i = 0; i < data_length_; i++) {
+      data_[i] &= other.data_[i];
+    }
+  }
+
+  void Clear() {
+    for (int i = 0; i < data_length_; i++) {
+      data_[i] = 0;
+    }
+  }
+
+  bool IsEmpty() const {
+    for (int i = 0; i < data_length_; i++) {
+      if (data_[i] != 0) return false;
+    }
+    return true;
+  }
+
+  int length() const { return length_; }
+
+ private:
+  int length_;
+  int data_length_;
+  uint32_t* data_;
+};
+
+
+// Forward declarations of Node types.
+class Node;
+class BranchNode;
+class JoinNode;
+
+// Flow graphs have a single entry and single exit.  The empty flowgraph is
+// represented by both entry and exit being NULL.
+class FlowGraph BASE_EMBEDDED {
+ public:
+  FlowGraph() : entry_(NULL), exit_(NULL) {}
+
+  static FlowGraph Empty() { return FlowGraph(); }
+
+  bool is_empty() const { return entry_ == NULL; }
+  Node* entry() const { return entry_; }
+  Node* exit() const { return exit_; }
+
+  // Add a single instruction to the end of this flowgraph.
+  void AppendInstruction(AstNode* instruction);
+
+  // Add a single node to the end of this flow graph.
+  void AppendNode(Node* node);
+
+  // Add a flow graph fragment to the end of this one.
+  void AppendGraph(FlowGraph* graph);
+
+  // Concatenate an if-then-else flow-graph to this one.  Control is split
+  // and merged, so the graph remains single-entry, single-exit.
+  void Split(BranchNode* branch,
+             FlowGraph* left,
+             FlowGraph* right,
+             JoinNode* merge);
+
+  // Concatenate a forward loop (e.g., while or for loop) flow-graph to this
+  // one.  Control is split by the condition and merged back from the back
+  // edge at end of the body to the beginning of the condition.  The single
+  // (free) exit of the result graph is the right (false) arm of the branch
+  // node.
+  void Loop(JoinNode* merge,
+            FlowGraph* condition,
+            BranchNode* branch,
+            FlowGraph* body);
+
+#ifdef DEBUG
+  void PrintText(ZoneList<Node*>* postorder);
+#endif
+
+ private:
+  Node* entry_;
+  Node* exit_;
+};
+
+
+// Flow-graph nodes.
+class Node: public ZoneObject {
+ public:
+  Node() : number_(-1), mark_(false) {}
+
+  virtual ~Node() {}
+
+  virtual bool IsBlockNode() { return false; }
+  virtual bool IsJoinNode() { return false; }
+
+  virtual void AddPredecessor(Node* predecessor) = 0;
+  virtual void AddSuccessor(Node* successor) = 0;
+
+  bool IsMarkedWith(bool mark) { return mark_ == mark; }
+  void MarkWith(bool mark) { mark_ = mark; }
+
+  // Perform a depth first search and record preorder and postorder
+  // traversal orders.
+  virtual void Traverse(bool mark,
+                        ZoneList<Node*>* preorder,
+                        ZoneList<Node*>* postorder) = 0;
+
+  int number() { return number_; }
+  void set_number(int number) { number_ = number; }
+
+#ifdef DEBUG
+  virtual void AssignNumbers();
+  virtual void PrintText() = 0;
+#endif
+
+ private:
+  int number_;
+  bool mark_;
+
+  DISALLOW_COPY_AND_ASSIGN(Node);
+};
+
+
+// An entry node has no predecessors and a single successor.
+class EntryNode: public Node {
+ public:
+  EntryNode() : successor_(NULL) {}
+
+  void AddPredecessor(Node* predecessor) { UNREACHABLE(); }
+
+  void AddSuccessor(Node* successor) {
+    ASSERT(successor_ == NULL && successor != NULL);
+    successor_ = successor;
+  }
+
+  void Traverse(bool mark,
+                ZoneList<Node*>* preorder,
+                ZoneList<Node*>* postorder);
+
+#ifdef DEBUG
+  void PrintText();
+#endif
+
+ private:
+  Node* successor_;
+
+  DISALLOW_COPY_AND_ASSIGN(EntryNode);
+};
+
+
+// An exit node has a arbitrarily many predecessors and no successors.
+class ExitNode: public Node {
+ public:
+  ExitNode() : predecessors_(4) {}
+
+  void AddPredecessor(Node* predecessor) {
+    ASSERT(predecessor != NULL);
+    predecessors_.Add(predecessor);
+  }
+
+  void AddSuccessor(Node* successor) { /* Do nothing. */ }
+
+  void Traverse(bool mark,
+                ZoneList<Node*>* preorder,
+                ZoneList<Node*>* postorder);
+
+#ifdef DEBUG
+  void PrintText();
+#endif
+
+ private:
+  ZoneList<Node*> predecessors_;
+
+  DISALLOW_COPY_AND_ASSIGN(ExitNode);
+};
+
+
+// Block nodes have a single successor and predecessor and a list of
+// instructions.
+class BlockNode: public Node {
+ public:
+  BlockNode() : predecessor_(NULL), successor_(NULL), instructions_(4) {}
+
+  static BlockNode* cast(Node* node) {
+    ASSERT(node->IsBlockNode());
+    return reinterpret_cast<BlockNode*>(node);
+  }
+
+  bool IsBlockNode() { return true; }
+
+  void AddPredecessor(Node* predecessor) {
+    ASSERT(predecessor_ == NULL && predecessor != NULL);
+    predecessor_ = predecessor;
+  }
+
+  void AddSuccessor(Node* successor) {
+    ASSERT(successor_ == NULL && successor != NULL);
+    successor_ = successor;
+  }
+
+  void AddInstruction(AstNode* instruction) {
+    instructions_.Add(instruction);
+  }
+
+  void Traverse(bool mark,
+                ZoneList<Node*>* preorder,
+                ZoneList<Node*>* postorder);
+
+#ifdef DEBUG
+  void AssignNumbers();
+  void PrintText();
+#endif
+
+ private:
+  Node* predecessor_;
+  Node* successor_;
+  ZoneList<AstNode*> instructions_;
+
+  DISALLOW_COPY_AND_ASSIGN(BlockNode);
+};
+
+
+// Branch nodes have a single predecessor and a pair of successors.
+class BranchNode: public Node {
+ public:
+  BranchNode() : predecessor_(NULL), successor0_(NULL), successor1_(NULL) {}
+
+  void AddPredecessor(Node* predecessor) {
+    ASSERT(predecessor_ == NULL && predecessor != NULL);
+    predecessor_ = predecessor;
+  }
+
+  void AddSuccessor(Node* successor) {
+    ASSERT(successor1_ == NULL && successor != NULL);
+    if (successor0_ == NULL) {
+      successor0_ = successor;
+    } else {
+      successor1_ = successor;
+    }
+  }
+
+  void Traverse(bool mark,
+                ZoneList<Node*>* preorder,
+                ZoneList<Node*>* postorder);
+
+#ifdef DEBUG
+  void PrintText();
+#endif
+
+ private:
+  Node* predecessor_;
+  Node* successor0_;
+  Node* successor1_;
+
+  DISALLOW_COPY_AND_ASSIGN(BranchNode);
+};
+
+
+// Join nodes have arbitrarily many predecessors and a single successor.
+class JoinNode: public Node {
+ public:
+  JoinNode() : predecessors_(2), successor_(NULL) {}
+
+  static JoinNode* cast(Node* node) {
+    ASSERT(node->IsJoinNode());
+    return reinterpret_cast<JoinNode*>(node);
+  }
+
+  bool IsJoinNode() { return true; }
+
+  void AddPredecessor(Node* predecessor) {
+    ASSERT(predecessor != NULL);
+    predecessors_.Add(predecessor);
+  }
+
+  void AddSuccessor(Node* successor) {
+    ASSERT(successor_ == NULL && successor != NULL);
+    successor_ = successor;
+  }
+
+  void Traverse(bool mark,
+                ZoneList<Node*>* preorder,
+                ZoneList<Node*>* postorder);
+
+#ifdef DEBUG
+  void PrintText();
+#endif
+
+ private:
+  ZoneList<Node*> predecessors_;
+  Node* successor_;
+
+  DISALLOW_COPY_AND_ASSIGN(JoinNode);
+};
+
+
+// Construct a flow graph from a function literal.  Build pre- and postorder
+// traversal orders as a byproduct.
+class FlowGraphBuilder: public AstVisitor {
+ public:
+  FlowGraphBuilder()
+      : global_exit_(NULL),
+        preorder_(4),
+        postorder_(4),
+        definitions_(4) {
+  }
+
+  void Build(FunctionLiteral* lit);
+
+  FlowGraph* graph() { return &graph_; }
+
+  ZoneList<Node*>* postorder() { return &postorder_; }
+
+ private:
+  ExitNode* global_exit() { return global_exit_; }
+
+  // AST node visit functions.
+#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
+  AST_NODE_LIST(DECLARE_VISIT)
+#undef DECLARE_VISIT
+
+  FlowGraph graph_;
+  ExitNode* global_exit_;
+  ZoneList<Node*> preorder_;
+  ZoneList<Node*> postorder_;
+
+  // The flow graph builder collects a list of definitions (assignments and
+  // count operations) to stack-allocated variables to use for reaching
+  // definitions analysis.
+  ZoneList<AstNode*> definitions_;
+
+  DISALLOW_COPY_AND_ASSIGN(FlowGraphBuilder);
+};
+
+
 // This class is used to number all expressions in the AST according to
 // their evaluation order (post-order left-to-right traversal).
 class AstLabeler: public AstVisitor {
index 7d8f458..c0180c2 100644 (file)
@@ -113,8 +113,11 @@ function EquivalentTime(t) {
   // we must do this, but for compatibility with other browsers, we use
   // the actual year if it is in the range 1970..2037
   if (t >= 0 && t <= 2.1e12) return t;
-  var day = MakeDay(EquivalentYear(YEAR_FROM_TIME(t)), MONTH_FROM_TIME(t), DATE_FROM_TIME(t));
-  return TimeClip(MakeDate(day, TimeWithinDay(t)));
+
+  var day = MakeDay(EquivalentYear(YEAR_FROM_TIME(t)),
+                    MONTH_FROM_TIME(t),
+                    DATE_FROM_TIME(t));
+  return MakeDate(day, TimeWithinDay(t));
 }
 
 
@@ -257,14 +260,6 @@ function TimeInYear(year) {
 }
 
 
-// Compute modified Julian day from year, month, date.
-function ToJulianDay(year, month, date) {
-  var jy = (month > 1) ? year : year - 1;
-  var jm = (month > 1) ? month + 2 : month + 14;
-  var ja = FLOOR(jy / 100);
-  return FLOOR(FLOOR(365.25*jy) + FLOOR(30.6001*jm) + date + 1720995) + 2 - ja + FLOOR(0.25*ja);
-}
-
 var four_year_cycle_table = CalculateDateTable();
 
 
@@ -359,20 +354,18 @@ function FromJulianDay(julian) {
 function MakeDay(year, month, date) {
   if (!$isFinite(year) || !$isFinite(month) || !$isFinite(date)) return $NaN;
 
-  // Conversion to integers.
   year = TO_INTEGER(year);
   month = TO_INTEGER(month);
   date = TO_INTEGER(date);
 
-  // Overflow months into year.
-  year = year + FLOOR(month/12);
-  month = month % 12;
-  if (month < 0) {
-    month += 12;
+  if (year < kMinYear || year > kMaxYear ||
+      month < kMinMonth || month > kMaxMonth ||
+      date < kMinDate || date > kMaxDate) {
+    return $NaN;
   }
 
-  // Return days relative to Jan 1 1970.
-  return ToJulianDay(year, month, date) - kDayZeroInJulianDay;
+  // Now we rely on year, month and date being SMIs.
+  return %DateMakeDay(year, month, date);
 }
 
 
index 55c25a9..5ba5a3b 100644 (file)
@@ -1251,7 +1251,9 @@ DebugCommandProcessor.prototype.processDebugJSONRequest = function(json_request)
       } else if (request.command == 'version') {
         this.versionRequest_(request, response);
       } else if (request.command == 'profile') {
-        this.profileRequest_(request, response);
+          this.profileRequest_(request, response);
+      } else if (request.command == 'changelive') {
+          this.changeLiveRequest_(request, response);
       } else {
         throw new Error('Unknown command "' + request.command + '" in request');
       }
@@ -1954,6 +1956,52 @@ DebugCommandProcessor.prototype.profileRequest_ = function(request, response) {
 };
 
 
+DebugCommandProcessor.prototype.changeLiveRequest_ = function(request, response) {
+  if (!Debug.LiveEditChangeScript) {
+    return response.failed('LiveEdit feature is not supported');
+  }
+  if (!request.arguments) {
+    return response.failed('Missing arguments');
+  }
+  var script_id = request.arguments.script_id;
+  var change_pos = parseInt(request.arguments.change_pos);
+  var change_len = parseInt(request.arguments.change_len);
+  var new_string = request.arguments.new_string;
+  if (!IS_STRING(new_string)) {
+    response.failed('Argument "new_string" is not a string value');
+    return;
+  }
+  
+  var scripts = %DebugGetLoadedScripts();
+
+  var the_script = null;
+  for (var i = 0; i < scripts.length; i++) {
+    if (scripts[i].id == script_id) {
+      the_script = scripts[i];
+    }
+  }
+  if (!the_script) {
+    response.failed('Script not found');
+    return;
+  }
+  
+  var change_log = new Array();
+  try {
+    Debug.LiveEditChangeScript(the_script, change_pos, change_len, new_string,
+                               change_log);
+  } catch (e) {
+    if (e instanceof Debug.LiveEditChangeScript.Failure) {
+      // Let's treat it as a "success" so that body with change_log will be
+      // sent back. "change_log" will have "failure" field set.
+      change_log.push( { failure: true } ); 
+    } else {
+      throw e;
+    }
+  }
+  response.body = {change_log: change_log};
+};
+
+
 // Check whether the previously processed command caused the VM to become
 // running.
 DebugCommandProcessor.prototype.isRunning = function() {
index 8c4f51d..959bea1 100644 (file)
@@ -39,6 +39,7 @@
 #include "global-handles.h"
 #include "ic.h"
 #include "ic-inl.h"
+#include "messages.h"
 #include "natives.h"
 #include "stub-cache.h"
 #include "log.h"
@@ -123,7 +124,9 @@ void BreakLocationIterator::Next() {
     if (RelocInfo::IsCodeTarget(rmode())) {
       Address target = original_rinfo()->target_address();
       Code* code = Code::GetCodeFromTargetAddress(target);
-      if (code->is_inline_cache_stub() || RelocInfo::IsConstructCall(rmode())) {
+      if ((code->is_inline_cache_stub() &&
+           code->kind() != Code::BINARY_OP_IC) ||
+          RelocInfo::IsConstructCall(rmode())) {
         break_point_++;
         return;
       }
@@ -755,6 +758,12 @@ bool Debug::Load() {
   bool caught_exception =
       !CompileDebuggerScript(Natives::GetIndex("mirror")) ||
       !CompileDebuggerScript(Natives::GetIndex("debug"));
+
+  if (FLAG_enable_liveedit) {
+    caught_exception = caught_exception ||
+        !CompileDebuggerScript(Natives::GetIndex("liveedit"));
+  }
+
   Debugger::set_compiling_natives(false);
 
   // Make sure we mark the debugger as not loading before we might
@@ -1337,24 +1346,26 @@ Handle<Code> Debug::FindDebugBreak(Handle<Code> code, RelocInfo::Mode mode) {
   // Find the builtin debug break function matching the calling convention
   // used by the call site.
   if (code->is_inline_cache_stub()) {
-    if (code->is_call_stub()) {
-      return ComputeCallDebugBreak(code->arguments_count());
-    }
-    if (code->is_load_stub()) {
-      return Handle<Code>(Builtins::builtin(Builtins::LoadIC_DebugBreak));
-    }
-    if (code->is_store_stub()) {
-      return Handle<Code>(Builtins::builtin(Builtins::StoreIC_DebugBreak));
-    }
-    if (code->is_keyed_load_stub()) {
-      Handle<Code> result =
-          Handle<Code>(Builtins::builtin(Builtins::KeyedLoadIC_DebugBreak));
-      return result;
-    }
-    if (code->is_keyed_store_stub()) {
-      Handle<Code> result =
-          Handle<Code>(Builtins::builtin(Builtins::KeyedStoreIC_DebugBreak));
-      return result;
+    switch (code->kind()) {
+      case Code::CALL_IC:
+        return ComputeCallDebugBreak(code->arguments_count());
+
+      case Code::LOAD_IC:
+        return Handle<Code>(Builtins::builtin(Builtins::LoadIC_DebugBreak));
+
+      case Code::STORE_IC:
+        return Handle<Code>(Builtins::builtin(Builtins::StoreIC_DebugBreak));
+
+      case Code::KEYED_LOAD_IC:
+        return Handle<Code>(
+            Builtins::builtin(Builtins::KeyedLoadIC_DebugBreak));
+
+      case Code::KEYED_STORE_IC:
+        return Handle<Code>(
+            Builtins::builtin(Builtins::KeyedStoreIC_DebugBreak));
+
+      default:
+        UNREACHABLE();
     }
   }
   if (RelocInfo::IsConstructCall(mode)) {
@@ -1959,7 +1970,8 @@ void Debugger::OnBeforeCompile(Handle<Script> script) {
 
 
 // Handle debugger actions when a new script is compiled.
-void Debugger::OnAfterCompile(Handle<Script> script, Handle<JSFunction> fun) {
+void Debugger::OnAfterCompile(Handle<Script> script,
+                              AfterCompileFlags after_compile_flags) {
   HandleScope scope;
 
   // Add the newly compiled script to the script cache.
@@ -2006,7 +2018,7 @@ void Debugger::OnAfterCompile(Handle<Script> script, Handle<JSFunction> fun) {
     return;
   }
   // Bail out based on state or if there is no listener for this event
-  if (in_debugger) return;
+  if (in_debugger && (after_compile_flags & SEND_WHEN_DEBUGGING) == 0) return;
   if (!Debugger::EventActive(v8::AfterCompile)) return;
 
   // Create the compile state object.
index cab9e8e..546512b 100644 (file)
@@ -604,8 +604,13 @@ class Debugger {
   static void OnDebugBreak(Handle<Object> break_points_hit, bool auto_continue);
   static void OnException(Handle<Object> exception, bool uncaught);
   static void OnBeforeCompile(Handle<Script> script);
+
+  enum AfterCompileFlags {
+    NO_AFTER_COMPILE_FLAGS,
+    SEND_WHEN_DEBUGGING
+  };
   static void OnAfterCompile(Handle<Script> script,
-                           Handle<JSFunction> fun);
+                             AfterCompileFlags after_compile_flags);
   static void OnNewFunction(Handle<JSFunction> fun);
   static void OnScriptCollected(int id);
   static void ProcessDebugEvent(v8::DebugEvent event,
index 2a347cd..36911da 100644 (file)
 
 #include "globals.h"
 #include "heap.h"
-#include "zone-inl.h"
 
 namespace v8 {
 namespace internal {
 
+// Forward declarations.
+class ZoneScopeInfo;
 
 // Interface for handle based allocation.
 
index e96daf6..a0282bb 100644 (file)
@@ -93,6 +93,7 @@ class FastCodeGenerator: public AstVisitor {
   Register accumulator1();
   Register scratch0();
   Register scratch1();
+  Register scratch2();
   Register receiver_reg();
   Register context_reg();
 
index 6e22d5b..573d893 100644 (file)
@@ -153,6 +153,9 @@ DEFINE_bool(always_fast_compiler, false,
             "try to use the speculative optimizing backend for all code")
 DEFINE_bool(trace_bailout, false,
             "print reasons for falling back to using the classic V8 backend")
+DEFINE_bool(safe_int32_compiler, false,
+            "enable optimized side-effect-free int32 expressions.")
+DEFINE_bool(use_flow_graph, false, "perform flow-graph based optimizations")
 
 // compilation-cache.cc
 DEFINE_bool(compilation_cache, true, "enable compilation cache")
@@ -163,6 +166,7 @@ DEFINE_bool(trace_debug_json, false, "trace debugging JSON request/response")
 DEFINE_bool(debugger_auto_break, true,
             "automatically set the debug break flag when debugger commands are "
             "in the queue")
+DEFINE_bool(enable_liveedit, true, "enable liveedit experimental feature")
 
 // frames.cc
 DEFINE_int(max_stack_trace_source_length, 300,
@@ -230,9 +234,6 @@ DEFINE_bool(trace_exception, false,
 DEFINE_bool(preallocate_message_memory, false,
             "preallocate some memory to build stack traces.")
 
-// usage-analyzer.cc
-DEFINE_bool(usage_computation, true, "compute variable usage counts")
-
 // v8.cc
 DEFINE_bool(preemption, false,
             "activate a 100ms timer that switches between V8 threads")
@@ -304,6 +305,8 @@ DEFINE_string(stop_at, "", "function name where to insert a breakpoint")
 DEFINE_bool(print_builtin_scopes, false, "print scopes for builtins")
 DEFINE_bool(print_scopes, false, "print scopes")
 DEFINE_bool(print_ir, false, "print the AST as seen by the backend")
+DEFINE_bool(print_graph_text, false,
+            "print a text representation of the flow graph")
 
 // contexts.cc
 DEFINE_bool(trace_contexts, false, "trace contexts operations")
index 1455559..ee7be95 100644 (file)
@@ -28,6 +28,7 @@
 #include "v8.h"
 
 #include "frame-element.h"
+#include "zone-inl.h"
 
 namespace v8 {
 namespace internal {
index 5762814..3c5a389 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "number-info.h"
 #include "macro-assembler.h"
+#include "zone.h"
 
 namespace v8 {
 namespace internal {
@@ -53,23 +54,25 @@ class FrameElement BASE_EMBEDDED {
     SYNCED
   };
 
-  inline NumberInfo::Type number_info() {
+  inline NumberInfo number_info() {
     // Copied elements do not have number info. Instead
     // we have to inspect their backing element in the frame.
     ASSERT(!is_copy());
-    if (!is_constant()) return NumberInfoField::decode(value_);
+    if (!is_constant()) {
+      return NumberInfo::FromInt(NumberInfoField::decode(value_));
+    }
     Handle<Object> value = handle();
-    if (value->IsSmi()) return NumberInfo::kSmi;
-    if (value->IsHeapNumber()) return NumberInfo::kHeapNumber;
-    return NumberInfo::kUnknown;
+    if (value->IsSmi()) return NumberInfo::Smi();
+    if (value->IsHeapNumber()) return NumberInfo::HeapNumber();
+    return NumberInfo::Unknown();
   }
 
-  inline void set_number_info(NumberInfo::Type info) {
+  inline void set_number_info(NumberInfo info) {
     // Copied elements do not have number info. Instead
     // we have to inspect their backing element in the frame.
     ASSERT(!is_copy());
     value_ = value_ & ~NumberInfoField::mask();
-    value_ = value_ | NumberInfoField::encode(info);
+    value_ = value_ | NumberInfoField::encode(info.ToInt());
   }
 
   // The default constructor creates an invalid frame element.
@@ -77,7 +80,7 @@ class FrameElement BASE_EMBEDDED {
     value_ = TypeField::encode(INVALID)
         | CopiedField::encode(false)
         | SyncedField::encode(false)
-        | NumberInfoField::encode(NumberInfo::kUninitialized)
+        | NumberInfoField::encode(NumberInfo::Uninitialized().ToInt())
         | DataField::encode(0);
   }
 
@@ -88,7 +91,7 @@ class FrameElement BASE_EMBEDDED {
   }
 
   // Factory function to construct an in-memory frame element.
-  static FrameElement MemoryElement(NumberInfo::Type info) {
+  static FrameElement MemoryElement(NumberInfo info) {
     FrameElement result(MEMORY, no_reg, SYNCED, info);
     return result;
   }
@@ -96,7 +99,7 @@ class FrameElement BASE_EMBEDDED {
   // Factory function to construct an in-register frame element.
   static FrameElement RegisterElement(Register reg,
                                       SyncFlag is_synced,
-                                      NumberInfo::Type info) {
+                                      NumberInfo info) {
     return FrameElement(REGISTER, reg, is_synced, info);
   }
 
@@ -210,11 +213,11 @@ class FrameElement BASE_EMBEDDED {
   FrameElement(Type type,
                Register reg,
                SyncFlag is_synced,
-               NumberInfo::Type info) {
+               NumberInfo info) {
     value_ = TypeField::encode(type)
         | CopiedField::encode(false)
         | SyncedField::encode(is_synced != NOT_SYNCED)
-        | NumberInfoField::encode(info)
+        | NumberInfoField::encode(info.ToInt())
         | DataField::encode(reg.code_ > 0 ? reg.code_ : 0);
   }
 
@@ -223,7 +226,7 @@ class FrameElement BASE_EMBEDDED {
     value_ = TypeField::encode(CONSTANT)
         | CopiedField::encode(false)
         | SyncedField::encode(is_synced != NOT_SYNCED)
-        | NumberInfoField::encode(NumberInfo::kUninitialized)
+        | NumberInfoField::encode(NumberInfo::Uninitialized().ToInt())
         | DataField::encode(ConstantList()->length());
     ConstantList()->Add(value);
   }
@@ -252,8 +255,8 @@ class FrameElement BASE_EMBEDDED {
   class TypeField: public BitField<Type, 0, 3> {};
   class CopiedField: public BitField<bool, 3, 1> {};
   class SyncedField: public BitField<bool, 4, 1> {};
-  class NumberInfoField: public BitField<NumberInfo::Type, 5, 3> {};
-  class DataField: public BitField<uint32_t, 8, 32 - 8> {};
+  class NumberInfoField: public BitField<int, 5, 4> {};
+  class DataField: public BitField<uint32_t, 9, 32 - 9> {};
 
   friend class VirtualFrame;
 };
index 5d88265..3bf4c93 100644 (file)
@@ -32,7 +32,6 @@
 #include "scopeinfo.h"
 #include "string-stream.h"
 #include "top.h"
-#include "zone-inl.h"
 
 namespace v8 {
 namespace internal {
index 8f6f47c..3840fee 100644 (file)
@@ -261,6 +261,8 @@ template<class Allocator = FreeStoreAllocationPolicy> class ScopeInfo;
 class Script;
 class Slot;
 class Smi;
+template <typename Config, class Allocator = FreeStoreAllocationPolicy>
+    class SplayTree;
 class Statement;
 class String;
 class Struct;
index 971c916..c71d92b 100644 (file)
@@ -203,7 +203,7 @@ void TransformToFastProperties(Handle<JSObject> object,
 
 
 void FlattenString(Handle<String> string) {
-  CALL_HEAP_FUNCTION_VOID(string->TryFlattenIfNotFlat());
+  CALL_HEAP_FUNCTION_VOID(string->TryFlatten());
   ASSERT(string->IsFlat());
 }
 
@@ -283,6 +283,12 @@ Handle<Object> GetProperty(Handle<Object> obj,
 }
 
 
+Handle<Object> GetElement(Handle<Object> obj,
+                          uint32_t index) {
+  CALL_HEAP_FUNCTION(Runtime::GetElement(obj, index), Object);
+}
+
+
 Handle<Object> GetPropertyWithInterceptor(Handle<JSObject> receiver,
                                           Handle<JSObject> holder,
                                           Handle<String> name,
@@ -362,8 +368,11 @@ Handle<Object> LookupSingleCharacterStringFromCode(uint32_t index) {
 }
 
 
-Handle<String> SubString(Handle<String> str, int start, int end) {
-  CALL_HEAP_FUNCTION(str->SubString(start, end), String);
+Handle<String> SubString(Handle<String> str,
+                         int start,
+                         int end,
+                         PretenureFlag pretenure) {
+  CALL_HEAP_FUNCTION(str->SubString(start, end, pretenure), String);
 }
 
 
index 90e51fa..0c137a4 100644 (file)
@@ -233,6 +233,9 @@ Handle<Object> GetProperty(Handle<JSObject> obj,
 Handle<Object> GetProperty(Handle<Object> obj,
                            Handle<Object> key);
 
+Handle<Object> GetElement(Handle<Object> obj,
+                          uint32_t index);
+
 Handle<Object> GetPropertyWithInterceptor(Handle<JSObject> receiver,
                                           Handle<JSObject> holder,
                                           Handle<String> name,
@@ -287,7 +290,10 @@ Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
 Handle<FixedArray> UnionOfKeys(Handle<FixedArray> first,
                                Handle<FixedArray> second);
 
-Handle<String> SubString(Handle<String> str, int start, int end);
+Handle<String> SubString(Handle<String> str,
+                         int start,
+                         int end,
+                         PretenureFlag pretenure = NOT_TENURED);
 
 
 // Sets the expected number of properties for the function's instances.
index f18bf0f..1acdb2a 100644 (file)
@@ -187,6 +187,18 @@ void Heap::RecordWrite(Address address, int offset) {
 }
 
 
+void Heap::RecordWrites(Address address, int start, int len) {
+  if (new_space_.Contains(address)) return;
+  ASSERT(!new_space_.FromSpaceContains(address));
+  for (int offset = start;
+       offset < start + len * kPointerSize;
+       offset += kPointerSize) {
+    SLOW_ASSERT(Contains(address + offset));
+    Page::SetRSet(address, offset);
+  }
+}
+
+
 OldSpace* Heap::TargetSpace(HeapObject* object) {
   InstanceType type = object->map()->instance_type();
   AllocationSpace space = TargetSpaceId(type);
index 3cb65ee..90544f1 100644 (file)
@@ -31,6 +31,7 @@
 #include "frames-inl.h"
 #include "global-handles.h"
 #include "string-stream.h"
+#include "zone-inl.h"
 
 namespace v8 {
 namespace internal {
index c615942..d6f2650 100644 (file)
@@ -28,6 +28,8 @@
 #ifndef V8_HEAP_PROFILER_H_
 #define V8_HEAP_PROFILER_H_
 
+#include "zone.h"
+
 namespace v8 {
 namespace internal {
 
index 9ff57d2..fbe0464 100644 (file)
@@ -46,6 +46,7 @@
 #include "arm/regexp-macro-assembler-arm.h"
 #endif
 
+
 namespace v8 {
 namespace internal {
 
@@ -371,11 +372,6 @@ void Heap::CollectAllGarbage(bool force_compaction) {
 }
 
 
-void Heap::NotifyContextDisposed() {
-  contexts_disposed_++;
-}
-
-
 bool Heap::CollectGarbage(int requested_size, AllocationSpace space) {
   // The VM is in the GC state until exiting this function.
   VMState state(GC);
@@ -545,12 +541,22 @@ void Heap::PerformGarbageCollection(AllocationSpace space,
   VerifySymbolTable();
   if (collector == MARK_COMPACTOR && global_gc_prologue_callback_) {
     ASSERT(!allocation_allowed_);
+    GCTracer::ExternalScope scope(tracer);
     global_gc_prologue_callback_();
   }
   EnsureFromSpaceIsCommitted();
+
+  // Perform mark-sweep with optional compaction.
   if (collector == MARK_COMPACTOR) {
     MarkCompact(tracer);
+  }
+
+  // Always perform a scavenge to make room in new space.
+  Scavenge();
 
+  // Update the old space promotion limits after the scavenge due to
+  // promotions during scavenge.
+  if (collector == MARK_COMPACTOR) {
     int old_gen_size = PromotedSpaceSize();
     old_gen_promotion_limit_ =
         old_gen_size + Max(kMinimumPromotionLimit, old_gen_size / 3);
@@ -558,12 +564,12 @@ void Heap::PerformGarbageCollection(AllocationSpace space,
         old_gen_size + Max(kMinimumAllocationLimit, old_gen_size / 2);
     old_gen_exhausted_ = false;
   }
-  Scavenge();
 
   Counters::objs_since_last_young.Set(0);
 
   if (collector == MARK_COMPACTOR) {
     DisableAssertNoAllocation allow_allocation;
+    GCTracer::ExternalScope scope(tracer);
     GlobalHandles::PostGarbageCollectionProcessing();
   }
 
@@ -578,6 +584,7 @@ void Heap::PerformGarbageCollection(AllocationSpace space,
 
   if (collector == MARK_COMPACTOR && global_gc_epilogue_callback_) {
     ASSERT(!allocation_allowed_);
+    GCTracer::ExternalScope scope(tracer);
     global_gc_epilogue_callback_();
   }
   VerifySymbolTable();
@@ -1209,6 +1216,16 @@ Object* Heap::AllocateMap(InstanceType instance_type, int instance_size) {
 }
 
 
+Object* Heap::AllocateCodeCache() {
+  Object* result = AllocateStruct(CODE_CACHE_TYPE);
+  if (result->IsFailure()) return result;
+  CodeCache* code_cache = CodeCache::cast(result);
+  code_cache->set_default_cache(empty_fixed_array());
+  code_cache->set_normal_type_cache(undefined_value());
+  return code_cache;
+}
+
+
 const Heap::StringTypeTable Heap::string_type_table[] = {
 #define STRING_TYPE_ELEMENT(type, size, name, camel_name)                      \
   {type, size, k##camel_name##MapRootIndex},
@@ -1625,7 +1642,7 @@ bool Heap::CreateInitialObjects() {
   if (InitializeNumberStringCache()->IsFailure()) return false;
 
   // Allocate cache for single character strings.
-  obj = AllocateFixedArray(String::kMaxAsciiCharCode+1);
+  obj = AllocateFixedArray(String::kMaxAsciiCharCode+1, TENURED);
   if (obj->IsFailure()) return false;
   set_single_character_string_cache(FixedArray::cast(obj));
 
@@ -1659,7 +1676,7 @@ Object* Heap::InitializeNumberStringCache() {
   // max_semispace_size_ ==   8 MB => number_string_cache_size = 16KB.
   int number_string_cache_size = max_semispace_size_ / 512;
   number_string_cache_size = Max(32, Min(16*KB, number_string_cache_size));
-  Object* obj = AllocateFixedArray(number_string_cache_size * 2);
+  Object* obj = AllocateFixedArray(number_string_cache_size * 2, TENURED);
   if (!obj->IsFailure()) set_number_string_cache(FixedArray::cast(obj));
   return obj;
 }
@@ -1982,7 +1999,8 @@ Object* Heap::AllocateConsString(String* first, String* second) {
 
 Object* Heap::AllocateSubString(String* buffer,
                                 int start,
-                                int end) {
+                                int end,
+                                PretenureFlag pretenure) {
   int length = end - start;
 
   if (length == 1) {
@@ -1998,16 +2016,13 @@ Object* Heap::AllocateSubString(String* buffer,
   }
 
   // Make an attempt to flatten the buffer to reduce access time.
-  if (!buffer->IsFlat()) {
-    buffer->TryFlatten();
-  }
+  buffer->TryFlatten();
 
   Object* result = buffer->IsAsciiRepresentation()
-      ? AllocateRawAsciiString(length)
-      : AllocateRawTwoByteString(length);
+      ? AllocateRawAsciiString(length, pretenure )
+      : AllocateRawTwoByteString(length, pretenure);
   if (result->IsFailure()) return result;
   String* string_result = String::cast(result);
-
   // Copy the characters into the new object.
   if (buffer->IsAsciiRepresentation()) {
     ASSERT(string_result->IsAsciiRepresentation());
@@ -2957,6 +2972,18 @@ Object* Heap::AllocateFixedArray(int length, PretenureFlag pretenure) {
 }
 
 
+Object* Heap::AllocateUninitializedFixedArray(int length) {
+  if (length == 0) return empty_fixed_array();
+
+  Object* obj = AllocateRawFixedArray(length);
+  if (obj->IsFailure()) return obj;
+
+  reinterpret_cast<FixedArray*>(obj)->set_map(fixed_array_map());
+  FixedArray::cast(obj)->set_length(length);
+  return obj;
+}
+
+
 Object* Heap::AllocateFixedArrayWithHoles(int length) {
   if (length == 0) return empty_fixed_array();
   Object* result = AllocateRawFixedArray(length);
@@ -2966,18 +2993,17 @@ Object* Heap::AllocateFixedArrayWithHoles(int length) {
     FixedArray* array = FixedArray::cast(result);
     array->set_length(length);
     // Initialize body.
-    Object* value = the_hole_value();
-    for (int index = 0; index < length; index++)  {
-      ASSERT(!Heap::InNewSpace(value));  // value = the hole
-      array->set(index, value, SKIP_WRITE_BARRIER);
-    }
+    ASSERT(!Heap::InNewSpace(the_hole_value()));
+    MemsetPointer(HeapObject::RawField(array, FixedArray::kHeaderSize),
+                  the_hole_value(),
+                  length);
   }
   return result;
 }
 
 
-Object* Heap::AllocateHashTable(int length) {
-  Object* result = Heap::AllocateFixedArray(length);
+Object* Heap::AllocateHashTable(int length, PretenureFlag pretenure) {
+  Object* result = Heap::AllocateFixedArray(length, pretenure);
   if (result->IsFailure()) return result;
   reinterpret_cast<Array*>(result)->set_map(hash_table_map());
   ASSERT(result->IsHashTable());
@@ -3060,13 +3086,7 @@ bool Heap::IdleNotification() {
   static int number_idle_notifications = 0;
   static int last_gc_count = gc_count_;
 
-  if (!FLAG_expose_gc && (contexts_disposed_ > 0)) {
-    HistogramTimerScope scope(&Counters::gc_context);
-    CollectAllGarbage(false);
-    ASSERT(contexts_disposed_ == 0);
-    return false;
-  }
-
+  bool uncommit = true;
   bool finished = false;
 
   if (last_gc_count == gc_count_) {
@@ -3077,7 +3097,12 @@ bool Heap::IdleNotification() {
   }
 
   if (number_idle_notifications == kIdlesBeforeScavenge) {
-    CollectGarbage(0, NEW_SPACE);
+    if (contexts_disposed_ > 0) {
+      HistogramTimerScope scope(&Counters::gc_context);
+      CollectAllGarbage(false);
+    } else {
+      CollectGarbage(0, NEW_SPACE);
+    }
     new_space_.Shrink();
     last_gc_count = gc_count_;
 
@@ -3097,10 +3122,29 @@ bool Heap::IdleNotification() {
     last_gc_count = gc_count_;
     number_idle_notifications = 0;
     finished = true;
+
+  } else if (contexts_disposed_ > 0) {
+    if (FLAG_expose_gc) {
+      contexts_disposed_ = 0;
+    } else {
+      HistogramTimerScope scope(&Counters::gc_context);
+      CollectAllGarbage(false);
+      last_gc_count = gc_count_;
+    }
+    // If this is the first idle notification, we reset the
+    // notification count to avoid letting idle notifications for
+    // context disposal garbage collections start a potentially too
+    // aggressive idle GC cycle.
+    if (number_idle_notifications <= 1) {
+      number_idle_notifications = 0;
+      uncommit = false;
+    }
   }
 
-  // Uncommit unused memory in new space.
-  Heap::UncommitFromSpace();
+  // Make sure that we have no pending context disposals and
+  // conditionally uncommit from space.
+  ASSERT(contexts_disposed_ == 0);
+  if (uncommit) Heap::UncommitFromSpace();
   return finished;
 }
 
@@ -4062,6 +4106,7 @@ void Heap::TracePathToGlobal() {
 GCTracer::GCTracer()
     : start_time_(0.0),
       start_size_(0.0),
+      external_time_(0.0),
       gc_count_(0),
       full_gc_count_(0),
       is_compacting_(false),
@@ -4079,10 +4124,12 @@ GCTracer::GCTracer()
 GCTracer::~GCTracer() {
   if (!FLAG_trace_gc) return;
   // Printf ONE line iff flag is set.
-  PrintF("%s %.1f -> %.1f MB, %d ms.\n",
-         CollectorString(),
-         start_size_, SizeOfHeapObjects(),
-         static_cast<int>(OS::TimeCurrentMillis() - start_time_));
+  int time = static_cast<int>(OS::TimeCurrentMillis() - start_time_);
+  int external_time = static_cast<int>(external_time_);
+  PrintF("%s %.1f -> %.1f MB, ",
+         CollectorString(), start_size_, SizeOfHeapObjects());
+  if (external_time > 0) PrintF("%d / ", external_time);
+  PrintF("%d ms.\n", time);
 
 #if defined(ENABLE_LOGGING_AND_PROFILING)
   Heap::PrintShortHeapStatistics();
index 5084649..eee5a05 100644 (file)
 
 #include <math.h>
 
-#include "zone-inl.h"
-
+#include "splay-tree-inl.h"
+#include "v8-counters.h"
 
 namespace v8 {
 namespace internal {
 
+// Forward declarations.
+class ZoneScopeInfo;
+
 // Defines all the roots in Heap.
 #define UNCONDITIONAL_STRONG_ROOT_LIST(V)                                      \
   /* Put the byte array map early.  We need it to be in place by the time   */ \
@@ -345,6 +348,9 @@ class Heap : public AllStatic {
   // Allocate a map for the specified function
   static Object* AllocateInitialMap(JSFunction* fun);
 
+  // Allocates an empty code cache.
+  static Object* AllocateCodeCache();
+
   // Allocates and fully initializes a String.  There are two String
   // encodings: ASCII and two byte. One should choose between the three string
   // allocation functions based on the encoding of the string buffer used to
@@ -449,9 +455,16 @@ class Heap : public AllStatic {
   // failed.
   // Please note this does not perform a garbage collection.
   static Object* AllocateFixedArray(int length, PretenureFlag pretenure);
-  // Allocate uninitialized, non-tenured fixed array with length elements.
+  // Allocates a fixed array initialized with undefined values
   static Object* AllocateFixedArray(int length);
 
+  // Allocates an uninitialized fixed array. It must be filled by the caller.
+  //
+  // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
+  // failed.
+  // Please note this does not perform a garbage collection.
+  static Object* AllocateUninitializedFixedArray(int length);
+
   // Make a copy of src and return it. Returns
   // Failure::RetryAfterGC(requested_bytes, space) if the allocation failed.
   static Object* CopyFixedArray(FixedArray* src);
@@ -464,7 +477,8 @@ class Heap : public AllStatic {
 
   // AllocateHashTable is identical to AllocateFixedArray except
   // that the resulting object has hash_table_map as map.
-  static Object* AllocateHashTable(int length);
+  static Object* AllocateHashTable(int length,
+                                   PretenureFlag pretenure = NOT_TENURED);
 
   // Allocate a global (but otherwise uninitialized) context.
   static Object* AllocateGlobalContext();
@@ -556,7 +570,8 @@ class Heap : public AllStatic {
   // Please note this does not perform a garbage collection.
   static Object* AllocateSubString(String* buffer,
                                    int start,
-                                   int end);
+                                   int end,
+                                   PretenureFlag pretenure = NOT_TENURED);
 
   // Allocate a new external string object, which is backed by a string
   // resource that resides outside the V8 heap.
@@ -633,7 +648,7 @@ class Heap : public AllStatic {
   static void CollectAllGarbage(bool force_compaction);
 
   // Notify the heap that a context has been disposed.
-  static void NotifyContextDisposed();
+  static int NotifyContextDisposed() { return ++contexts_disposed_; }
 
   // Utility to invoke the scavenger. This is needed in test code to
   // ensure correct callback for weak global handles.
@@ -765,6 +780,9 @@ class Heap : public AllStatic {
   // Write barrier support for address[offset] = o.
   static inline void RecordWrite(Address address, int offset);
 
+  // Write barrier support for address[start : start + len[ = o.
+  static inline void RecordWrites(Address address, int start, int len);
+
   // Given an address occupied by a live code object, return that object.
   static Object* FindCodeObject(Address a);
 
@@ -1518,8 +1536,23 @@ class DisableAssertNoAllocation {
 
 class GCTracer BASE_EMBEDDED {
  public:
-  GCTracer();
+  // Time spent while in the external scope counts towards the
+  // external time in the tracer and will be reported separately.
+  class ExternalScope BASE_EMBEDDED {
+   public:
+    explicit ExternalScope(GCTracer* tracer) : tracer_(tracer) {
+      start_time_ = OS::TimeCurrentMillis();
+    }
+    ~ExternalScope() {
+      tracer_->external_time_ += OS::TimeCurrentMillis() - start_time_;
+    }
+
+   private:
+    GCTracer* tracer_;
+    double start_time_;
+  };
 
+  GCTracer();
   ~GCTracer();
 
   // Sets the collector.
@@ -1553,6 +1586,9 @@ class GCTracer BASE_EMBEDDED {
   double start_size_;  // Size of objects in heap set in constructor.
   GarbageCollector collector_;  // Type of collector.
 
+  // Keep track of the amount of time spent in external callbacks.
+  double external_time_;
+
   // A count (including this one, eg, the first collection is 1) of the
   // number of garbage collections.
   int gc_count_;
@@ -1608,6 +1644,7 @@ class TranscendentalCache {
     if (e.in[0] == c.integers[0] &&
         e.in[1] == c.integers[1]) {
       ASSERT(e.output != NULL);
+      Counters::transcendental_cache_hit.Increment();
       return e.output;
     }
     double answer = Calculate(input);
@@ -1617,6 +1654,7 @@ class TranscendentalCache {
       elements_[hash].in[1] = c.integers[1];
       elements_[hash].output = heap_number;
     }
+    Counters::transcendental_cache_miss.Increment();
     return heap_number;
   }
 
@@ -1657,6 +1695,17 @@ class TranscendentalCache {
     hash ^= hash >> 8;
     return (hash & (kCacheSize - 1));
   }
+
+  static Address cache_array_address() {
+    // Used to create an external reference.
+    return reinterpret_cast<Address>(caches_);
+  }
+
+  // Allow access to the caches_ array as an ExternalReference.
+  friend class ExternalReference;
+  // Inline implementation of the caching.
+  friend class TranscendentalCacheStub;
+
   static TranscendentalCache* caches_[kNumberOfCaches];
   Element elements_[kCacheSize];
   Type type_;
index ffcefe0..f13556b 100644 (file)
@@ -753,6 +753,13 @@ void Assembler::cmov(Condition cc, Register dst, const Operand& src) {
 }
 
 
+void Assembler::cld() {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xFC);
+}
+
+
 void Assembler::rep_movs() {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
@@ -761,6 +768,14 @@ void Assembler::rep_movs() {
 }
 
 
+void Assembler::rep_stos() {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xF3);
+  EMIT(0xAB);
+}
+
+
 void Assembler::xchg(Register dst, Register src) {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
@@ -1637,6 +1652,13 @@ void Assembler::fld(int i) {
 }
 
 
+void Assembler::fstp(int i) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  emit_farith(0xDD, 0xD8, i);
+}
+
+
 void Assembler::fld1() {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
@@ -1645,6 +1667,14 @@ void Assembler::fld1() {
 }
 
 
+void Assembler::fldpi() {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xD9);
+  EMIT(0xEB);
+}
+
+
 void Assembler::fldz() {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
@@ -1685,6 +1715,14 @@ void Assembler::fstp_d(const Operand& adr) {
 }
 
 
+void Assembler::fst_d(const Operand& adr) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xDD);
+  emit_operand(edx, adr);
+}
+
+
 void Assembler::fild_s(const Operand& adr) {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
@@ -2012,6 +2050,17 @@ void Assembler::cvtsi2sd(XMMRegister dst, const Operand& src) {
 }
 
 
+void Assembler::cvtss2sd(XMMRegister dst, XMMRegister src) {
+  ASSERT(CpuFeatures::IsEnabled(SSE2));
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xF3);
+  EMIT(0x0F);
+  EMIT(0x5A);
+  emit_sse_operand(dst, src);
+}
+
+
 void Assembler::addsd(XMMRegister dst, XMMRegister src) {
   ASSERT(CpuFeatures::IsEnabled(SSE2));
   EnsureSpace ensure_space(this);
@@ -2067,6 +2116,16 @@ void Assembler::xorpd(XMMRegister dst, XMMRegister src) {
 }
 
 
+void Assembler::sqrtsd(XMMRegister dst, XMMRegister src) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xF2);
+  EMIT(0x0F);
+  EMIT(0x51);
+  emit_sse_operand(dst, src);
+}
+
+
 void Assembler::comisd(XMMRegister dst, XMMRegister src) {
   ASSERT(CpuFeatures::IsEnabled(SSE2));
   EnsureSpace ensure_space(this);
@@ -2078,6 +2137,17 @@ void Assembler::comisd(XMMRegister dst, XMMRegister src) {
 }
 
 
+void Assembler::ucomisd(XMMRegister dst, XMMRegister src) {
+  ASSERT(CpuFeatures::IsEnabled(SSE2));
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x66);
+  EMIT(0x0F);
+  EMIT(0x2E);
+  emit_sse_operand(dst, src);
+}
+
+
 void Assembler::movdqa(const Operand& dst, XMMRegister src ) {
   ASSERT(CpuFeatures::IsEnabled(SSE2));
   EnsureSpace ensure_space(this);
@@ -2157,6 +2227,50 @@ void Assembler::movsd(XMMRegister dst, const Operand& src) {
   emit_sse_operand(dst, src);
 }
 
+void Assembler::movsd(XMMRegister dst, XMMRegister src) {
+  ASSERT(CpuFeatures::IsEnabled(SSE2));
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xF2);
+  EMIT(0x0F);
+  EMIT(0x10);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::movd(XMMRegister dst, const Operand& src) {
+  ASSERT(CpuFeatures::IsEnabled(SSE2));
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x66);
+  EMIT(0x0F);
+  EMIT(0x6E);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::pxor(XMMRegister dst, XMMRegister src) {
+  ASSERT(CpuFeatures::IsEnabled(SSE2));
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x66);
+  EMIT(0x0F);
+  EMIT(0xEF);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::ptest(XMMRegister dst, XMMRegister src) {
+  ASSERT(CpuFeatures::IsEnabled(SSE2));
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x66);
+  EMIT(0x0F);
+  EMIT(0x38);
+  EMIT(0x17);
+  emit_sse_operand(dst, src);
+}
+
 
 void Assembler::emit_sse_operand(XMMRegister reg, const Operand& adr) {
   Register ireg = { reg.code() };
index 3d7af82..4497e2a 100644 (file)
@@ -93,7 +93,7 @@ const Register no_reg = { -1 };
 
 
 struct XMMRegister {
-  bool is_valid() const  { return 0 <= code_ && code_ < 2; }  // currently
+  bool is_valid() const  { return 0 <= code_ && code_ < 8; }
   int code() const  {
     ASSERT(is_valid());
     return code_;
@@ -542,8 +542,12 @@ class Assembler : public Malloced {
   void cmov(Condition cc, Register dst, Handle<Object> handle);
   void cmov(Condition cc, Register dst, const Operand& src);
 
+  // Flag management.
+  void cld();
+
   // Repetitive string instructions.
   void rep_movs();
+  void rep_stos();
 
   // Exchange two registers
   void xchg(Register dst, Register src);
@@ -668,6 +672,7 @@ class Assembler : public Malloced {
   void call(Label* L);
   void call(byte* entry, RelocInfo::Mode rmode);
   void call(const Operand& adr);
+  void call(const ExternalReference& target);
   void call(Handle<Code> code, RelocInfo::Mode rmode);
 
   // Jumps
@@ -683,15 +688,18 @@ class Assembler : public Malloced {
 
   // Floating-point operations
   void fld(int i);
+  void fstp(int i);
 
   void fld1();
   void fldz();
+  void fldpi();
 
   void fld_s(const Operand& adr);
   void fld_d(const Operand& adr);
 
   void fstp_s(const Operand& adr);
   void fstp_d(const Operand& adr);
+  void fst_d(const Operand& adr);
 
   void fild_s(const Operand& adr);
   void fild_d(const Operand& adr);
@@ -750,14 +758,17 @@ class Assembler : public Malloced {
   void cvttsd2si(Register dst, const Operand& src);
 
   void cvtsi2sd(XMMRegister dst, const Operand& src);
+  void cvtss2sd(XMMRegister dst, XMMRegister src);
 
   void addsd(XMMRegister dst, XMMRegister src);
   void subsd(XMMRegister dst, XMMRegister src);
   void mulsd(XMMRegister dst, XMMRegister src);
   void divsd(XMMRegister dst, XMMRegister src);
   void xorpd(XMMRegister dst, XMMRegister src);
+  void sqrtsd(XMMRegister dst, XMMRegister src);
 
   void comisd(XMMRegister dst, XMMRegister src);
+  void ucomisd(XMMRegister dst, XMMRegister src);
 
   void movdqa(XMMRegister dst, const Operand& src);
   void movdqa(const Operand& dst, XMMRegister src);
@@ -768,6 +779,12 @@ class Assembler : public Malloced {
   void movdbl(XMMRegister dst, const Operand& src);
   void movdbl(const Operand& dst, XMMRegister src);
 
+  void movd(XMMRegister dst, const Operand& src);
+  void movsd(XMMRegister dst, XMMRegister src);
+
+  void pxor(XMMRegister dst, XMMRegister src);
+  void ptest(XMMRegister dst, XMMRegister src);
+
   // Debugging
   void Print();
 
index 54ef382..80e421b 100644 (file)
@@ -63,10 +63,10 @@ void Builtins::Generate_Adaptor(MacroAssembler* masm,
     ASSERT(extra_args == NO_EXTRA_ARGUMENTS);
   }
 
-  // JumpToRuntime expects eax to contain the number of arguments
+  // JumpToExternalReference expects eax to contain the number of arguments
   // including the receiver and the extra arguments.
   __ add(Operand(eax), Immediate(num_extra_args + 1));
-  __ JumpToRuntime(ExternalReference(id));
+  __ JumpToExternalReference(ExternalReference(id));
 }
 
 
@@ -797,38 +797,23 @@ static void AllocateEmptyJSArray(MacroAssembler* masm,
 // register elements_array is scratched.
 static void AllocateJSArray(MacroAssembler* masm,
                             Register array_function,  // Array function.
-                            Register array_size,  // As a smi.
+                            Register array_size,  // As a smi, cannot be 0.
                             Register result,
                             Register elements_array,
                             Register elements_array_end,
                             Register scratch,
                             bool fill_with_hole,
                             Label* gc_required) {
-  Label not_empty, allocated;
+  ASSERT(scratch.is(edi));  // rep stos destination
+  ASSERT(!fill_with_hole || array_size.is(ecx));  // rep stos count
 
   // Load the initial map from the array function.
   __ mov(elements_array,
          FieldOperand(array_function,
                       JSFunction::kPrototypeOrInitialMapOffset));
 
-  // Check whether an empty sized array is requested.
-  __ test(array_size, Operand(array_size));
-  __ j(not_zero, &not_empty);
-
-  // If an empty array is requested allocate a small elements array anyway. This
-  // keeps the code below free of special casing for the empty array.
-  int size = JSArray::kSize + FixedArray::SizeFor(kPreallocatedArrayElements);
-  __ AllocateInNewSpace(size,
-                        result,
-                        elements_array_end,
-                        scratch,
-                        gc_required,
-                        TAG_OBJECT);
-  __ jmp(&allocated);
-
   // Allocate the JSArray object together with space for a FixedArray with the
   // requested elements.
-  __ bind(&not_empty);
   ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
   __ AllocateInNewSpace(JSArray::kSize + FixedArray::kHeaderSize,
                         times_half_pointer_size,  // array_size is a smi.
@@ -845,7 +830,6 @@ static void AllocateJSArray(MacroAssembler* masm,
   // elements_array: initial map
   // elements_array_end: start of next object
   // array_size: size of array (smi)
-  __ bind(&allocated);
   __ mov(FieldOperand(result, JSObject::kMapOffset), elements_array);
   __ mov(elements_array, Factory::empty_fixed_array());
   __ mov(FieldOperand(result, JSArray::kPropertiesOffset), elements_array);
@@ -869,15 +853,6 @@ static void AllocateJSArray(MacroAssembler* masm,
   __ SmiUntag(array_size);  // Convert from smi to value.
   __ mov(FieldOperand(elements_array, JSObject::kMapOffset),
          Factory::fixed_array_map());
-  Label not_empty_2, fill_array;
-  __ test(array_size, Operand(array_size));
-  __ j(not_zero, &not_empty_2);
-  // Length of the FixedArray is the number of pre-allocated elements even
-  // though the actual JSArray has length 0.
-  __ mov(FieldOperand(elements_array, Array::kLengthOffset),
-         Immediate(kPreallocatedArrayElements));
-  __ jmp(&fill_array);
-  __ bind(&not_empty_2);
   // For non-empty JSArrays the length of the FixedArray and the JSArray is the
   // same.
   __ mov(FieldOperand(elements_array, Array::kLengthOffset), array_size);
@@ -885,20 +860,18 @@ static void AllocateJSArray(MacroAssembler* masm,
   // Fill the allocated FixedArray with the hole value if requested.
   // result: JSObject
   // elements_array: elements array
-  // elements_array_end: start of next object
-  __ bind(&fill_array);
   if (fill_with_hole) {
-    Label loop, entry;
-    __ mov(scratch, Factory::the_hole_value());
-    __ lea(elements_array, Operand(elements_array,
-                                   FixedArray::kHeaderSize - kHeapObjectTag));
-    __ jmp(&entry);
-    __ bind(&loop);
-    __ mov(Operand(elements_array, 0), scratch);
-    __ add(Operand(elements_array), Immediate(kPointerSize));
-    __ bind(&entry);
-    __ cmp(elements_array, Operand(elements_array_end));
-    __ j(below, &loop);
+    __ lea(edi, Operand(elements_array,
+                        FixedArray::kHeaderSize - kHeapObjectTag));
+
+    __ push(eax);
+    __ mov(eax, Factory::the_hole_value());
+
+    __ cld();
+    __ rep_stos();
+
+    // Restore saved registers.
+    __ pop(eax);
   }
 }
 
@@ -920,7 +893,8 @@ static void AllocateJSArray(MacroAssembler* masm,
 static void ArrayNativeCode(MacroAssembler* masm,
                             bool construct_call,
                             Label* call_generic_code) {
-  Label argc_one_or_more, argc_two_or_more, prepare_generic_code_call;
+  Label argc_one_or_more, argc_two_or_more, prepare_generic_code_call,
+        empty_array, not_empty_array;
 
   // Push the constructor and argc. No need to tag argc as a smi, as there will
   // be no garbage collection with this on the stack.
@@ -936,6 +910,7 @@ static void ArrayNativeCode(MacroAssembler* masm,
   __ test(eax, Operand(eax));
   __ j(not_zero, &argc_one_or_more);
 
+  __ bind(&empty_array);
   // Handle construction of an empty array.
   AllocateEmptyJSArray(masm,
                        edi,
@@ -958,30 +933,46 @@ static void ArrayNativeCode(MacroAssembler* masm,
   __ cmp(eax, 1);
   __ j(not_equal, &argc_two_or_more);
   ASSERT(kSmiTag == 0);
-  __ test(Operand(esp, (push_count + 1) * kPointerSize),
-          Immediate(kIntptrSignBit | kSmiTagMask));
+  __ mov(ecx, Operand(esp, (push_count + 1) * kPointerSize));
+  __ test(ecx, Operand(ecx));
+  __ j(not_zero, &not_empty_array);
+
+  // The single argument passed is zero, so we jump to the code above used to
+  // handle the case of no arguments passed. To adapt the stack for that we move
+  // the return address and the pushed constructor (if pushed) one stack slot up
+  // thereby removing the passed argument. Argc is also on the stack - at the
+  // bottom - and it needs to be changed from 1 to 0 to have the call into the
+  // runtime system work in case a GC is required.
+  for (int i = push_count; i > 0; i--) {
+    __ mov(eax, Operand(esp, i * kPointerSize));
+    __ mov(Operand(esp, (i + 1) * kPointerSize), eax);
+  }
+  __ add(Operand(esp), Immediate(2 * kPointerSize));  // Drop two stack slots.
+  __ push(Immediate(0));  // Treat this as a call with argc of zero.
+  __ jmp(&empty_array);
+
+  __ bind(&not_empty_array);
+  __ test(ecx, Immediate(kIntptrSignBit | kSmiTagMask));
   __ j(not_zero, &prepare_generic_code_call);
 
   // Handle construction of an empty array of a certain size. Get the size from
   // the stack and bail out if size is to large to actually allocate an elements
   // array.
-  __ mov(edx, Operand(esp, (push_count + 1) * kPointerSize));
-  ASSERT(kSmiTag == 0);
-  __ cmp(edx, JSObject::kInitialMaxFastElementArray << kSmiTagSize);
+  __ cmp(ecx, JSObject::kInitialMaxFastElementArray << kSmiTagSize);
   __ j(greater_equal, &prepare_generic_code_call);
 
   // edx: array_size (smi)
   // edi: constructor
-  // esp[0]: argc
+  // esp[0]: argc (cannot be 0 here)
   // esp[4]: constructor (only if construct_call)
   // esp[8]: return address
   // esp[C]: argument
   AllocateJSArray(masm,
                   edi,
-                  edx,
+                  ecx,
                   eax,
                   ebx,
-                  ecx,
+                  edx,
                   edi,
                   true,
                   &prepare_generic_code_call);
index bd2a994..bdd1c4a 100644 (file)
@@ -126,6 +126,7 @@ CodeGenerator::CodeGenerator(MacroAssembler* masm)
 void CodeGenerator::Generate(CompilationInfo* info) {
   // Record the position for debugging purposes.
   CodeForFunctionPosition(info->function());
+  Comment cmnt(masm_, "[ function compiled by virtual frame code generator");
 
   // Initialize state.
   info_ = info;
@@ -732,7 +733,27 @@ void CodeGenerator::ToBoolean(ControlDestination* dest) {
   Result value = frame_->Pop();
   value.ToRegister();
 
-  if (value.is_number()) {
+  if (value.is_integer32()) {  // Also takes Smi case.
+    Comment cmnt(masm_, "ONLY_INTEGER_32");
+    if (FLAG_debug_code) {
+      Label ok;
+      __ AbortIfNotNumber(value.reg(), "ToBoolean operand is not a number.");
+      __ test(value.reg(), Immediate(kSmiTagMask));
+      __ j(zero, &ok);
+      __ fldz();
+      __ fld_d(FieldOperand(value.reg(), HeapNumber::kValueOffset));
+      __ FCmp();
+      __ j(not_zero, &ok);
+      __ Abort("Smi was wrapped in HeapNumber in output from bitop");
+      __ bind(&ok);
+    }
+    // In the integer32 case there are no Smis hidden in heap numbers, so we
+    // need only test for Smi zero.
+    __ test(value.reg(), Operand(value.reg()));
+    dest->false_target()->Branch(zero);
+    value.Unuse();
+    dest->Split(not_zero);
+  } else if (value.is_number()) {
     Comment cmnt(masm_, "ONLY_NUMBER");
     // Fast case if NumberInfo indicates only numbers.
     if (FLAG_debug_code) {
@@ -816,8 +837,17 @@ class FloatingPointHelper : public AllStatic {
   // Takes the operands in edx and eax and loads them as integers in eax
   // and ecx.
   static void LoadAsIntegers(MacroAssembler* masm,
+                             NumberInfo number_info,
                              bool use_sse3,
                              Label* operand_conversion_failure);
+  static void LoadNumbersAsIntegers(MacroAssembler* masm,
+                                    NumberInfo number_info,
+                                    bool use_sse3,
+                                    Label* operand_conversion_failure);
+  static void LoadUnknownsAsIntegers(MacroAssembler* masm,
+                                     bool use_sse3,
+                                     Label* operand_conversion_failure);
+
   // Test if operands are smis or heap numbers and load them
   // into xmm0 and xmm1 if they are. Operands are in edx and eax.
   // Leaves operands unchanged.
@@ -849,13 +879,14 @@ const char* GenericBinaryOpStub::GetName() {
   }
 
   OS::SNPrintF(Vector<char>(name_, kMaxNameLength),
-               "GenericBinaryOpStub_%s_%s%s_%s%s_%s",
+               "GenericBinaryOpStub_%s_%s%s_%s%s_%s_%s",
                op_name,
                overwrite_name,
                (flags_ & NO_SMI_CODE_IN_STUB) ? "_NoSmiInStub" : "",
                args_in_registers_ ? "RegArgs" : "StackArgs",
                args_reversed_ ? "_R" : "",
-               NumberInfo::ToString(operands_type_));
+               static_operands_type_.ToString(),
+               BinaryOpIC::GetName(runtime_operands_type_));
   return name_;
 }
 
@@ -867,8 +898,11 @@ class DeferredInlineBinaryOperation: public DeferredCode {
                                 Register dst,
                                 Register left,
                                 Register right,
+                                NumberInfo left_info,
+                                NumberInfo right_info,
                                 OverwriteMode mode)
-      : op_(op), dst_(dst), left_(left), right_(right), mode_(mode) {
+      : op_(op), dst_(dst), left_(left), right_(right),
+        left_info_(left_info), right_info_(right_info), mode_(mode) {
     set_comment("[ DeferredInlineBinaryOperation");
   }
 
@@ -879,6 +913,8 @@ class DeferredInlineBinaryOperation: public DeferredCode {
   Register dst_;
   Register left_;
   Register right_;
+  NumberInfo left_info_;
+  NumberInfo right_info_;
   OverwriteMode mode_;
 };
 
@@ -892,18 +928,22 @@ void DeferredInlineBinaryOperation::Generate() {
     CpuFeatures::Scope use_sse2(SSE2);
     Label call_runtime, after_alloc_failure;
     Label left_smi, right_smi, load_right, do_op;
-    __ test(left_, Immediate(kSmiTagMask));
-    __ j(zero, &left_smi);
-    __ cmp(FieldOperand(left_, HeapObject::kMapOffset),
-           Factory::heap_number_map());
-    __ j(not_equal, &call_runtime);
-    __ movdbl(xmm0, FieldOperand(left_, HeapNumber::kValueOffset));
-    if (mode_ == OVERWRITE_LEFT) {
-      __ mov(dst_, left_);
-    }
-    __ jmp(&load_right);
+    if (!left_info_.IsSmi()) {
+      __ test(left_, Immediate(kSmiTagMask));
+      __ j(zero, &left_smi);
+      if (!left_info_.IsNumber()) {
+        __ cmp(FieldOperand(left_, HeapObject::kMapOffset),
+               Factory::heap_number_map());
+        __ j(not_equal, &call_runtime);
+      }
+      __ movdbl(xmm0, FieldOperand(left_, HeapNumber::kValueOffset));
+      if (mode_ == OVERWRITE_LEFT) {
+        __ mov(dst_, left_);
+      }
+      __ jmp(&load_right);
 
-    __ bind(&left_smi);
+      __ bind(&left_smi);
+    }
     __ SmiUntag(left_);
     __ cvtsi2sd(xmm0, Operand(left_));
     __ SmiTag(left_);
@@ -915,23 +955,27 @@ void DeferredInlineBinaryOperation::Generate() {
     }
 
     __ bind(&load_right);
-    __ test(right_, Immediate(kSmiTagMask));
-    __ j(zero, &right_smi);
-    __ cmp(FieldOperand(right_, HeapObject::kMapOffset),
-           Factory::heap_number_map());
-    __ j(not_equal, &call_runtime);
-    __ movdbl(xmm1, FieldOperand(right_, HeapNumber::kValueOffset));
-    if (mode_ == OVERWRITE_RIGHT) {
-      __ mov(dst_, right_);
-    } else if (mode_ == NO_OVERWRITE) {
-      Label alloc_failure;
-      __ push(left_);
-      __ AllocateHeapNumber(dst_, left_, no_reg, &after_alloc_failure);
-      __ pop(left_);
-    }
-    __ jmp(&do_op);
+    if (!right_info_.IsSmi()) {
+      __ test(right_, Immediate(kSmiTagMask));
+      __ j(zero, &right_smi);
+      if (!right_info_.IsNumber()) {
+        __ cmp(FieldOperand(right_, HeapObject::kMapOffset),
+               Factory::heap_number_map());
+        __ j(not_equal, &call_runtime);
+      }
+      __ movdbl(xmm1, FieldOperand(right_, HeapNumber::kValueOffset));
+      if (mode_ == OVERWRITE_RIGHT) {
+        __ mov(dst_, right_);
+      } else if (mode_ == NO_OVERWRITE) {
+        Label alloc_failure;
+        __ push(left_);
+        __ AllocateHeapNumber(dst_, left_, no_reg, &after_alloc_failure);
+        __ pop(left_);
+      }
+      __ jmp(&do_op);
 
-    __ bind(&right_smi);
+      __ bind(&right_smi);
+    }
     __ SmiUntag(right_);
     __ cvtsi2sd(xmm1, Operand(right_));
     __ SmiTag(right_);
@@ -957,13 +1001,105 @@ void DeferredInlineBinaryOperation::Generate() {
     __ pop(left_);
     __ bind(&call_runtime);
   }
-  GenericBinaryOpStub stub(op_, mode_, NO_SMI_CODE_IN_STUB);
+  GenericBinaryOpStub stub(op_,
+                           mode_,
+                           NO_SMI_CODE_IN_STUB,
+                           NumberInfo::Combine(left_info_, right_info_));
   stub.GenerateCall(masm_, left_, right_);
   if (!dst_.is(eax)) __ mov(dst_, eax);
   __ bind(&done);
 }
 
 
+static NumberInfo CalculateNumberInfo(NumberInfo operands_type,
+                                      Token::Value op,
+                                      const Result& right,
+                                      const Result& left) {
+  // Set NumberInfo of result according to the operation performed.
+  // Rely on the fact that smis have a 31 bit payload on ia32.
+  ASSERT(kSmiValueSize == 31);
+  switch (op) {
+    case Token::COMMA:
+      return right.number_info();
+    case Token::OR:
+    case Token::AND:
+      // Result type can be either of the two input types.
+      return operands_type;
+    case Token::BIT_AND: {
+      // Anding with positive Smis will give you a Smi.
+      if (right.is_constant() && right.handle()->IsSmi() &&
+          Smi::cast(*right.handle())->value() >= 0) {
+        return NumberInfo::Smi();
+      } else if (left.is_constant() && left.handle()->IsSmi() &&
+          Smi::cast(*left.handle())->value() >= 0) {
+        return NumberInfo::Smi();
+      }
+      return (operands_type.IsSmi())
+          ? NumberInfo::Smi()
+          : NumberInfo::Integer32();
+    }
+    case Token::BIT_OR: {
+      // Oring with negative Smis will give you a Smi.
+      if (right.is_constant() && right.handle()->IsSmi() &&
+          Smi::cast(*right.handle())->value() < 0) {
+        return NumberInfo::Smi();
+      } else if (left.is_constant() && left.handle()->IsSmi() &&
+          Smi::cast(*left.handle())->value() < 0) {
+        return NumberInfo::Smi();
+      }
+      return (operands_type.IsSmi())
+          ? NumberInfo::Smi()
+          : NumberInfo::Integer32();
+    }
+    case Token::BIT_XOR:
+      // Result is always a 32 bit integer. Smi property of inputs is preserved.
+      return (operands_type.IsSmi())
+          ? NumberInfo::Smi()
+          : NumberInfo::Integer32();
+    case Token::SAR:
+      if (left.is_smi()) return NumberInfo::Smi();
+      // Result is a smi if we shift by a constant >= 1, otherwise an integer32.
+      return (right.is_constant() && right.handle()->IsSmi()
+                     && Smi::cast(*right.handle())->value() >= 1)
+          ? NumberInfo::Smi()
+          : NumberInfo::Integer32();
+    case Token::SHR:
+      // Result is a smi if we shift by a constant >= 2, otherwise an integer32.
+      return (right.is_constant() && right.handle()->IsSmi()
+                     && Smi::cast(*right.handle())->value() >= 2)
+          ? NumberInfo::Smi()
+          : NumberInfo::Integer32();
+    case Token::ADD:
+      if (operands_type.IsSmi()) {
+        // The Integer32 range is big enough to take the sum of any two Smis.
+        return NumberInfo::Integer32();
+      } else {
+        // Result could be a string or a number. Check types of inputs.
+        return operands_type.IsNumber()
+            ? NumberInfo::Number()
+            : NumberInfo::Unknown();
+      }
+    case Token::SHL:
+      return NumberInfo::Integer32();
+    case Token::SUB:
+      // The Integer32 range is big enough to take the difference of any two
+      // Smis.
+      return (operands_type.IsSmi()) ?
+                    NumberInfo::Integer32() :
+                    NumberInfo::Number();
+    case Token::MUL:
+    case Token::DIV:
+    case Token::MOD:
+      // Result is always a number.
+      return NumberInfo::Number();
+    default:
+      UNREACHABLE();
+  }
+  UNREACHABLE();
+  return NumberInfo::Unknown();
+}
+
+
 void CodeGenerator::GenericBinaryOperation(Token::Value op,
                                            StaticType* type,
                                            OverwriteMode overwrite_mode) {
@@ -1019,9 +1155,11 @@ void CodeGenerator::GenericBinaryOperation(Token::Value op,
   }
 
   // Get number type of left and right sub-expressions.
-  NumberInfo::Type operands_type =
+  NumberInfo operands_type =
       NumberInfo::Combine(left.number_info(), right.number_info());
 
+  NumberInfo result_type = CalculateNumberInfo(operands_type, op, right, left);
+
   Result answer;
   if (left_is_non_smi_constant || right_is_non_smi_constant) {
     // Go straight to the slow case, with no smi code.
@@ -1042,7 +1180,10 @@ void CodeGenerator::GenericBinaryOperation(Token::Value op,
     // generate the inline Smi check code if this operation is part of a loop.
     // For all other operations only inline the Smi check code for likely smis
     // if the operation is part of a loop.
-    if (loop_nesting() > 0 && (Token::IsBitOp(op) || type->IsLikelySmi())) {
+    if (loop_nesting() > 0 &&
+        (Token::IsBitOp(op) ||
+         operands_type.IsInteger32() ||
+         type->IsLikelySmi())) {
       answer = LikelySmiBinaryOperation(op, &left, &right, overwrite_mode);
     } else {
       GenericBinaryOpStub stub(op,
@@ -1053,58 +1194,6 @@ void CodeGenerator::GenericBinaryOperation(Token::Value op,
     }
   }
 
-  // Set NumberInfo of result according to the operation performed.
-  // Rely on the fact that smis have a 31 bit payload on ia32.
-  ASSERT(kSmiValueSize == 31);
-  NumberInfo::Type result_type = NumberInfo::kUnknown;
-  switch (op) {
-    case Token::COMMA:
-      result_type = right.number_info();
-      break;
-    case Token::OR:
-    case Token::AND:
-      // Result type can be either of the two input types.
-      result_type = operands_type;
-      break;
-    case Token::BIT_OR:
-    case Token::BIT_XOR:
-    case Token::BIT_AND:
-      // Result is always a number. Smi property of inputs is preserved.
-      result_type = (operands_type == NumberInfo::kSmi)
-          ? NumberInfo::kSmi
-          : NumberInfo::kNumber;
-      break;
-    case Token::SAR:
-      // Result is a smi if we shift by a constant >= 1, otherwise a number.
-      result_type = (right.is_constant() && right.handle()->IsSmi()
-                     && Smi::cast(*right.handle())->value() >= 1)
-          ? NumberInfo::kSmi
-          : NumberInfo::kNumber;
-      break;
-    case Token::SHR:
-      // Result is a smi if we shift by a constant >= 2, otherwise a number.
-      result_type = (right.is_constant() && right.handle()->IsSmi()
-                     && Smi::cast(*right.handle())->value() >= 2)
-          ? NumberInfo::kSmi
-          : NumberInfo::kNumber;
-      break;
-    case Token::ADD:
-      // Result could be a string or a number. Check types of inputs.
-      result_type = NumberInfo::IsNumber(operands_type)
-          ? NumberInfo::kNumber
-          : NumberInfo::kUnknown;
-      break;
-    case Token::SHL:
-    case Token::SUB:
-    case Token::MUL:
-    case Token::DIV:
-    case Token::MOD:
-      // Result is always a number.
-      result_type = NumberInfo::kNumber;
-      break;
-    default:
-      UNREACHABLE();
-  }
   answer.set_number_info(result_type);
   frame_->Push(&answer);
 }
@@ -1191,6 +1280,12 @@ bool CodeGenerator::FoldConstantSmis(Token::Value op, int left, int right) {
 }
 
 
+static void CheckTwoForSminess(MacroAssembler* masm,
+                               Register left, Register right, Register scratch,
+                               NumberInfo left_info, NumberInfo right_info,
+                               DeferredInlineBinaryOperation* deferred);
+
+
 // Implements a binary operation using a deferred code object and some
 // inline code to operate on smis quickly.
 Result CodeGenerator::LikelySmiBinaryOperation(Token::Value op,
@@ -1271,6 +1366,8 @@ Result CodeGenerator::LikelySmiBinaryOperation(Token::Value op,
                                           (op == Token::DIV) ? eax : edx,
                                           left->reg(),
                                           right->reg(),
+                                          left->number_info(),
+                                          right->number_info(),
                                           overwrite_mode);
     if (left->reg().is(right->reg())) {
       __ test(left->reg(), Immediate(kSmiTagMask));
@@ -1368,11 +1465,11 @@ Result CodeGenerator::LikelySmiBinaryOperation(Token::Value op,
                                           answer.reg(),
                                           left->reg(),
                                           ecx,
+                                          left->number_info(),
+                                          right->number_info(),
                                           overwrite_mode);
-    __ mov(answer.reg(), left->reg());
-    __ or_(answer.reg(), Operand(ecx));
-    __ test(answer.reg(), Immediate(kSmiTagMask));
-    deferred->Branch(not_zero);
+    CheckTwoForSminess(masm_, left->reg(), right->reg(), answer.reg(),
+                       left->number_info(), right->number_info(), deferred);
 
     // Untag both operands.
     __ mov(answer.reg(), left->reg());
@@ -1442,16 +1539,12 @@ Result CodeGenerator::LikelySmiBinaryOperation(Token::Value op,
                                         answer.reg(),
                                         left->reg(),
                                         right->reg(),
+                                        left->number_info(),
+                                        right->number_info(),
                                         overwrite_mode);
-  if (left->reg().is(right->reg())) {
-    __ test(left->reg(), Immediate(kSmiTagMask));
-  } else {
-    __ mov(answer.reg(), left->reg());
-    __ or_(answer.reg(), Operand(right->reg()));
-    ASSERT(kSmiTag == 0);  // Adjust test if not the case.
-    __ test(answer.reg(), Immediate(kSmiTagMask));
-  }
-  deferred->Branch(not_zero);
+  CheckTwoForSminess(masm_, left->reg(), right->reg(), answer.reg(),
+                     left->number_info(), right->number_info(), deferred);
+
   __ mov(answer.reg(), left->reg());
   switch (op) {
     case Token::ADD:
@@ -1520,13 +1613,16 @@ class DeferredInlineSmiOperation: public DeferredCode {
   DeferredInlineSmiOperation(Token::Value op,
                              Register dst,
                              Register src,
+                             NumberInfo number_info,
                              Smi* value,
                              OverwriteMode overwrite_mode)
       : op_(op),
         dst_(dst),
         src_(src),
+        number_info_(number_info),
         value_(value),
         overwrite_mode_(overwrite_mode) {
+    if (number_info.IsSmi()) overwrite_mode_ = NO_OVERWRITE;
     set_comment("[ DeferredInlineSmiOperation");
   }
 
@@ -1536,6 +1632,7 @@ class DeferredInlineSmiOperation: public DeferredCode {
   Token::Value op_;
   Register dst_;
   Register src_;
+  NumberInfo number_info_;
   Smi* value_;
   OverwriteMode overwrite_mode_;
 };
@@ -1546,7 +1643,8 @@ void DeferredInlineSmiOperation::Generate() {
   GenericBinaryOpStub stub(
       op_,
       overwrite_mode_,
-      (op_ == Token::MOD) ? NO_GENERIC_BINARY_FLAGS : NO_SMI_CODE_IN_STUB);
+      (op_ == Token::MOD) ? NO_GENERIC_BINARY_FLAGS : NO_SMI_CODE_IN_STUB,
+      NumberInfo::Combine(NumberInfo::Smi(), number_info_));
   stub.GenerateCall(masm_, src_, value_);
   if (!dst_.is(eax)) __ mov(dst_, eax);
 }
@@ -1560,9 +1658,11 @@ class DeferredInlineSmiOperationReversed: public DeferredCode {
                                      Register dst,
                                      Smi* value,
                                      Register src,
+                                     NumberInfo number_info,
                                      OverwriteMode overwrite_mode)
       : op_(op),
         dst_(dst),
+        number_info_(number_info),
         value_(value),
         src_(src),
         overwrite_mode_(overwrite_mode) {
@@ -1574,6 +1674,7 @@ class DeferredInlineSmiOperationReversed: public DeferredCode {
  private:
   Token::Value op_;
   Register dst_;
+  NumberInfo number_info_;
   Smi* value_;
   Register src_;
   OverwriteMode overwrite_mode_;
@@ -1581,7 +1682,11 @@ class DeferredInlineSmiOperationReversed: public DeferredCode {
 
 
 void DeferredInlineSmiOperationReversed::Generate() {
-  GenericBinaryOpStub igostub(op_, overwrite_mode_, NO_SMI_CODE_IN_STUB);
+  GenericBinaryOpStub igostub(
+      op_,
+      overwrite_mode_,
+      NO_SMI_CODE_IN_STUB,
+      NumberInfo::Combine(NumberInfo::Smi(), number_info_));
   igostub.GenerateCall(masm_, value_, src_);
   if (!dst_.is(eax)) __ mov(dst_, eax);
 }
@@ -1593,9 +1698,14 @@ void DeferredInlineSmiOperationReversed::Generate() {
 class DeferredInlineSmiAdd: public DeferredCode {
  public:
   DeferredInlineSmiAdd(Register dst,
+                       NumberInfo number_info,
                        Smi* value,
                        OverwriteMode overwrite_mode)
-      : dst_(dst), value_(value), overwrite_mode_(overwrite_mode) {
+      : dst_(dst),
+        number_info_(number_info),
+        value_(value),
+        overwrite_mode_(overwrite_mode) {
+    if (number_info_.IsSmi()) overwrite_mode_ = NO_OVERWRITE;
     set_comment("[ DeferredInlineSmiAdd");
   }
 
@@ -1603,6 +1713,7 @@ class DeferredInlineSmiAdd: public DeferredCode {
 
  private:
   Register dst_;
+  NumberInfo number_info_;
   Smi* value_;
   OverwriteMode overwrite_mode_;
 };
@@ -1611,7 +1722,11 @@ class DeferredInlineSmiAdd: public DeferredCode {
 void DeferredInlineSmiAdd::Generate() {
   // Undo the optimistic add operation and call the shared stub.
   __ sub(Operand(dst_), Immediate(value_));
-  GenericBinaryOpStub igostub(Token::ADD, overwrite_mode_, NO_SMI_CODE_IN_STUB);
+  GenericBinaryOpStub igostub(
+      Token::ADD,
+      overwrite_mode_,
+      NO_SMI_CODE_IN_STUB,
+      NumberInfo::Combine(NumberInfo::Smi(), number_info_));
   igostub.GenerateCall(masm_, dst_, value_);
   if (!dst_.is(eax)) __ mov(dst_, eax);
 }
@@ -1623,9 +1738,13 @@ void DeferredInlineSmiAdd::Generate() {
 class DeferredInlineSmiAddReversed: public DeferredCode {
  public:
   DeferredInlineSmiAddReversed(Register dst,
+                               NumberInfo number_info,
                                Smi* value,
                                OverwriteMode overwrite_mode)
-      : dst_(dst), value_(value), overwrite_mode_(overwrite_mode) {
+      : dst_(dst),
+        number_info_(number_info),
+        value_(value),
+        overwrite_mode_(overwrite_mode) {
     set_comment("[ DeferredInlineSmiAddReversed");
   }
 
@@ -1633,6 +1752,7 @@ class DeferredInlineSmiAddReversed: public DeferredCode {
 
  private:
   Register dst_;
+  NumberInfo number_info_;
   Smi* value_;
   OverwriteMode overwrite_mode_;
 };
@@ -1641,7 +1761,11 @@ class DeferredInlineSmiAddReversed: public DeferredCode {
 void DeferredInlineSmiAddReversed::Generate() {
   // Undo the optimistic add operation and call the shared stub.
   __ sub(Operand(dst_), Immediate(value_));
-  GenericBinaryOpStub igostub(Token::ADD, overwrite_mode_, NO_SMI_CODE_IN_STUB);
+  GenericBinaryOpStub igostub(
+      Token::ADD,
+      overwrite_mode_,
+      NO_SMI_CODE_IN_STUB,
+      NumberInfo::Combine(NumberInfo::Smi(), number_info_));
   igostub.GenerateCall(masm_, value_, dst_);
   if (!dst_.is(eax)) __ mov(dst_, eax);
 }
@@ -1654,9 +1778,14 @@ void DeferredInlineSmiAddReversed::Generate() {
 class DeferredInlineSmiSub: public DeferredCode {
  public:
   DeferredInlineSmiSub(Register dst,
+                       NumberInfo number_info,
                        Smi* value,
                        OverwriteMode overwrite_mode)
-      : dst_(dst), value_(value), overwrite_mode_(overwrite_mode) {
+      : dst_(dst),
+        number_info_(number_info),
+        value_(value),
+        overwrite_mode_(overwrite_mode) {
+    if (number_info.IsSmi()) overwrite_mode_ = NO_OVERWRITE;
     set_comment("[ DeferredInlineSmiSub");
   }
 
@@ -1664,6 +1793,7 @@ class DeferredInlineSmiSub: public DeferredCode {
 
  private:
   Register dst_;
+  NumberInfo number_info_;
   Smi* value_;
   OverwriteMode overwrite_mode_;
 };
@@ -1672,7 +1802,11 @@ class DeferredInlineSmiSub: public DeferredCode {
 void DeferredInlineSmiSub::Generate() {
   // Undo the optimistic sub operation and call the shared stub.
   __ add(Operand(dst_), Immediate(value_));
-  GenericBinaryOpStub igostub(Token::SUB, overwrite_mode_, NO_SMI_CODE_IN_STUB);
+  GenericBinaryOpStub igostub(
+      Token::SUB,
+      overwrite_mode_,
+      NO_SMI_CODE_IN_STUB,
+      NumberInfo::Combine(NumberInfo::Smi(), number_info_));
   igostub.GenerateCall(masm_, dst_, value_);
   if (!dst_.is(eax)) __ mov(dst_, eax);
 }
@@ -1716,17 +1850,21 @@ Result CodeGenerator::ConstantSmiBinaryOperation(Token::Value op,
       DeferredCode* deferred = NULL;
       if (reversed) {
         deferred = new DeferredInlineSmiAddReversed(operand->reg(),
+                                                    operand->number_info(),
                                                     smi_value,
                                                     overwrite_mode);
       } else {
         deferred = new DeferredInlineSmiAdd(operand->reg(),
+                                            operand->number_info(),
                                             smi_value,
                                             overwrite_mode);
       }
       __ add(Operand(operand->reg()), Immediate(value));
       deferred->Branch(overflow);
-      __ test(operand->reg(), Immediate(kSmiTagMask));
-      deferred->Branch(not_zero);
+      if (!operand->number_info().IsSmi()) {
+        __ test(operand->reg(), Immediate(kSmiTagMask));
+        deferred->Branch(not_zero);
+      }
       deferred->BindExit();
       answer = *operand;
       break;
@@ -1741,24 +1879,29 @@ Result CodeGenerator::ConstantSmiBinaryOperation(Token::Value op,
         answer = allocator()->Allocate();
         ASSERT(answer.is_valid());
         __ Set(answer.reg(), Immediate(value));
-        deferred = new DeferredInlineSmiOperationReversed(op,
-                                                          answer.reg(),
-                                                          smi_value,
-                                                          operand->reg(),
-                                                          overwrite_mode);
+        deferred =
+            new DeferredInlineSmiOperationReversed(op,
+                                                   answer.reg(),
+                                                   smi_value,
+                                                   operand->reg(),
+                                                   operand->number_info(),
+                                                   overwrite_mode);
         __ sub(answer.reg(), Operand(operand->reg()));
       } else {
         operand->ToRegister();
         frame_->Spill(operand->reg());
         answer = *operand;
         deferred = new DeferredInlineSmiSub(operand->reg(),
+                                            operand->number_info(),
                                             smi_value,
                                             overwrite_mode);
         __ sub(Operand(operand->reg()), Immediate(value));
       }
       deferred->Branch(overflow);
-      __ test(answer.reg(), Immediate(kSmiTagMask));
-      deferred->Branch(not_zero);
+      if (!operand->number_info().IsSmi()) {
+        __ test(answer.reg(), Immediate(kSmiTagMask));
+        deferred->Branch(not_zero);
+      }
       deferred->BindExit();
       operand->Unuse();
       break;
@@ -1775,19 +1918,27 @@ Result CodeGenerator::ConstantSmiBinaryOperation(Token::Value op,
         int shift_value = int_value & 0x1f;
         operand->ToRegister();
         frame_->Spill(operand->reg());
-        DeferredInlineSmiOperation* deferred =
-            new DeferredInlineSmiOperation(op,
-                                           operand->reg(),
-                                           operand->reg(),
-                                           smi_value,
-                                           overwrite_mode);
-        __ test(operand->reg(), Immediate(kSmiTagMask));
-        deferred->Branch(not_zero);
-        if (shift_value > 0) {
-          __ sar(operand->reg(), shift_value);
-          __ and_(operand->reg(), ~kSmiTagMask);
+        if (!operand->number_info().IsSmi()) {
+          DeferredInlineSmiOperation* deferred =
+              new DeferredInlineSmiOperation(op,
+                                             operand->reg(),
+                                             operand->reg(),
+                                             operand->number_info(),
+                                             smi_value,
+                                             overwrite_mode);
+          __ test(operand->reg(), Immediate(kSmiTagMask));
+          deferred->Branch(not_zero);
+          if (shift_value > 0) {
+            __ sar(operand->reg(), shift_value);
+            __ and_(operand->reg(), ~kSmiTagMask);
+          }
+          deferred->BindExit();
+        } else {
+          if (shift_value > 0) {
+            __ sar(operand->reg(), shift_value);
+            __ and_(operand->reg(), ~kSmiTagMask);
+          }
         }
-        deferred->BindExit();
         answer = *operand;
       }
       break;
@@ -1808,10 +1959,13 @@ Result CodeGenerator::ConstantSmiBinaryOperation(Token::Value op,
             new DeferredInlineSmiOperation(op,
                                            answer.reg(),
                                            operand->reg(),
+                                           operand->number_info(),
                                            smi_value,
                                            overwrite_mode);
-        __ test(operand->reg(), Immediate(kSmiTagMask));
-        deferred->Branch(not_zero);
+        if (!operand->number_info().IsSmi()) {
+          __ test(operand->reg(), Immediate(kSmiTagMask));
+          deferred->Branch(not_zero);
+        }
         __ mov(answer.reg(), operand->reg());
         __ SmiUntag(answer.reg());
         __ shr(answer.reg(), shift_value);
@@ -1853,10 +2007,13 @@ Result CodeGenerator::ConstantSmiBinaryOperation(Token::Value op,
                                                    answer.reg(),
                                                    smi_value,
                                                    right.reg(),
+                                                   right.number_info(),
                                                    overwrite_mode);
         __ mov(answer.reg(), Immediate(int_value));
         __ sar(ecx, kSmiTagSize);
-        deferred->Branch(carry);
+        if (!right.number_info().IsSmi()) {
+          deferred->Branch(carry);
+        }
         __ shl_cl(answer.reg());
         __ cmp(answer.reg(), 0xc0000000);
         deferred->Branch(sign);
@@ -1875,6 +2032,7 @@ Result CodeGenerator::ConstantSmiBinaryOperation(Token::Value op,
               new DeferredInlineSmiOperation(op,
                                              operand->reg(),
                                              operand->reg(),
+                                             operand->number_info(),
                                              smi_value,
                                              overwrite_mode);
           __ test(operand->reg(), Immediate(kSmiTagMask));
@@ -1889,10 +2047,13 @@ Result CodeGenerator::ConstantSmiBinaryOperation(Token::Value op,
               new DeferredInlineSmiOperation(op,
                                              answer.reg(),
                                              operand->reg(),
+                                             operand->number_info(),
                                              smi_value,
                                              overwrite_mode);
-          __ test(operand->reg(), Immediate(kSmiTagMask));
-          deferred->Branch(not_zero);
+          if (!operand->number_info().IsSmi()) {
+            __ test(operand->reg(), Immediate(kSmiTagMask));
+            deferred->Branch(not_zero);
+          }
           __ mov(answer.reg(), operand->reg());
           ASSERT(kSmiTag == 0);  // adjust code if not the case
           // We do no shifts, only the Smi conversion, if shift_value is 1.
@@ -1916,20 +2077,25 @@ Result CodeGenerator::ConstantSmiBinaryOperation(Token::Value op,
       frame_->Spill(operand->reg());
       DeferredCode* deferred = NULL;
       if (reversed) {
-        deferred = new DeferredInlineSmiOperationReversed(op,
-                                                          operand->reg(),
-                                                          smi_value,
-                                                          operand->reg(),
-                                                          overwrite_mode);
+        deferred =
+            new DeferredInlineSmiOperationReversed(op,
+                                                   operand->reg(),
+                                                   smi_value,
+                                                   operand->reg(),
+                                                   operand->number_info(),
+                                                   overwrite_mode);
       } else {
         deferred =  new DeferredInlineSmiOperation(op,
                                                    operand->reg(),
                                                    operand->reg(),
+                                                   operand->number_info(),
                                                    smi_value,
                                                    overwrite_mode);
       }
-      __ test(operand->reg(), Immediate(kSmiTagMask));
-      deferred->Branch(not_zero);
+      if (!operand->number_info().IsSmi()) {
+        __ test(operand->reg(), Immediate(kSmiTagMask));
+        deferred->Branch(not_zero);
+      }
       if (op == Token::BIT_AND) {
         __ and_(Operand(operand->reg()), Immediate(value));
       } else if (op == Token::BIT_XOR) {
@@ -1956,6 +2122,7 @@ Result CodeGenerator::ConstantSmiBinaryOperation(Token::Value op,
             new DeferredInlineSmiOperation(op,
                                            operand->reg(),
                                            operand->reg(),
+                                           operand->number_info(),
                                            smi_value,
                                            overwrite_mode);
         // Check that lowest log2(value) bits of operand are zero, and test
@@ -1987,11 +2154,13 @@ Result CodeGenerator::ConstantSmiBinaryOperation(Token::Value op,
           (IsPowerOf2(int_value) || IsPowerOf2(-int_value))) {
         operand->ToRegister();
         frame_->Spill(operand->reg());
-        DeferredCode* deferred = new DeferredInlineSmiOperation(op,
-                                                                operand->reg(),
-                                                                operand->reg(),
-                                                                smi_value,
-                                                                overwrite_mode);
+        DeferredCode* deferred =
+            new DeferredInlineSmiOperation(op,
+                                           operand->reg(),
+                                           operand->reg(),
+                                           operand->number_info(),
+                                           smi_value,
+                                           overwrite_mode);
         // Check for negative or non-Smi left hand side.
         __ test(operand->reg(), Immediate(kSmiTagMask | 0x80000000));
         deferred->Branch(not_zero);
@@ -2025,6 +2194,8 @@ Result CodeGenerator::ConstantSmiBinaryOperation(Token::Value op,
 
 
 static bool CouldBeNaN(const Result& result) {
+  if (result.number_info().IsSmi()) return false;
+  if (result.number_info().IsInteger32()) return false;
   if (!result.is_constant()) return true;
   if (!result.handle()->IsHeapNumber()) return false;
   return isnan(HeapNumber::cast(*result.handle())->value());
@@ -5420,6 +5591,54 @@ void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
 }
 
 
+void CodeGenerator::GenerateCharFromCode(ZoneList<Expression*>* args) {
+  Comment(masm_, "[ GenerateCharFromCode");
+  ASSERT(args->length() == 1);
+
+  Load(args->at(0));
+  Result code = frame_->Pop();
+  code.ToRegister();
+  ASSERT(code.is_valid());
+
+  Result temp = allocator()->Allocate();
+  ASSERT(temp.is_valid());
+
+  JumpTarget slow_case;
+  JumpTarget exit;
+
+  // Fast case of Heap::LookupSingleCharacterStringFromCode.
+  ASSERT(kSmiTag == 0);
+  ASSERT(kSmiShiftSize == 0);
+  ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1));
+  __ test(code.reg(),
+          Immediate(kSmiTagMask |
+                    ((~String::kMaxAsciiCharCode) << kSmiTagSize)));
+  slow_case.Branch(not_zero, &code, not_taken);
+
+  __ Set(temp.reg(), Immediate(Factory::single_character_string_cache()));
+  ASSERT(kSmiTag == 0);
+  ASSERT(kSmiTagSize == 1);
+  ASSERT(kSmiShiftSize == 0);
+  // At this point code register contains smi tagged ascii char code.
+  __ mov(temp.reg(), FieldOperand(temp.reg(),
+                                  code.reg(), times_half_pointer_size,
+                                  FixedArray::kHeaderSize));
+  __ cmp(temp.reg(), Factory::undefined_value());
+  slow_case.Branch(equal, &code, not_taken);
+  code.Unuse();
+
+  frame_->Push(&temp);
+  exit.Jump();
+
+  slow_case.Bind(&code);
+  frame_->Push(&code);
+  Result result = frame_->CallRuntime(Runtime::kCharFromCode, 1);
+  frame_->Push(&result);
+
+  exit.Bind();
+}
+
+
 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
   ASSERT(args->length() == 1);
   Load(args->at(0));
@@ -5740,21 +5959,12 @@ void CodeGenerator::GenerateRandomPositiveSmi(ZoneList<Expression*>* args) {
   ASSERT(args->length() == 0);
   frame_->SpillAll();
 
-  // Make sure the frame is aligned like the OS expects.
-  static const int kFrameAlignment = OS::ActivationFrameAlignment();
-  if (kFrameAlignment > 0) {
-    ASSERT(IsPowerOf2(kFrameAlignment));
-    __ mov(edi, Operand(esp));  // Save in callee-saved register.
-    __ and_(esp, -kFrameAlignment);
-  }
+  static const int num_arguments = 0;
+  __ PrepareCallCFunction(num_arguments, eax);
 
   // Call V8::RandomPositiveSmi().
-  __ call(FUNCTION_ADDR(V8::RandomPositiveSmi), RelocInfo::RUNTIME_ENTRY);
-
-  // Restore stack pointer from callee-saved register edi.
-  if (kFrameAlignment > 0) {
-    __ mov(esp, Operand(edi));
-  }
+  __ CallCFunction(ExternalReference::random_positive_smi_function(),
+                   num_arguments);
 
   Result result = allocator_->Allocate(eax);
   frame_->Push(&result);
@@ -5823,6 +6033,269 @@ void CodeGenerator::GenerateNumberToString(ZoneList<Expression*>* args) {
 }
 
 
+// Generates the Math.pow method - only handles special cases and branches to
+// the runtime system if not.Please note - this function assumes that
+// the callsite has executed ToNumber on both arguments and that the
+// arguments are not the same identifier.
+void CodeGenerator::GenerateMathPow(ZoneList<Expression*>* args) {
+  ASSERT(args->length() == 2);
+  Load(args->at(0));
+  Load(args->at(1));
+  if (!CpuFeatures::IsSupported(SSE2)) {
+    Result res = frame_->CallRuntime(Runtime::kMath_pow, 2);
+    frame_->Push(&res);
+  } else {
+    CpuFeatures::Scope use_sse2(SSE2);
+    Label allocate_return;
+    // Load the two operands while leaving the values on the frame.
+    frame()->Dup();
+    Result exponent = frame()->Pop();
+    exponent.ToRegister();
+    frame()->Spill(exponent.reg());
+    frame()->PushElementAt(1);
+    Result base = frame()->Pop();
+    base.ToRegister();
+    frame()->Spill(base.reg());
+
+    Result answer = allocator()->Allocate();
+    ASSERT(answer.is_valid());
+    // We can safely assume that the base and exponent is not in the same
+    // register since we only call this from one callsite (math.js).
+    ASSERT(!exponent.reg().is(base.reg()));
+    JumpTarget call_runtime;
+
+    // Save 1 in xmm3 - we need this several times later on.
+    __ mov(answer.reg(), Immediate(1));
+    __ cvtsi2sd(xmm3, Operand(answer.reg()));
+
+    Label exponent_nonsmi;
+    Label base_nonsmi;
+    // If the exponent is a heap number go to that specific case.
+    __ test(exponent.reg(), Immediate(kSmiTagMask));
+    __ j(not_zero, &exponent_nonsmi);
+    __ test(base.reg(), Immediate(kSmiTagMask));
+    __ j(not_zero, &base_nonsmi);
+
+    // Optimized version when y is an integer.
+    Label powi;
+    __ SmiUntag(base.reg());
+    __ cvtsi2sd(xmm0, Operand(base.reg()));
+    __ jmp(&powi);
+    // exponent is smi and base is a heapnumber.
+    __ bind(&base_nonsmi);
+    __ cmp(FieldOperand(base.reg(), HeapObject::kMapOffset),
+           Factory::heap_number_map());
+    call_runtime.Branch(not_equal);
+
+    __ movdbl(xmm0, FieldOperand(base.reg(), HeapNumber::kValueOffset));
+
+    // Optimized version of pow if y is an integer.
+    __ bind(&powi);
+    __ SmiUntag(exponent.reg());
+
+    // Save exponent in base as we need to check if exponent is negative later.
+    // We know that base and exponent are in different registers.
+    __ mov(base.reg(), exponent.reg());
+
+    // Get absolute value of exponent.
+    Label no_neg;
+    __ cmp(exponent.reg(), 0);
+    __ j(greater_equal, &no_neg);
+    __ neg(exponent.reg());
+    __ bind(&no_neg);
+
+    // Load xmm1 with 1.
+    __ movsd(xmm1, xmm3);
+    Label while_true;
+    Label no_multiply;
+
+    //  Label allocate_and_return;
+    __ bind(&while_true);
+    __ shr(exponent.reg(), 1);
+    __ j(not_carry, &no_multiply);
+    __ mulsd(xmm1, xmm0);
+    __ bind(&no_multiply);
+    __ test(exponent.reg(), Operand(exponent.reg()));
+    __ mulsd(xmm0, xmm0);
+    __ j(not_zero, &while_true);
+
+    // x has the original value of y - if y is negative return 1/result.
+    __ test(base.reg(), Operand(base.reg()));
+    __ j(positive, &allocate_return);
+    // Special case if xmm1 has reached infinity.
+    __ mov(answer.reg(), Immediate(0x7FB00000));
+    __ movd(xmm0, Operand(answer.reg()));
+    __ cvtss2sd(xmm0, xmm0);
+    __ ucomisd(xmm0, xmm1);
+    call_runtime.Branch(equal);
+    __ divsd(xmm3, xmm1);
+    __ movsd(xmm1, xmm3);
+    __ jmp(&allocate_return);
+
+    // exponent (or both) is a heapnumber - no matter what we should now work
+    // on doubles.
+    __ bind(&exponent_nonsmi);
+    __ cmp(FieldOperand(exponent.reg(), HeapObject::kMapOffset),
+           Factory::heap_number_map());
+    call_runtime.Branch(not_equal);
+    __ movdbl(xmm1, FieldOperand(exponent.reg(), HeapNumber::kValueOffset));
+    // Test if exponent is nan.
+    __ ucomisd(xmm1, xmm1);
+    call_runtime.Branch(parity_even);
+
+    Label base_not_smi;
+    Label handle_special_cases;
+    __ test(base.reg(), Immediate(kSmiTagMask));
+    __ j(not_zero, &base_not_smi);
+    __ SmiUntag(base.reg());
+    __ cvtsi2sd(xmm0, Operand(base.reg()));
+    __ jmp(&handle_special_cases);
+    __ bind(&base_not_smi);
+    __ cmp(FieldOperand(base.reg(), HeapObject::kMapOffset),
+           Factory::heap_number_map());
+    call_runtime.Branch(not_equal);
+    __ mov(answer.reg(), FieldOperand(base.reg(), HeapNumber::kExponentOffset));
+    __ and_(answer.reg(), HeapNumber::kExponentMask);
+    __ cmp(Operand(answer.reg()), Immediate(HeapNumber::kExponentMask));
+    // base is NaN or +/-Infinity
+    call_runtime.Branch(greater_equal);
+    __ movdbl(xmm0, FieldOperand(base.reg(), HeapNumber::kValueOffset));
+
+    // base is in xmm0 and exponent is in xmm1.
+    __ bind(&handle_special_cases);
+    Label not_minus_half;
+    // Test for -0.5.
+    // Load xmm2 with -0.5.
+    __ mov(answer.reg(), Immediate(0xBF000000));
+    __ movd(xmm2, Operand(answer.reg()));
+    __ cvtss2sd(xmm2, xmm2);
+    // xmm2 now has -0.5.
+    __ ucomisd(xmm2, xmm1);
+    __ j(not_equal, &not_minus_half);
+
+    // Calculates reciprocal of square root.
+    // Note that 1/sqrt(x) = sqrt(1/x))
+    __ divsd(xmm3, xmm0);
+    __ movsd(xmm1, xmm3);
+    __ sqrtsd(xmm1, xmm1);
+    __ jmp(&allocate_return);
+
+    // Test for 0.5.
+    __ bind(&not_minus_half);
+    // Load xmm2 with 0.5.
+    // Since xmm3 is 1 and xmm2 is -0.5 this is simply xmm2 + xmm3.
+    __ addsd(xmm2, xmm3);
+    // xmm2 now has 0.5.
+    __ comisd(xmm2, xmm1);
+    call_runtime.Branch(not_equal);
+    // Calculates square root.
+    __ movsd(xmm1, xmm0);
+    __ sqrtsd(xmm1, xmm1);
+
+    JumpTarget done;
+    Label failure, success;
+    __ bind(&allocate_return);
+    // Make a copy of the frame to enable us to handle allocation
+    // failure after the JumpTarget jump.
+    VirtualFrame* clone = new VirtualFrame(frame());
+    __ AllocateHeapNumber(answer.reg(), exponent.reg(),
+                          base.reg(), &failure);
+    __ movdbl(FieldOperand(answer.reg(), HeapNumber::kValueOffset), xmm1);
+    // Remove the two original values from the frame - we only need those
+    // in the case where we branch to runtime.
+    frame()->Drop(2);
+    exponent.Unuse();
+    base.Unuse();
+    done.Jump(&answer);
+    // Use the copy of the original frame as our current frame.
+    RegisterFile empty_regs;
+    SetFrame(clone, &empty_regs);
+    // If we experience an allocation failure we branch to runtime.
+    __ bind(&failure);
+    call_runtime.Bind();
+    answer = frame()->CallRuntime(Runtime::kMath_pow_cfunction, 2);
+
+    done.Bind(&answer);
+    frame()->Push(&answer);
+  }
+}
+
+
+void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) {
+  ASSERT_EQ(args->length(), 1);
+  Load(args->at(0));
+  TranscendentalCacheStub stub(TranscendentalCache::SIN);
+  Result result = frame_->CallStub(&stub, 1);
+  frame_->Push(&result);
+}
+
+
+void CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) {
+  ASSERT_EQ(args->length(), 1);
+  Load(args->at(0));
+  TranscendentalCacheStub stub(TranscendentalCache::COS);
+  Result result = frame_->CallStub(&stub, 1);
+  frame_->Push(&result);
+}
+
+
+// Generates the Math.sqrt method. Please note - this function assumes that
+// the callsite has executed ToNumber on the argument.
+void CodeGenerator::GenerateMathSqrt(ZoneList<Expression*>* args) {
+  ASSERT_EQ(args->length(), 1);
+  Load(args->at(0));
+
+  if (!CpuFeatures::IsSupported(SSE2)) {
+    Result result = frame()->CallRuntime(Runtime::kMath_sqrt, 1);
+    frame()->Push(&result);
+  } else {
+    CpuFeatures::Scope use_sse2(SSE2);
+    // Leave original value on the frame if we need to call runtime.
+    frame()->Dup();
+    Result result = frame()->Pop();
+    result.ToRegister();
+    frame()->Spill(result.reg());
+    Label runtime;
+    Label non_smi;
+    Label load_done;
+    JumpTarget end;
+
+    __ test(result.reg(), Immediate(kSmiTagMask));
+    __ j(not_zero, &non_smi);
+    __ SmiUntag(result.reg());
+    __ cvtsi2sd(xmm0, Operand(result.reg()));
+    __ jmp(&load_done);
+    __ bind(&non_smi);
+    __ cmp(FieldOperand(result.reg(), HeapObject::kMapOffset),
+           Factory::heap_number_map());
+    __ j(not_equal, &runtime);
+    __ movdbl(xmm0, FieldOperand(result.reg(), HeapNumber::kValueOffset));
+
+    __ bind(&load_done);
+    __ sqrtsd(xmm0, xmm0);
+    // A copy of the virtual frame to allow us to go to runtime after the
+    // JumpTarget jump.
+    Result scratch = allocator()->Allocate();
+    VirtualFrame* clone = new VirtualFrame(frame());
+    __ AllocateHeapNumber(result.reg(), scratch.reg(), no_reg, &runtime);
+
+    __ movdbl(FieldOperand(result.reg(), HeapNumber::kValueOffset), xmm0);
+    frame()->Drop(1);
+    scratch.Unuse();
+    end.Jump(&result);
+    // We only branch to runtime if we have an allocation error.
+    // Use the copy of the original frame as our current frame.
+    RegisterFile empty_regs;
+    SetFrame(clone, &empty_regs);
+    __ bind(&runtime);
+    result = frame()->CallRuntime(Runtime::kMath_sqrt, 1);
+
+    end.Bind(&result);
+    frame()->Push(&result);
+  }
+}
+
+
 void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
   if (CheckForInlineRuntimeCall(node)) {
     return;
@@ -6682,8 +7155,12 @@ class DeferredReferenceSetKeyedValue: public DeferredCode {
  public:
   DeferredReferenceSetKeyedValue(Register value,
                                  Register key,
-                                 Register receiver)
-      : value_(value), key_(key), receiver_(receiver) {
+                                 Register receiver,
+                                 Register scratch)
+      : value_(value),
+        key_(key),
+        receiver_(receiver),
+        scratch_(scratch) {
     set_comment("[ DeferredReferenceSetKeyedValue");
   }
 
@@ -6695,17 +7172,65 @@ class DeferredReferenceSetKeyedValue: public DeferredCode {
   Register value_;
   Register key_;
   Register receiver_;
+  Register scratch_;
   Label patch_site_;
 };
 
 
 void DeferredReferenceSetKeyedValue::Generate() {
   __ IncrementCounter(&Counters::keyed_store_inline_miss, 1);
-  // Push receiver and key arguments on the stack.
-  __ push(receiver_);
-  __ push(key_);
-  // Move value argument to eax as expected by the IC stub.
-  if (!value_.is(eax)) __ mov(eax, value_);
+  // Move value_ to eax, key_ to ecx, and receiver_ to edx.
+  Register old_value = value_;
+
+  // First, move value to eax.
+  if (!value_.is(eax)) {
+    if (key_.is(eax)) {
+      // Move key_ out of eax, preferably to ecx.
+      if (!value_.is(ecx) && !receiver_.is(ecx)) {
+        __ mov(ecx, key_);
+        key_ = ecx;
+      } else {
+        __ mov(scratch_, key_);
+        key_ = scratch_;
+      }
+    }
+    if (receiver_.is(eax)) {
+      // Move receiver_ out of eax, preferably to edx.
+      if (!value_.is(edx) && !key_.is(edx)) {
+        __ mov(edx, receiver_);
+        receiver_ = edx;
+      } else {
+        // Both moves to scratch are from eax, also, no valid path hits both.
+        __ mov(scratch_, receiver_);
+        receiver_ = scratch_;
+      }
+    }
+    __ mov(eax, value_);
+    value_ = eax;
+  }
+
+  // Now value_ is in eax.  Move the other two to the right positions.
+  // We do not update the variables key_ and receiver_ to ecx and edx.
+  if (key_.is(ecx)) {
+    if (!receiver_.is(edx)) {
+      __ mov(edx, receiver_);
+    }
+  } else if (key_.is(edx)) {
+    if (receiver_.is(ecx)) {
+      __ xchg(edx, ecx);
+    } else {
+      __ mov(ecx, key_);
+      if (!receiver_.is(edx)) {
+        __ mov(edx, receiver_);
+      }
+    }
+  } else {  // Key is not in edx or ecx.
+    if (!receiver_.is(edx)) {
+      __ mov(edx, receiver_);
+    }
+    __ mov(ecx, key_);
+  }
+
   // Call the IC stub.
   Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
   __ call(ic, RelocInfo::CODE_TARGET);
@@ -6718,11 +7243,8 @@ void DeferredReferenceSetKeyedValue::Generate() {
   // Here we use masm_-> instead of the __ macro because this is the
   // instruction that gets patched and coverage code gets in the way.
   masm_->test(eax, Immediate(-delta_to_patch_site));
-  // Restore value (returned from store IC), key and receiver
-  // registers.
-  if (!value_.is(eax)) __ mov(value_, eax);
-  __ pop(key_);
-  __ pop(receiver_);
+  // Restore value (returned from store IC) register.
+  if (!old_value.is(eax)) __ mov(old_value, eax);
 }
 
 
@@ -6846,8 +7368,10 @@ Result CodeGenerator::EmitKeyedLoad() {
     deferred->Branch(not_equal);
 
     // Check that the key is a smi.
-    __ test(key.reg(), Immediate(kSmiTagMask));
-    deferred->Branch(not_zero);
+    if (!key.is_smi()) {
+      __ test(key.reg(), Immediate(kSmiTagMask));
+      deferred->Branch(not_zero);
+    }
 
     // Get the elements array from the receiver and check that it
     // is not a dictionary.
@@ -6921,7 +7445,8 @@ Result CodeGenerator::EmitKeyedStore(StaticType* key_type) {
     DeferredReferenceSetKeyedValue* deferred =
         new DeferredReferenceSetKeyedValue(result.reg(),
                                            key.reg(),
-                                           receiver.reg());
+                                           receiver.reg(),
+                                           tmp.reg());
 
     // Check that the value is a smi if it is not a constant.  We can skip
     // the write barrier for smis and constants.
@@ -6981,7 +7506,6 @@ Result CodeGenerator::EmitKeyedStore(StaticType* key_type) {
     // indicate that we have generated an inline version of the
     // keyed store.
     __ nop();
-    frame()->Drop(2);
   }
   ASSERT(frame()->height() == original_height - 3);
   return result;
@@ -6992,6 +7516,34 @@ Result CodeGenerator::EmitKeyedStore(StaticType* key_type) {
 #define __ ACCESS_MASM(masm)
 
 
+static void CheckTwoForSminess(MacroAssembler* masm,
+                               Register left, Register right, Register scratch,
+                               NumberInfo left_info, NumberInfo right_info,
+                               DeferredInlineBinaryOperation* deferred) {
+  if (left.is(right)) {
+    if (!left_info.IsSmi()) {
+      __ test(left, Immediate(kSmiTagMask));
+      deferred->Branch(not_zero);
+    }
+  } else if (!left_info.IsSmi()) {
+    if (!right_info.IsSmi()) {
+      __ mov(scratch, left);
+      __ or_(scratch, Operand(right));
+      __ test(scratch, Immediate(kSmiTagMask));
+      deferred->Branch(not_zero);
+    } else {
+      __ test(left, Immediate(kSmiTagMask));
+      deferred->Branch(not_zero);
+    }
+  } else {
+    if (!right_info.IsSmi()) {
+      __ test(right, Immediate(kSmiTagMask));
+      deferred->Branch(not_zero);
+    }
+  }
+}
+
+
 Handle<String> Reference::GetName() {
   ASSERT(type_ == NAMED);
   Property* property = expression_->AsProperty();
@@ -7123,6 +7675,7 @@ void Reference::SetValue(InitState init_state) {
       Comment cmnt(masm, "[ Store to keyed Property");
       Property* property = expression()->AsProperty();
       ASSERT(property != NULL);
+
       Result answer = cgen_->EmitKeyedStore(property->key()->type());
       cgen_->frame()->Push(&answer);
       set_unloaded();
@@ -7175,7 +7728,7 @@ void FastNewClosureStub::Generate(MacroAssembler* masm) {
   __ push(esi);
   __ push(edx);
   __ push(ecx);  // Restore return address.
-  __ TailCallRuntime(ExternalReference(Runtime::kNewClosure), 2, 1);
+  __ TailCallRuntime(Runtime::kNewClosure, 2, 1);
 }
 
 
@@ -7219,7 +7772,7 @@ void FastNewContextStub::Generate(MacroAssembler* masm) {
 
   // Need to collect. Call into runtime system.
   __ bind(&gc);
-  __ TailCallRuntime(ExternalReference(Runtime::kNewContext), 1, 1);
+  __ TailCallRuntime(Runtime::kNewContext, 1, 1);
 }
 
 
@@ -7274,8 +7827,7 @@ void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) {
   __ ret(3 * kPointerSize);
 
   __ bind(&slow_case);
-  ExternalReference runtime(Runtime::kCreateArrayLiteralShallow);
-  __ TailCallRuntime(runtime, 3, 1);
+  __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1);
 }
 
 
@@ -7492,6 +8044,22 @@ void GenericBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, Label* slow) {
     __ mov(left, Operand(esp, 2 * kPointerSize));
   }
 
+  if (static_operands_type_.IsSmi()) {
+    if (op_ == Token::BIT_OR) {
+      __ or_(right, Operand(left));
+      GenerateReturn(masm);
+      return;
+    } else if (op_ == Token::BIT_AND) {
+      __ and_(right, Operand(left));
+      GenerateReturn(masm);
+      return;
+    } else if (op_ == Token::BIT_XOR) {
+      __ xor_(right, Operand(left));
+      GenerateReturn(masm);
+      return;
+    }
+  }
+
   // 2. Prepare the smi check of both operands by oring them together.
   Comment smi_check_comment(masm, "-- Smi check arguments");
   Label not_smis;
@@ -7800,146 +8368,181 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
   // Generate fast case smi code if requested. This flag is set when the fast
   // case smi code is not generated by the caller. Generating it here will speed
   // up common operations.
-  if (HasSmiCodeInStub()) {
+  if (ShouldGenerateSmiCode()) {
     GenerateSmiCode(masm, &call_runtime);
   } else if (op_ != Token::MOD) {  // MOD goes straight to runtime.
-    GenerateLoadArguments(masm);
+    if (!HasArgsInRegisters()) {
+      GenerateLoadArguments(masm);
+    }
   }
 
   // Floating point case.
-  switch (op_) {
-    case Token::ADD:
-    case Token::SUB:
-    case Token::MUL:
-    case Token::DIV: {
-      if (CpuFeatures::IsSupported(SSE2)) {
-        CpuFeatures::Scope use_sse2(SSE2);
-        if (NumberInfo::IsNumber(operands_type_)) {
-          if (FLAG_debug_code) {
-            // Assert at runtime that inputs are only numbers.
-            __ AbortIfNotNumber(edx,
-                                "GenericBinaryOpStub operand not a number.");
-            __ AbortIfNotNumber(eax,
-                                "GenericBinaryOpStub operand not a number.");
-          }
-          FloatingPointHelper::LoadSSE2Operands(masm);
-        } else {
-          FloatingPointHelper::LoadSSE2Operands(masm, &call_runtime);
+  if (ShouldGenerateFPCode()) {
+    switch (op_) {
+      case Token::ADD:
+      case Token::SUB:
+      case Token::MUL:
+      case Token::DIV: {
+        if (runtime_operands_type_ == BinaryOpIC::DEFAULT &&
+            HasSmiCodeInStub()) {
+          // Execution reaches this point when the first non-smi argument occurs
+          // (and only if smi code is generated). This is the right moment to
+          // patch to HEAP_NUMBERS state. The transition is attempted only for
+          // the four basic operations. The stub stays in the DEFAULT state
+          // forever for all other operations (also if smi code is skipped).
+          GenerateTypeTransition(masm);
         }
 
-        switch (op_) {
-          case Token::ADD: __ addsd(xmm0, xmm1); break;
-          case Token::SUB: __ subsd(xmm0, xmm1); break;
-          case Token::MUL: __ mulsd(xmm0, xmm1); break;
-          case Token::DIV: __ divsd(xmm0, xmm1); break;
-          default: UNREACHABLE();
-        }
-        GenerateHeapResultAllocation(masm, &call_runtime);
-        __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
-        GenerateReturn(masm);
-      } else {  // SSE2 not available, use FPU.
-        if (NumberInfo::IsNumber(operands_type_)) {
-          if (FLAG_debug_code) {
-            // Assert at runtime that inputs are only numbers.
-            __ AbortIfNotNumber(edx,
-                                "GenericBinaryOpStub operand not a number.");
-            __ AbortIfNotNumber(eax,
-                                "GenericBinaryOpStub operand not a number.");
+        Label not_floats;
+        if (CpuFeatures::IsSupported(SSE2)) {
+          CpuFeatures::Scope use_sse2(SSE2);
+          if (static_operands_type_.IsNumber()) {
+            if (FLAG_debug_code) {
+              // Assert at runtime that inputs are only numbers.
+              __ AbortIfNotNumber(edx,
+                                  "GenericBinaryOpStub operand not a number.");
+              __ AbortIfNotNumber(eax,
+                                  "GenericBinaryOpStub operand not a number.");
+            }
+            if (static_operands_type_.IsSmi()) {
+              FloatingPointHelper::LoadSSE2Smis(masm, ecx);
+            } else {
+              FloatingPointHelper::LoadSSE2Operands(masm);
+            }
+          } else {
+            FloatingPointHelper::LoadSSE2Operands(masm, &call_runtime);
           }
-        } else {
-          FloatingPointHelper::CheckFloatOperands(masm, &call_runtime, ebx);
+
+          switch (op_) {
+            case Token::ADD: __ addsd(xmm0, xmm1); break;
+            case Token::SUB: __ subsd(xmm0, xmm1); break;
+            case Token::MUL: __ mulsd(xmm0, xmm1); break;
+            case Token::DIV: __ divsd(xmm0, xmm1); break;
+            default: UNREACHABLE();
+          }
+          GenerateHeapResultAllocation(masm, &call_runtime);
+          __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
+          GenerateReturn(masm);
+        } else {  // SSE2 not available, use FPU.
+          if (static_operands_type_.IsNumber()) {
+            if (FLAG_debug_code) {
+              // Assert at runtime that inputs are only numbers.
+              __ AbortIfNotNumber(edx,
+                                  "GenericBinaryOpStub operand not a number.");
+              __ AbortIfNotNumber(eax,
+                                  "GenericBinaryOpStub operand not a number.");
+            }
+          } else {
+            FloatingPointHelper::CheckFloatOperands(masm, &call_runtime, ebx);
+          }
+          FloatingPointHelper::LoadFloatOperands(
+              masm,
+              ecx,
+              FloatingPointHelper::ARGS_IN_REGISTERS);
+          switch (op_) {
+            case Token::ADD: __ faddp(1); break;
+            case Token::SUB: __ fsubp(1); break;
+            case Token::MUL: __ fmulp(1); break;
+            case Token::DIV: __ fdivp(1); break;
+            default: UNREACHABLE();
+          }
+          Label after_alloc_failure;
+          GenerateHeapResultAllocation(masm, &after_alloc_failure);
+          __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
+          GenerateReturn(masm);
+          __ bind(&after_alloc_failure);
+          __ ffree();
+          __ jmp(&call_runtime);
         }
-        FloatingPointHelper::LoadFloatOperands(
-            masm,
-            ecx,
-            FloatingPointHelper::ARGS_IN_REGISTERS);
-        switch (op_) {
-          case Token::ADD: __ faddp(1); break;
-          case Token::SUB: __ fsubp(1); break;
-          case Token::MUL: __ fmulp(1); break;
-          case Token::DIV: __ fdivp(1); break;
-          default: UNREACHABLE();
+        __ bind(&not_floats);
+        if (runtime_operands_type_ == BinaryOpIC::DEFAULT &&
+            !HasSmiCodeInStub()) {
+          // Execution reaches this point when the first non-number argument
+          // occurs (and only if smi code is skipped from the stub, otherwise
+          // the patching has already been done earlier in this case branch).
+          // Try patching to STRINGS for ADD operation.
+          if (op_ == Token::ADD) {
+            GenerateTypeTransition(masm);
+          }
         }
-        Label after_alloc_failure;
-        GenerateHeapResultAllocation(masm, &after_alloc_failure);
-        __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
-        GenerateReturn(masm);
-        __ bind(&after_alloc_failure);
-        __ ffree();
-        __ jmp(&call_runtime);
-      }
-    }
-    case Token::MOD: {
-      // For MOD we go directly to runtime in the non-smi case.
-      break;
-    }
-    case Token::BIT_OR:
-    case Token::BIT_AND:
-    case Token::BIT_XOR:
-    case Token::SAR:
-    case Token::SHL:
-    case Token::SHR: {
-      Label non_smi_result;
-      FloatingPointHelper::LoadAsIntegers(masm, use_sse3_, &call_runtime);
-      switch (op_) {
-        case Token::BIT_OR:  __ or_(eax, Operand(ecx)); break;
-        case Token::BIT_AND: __ and_(eax, Operand(ecx)); break;
-        case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break;
-        case Token::SAR: __ sar_cl(eax); break;
-        case Token::SHL: __ shl_cl(eax); break;
-        case Token::SHR: __ shr_cl(eax); break;
-        default: UNREACHABLE();
+        break;
       }
-      if (op_ == Token::SHR) {
-        // Check if result is non-negative and fits in a smi.
-        __ test(eax, Immediate(0xc0000000));
-        __ j(not_zero, &call_runtime);
-      } else {
-        // Check if result fits in a smi.
-        __ cmp(eax, 0xc0000000);
-        __ j(negative, &non_smi_result);
+      case Token::MOD: {
+        // For MOD we go directly to runtime in the non-smi case.
+        break;
       }
-      // Tag smi result and return.
-      __ SmiTag(eax);
-      GenerateReturn(masm);
-
-      // All ops except SHR return a signed int32 that we load in a HeapNumber.
-      if (op_ != Token::SHR) {
-        __ bind(&non_smi_result);
-        // Allocate a heap number if needed.
-        __ mov(ebx, Operand(eax));  // ebx: result
-        Label skip_allocation;
-        switch (mode_) {
-          case OVERWRITE_LEFT:
-          case OVERWRITE_RIGHT:
-            // If the operand was an object, we skip the
-            // allocation of a heap number.
-            __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ?
-                                1 * kPointerSize : 2 * kPointerSize));
-            __ test(eax, Immediate(kSmiTagMask));
-            __ j(not_zero, &skip_allocation, not_taken);
-            // Fall through!
-          case NO_OVERWRITE:
-            __ AllocateHeapNumber(eax, ecx, edx, &call_runtime);
-            __ bind(&skip_allocation);
-            break;
+      case Token::BIT_OR:
+      case Token::BIT_AND:
+      case Token::BIT_XOR:
+      case Token::SAR:
+      case Token::SHL:
+      case Token::SHR: {
+        Label non_smi_result;
+        FloatingPointHelper::LoadAsIntegers(masm,
+                                            static_operands_type_,
+                                            use_sse3_,
+                                            &call_runtime);
+        switch (op_) {
+          case Token::BIT_OR:  __ or_(eax, Operand(ecx)); break;
+          case Token::BIT_AND: __ and_(eax, Operand(ecx)); break;
+          case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break;
+          case Token::SAR: __ sar_cl(eax); break;
+          case Token::SHL: __ shl_cl(eax); break;
+          case Token::SHR: __ shr_cl(eax); break;
           default: UNREACHABLE();
         }
-        // Store the result in the HeapNumber and return.
-        if (CpuFeatures::IsSupported(SSE2)) {
-          CpuFeatures::Scope use_sse2(SSE2);
-          __ cvtsi2sd(xmm0, Operand(ebx));
-          __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
+        if (op_ == Token::SHR) {
+          // Check if result is non-negative and fits in a smi.
+          __ test(eax, Immediate(0xc0000000));
+          __ j(not_zero, &call_runtime);
         } else {
-          __ mov(Operand(esp, 1 * kPointerSize), ebx);
-          __ fild_s(Operand(esp, 1 * kPointerSize));
-          __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
+          // Check if result fits in a smi.
+          __ cmp(eax, 0xc0000000);
+          __ j(negative, &non_smi_result);
         }
+        // Tag smi result and return.
+        __ SmiTag(eax);
         GenerateReturn(masm);
+
+        // All ops except SHR return a signed int32 that we load in
+        // a HeapNumber.
+        if (op_ != Token::SHR) {
+          __ bind(&non_smi_result);
+          // Allocate a heap number if needed.
+          __ mov(ebx, Operand(eax));  // ebx: result
+          Label skip_allocation;
+          switch (mode_) {
+            case OVERWRITE_LEFT:
+            case OVERWRITE_RIGHT:
+              // If the operand was an object, we skip the
+              // allocation of a heap number.
+              __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ?
+                                  1 * kPointerSize : 2 * kPointerSize));
+              __ test(eax, Immediate(kSmiTagMask));
+              __ j(not_zero, &skip_allocation, not_taken);
+              // Fall through!
+            case NO_OVERWRITE:
+              __ AllocateHeapNumber(eax, ecx, edx, &call_runtime);
+              __ bind(&skip_allocation);
+              break;
+            default: UNREACHABLE();
+          }
+          // Store the result in the HeapNumber and return.
+          if (CpuFeatures::IsSupported(SSE2)) {
+            CpuFeatures::Scope use_sse2(SSE2);
+            __ cvtsi2sd(xmm0, Operand(ebx));
+            __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
+          } else {
+            __ mov(Operand(esp, 1 * kPointerSize), ebx);
+            __ fild_s(Operand(esp, 1 * kPointerSize));
+            __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
+          }
+          GenerateReturn(masm);
+        }
+        break;
       }
-      break;
+      default: UNREACHABLE(); break;
     }
-    default: UNREACHABLE(); break;
   }
 
   // If all else fails, use the runtime system to get the correct
@@ -7947,30 +8550,40 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
   // stack in the correct order below the return address.
   __ bind(&call_runtime);
   if (HasArgsInRegisters()) {
-    __ pop(ecx);
-    if (HasArgsReversed()) {
-      __ push(eax);
-      __ push(edx);
-    } else {
-      __ push(edx);
-      __ push(eax);
-    }
-    __ push(ecx);
+    GenerateRegisterArgsPush(masm);
   }
+
   switch (op_) {
     case Token::ADD: {
       // Test for string arguments before calling runtime.
       Label not_strings, not_string1, string1, string1_smi2;
-      Result answer;
-      __ test(edx, Immediate(kSmiTagMask));
+
+      // If this stub has already generated FP-specific code then the arguments
+      // are already in edx, eax
+      if (!ShouldGenerateFPCode() && !HasArgsInRegisters()) {
+        GenerateLoadArguments(masm);
+      }
+
+      // Registers containing left and right operands respectively.
+      Register lhs, rhs;
+      if (HasArgsReversed()) {
+        lhs = eax;
+        rhs = edx;
+      } else {
+        lhs = edx;
+        rhs = eax;
+      }
+
+      // Test if first argument is a string.
+      __ test(lhs, Immediate(kSmiTagMask));
       __ j(zero, &not_string1);
-      __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, ecx);
+      __ CmpObjectType(lhs, FIRST_NONSTRING_TYPE, ecx);
       __ j(above_equal, &not_string1);
 
       // First argument is a string, test second.
-      __ test(eax, Immediate(kSmiTagMask));
+      __ test(rhs, Immediate(kSmiTagMask));
       __ j(zero, &string1_smi2);
-      __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ecx);
+      __ CmpObjectType(rhs, FIRST_NONSTRING_TYPE, ecx);
       __ j(above_equal, &string1);
 
       // First and second argument are strings. Jump to the string add stub.
@@ -7981,36 +8594,26 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
       // First argument is a string, second is a smi. Try to lookup the number
       // string for the smi in the number string cache.
       NumberToStringStub::GenerateLookupNumberStringCache(
-          masm, eax, edi, ebx, ecx, true, &string1);
+          masm, rhs, edi, ebx, ecx, true, &string1);
 
-      // Call the string add stub to make the result.
-      __ EnterInternalFrame();
-      __ push(edx);  // Original first argument.
-      __ push(edi);  // Number to string result for second argument.
-      __ CallStub(&string_add_stub);
-      __ LeaveInternalFrame();
-      __ ret(2 * kPointerSize);
+      // Replace second argument on stack and tailcall string add stub to make
+      // the result.
+      __ mov(Operand(esp, 1 * kPointerSize), edi);
+      __ TailCallStub(&string_add_stub);
 
+      // Only first argument is a string.
       __ bind(&string1);
-      __ InvokeBuiltin(
-          HasArgsReversed() ?
-              Builtins::STRING_ADD_RIGHT :
-              Builtins::STRING_ADD_LEFT,
-          JUMP_FUNCTION);
+      __ InvokeBuiltin(Builtins::STRING_ADD_LEFT, JUMP_FUNCTION);
 
       // First argument was not a string, test second.
       __ bind(&not_string1);
-      __ test(eax, Immediate(kSmiTagMask));
+      __ test(rhs, Immediate(kSmiTagMask));
       __ j(zero, &not_strings);
-      __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ecx);
+      __ CmpObjectType(rhs, FIRST_NONSTRING_TYPE, ecx);
       __ j(above_equal, &not_strings);
 
       // Only second argument is a string.
-      __ InvokeBuiltin(
-          HasArgsReversed() ?
-              Builtins::STRING_ADD_LEFT :
-              Builtins::STRING_ADD_RIGHT,
-          JUMP_FUNCTION);
+      __ InvokeBuiltin(Builtins::STRING_ADD_RIGHT, JUMP_FUNCTION);
 
       __ bind(&not_strings);
       // Neither argument is a string.
@@ -8050,6 +8653,13 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
     default:
       UNREACHABLE();
   }
+
+  // Generate an unreachable reference to the DEFAULT stub so that it can be
+  // found at the end of this stub when clearing ICs at GC.
+  if (runtime_operands_type_ != BinaryOpIC::DEFAULT) {
+    GenericBinaryOpStub uninit(MinorKey(), BinaryOpIC::DEFAULT);
+    __ TailCallStub(&uninit);
+  }
 }
 
 
@@ -8103,10 +8713,9 @@ void GenericBinaryOpStub::GenerateHeapResultAllocation(MacroAssembler* masm,
 
 void GenericBinaryOpStub::GenerateLoadArguments(MacroAssembler* masm) {
   // If arguments are not passed in registers read them from the stack.
-  if (!HasArgsInRegisters()) {
-    __ mov(eax, Operand(esp, 1 * kPointerSize));
-    __ mov(edx, Operand(esp, 2 * kPointerSize));
-  }
+  ASSERT(!HasArgsInRegisters());
+  __ mov(eax, Operand(esp, 1 * kPointerSize));
+  __ mov(edx, Operand(esp, 2 * kPointerSize));
 }
 
 
@@ -8121,30 +8730,310 @@ void GenericBinaryOpStub::GenerateReturn(MacroAssembler* masm) {
 }
 
 
+void GenericBinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) {
+  ASSERT(HasArgsInRegisters());
+  __ pop(ecx);
+  if (HasArgsReversed()) {
+    __ push(eax);
+    __ push(edx);
+  } else {
+    __ push(edx);
+    __ push(eax);
+  }
+  __ push(ecx);
+}
+
+
+void GenericBinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
+  Label get_result;
+
+  // Keep a copy of operands on the stack and make sure they are also in
+  // edx, eax.
+  if (HasArgsInRegisters()) {
+    GenerateRegisterArgsPush(masm);
+  } else {
+    GenerateLoadArguments(masm);
+  }
+
+  // Internal frame is necessary to handle exceptions properly.
+  __ EnterInternalFrame();
+
+  // Push arguments on stack if the stub expects them there.
+  if (!HasArgsInRegisters()) {
+    __ push(edx);
+    __ push(eax);
+  }
+  // Call the stub proper to get the result in eax.
+  __ call(&get_result);
+  __ LeaveInternalFrame();
+
+  __ pop(ecx);  // Return address.
+  // Left and right arguments are now on top.
+  // Push the operation result. The tail call to BinaryOp_Patch will
+  // return it to the original caller.
+  __ push(eax);
+  // Push this stub's key. Although the operation and the type info are
+  // encoded into the key, the encoding is opaque, so push them too.
+  __ push(Immediate(Smi::FromInt(MinorKey())));
+  __ push(Immediate(Smi::FromInt(op_)));
+  __ push(Immediate(Smi::FromInt(runtime_operands_type_)));
+
+  __ push(ecx);  // Return address.
+
+  // Patch the caller to an appropriate specialized stub
+  // and return the operation result.
+  __ TailCallExternalReference(
+      ExternalReference(IC_Utility(IC::kBinaryOp_Patch)),
+      6,
+      1);
+
+  // The entry point for the result calculation is assumed to be immediately
+  // after this sequence.
+  __ bind(&get_result);
+}
+
+Handle<Code> GetBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info) {
+  GenericBinaryOpStub stub(key, type_info);
+  HandleScope scope;
+  return stub.GetCode();
+}
+
+
+void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
+  // Input on stack:
+  // esp[4]: argument (should be number).
+  // esp[0]: return address.
+  // Test that eax is a number.
+  Label runtime_call;
+  Label runtime_call_clear_stack;
+  Label input_not_smi;
+  Label loaded;
+  __ mov(eax, Operand(esp, kPointerSize));
+  __ test(eax, Immediate(kSmiTagMask));
+  __ j(not_zero, &input_not_smi);
+  // Input is a smi. Untag and load it onto the FPU stack.
+  // Then load the low and high words of the double into ebx, edx.
+  ASSERT_EQ(1, kSmiTagSize);
+  __ sar(eax, 1);
+  __ sub(Operand(esp), Immediate(2 * kPointerSize));
+  __ mov(Operand(esp, 0), eax);
+  __ fild_s(Operand(esp, 0));
+  __ fst_d(Operand(esp, 0));
+  __ pop(edx);
+  __ pop(ebx);
+  __ jmp(&loaded);
+  __ bind(&input_not_smi);
+  // Check if input is a HeapNumber.
+  __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
+  __ cmp(Operand(ebx), Immediate(Factory::heap_number_map()));
+  __ j(not_equal, &runtime_call);
+  // Input is a HeapNumber. Push it on the FPU stack and load its
+  // low and high words into ebx, edx.
+  __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
+  __ mov(edx, FieldOperand(eax, HeapNumber::kExponentOffset));
+  __ mov(ebx, FieldOperand(eax, HeapNumber::kMantissaOffset));
+
+  __ bind(&loaded);
+  // ST[0] == double value
+  // ebx = low 32 bits of double value
+  // edx = high 32 bits of double value
+  // Compute hash:
+  //   h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1);
+  __ mov(ecx, ebx);
+  __ xor_(ecx, Operand(edx));
+  __ mov(eax, ecx);
+  __ sar(eax, 16);
+  __ xor_(ecx, Operand(eax));
+  __ mov(eax, ecx);
+  __ sar(eax, 8);
+  __ xor_(ecx, Operand(eax));
+  ASSERT(IsPowerOf2(TranscendentalCache::kCacheSize));
+  __ and_(Operand(ecx), Immediate(TranscendentalCache::kCacheSize - 1));
+  // ST[0] == double value.
+  // ebx = low 32 bits of double value.
+  // edx = high 32 bits of double value.
+  // ecx = TranscendentalCache::hash(double value).
+  __ mov(eax,
+         Immediate(ExternalReference::transcendental_cache_array_address()));
+  // Eax points to cache array.
+  __ mov(eax, Operand(eax, type_ * sizeof(TranscendentalCache::caches_[0])));
+  // Eax points to the cache for the type type_.
+  // If NULL, the cache hasn't been initialized yet, so go through runtime.
+  __ test(eax, Operand(eax));
+  __ j(zero, &runtime_call_clear_stack);
+#ifdef DEBUG
+  // Check that the layout of cache elements match expectations.
+  {  // NOLINT - doesn't like a single brace on a line.
+    TranscendentalCache::Element test_elem[2];
+    char* elem_start = reinterpret_cast<char*>(&test_elem[0]);
+    char* elem2_start = reinterpret_cast<char*>(&test_elem[1]);
+    char* elem_in0  = reinterpret_cast<char*>(&(test_elem[0].in[0]));
+    char* elem_in1  = reinterpret_cast<char*>(&(test_elem[0].in[1]));
+    char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output));
+    CHECK_EQ(12, elem2_start - elem_start);  // Two uint_32's and a pointer.
+    CHECK_EQ(0, elem_in0 - elem_start);
+    CHECK_EQ(kIntSize, elem_in1 - elem_start);
+    CHECK_EQ(2 * kIntSize, elem_out - elem_start);
+  }
+#endif
+  // Find the address of the ecx'th entry in the cache, i.e., &eax[ecx*12].
+  __ lea(ecx, Operand(ecx, ecx, times_2, 0));
+  __ lea(ecx, Operand(eax, ecx, times_4, 0));
+  // Check if cache matches: Double value is stored in uint32_t[2] array.
+  Label cache_miss;
+  __ cmp(ebx, Operand(ecx, 0));
+  __ j(not_equal, &cache_miss);
+  __ cmp(edx, Operand(ecx, kIntSize));
+  __ j(not_equal, &cache_miss);
+  // Cache hit!
+  __ mov(eax, Operand(ecx, 2 * kIntSize));
+  __ fstp(0);
+  __ ret(kPointerSize);
+
+  __ bind(&cache_miss);
+  // Update cache with new value.
+  // We are short on registers, so use no_reg as scratch.
+  // This gives slightly larger code.
+  __ AllocateHeapNumber(eax, edi, no_reg, &runtime_call_clear_stack);
+  GenerateOperation(masm);
+  __ mov(Operand(ecx, 0), ebx);
+  __ mov(Operand(ecx, kIntSize), edx);
+  __ mov(Operand(ecx, 2 * kIntSize), eax);
+  __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
+  __ ret(kPointerSize);
+
+  __ bind(&runtime_call_clear_stack);
+  __ fstp(0);
+  __ bind(&runtime_call);
+  __ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1);
+}
+
+
+Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() {
+  switch (type_) {
+    // Add more cases when necessary.
+    case TranscendentalCache::SIN: return Runtime::kMath_sin;
+    case TranscendentalCache::COS: return Runtime::kMath_cos;
+    default:
+      UNIMPLEMENTED();
+      return Runtime::kAbort;
+  }
+}
+
+
+void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm) {
+  // Only free register is edi.
+  Label done;
+  ASSERT(type_ == TranscendentalCache::SIN ||
+         type_ == TranscendentalCache::COS);
+  // More transcendental types can be added later.
+
+  // Both fsin and fcos require arguments in the range +/-2^63 and
+  // return NaN for infinities and NaN. They can share all code except
+  // the actual fsin/fcos operation.
+  Label in_range;
+  // If argument is outside the range -2^63..2^63, fsin/cos doesn't
+  // work. We must reduce it to the appropriate range.
+  __ mov(edi, edx);
+  __ and_(Operand(edi), Immediate(0x7ff00000));  // Exponent only.
+  int supported_exponent_limit =
+      (63 + HeapNumber::kExponentBias) << HeapNumber::kExponentShift;
+  __ cmp(Operand(edi), Immediate(supported_exponent_limit));
+  __ j(below, &in_range, taken);
+  // Check for infinity and NaN. Both return NaN for sin.
+  __ cmp(Operand(edi), Immediate(0x7ff00000));
+  Label non_nan_result;
+  __ j(not_equal, &non_nan_result, taken);
+  // Input is +/-Infinity or NaN. Result is NaN.
+  __ fstp(0);
+  // NaN is represented by 0x7ff8000000000000.
+  __ push(Immediate(0x7ff80000));
+  __ push(Immediate(0));
+  __ fld_d(Operand(esp, 0));
+  __ add(Operand(esp), Immediate(2 * kPointerSize));
+  __ jmp(&done);
+
+  __ bind(&non_nan_result);
+
+  // Use fpmod to restrict argument to the range +/-2*PI.
+  __ mov(edi, eax);  // Save eax before using fnstsw_ax.
+  __ fldpi();
+  __ fadd(0);
+  __ fld(1);
+  // FPU Stack: input, 2*pi, input.
+  {
+    Label no_exceptions;
+    __ fwait();
+    __ fnstsw_ax();
+    // Clear if Illegal Operand or Zero Division exceptions are set.
+    __ test(Operand(eax), Immediate(5));
+    __ j(zero, &no_exceptions);
+    __ fnclex();
+    __ bind(&no_exceptions);
+  }
+
+  // Compute st(0) % st(1)
+  {
+    Label partial_remainder_loop;
+    __ bind(&partial_remainder_loop);
+    __ fprem1();
+    __ fwait();
+    __ fnstsw_ax();
+    __ test(Operand(eax), Immediate(0x400 /* C2 */));
+    // If C2 is set, computation only has partial result. Loop to
+    // continue computation.
+    __ j(not_zero, &partial_remainder_loop);
+  }
+  // FPU Stack: input, 2*pi, input % 2*pi
+  __ fstp(2);
+  __ fstp(0);
+  __ mov(eax, edi);  // Restore eax (allocated HeapNumber pointer).
+
+  // FPU Stack: input % 2*pi
+  __ bind(&in_range);
+  switch (type_) {
+    case TranscendentalCache::SIN:
+      __ fsin();
+      break;
+    case TranscendentalCache::COS:
+      __ fcos();
+      break;
+    default:
+      UNREACHABLE();
+  }
+  __ bind(&done);
+}
+
+
 // Get the integer part of a heap number.  Surprisingly, all this bit twiddling
 // is faster than using the built-in instructions on floating point registers.
 // Trashes edi and ebx.  Dest is ecx.  Source cannot be ecx or one of the
 // trashed registers.
 void IntegerConvert(MacroAssembler* masm,
                     Register source,
+                    NumberInfo number_info,
                     bool use_sse3,
                     Label* conversion_failure) {
   ASSERT(!source.is(ecx) && !source.is(edi) && !source.is(ebx));
   Label done, right_exponent, normal_exponent;
   Register scratch = ebx;
   Register scratch2 = edi;
-  // Get exponent word.
-  __ mov(scratch, FieldOperand(source, HeapNumber::kExponentOffset));
-  // Get exponent alone in scratch2.
-  __ mov(scratch2, scratch);
-  __ and_(scratch2, HeapNumber::kExponentMask);
+  if (!number_info.IsInteger32() || !use_sse3) {
+    // Get exponent word.
+    __ mov(scratch, FieldOperand(source, HeapNumber::kExponentOffset));
+    // Get exponent alone in scratch2.
+    __ mov(scratch2, scratch);
+    __ and_(scratch2, HeapNumber::kExponentMask);
+  }
   if (use_sse3) {
     CpuFeatures::Scope scope(SSE3);
-    // Check whether the exponent is too big for a 64 bit signed integer.
-    static const uint32_t kTooBigExponent =
-        (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
-    __ cmp(Operand(scratch2), Immediate(kTooBigExponent));
-    __ j(greater_equal, conversion_failure);
+    if (!number_info.IsInteger32()) {
+      // Check whether the exponent is too big for a 64 bit signed integer.
+      static const uint32_t kTooBigExponent =
+          (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
+      __ cmp(Operand(scratch2), Immediate(kTooBigExponent));
+      __ j(greater_equal, conversion_failure);
+    }
     // Load x87 register with heap number.
     __ fld_d(FieldOperand(source, HeapNumber::kValueOffset));
     // Reserve space for 64 bit answer.
@@ -8258,16 +9147,66 @@ void IntegerConvert(MacroAssembler* masm,
 
 // Input: edx, eax are the left and right objects of a bit op.
 // Output: eax, ecx are left and right integers for a bit op.
-void FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm,
-                                         bool use_sse3,
-                                         Label* conversion_failure) {
+void FloatingPointHelper::LoadNumbersAsIntegers(MacroAssembler* masm,
+                                                NumberInfo number_info,
+                                                bool use_sse3,
+                                                Label* conversion_failure) {
   // Check float operands.
   Label arg1_is_object, check_undefined_arg1;
   Label arg2_is_object, check_undefined_arg2;
   Label load_arg2, done;
 
+  if (!number_info.IsHeapNumber()) {
+    if (!number_info.IsSmi()) {
+      __ test(edx, Immediate(kSmiTagMask));
+      __ j(not_zero, &arg1_is_object);
+    }
+    __ SmiUntag(edx);
+    __ jmp(&load_arg2);
+  }
+
+  __ bind(&arg1_is_object);
+
+  // Get the untagged integer version of the edx heap number in ecx.
+  IntegerConvert(masm, edx, number_info, use_sse3, conversion_failure);
+  __ mov(edx, ecx);
+
+  // Here edx has the untagged integer, eax has a Smi or a heap number.
+  __ bind(&load_arg2);
+  if (!number_info.IsHeapNumber()) {
+    // Test if arg2 is a Smi.
+    if (!number_info.IsSmi()) {
+      __ test(eax, Immediate(kSmiTagMask));
+      __ j(not_zero, &arg2_is_object);
+    }
+    __ SmiUntag(eax);
+    __ mov(ecx, eax);
+    __ jmp(&done);
+  }
+
+  __ bind(&arg2_is_object);
+
+  // Get the untagged integer version of the eax heap number in ecx.
+  IntegerConvert(masm, eax, number_info, use_sse3, conversion_failure);
+  __ bind(&done);
+  __ mov(eax, edx);
+}
+
+
+// Input: edx, eax are the left and right objects of a bit op.
+// Output: eax, ecx are left and right integers for a bit op.
+void FloatingPointHelper::LoadUnknownsAsIntegers(MacroAssembler* masm,
+                                                 bool use_sse3,
+                                                 Label* conversion_failure) {
+  // Check float operands.
+  Label arg1_is_object, check_undefined_arg1;
+  Label arg2_is_object, check_undefined_arg2;
+  Label load_arg2, done;
+
+  // Test if arg1 is a Smi.
   __ test(edx, Immediate(kSmiTagMask));
   __ j(not_zero, &arg1_is_object);
+
   __ SmiUntag(edx);
   __ jmp(&load_arg2);
 
@@ -8282,15 +9221,22 @@ void FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm,
   __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
   __ cmp(ebx, Factory::heap_number_map());
   __ j(not_equal, &check_undefined_arg1);
+
   // Get the untagged integer version of the edx heap number in ecx.
-  IntegerConvert(masm, edx, use_sse3, conversion_failure);
+  IntegerConvert(masm,
+                 edx,
+                 NumberInfo::Unknown(),
+                 use_sse3,
+                 conversion_failure);
   __ mov(edx, ecx);
 
   // Here edx has the untagged integer, eax has a Smi or a heap number.
   __ bind(&load_arg2);
+
   // Test if arg2 is a Smi.
   __ test(eax, Immediate(kSmiTagMask));
   __ j(not_zero, &arg2_is_object);
+
   __ SmiUntag(eax);
   __ mov(ecx, eax);
   __ jmp(&done);
@@ -8306,13 +9252,30 @@ void FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm,
   __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
   __ cmp(ebx, Factory::heap_number_map());
   __ j(not_equal, &check_undefined_arg2);
+
   // Get the untagged integer version of the eax heap number in ecx.
-  IntegerConvert(masm, eax, use_sse3, conversion_failure);
+  IntegerConvert(masm,
+                 eax,
+                 NumberInfo::Unknown(),
+                 use_sse3,
+                 conversion_failure);
   __ bind(&done);
   __ mov(eax, edx);
 }
 
 
+void FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm,
+                                         NumberInfo number_info,
+                                         bool use_sse3,
+                                         Label* conversion_failure) {
+  if (number_info.IsNumber()) {
+    LoadNumbersAsIntegers(masm, number_info, use_sse3, conversion_failure);
+  } else {
+    LoadUnknownsAsIntegers(masm, use_sse3, conversion_failure);
+  }
+}
+
+
 void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm,
                                            Register number) {
   Label load_smi, done;
@@ -8549,7 +9512,11 @@ void GenericUnaryOpStub::Generate(MacroAssembler* masm) {
     __ j(not_equal, &slow, not_taken);
 
     // Convert the heap number in eax to an untagged integer in ecx.
-    IntegerConvert(masm, eax, CpuFeatures::IsSupported(SSE3), &slow);
+    IntegerConvert(masm,
+                   eax,
+                   NumberInfo::Unknown(),
+                   CpuFeatures::IsSupported(SSE3),
+                   &slow);
 
     // Do the bitwise operation and check if the result fits in a smi.
     Label try_float;
@@ -8685,7 +9652,7 @@ void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
   __ pop(ebx);  // Return address.
   __ push(edx);
   __ push(ebx);
-  __ TailCallRuntime(ExternalReference(Runtime::kGetArgumentsProperty), 1, 1);
+  __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1);
 }
 
 
@@ -8786,7 +9753,7 @@ void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) {
 
   // Do the runtime call to allocate the arguments object.
   __ bind(&runtime);
-  __ TailCallRuntime(ExternalReference(Runtime::kNewArgumentsFast), 3, 1);
+  __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1);
 }
 
 
@@ -8795,10 +9762,10 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
   // time or if regexp entry in generated code is turned off runtime switch or
   // at compilation.
 #ifndef V8_NATIVE_REGEXP
-  __ TailCallRuntime(ExternalReference(Runtime::kRegExpExec), 4, 1);
+  __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
 #else  // V8_NATIVE_REGEXP
   if (!FLAG_regexp_entry_native) {
-    __ TailCallRuntime(ExternalReference(Runtime::kRegExpExec), 4, 1);
+    __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
     return;
   }
 
@@ -8981,48 +9948,50 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
   // All checks done. Now push arguments for native regexp code.
   __ IncrementCounter(&Counters::regexp_entry_native, 1);
 
+  static const int kRegExpExecuteArguments = 7;
+  __ PrepareCallCFunction(kRegExpExecuteArguments, ecx);
+
   // Argument 7: Indicate that this is a direct call from JavaScript.
-  __ push(Immediate(1));
+  __ mov(Operand(esp, 6 * kPointerSize), Immediate(1));
 
   // Argument 6: Start (high end) of backtracking stack memory area.
   __ mov(ecx, Operand::StaticVariable(address_of_regexp_stack_memory_address));
   __ add(ecx, Operand::StaticVariable(address_of_regexp_stack_memory_size));
-  __ push(ecx);
+  __ mov(Operand(esp, 5 * kPointerSize), ecx);
 
   // Argument 5: static offsets vector buffer.
-  __ push(Immediate(ExternalReference::address_of_static_offsets_vector()));
+  __ mov(Operand(esp, 4 * kPointerSize),
+         Immediate(ExternalReference::address_of_static_offsets_vector()));
 
   // Argument 4: End of string data
   // Argument 3: Start of string data
-  Label push_two_byte, push_rest;
+  Label setup_two_byte, setup_rest;
   __ test(edi, Operand(edi));
   __ mov(edi, FieldOperand(eax, String::kLengthOffset));
-  __ j(zero, &push_two_byte);
+  __ j(zero, &setup_two_byte);
   __ lea(ecx, FieldOperand(eax, edi, times_1, SeqAsciiString::kHeaderSize));
-  __ push(ecx);  // Argument 4.
+  __ mov(Operand(esp, 3 * kPointerSize), ecx);  // Argument 4.
   __ lea(ecx, FieldOperand(eax, ebx, times_1, SeqAsciiString::kHeaderSize));
-  __ push(ecx);  // Argument 3.
-  __ jmp(&push_rest);
+  __ mov(Operand(esp, 2 * kPointerSize), ecx);  // Argument 3.
+  __ jmp(&setup_rest);
 
-  __ bind(&push_two_byte);
+  __ bind(&setup_two_byte);
   __ lea(ecx, FieldOperand(eax, edi, times_2, SeqTwoByteString::kHeaderSize));
-  __ push(ecx);  // Argument 4.
+  __ mov(Operand(esp, 3 * kPointerSize), ecx);  // Argument 4.
   __ lea(ecx, FieldOperand(eax, ebx, times_2, SeqTwoByteString::kHeaderSize));
-  __ push(ecx);  // Argument 3.
+  __ mov(Operand(esp, 2 * kPointerSize), ecx);  // Argument 3.
 
-  __ bind(&push_rest);
+  __ bind(&setup_rest);
 
   // Argument 2: Previous index.
-  __ push(ebx);
+  __ mov(Operand(esp, 1 * kPointerSize), ebx);
 
   // Argument 1: Subject string.
-  __ push(eax);
+  __ mov(Operand(esp, 0 * kPointerSize), eax);
 
   // Locate the code entry and call it.
   __ add(Operand(edx), Immediate(Code::kHeaderSize - kHeapObjectTag));
-  __ call(Operand(edx));
-  // Remove arguments.
-  __ add(Operand(esp), Immediate(7 * kPointerSize));
+  __ CallCFunction(edx, kRegExpExecuteArguments);
 
   // Check the result.
   Label success;
@@ -9120,7 +10089,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
 
   // Do the runtime call to execute the regexp.
   __ bind(&runtime);
-  __ TailCallRuntime(ExternalReference(Runtime::kRegExpExec), 4, 1);
+  __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
 #endif  // V8_NATIVE_REGEXP
 }
 
@@ -9189,7 +10158,7 @@ void NumberToStringStub::Generate(MacroAssembler* masm) {
 
   __ bind(&runtime);
   // Handle number to string in the runtime system if not found in the cache.
-  __ TailCallRuntime(ExternalReference(Runtime::kNumberToString), 1, 1);
+  __ TailCallRuntime(Runtime::kNumberToString, 1, 1);
 }
 
 
@@ -9474,7 +10443,7 @@ void StackCheckStub::Generate(MacroAssembler* masm) {
   __ push(eax);
 
   // Do tail-call to runtime routine.
-  __ TailCallRuntime(ExternalReference(Runtime::kStackGuard), 1, 1);
+  __ TailCallRuntime(Runtime::kStackGuard, 1, 1);
 }
 
 
@@ -9635,9 +10604,7 @@ void ApiGetterEntryStub::Generate(MacroAssembler* masm) {
   __ LeaveExitFrame(ExitFrame::MODE_NORMAL);
   __ ret(0);
   __ bind(&promote_scheduled_exception);
-  __ TailCallRuntime(ExternalReference(Runtime::kPromoteScheduledException),
-                     0,
-                     1);
+  __ TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1);
 }
 
 
@@ -10122,6 +11089,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
   Label make_two_character_string, make_flat_ascii_string;
   GenerateTwoCharacterSymbolTableProbe(masm, ebx, ecx, eax, edx, edi,
                                        &make_two_character_string);
+  __ IncrementCounter(&Counters::string_add_native, 1);
   __ ret(2 * kPointerSize);
 
   __ bind(&make_two_character_string);
@@ -10266,7 +11234,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
 
   // Just jump to runtime to add the two strings.
   __ bind(&string_add_runtime);
-  __ TailCallRuntime(ExternalReference(Runtime::kStringAdd), 2, 1);
+  __ TailCallRuntime(Runtime::kStringAdd, 2, 1);
 }
 
 
@@ -10330,6 +11298,7 @@ void StringStubBase::GenerateCopyCharactersREP(MacroAssembler* masm,
   // Copy from edi to esi using rep movs instruction.
   __ mov(scratch, count);
   __ sar(count, 2);  // Number of doublewords to copy.
+  __ cld();
   __ rep_movs();
 
   // Find number of bytes left.
@@ -10401,10 +11370,7 @@ void StringStubBase::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
 
   // Calculate capacity mask from the symbol table capacity.
   Register mask = scratch2;
-  static const int kCapacityOffset =
-      FixedArray::kHeaderSize +
-      SymbolTable::kCapacityIndex * kPointerSize;
-  __ mov(mask, FieldOperand(symbol_table, kCapacityOffset));
+  __ mov(mask, FieldOperand(symbol_table, SymbolTable::kCapacityOffset));
   __ SmiUntag(mask);
   __ sub(Operand(mask), Immediate(1));
 
@@ -10429,16 +11395,12 @@ void StringStubBase::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
 
     // Load the entry from the symble table.
     Register candidate = scratch;  // Scratch register contains candidate.
-    ASSERT_EQ(1, SymbolTableShape::kEntrySize);
-    static const int kFirstElementOffset =
-        FixedArray::kHeaderSize +
-        SymbolTable::kPrefixStartIndex * kPointerSize +
-        SymbolTableShape::kPrefixSize * kPointerSize;
+    ASSERT_EQ(1, SymbolTable::kEntrySize);
     __ mov(candidate,
            FieldOperand(symbol_table,
                         scratch,
                         times_pointer_size,
-                        kFirstElementOffset));
+                        SymbolTable::kElementsStartOffset));
 
     // If entry is undefined no string with this hash can be found.
     __ cmp(candidate, Factory::undefined_value());
@@ -10592,7 +11554,7 @@ void SubStringStub::Generate(MacroAssembler* masm) {
   Label make_two_character_string;
   GenerateTwoCharacterSymbolTableProbe(masm, ebx, ecx, eax, edx, edi,
                                      &make_two_character_string);
-  __ ret(2 * kPointerSize);
+  __ ret(3 * kPointerSize);
 
   __ bind(&make_two_character_string);
   // Setup registers for allocating the two character string.
@@ -10676,7 +11638,7 @@ void SubStringStub::Generate(MacroAssembler* masm) {
 
   // Just jump to runtime to create the sub string.
   __ bind(&runtime);
-  __ TailCallRuntime(ExternalReference(Runtime::kSubString), 3, 1);
+  __ TailCallRuntime(Runtime::kSubString, 3, 1);
 }
 
 
@@ -10792,7 +11754,7 @@ void StringCompareStub::Generate(MacroAssembler* masm) {
   // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
   // tagged as a small integer.
   __ bind(&runtime);
-  __ TailCallRuntime(ExternalReference(Runtime::kStringCompare), 2, 1);
+  __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
 }
 
 #undef __
index 0fa6919..79cad72 100644 (file)
@@ -28,6 +28,8 @@
 #ifndef V8_IA32_CODEGEN_IA32_H_
 #define V8_IA32_CODEGEN_IA32_H_
 
+#include "ic-inl.h"
+
 namespace v8 {
 namespace internal {
 
@@ -494,8 +496,8 @@ class CodeGenerator: public AstVisitor {
 
   // To prevent long attacker-controlled byte sequences, integer constants
   // from the JavaScript source are loaded in two parts if they are larger
-  // than 16 bits.
-  static const int kMaxSmiInlinedBits = 16;
+  // than 17 bits.
+  static const int kMaxSmiInlinedBits = 17;
   bool IsUnsafeSmi(Handle<Object> value);
   // Load an integer constant x into a register target or into the stack using
   // at most 16 bits of user-controlled data per assembly operation.
@@ -563,6 +565,9 @@ class CodeGenerator: public AstVisitor {
   // Fast support for charCodeAt(n).
   void GenerateFastCharCodeAt(ZoneList<Expression*>* args);
 
+  // Fast support for string.charAt(n) and string[n].
+  void GenerateCharFromCode(ZoneList<Expression*>* args);
+
   // Fast support for object equality testing.
   void GenerateObjectEquals(ZoneList<Expression*>* args);
 
@@ -588,6 +593,16 @@ class CodeGenerator: public AstVisitor {
   // Fast support for number to string.
   void GenerateNumberToString(ZoneList<Expression*>* args);
 
+  // Fast support for Math.pow().
+  void GenerateMathPow(ZoneList<Expression*>* args);
+
+  // Fast call to transcendental functions.
+  void GenerateMathSin(ZoneList<Expression*>* args);
+  void GenerateMathCos(ZoneList<Expression*>* args);
+
+  // Fast case for sqrt
+  void GenerateMathSqrt(ZoneList<Expression*>* args);
+
   // Simple condition analysis.
   enum ConditionAnalysis {
     ALWAYS_TRUE,
@@ -655,6 +670,22 @@ class CodeGenerator: public AstVisitor {
 };
 
 
+// Compute a transcendental math function natively, or call the
+// TranscendentalCache runtime function.
+class TranscendentalCacheStub: public CodeStub {
+ public:
+  explicit TranscendentalCacheStub(TranscendentalCache::Type type)
+      : type_(type) {}
+  void Generate(MacroAssembler* masm);
+ private:
+  TranscendentalCache::Type type_;
+  Major MajorKey() { return TranscendentalCache; }
+  int MinorKey() { return type_; }
+  Runtime::FunctionId RuntimeFunction();
+  void GenerateOperation(MacroAssembler* masm);
+};
+
+
 // Flag that indicates how to generate code for the stub GenericBinaryOpStub.
 enum GenericBinaryFlags {
   NO_GENERIC_BINARY_FLAGS = 0,
@@ -667,18 +698,35 @@ class GenericBinaryOpStub: public CodeStub {
   GenericBinaryOpStub(Token::Value op,
                       OverwriteMode mode,
                       GenericBinaryFlags flags,
-                      NumberInfo::Type operands_type = NumberInfo::kUnknown)
+                      NumberInfo operands_type)
       : op_(op),
         mode_(mode),
         flags_(flags),
         args_in_registers_(false),
         args_reversed_(false),
-        name_(NULL),
-        operands_type_(operands_type) {
+        static_operands_type_(operands_type),
+        runtime_operands_type_(BinaryOpIC::DEFAULT),
+        name_(NULL) {
+    if (static_operands_type_.IsSmi()) {
+      mode_ = NO_OVERWRITE;
+    }
     use_sse3_ = CpuFeatures::IsSupported(SSE3);
     ASSERT(OpBits::is_valid(Token::NUM_TOKENS));
   }
 
+  GenericBinaryOpStub(int key, BinaryOpIC::TypeInfo runtime_operands_type)
+      : op_(OpBits::decode(key)),
+        mode_(ModeBits::decode(key)),
+        flags_(FlagBits::decode(key)),
+        args_in_registers_(ArgsInRegistersBits::decode(key)),
+        args_reversed_(ArgsReversedBits::decode(key)),
+        use_sse3_(SSE3Bits::decode(key)),
+        static_operands_type_(NumberInfo::ExpandedRepresentation(
+            StaticTypeInfoBits::decode(key))),
+        runtime_operands_type_(runtime_operands_type),
+        name_(NULL) {
+  }
+
   // Generate code to call the stub with the supplied arguments. This will add
   // code at the call site to prepare arguments either in registers or on the
   // stack together with the actual call.
@@ -698,8 +746,14 @@ class GenericBinaryOpStub: public CodeStub {
   bool args_in_registers_;  // Arguments passed in registers not on the stack.
   bool args_reversed_;  // Left and right argument are swapped.
   bool use_sse3_;
+
+  // Number type information of operands, determined by code generator.
+  NumberInfo static_operands_type_;
+
+  // Operand type information determined at runtime.
+  BinaryOpIC::TypeInfo runtime_operands_type_;
+
   char* name_;
-  NumberInfo::Type operands_type_;  // Number type information of operands.
 
   const char* GetName();
 
@@ -713,29 +767,32 @@ class GenericBinaryOpStub: public CodeStub {
            static_cast<int>(flags_),
            static_cast<int>(args_in_registers_),
            static_cast<int>(args_reversed_),
-           NumberInfo::ToString(operands_type_));
+           static_operands_type_.ToString());
   }
 #endif
 
-  // Minor key encoding in 16 bits NNNFRASOOOOOOOMM.
+  // Minor key encoding in 18 bits RRNNNFRASOOOOOOOMM.
   class ModeBits: public BitField<OverwriteMode, 0, 2> {};
   class OpBits: public BitField<Token::Value, 2, 7> {};
   class SSE3Bits: public BitField<bool, 9, 1> {};
   class ArgsInRegistersBits: public BitField<bool, 10, 1> {};
   class ArgsReversedBits: public BitField<bool, 11, 1> {};
   class FlagBits: public BitField<GenericBinaryFlags, 12, 1> {};
-  class NumberInfoBits: public BitField<NumberInfo::Type, 13, 3> {};
+  class StaticTypeInfoBits: public BitField<int, 13, 3> {};
+  class RuntimeTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 16, 2> {};
 
   Major MajorKey() { return GenericBinaryOp; }
   int MinorKey() {
-    // Encode the parameters in a unique 16 bit value.
+    // Encode the parameters in a unique 18 bit value.
     return OpBits::encode(op_)
            | ModeBits::encode(mode_)
            | FlagBits::encode(flags_)
            | SSE3Bits::encode(use_sse3_)
            | ArgsInRegistersBits::encode(args_in_registers_)
            | ArgsReversedBits::encode(args_reversed_)
-           | NumberInfoBits::encode(operands_type_);
+           | StaticTypeInfoBits::encode(
+                 static_operands_type_.ThreeBitRepresentation())
+           | RuntimeTypeInfoBits::encode(runtime_operands_type_);
   }
 
   void Generate(MacroAssembler* masm);
@@ -743,6 +800,8 @@ class GenericBinaryOpStub: public CodeStub {
   void GenerateLoadArguments(MacroAssembler* masm);
   void GenerateReturn(MacroAssembler* masm);
   void GenerateHeapResultAllocation(MacroAssembler* masm, Label* alloc_failure);
+  void GenerateRegisterArgsPush(MacroAssembler* masm);
+  void GenerateTypeTransition(MacroAssembler* masm);
 
   bool ArgsInRegistersSupported() {
     return op_ == Token::ADD || op_ == Token::SUB
@@ -757,6 +816,22 @@ class GenericBinaryOpStub: public CodeStub {
   bool HasSmiCodeInStub() { return (flags_ & NO_SMI_CODE_IN_STUB) == 0; }
   bool HasArgsInRegisters() { return args_in_registers_; }
   bool HasArgsReversed() { return args_reversed_; }
+
+  bool ShouldGenerateSmiCode() {
+    return HasSmiCodeInStub() &&
+        runtime_operands_type_ != BinaryOpIC::HEAP_NUMBERS &&
+        runtime_operands_type_ != BinaryOpIC::STRINGS;
+  }
+
+  bool ShouldGenerateFPCode() {
+    return runtime_operands_type_ != BinaryOpIC::STRINGS;
+  }
+
+  virtual int GetCodeKind() { return Code::BINARY_OP_IC; }
+
+  virtual InlineCacheState GetICState() {
+    return BinaryOpIC::ToState(runtime_operands_type_);
+  }
 };
 
 
index a9e2626..5d18a03 100644 (file)
@@ -146,9 +146,10 @@ void Debug::GenerateStoreICDebugBreak(MacroAssembler* masm) {
 void Debug::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) {
   // Register state for keyed IC load call (from ic-ia32.cc).
   // ----------- S t a t e -------------
-  //  No registers used on entry.
+  //  -- edx    : receiver
+  //  -- eax    : key
   // -----------------------------------
-  Generate_DebugBreakCallHelper(masm, 0, false);
+  Generate_DebugBreakCallHelper(masm, eax.bit() | edx.bit(), false);
 }
 
 
@@ -156,10 +157,12 @@ void Debug::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) {
   // Register state for keyed IC load call (from ic-ia32.cc).
   // ----------- S t a t e -------------
   //  -- eax    : value
+  //  -- ecx    : key
+  //  -- edx    : receiver
   // -----------------------------------
   // Register eax contains an object that needs to be pushed on the
   // expression stack of the fake JS frame.
-  Generate_DebugBreakCallHelper(masm, eax.bit(), false);
+  Generate_DebugBreakCallHelper(masm, eax.bit() | ecx.bit() | edx.bit(), false);
 }
 
 
index a3b7016..0d85b10 100644 (file)
@@ -89,6 +89,7 @@ static ByteMnemonic zero_operands_instr[] = {
   {0x9E, "sahf", UNSET_OP_ORDER},
   {0x99, "cdq", UNSET_OP_ORDER},
   {0x9B, "fwait", UNSET_OP_ORDER},
+  {0xFC, "cld", UNSET_OP_ORDER},
   {-1, "", UNSET_OP_ORDER}
 };
 
@@ -679,6 +680,7 @@ int DisassemblerIA32::MemoryFPUInstruction(int escape_opcode,
 
     case 0xDD: switch (regop) {
         case 0: mnem = "fld_d"; break;
+        case 2: mnem = "fstp"; break;
         case 3: mnem = "fstp_d"; break;
         default: UnimplementedInstruction();
       }
@@ -720,6 +722,7 @@ int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode,
             case 0xE1: mnem = "fabs"; break;
             case 0xE4: mnem = "ftst"; break;
             case 0xE8: mnem = "fld1"; break;
+            case 0xEB: mnem = "fldpi"; break;
             case 0xEE: mnem = "fldz"; break;
             case 0xF5: mnem = "fprem1"; break;
             case 0xF7: mnem = "fincstp"; break;
@@ -1053,7 +1056,20 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
           AppendToBuffer(",%s", NameOfCPURegister(regop));
         } else if (*data == 0x0F) {
           data++;
-          if (*data == 0x2F) {
+          if (*data == 0x38) {
+            data++;
+            if (*data == 0x17) {
+              data++;
+              int mod, regop, rm;
+              get_modrm(*data, &mod, &regop, &rm);
+              AppendToBuffer("ptest %s,%s",
+                             NameOfXMMRegister(regop),
+                             NameOfXMMRegister(rm));
+              data++;
+            } else {
+              UnimplementedInstruction();
+            }
+          } else if (*data == 0x2F) {
             data++;
             int mod, regop, rm;
             get_modrm(*data, &mod, &regop, &rm);
@@ -1069,6 +1085,12 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
                            NameOfXMMRegister(regop),
                            NameOfXMMRegister(rm));
             data++;
+          } else if (*data == 0x6E) {
+            data++;
+            int mod, regop, rm;
+            get_modrm(*data, &mod, &regop, &rm);
+            AppendToBuffer("movd %s,", NameOfXMMRegister(regop));
+            data += PrintRightOperand(data);
           } else if (*data == 0x6F) {
             data++;
             int mod, regop, rm;
@@ -1082,6 +1104,14 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
             get_modrm(*data, &mod, &regop, &rm);
             data += PrintRightOperand(data);
             AppendToBuffer(",%s", NameOfXMMRegister(regop));
+          } else if (*data == 0xEF) {
+             data++;
+             int mod, regop, rm;
+             get_modrm(*data, &mod, &regop, &rm);
+             AppendToBuffer("pxor %s,%s",
+                            NameOfXMMRegister(regop),
+                            NameOfXMMRegister(rm));
+             data++;
           } else {
             UnimplementedInstruction();
           }
@@ -1168,6 +1198,7 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
             const char* mnem = "?";
             switch (b2) {
               case 0x2A: mnem = "cvtsi2sd"; break;
+              case 0x51: mnem = "sqrtsd"; break;
               case 0x58: mnem = "addsd"; break;
               case 0x59: mnem = "mulsd"; break;
               case 0x5C: mnem = "subsd"; break;
@@ -1197,6 +1228,14 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
           if (*(data+2) == 0x2C) {
             data += 3;
             data += PrintOperands("cvttss2si", REG_OPER_OP_ORDER, data);
+          } else  if (*(data+2) == 0x5A) {
+            data += 3;
+            int mod, regop, rm;
+            get_modrm(*data, &mod, &regop, &rm);
+            AppendToBuffer("cvtss2sd %s,%s",
+                           NameOfXMMRegister(regop),
+                           NameOfXMMRegister(rm));
+            data++;
           } else  if (*(data+2) == 0x6F) {
             data += 3;
             int mod, regop, rm;
@@ -1216,6 +1255,9 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
         } else if (*(data+1) == 0xA5) {
           data += 2;
           AppendToBuffer("rep_movs");
+        } else if (*(data+1) == 0xAB) {
+          data += 2;
+          AppendToBuffer("rep_stos");
         } else {
           UnimplementedInstruction();
         }
index f1c2507..4dcf232 100644 (file)
@@ -621,6 +621,7 @@ void FastCodeGenerator::EmitBitOr() {
 void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
   ASSERT(info_ == NULL);
   info_ = compilation_info;
+  Comment cmnt(masm_, "[ function compiled by fast code generator");
 
   // Save the caller's frame pointer and set up our own.
   Comment prologue_cmnt(masm(), ";; Prologue");
index e42fcc8..6e3ae10 100644 (file)
@@ -56,6 +56,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info, Mode mode) {
   ASSERT(info_ == NULL);
   info_ = info;
   SetFunctionPosition(function());
+  Comment cmnt(masm_, "[ function compiled by full code generator");
 
   if (mode == PRIMARY) {
     __ push(ebp);  // Caller's frame pointer.
@@ -741,23 +742,22 @@ void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
       // We are declaring a function or constant that rewrites to a
       // property.  Use (keyed) IC to set the initial value.
       VisitForValue(prop->obj(), kStack);
-      VisitForValue(prop->key(), kStack);
-
       if (decl->fun() != NULL) {
+        VisitForValue(prop->key(), kStack);
         VisitForValue(decl->fun(), kAccumulator);
+        __ pop(ecx);
       } else {
+        VisitForValue(prop->key(), kAccumulator);
+        __ mov(ecx, result_register());
         __ mov(result_register(), Factory::the_hole_value());
       }
+      __ pop(edx);
 
       Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
       __ call(ic, RelocInfo::CODE_TARGET);
       // Absence of a test eax instruction following the call
       // indicates that none of the load was inlined.
       __ nop();
-
-      // Value in eax is ignored (declarations are statements).  Receiver
-      // and key on stack are discarded.
-      __ Drop(2);
     }
   }
 }
@@ -1130,7 +1130,8 @@ void FullCodeGenerator::EmitBinaryOp(Token::Value op,
   __ push(result_register());
   GenericBinaryOpStub stub(op,
                            NO_OVERWRITE,
-                           NO_GENERIC_BINARY_FLAGS);
+                           NO_GENERIC_BINARY_FLAGS,
+                           NumberInfo::Unknown());
   __ CallStub(&stub);
   Apply(context, eax);
 }
@@ -1251,6 +1252,12 @@ void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
     __ pop(result_register());
   }
 
+  __ pop(ecx);
+  if (expr->ends_initialization_block()) {
+    __ mov(edx, Operand(esp, 0));  // Leave receiver on the stack for later.
+  } else {
+    __ pop(edx);
+  }
   // Record source code position before IC call.
   SetSourcePosition(expr->position());
   Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
@@ -1261,15 +1268,14 @@ void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
 
   // If the assignment ends an initialization block, revert to fast case.
   if (expr->ends_initialization_block()) {
+    __ pop(edx);
     __ push(eax);  // Result of assignment, saved even if not needed.
-    // Receiver is under the key and value.
-    __ push(Operand(esp, 2 * kPointerSize));
+    __ push(edx);
     __ CallRuntime(Runtime::kToFastProperties, 1);
     __ pop(eax);
   }
 
-  // Receiver and key are still on stack.
-  DropAndApply(2, context_, eax);
+  Apply(context_, eax);
 }
 
 
@@ -1739,7 +1745,8 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
   // Call stub for +1/-1.
   GenericBinaryOpStub stub(expr->binary_op(),
                            NO_OVERWRITE,
-                           NO_GENERIC_BINARY_FLAGS);
+                           NO_GENERIC_BINARY_FLAGS,
+                           NumberInfo::Unknown());
   stub.GenerateCall(masm(), eax, Smi::FromInt(1));
   __ bind(&done);
 
@@ -1777,18 +1784,20 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
       break;
     }
     case KEYED_PROPERTY: {
+      __ pop(ecx);
+      __ pop(edx);
       Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
       __ call(ic, RelocInfo::CODE_TARGET);
       // This nop signals to the IC that there is no inlined code at the call
       // site for it to patch.
       __ nop();
       if (expr->is_postfix()) {
-        __ Drop(2);  // Result is on the stack under the key and the receiver.
+        // Result is on the stack
         if (context_ != Expression::kEffect) {
           ApplyTOS(context_);
         }
       } else {
-        DropAndApply(2, context_, eax);
+        Apply(context_, eax);
       }
       break;
     }
index fcc8271..555cd1b 100644 (file)
@@ -610,8 +610,9 @@ void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
   __ push(ecx);  // return address
 
   // Perform tail call to the entry.
-  __ TailCallRuntime(ExternalReference(
-        IC_Utility(kKeyedLoadPropertyWithInterceptor)), 2, 1);
+  ExternalReference ref = ExternalReference(
+      IC_Utility(kKeyedLoadPropertyWithInterceptor));
+  __ TailCallExternalReference(ref, 2, 1);
 
   __ bind(&slow);
   GenerateMiss(masm);
@@ -621,54 +622,41 @@ void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
 void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
   // ----------- S t a t e -------------
   //  -- eax    : value
+  //  -- ecx    : key
+  //  -- edx    : receiver
   //  -- esp[0] : return address
-  //  -- esp[4] : key
-  //  -- esp[8] : receiver
   // -----------------------------------
   Label slow, fast, array, extra, check_pixel_array;
 
-  // Get the receiver from the stack.
-  __ mov(edx, Operand(esp, 2 * kPointerSize));  // 2 ~ return address, key
   // Check that the object isn't a smi.
   __ test(edx, Immediate(kSmiTagMask));
   __ j(zero, &slow, not_taken);
   // Get the map from the receiver.
-  __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
+  __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
   // Check that the receiver does not require access checks.  We need
   // to do this because this generic stub does not perform map checks.
-  __ movzx_b(ebx, FieldOperand(ecx, Map::kBitFieldOffset));
+  __ movzx_b(ebx, FieldOperand(edi, Map::kBitFieldOffset));
   __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
   __ j(not_zero, &slow, not_taken);
-  // Get the key from the stack.
-  __ mov(ebx, Operand(esp, 1 * kPointerSize));  // 1 ~ return address
   // Check that the key is a smi.
-  __ test(ebx, Immediate(kSmiTagMask));
+  __ test(ecx, Immediate(kSmiTagMask));
   __ j(not_zero, &slow, not_taken);
-  // Get the instance type from the map of the receiver.
-  __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
-  // Check if the object is a JS array or not.
-  __ cmp(ecx, JS_ARRAY_TYPE);
+  __ CmpInstanceType(edi, JS_ARRAY_TYPE);
   __ j(equal, &array);
   // Check that the object is some kind of JS object.
-  __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
-  __ j(less, &slow, not_taken);
+  __ CmpInstanceType(edi, FIRST_JS_OBJECT_TYPE);
+  __ j(below, &slow, not_taken);
 
   // Object case: Check key against length in the elements array.
   // eax: value
   // edx: JSObject
-  // ebx: index (as a smi)
-  __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
+  // ecx: key (a smi)
+  __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
   // Check that the object is in fast mode (not dictionary).
-  __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
-         Immediate(Factory::fixed_array_map()));
-  __ j(not_equal, &check_pixel_array, not_taken);
-  // Untag the key (for checking against untagged length in the fixed array).
-  __ mov(edx, Operand(ebx));
-  __ sar(edx, kSmiTagSize);  // untag the index and use it for the comparison
-  __ cmp(edx, FieldOperand(ecx, Array::kLengthOffset));
-  // eax: value
-  // ecx: FixedArray
-  // ebx: index (as a smi)
+  __ CheckMap(edi, Factory::fixed_array_map(), &check_pixel_array, true);
+  __ mov(ebx, Operand(ecx));
+  __ SmiUntag(ebx);
+  __ cmp(ebx, FieldOperand(edi, Array::kLengthOffset));
   __ j(below, &fast, taken);
 
   // Slow case: call runtime.
@@ -676,52 +664,51 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
   GenerateRuntimeSetProperty(masm);
 
   // Check whether the elements is a pixel array.
-  // eax: value
-  // ecx: elements array
-  // ebx: index (as a smi)
   __ bind(&check_pixel_array);
-  __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
-         Immediate(Factory::pixel_array_map()));
-  __ j(not_equal, &slow);
+  // eax: value
+  // ecx: key
+  // edx: receiver
+  // edi: elements array
+  __ CheckMap(edi, Factory::pixel_array_map(), &slow, true);
   // Check that the value is a smi. If a conversion is needed call into the
   // runtime to convert and clamp.
   __ test(eax, Immediate(kSmiTagMask));
   __ j(not_zero, &slow);
-  __ sar(ebx, kSmiTagSize);  // Untag the index.
-  __ cmp(ebx, FieldOperand(ecx, PixelArray::kLengthOffset));
+  __ mov(ebx, ecx);
+  __ SmiUntag(ebx);
+  __ cmp(ebx, FieldOperand(edi, PixelArray::kLengthOffset));
   __ j(above_equal, &slow);
-  __ mov(edx, eax);  // Save the value.
-  __ sar(eax, kSmiTagSize);  // Untag the value.
+  __ mov(ecx, eax);  // Save the value. Key is not longer needed.
+  __ SmiUntag(ecx);
   {  // Clamp the value to [0..255].
     Label done;
-    __ test(eax, Immediate(0xFFFFFF00));
+    __ test(ecx, Immediate(0xFFFFFF00));
     __ j(zero, &done);
-    __ setcc(negative, eax);  // 1 if negative, 0 if positive.
-    __ dec_b(eax);  // 0 if negative, 255 if positive.
+    __ setcc(negative, ecx);  // 1 if negative, 0 if positive.
+    __ dec_b(ecx);  // 0 if negative, 255 if positive.
     __ bind(&done);
   }
-  __ mov(ecx, FieldOperand(ecx, PixelArray::kExternalPointerOffset));
-  __ mov_b(Operand(ecx, ebx, times_1, 0), eax);
-  __ mov(eax, edx);  // Return the original value.
-  __ ret(0);
+  __ mov(edi, FieldOperand(edi, PixelArray::kExternalPointerOffset));
+  __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
+  __ ret(0);  // Return value in eax.
 
   // Extra capacity case: Check if there is extra capacity to
   // perform the store and update the length. Used for adding one
   // element to the array by writing to array[array.length].
   __ bind(&extra);
   // eax: value
-  // edx: JSArray
-  // ecx: FixedArray
-  // ebx: index (as a smi)
-  // flags: compare (ebx, edx.length())
+  // edx: receiver, a JSArray
+  // ecx: key, a smi.
+  // edi: receiver->elements, a FixedArray
+  // flags: compare (ecx, edx.length())
   __ j(not_equal, &slow, not_taken);  // do not leave holes in the array
-  __ sar(ebx, kSmiTagSize);  // untag
-  __ cmp(ebx, FieldOperand(ecx, Array::kLengthOffset));
+  __ mov(ebx, ecx);
+  __ SmiUntag(ebx);  // untag
+  __ cmp(ebx, FieldOperand(edi, Array::kLengthOffset));
   __ j(above_equal, &slow, not_taken);
-  // Restore tag and increment.
-  __ lea(ebx, Operand(ebx, times_2, 1 << kSmiTagSize));
-  __ mov(FieldOperand(edx, JSArray::kLengthOffset), ebx);
-  __ sub(Operand(ebx), Immediate(1 << kSmiTagSize));  // decrement ebx again
+  // Add 1 to receiver->length, and go to fast array write.
+  __ add(FieldOperand(edx, JSArray::kLengthOffset),
+         Immediate(1 << kSmiTagSize));
   __ jmp(&fast);
 
   // Array case: Get the length and the elements array from the JS
@@ -729,28 +716,26 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
   // length is always a smi.
   __ bind(&array);
   // eax: value
-  // edx: JSArray
-  // ebx: index (as a smi)
-  __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
-  __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
-         Immediate(Factory::fixed_array_map()));
-  __ j(not_equal, &check_pixel_array);
+  // edx: receiver, a JSArray
+  // ecx: key, a smi.
+  __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
+  __ CheckMap(edi, Factory::fixed_array_map(), &check_pixel_array, true);
 
   // Check the key against the length in the array, compute the
   // address to store into and fall through to fast case.
-  __ cmp(ebx, FieldOperand(edx, JSArray::kLengthOffset));
+  __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset));  // Compare smis.
   __ j(above_equal, &extra, not_taken);
 
   // Fast case: Do the store.
   __ bind(&fast);
   // eax: value
-  // ecx: FixedArray
-  // ebx: index (as a smi)
-  __ mov(Operand(ecx, ebx, times_2, FixedArray::kHeaderSize - kHeapObjectTag),
-         eax);
+  // ecx: key (a smi)
+  // edx: receiver
+  // edi: FixedArray receiver->elements
+  __ mov(FieldOperand(edi, ecx, times_2, FixedArray::kHeaderSize), eax);
   // Update write barrier for the elements array address.
   __ mov(edx, Operand(eax));
-  __ RecordWrite(ecx, 0, edx, ebx);
+  __ RecordWrite(edi, 0, edx, ecx);
   __ ret(0);
 }
 
@@ -759,92 +744,91 @@ void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm,
                                          ExternalArrayType array_type) {
   // ----------- S t a t e -------------
   //  -- eax    : value
+  //  -- ecx    : key
+  //  -- edx    : receiver
   //  -- esp[0] : return address
-  //  -- esp[4] : key
-  //  -- esp[8] : receiver
   // -----------------------------------
   Label slow, check_heap_number;
 
-  // Get the receiver from the stack.
-  __ mov(edx, Operand(esp, 2 * kPointerSize));
   // Check that the object isn't a smi.
   __ test(edx, Immediate(kSmiTagMask));
   __ j(zero, &slow);
   // Get the map from the receiver.
-  __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
+  __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
   // Check that the receiver does not require access checks.  We need
   // to do this because this generic stub does not perform map checks.
-  __ movzx_b(ebx, FieldOperand(ecx, Map::kBitFieldOffset));
+  __ movzx_b(ebx, FieldOperand(edi, Map::kBitFieldOffset));
   __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
   __ j(not_zero, &slow);
-  // Get the key from the stack.
-  __ mov(ebx, Operand(esp, 1 * kPointerSize));  // 1 ~ return address
   // Check that the key is a smi.
-  __ test(ebx, Immediate(kSmiTagMask));
+  __ test(ecx, Immediate(kSmiTagMask));
   __ j(not_zero, &slow);
   // Get the instance type from the map of the receiver.
-  __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
-  // Check that the object is a JS object.
-  __ cmp(ecx, JS_OBJECT_TYPE);
+  __ CmpInstanceType(edi, JS_OBJECT_TYPE);
   __ j(not_equal, &slow);
 
   // Check that the elements array is the appropriate type of
   // ExternalArray.
   // eax: value
-  // edx: JSObject
-  // ebx: index (as a smi)
-  __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
-  Handle<Map> map(Heap::MapForExternalArrayType(array_type));
-  __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
-         Immediate(map));
-  __ j(not_equal, &slow);
+  // edx: receiver, a JSObject
+  // ecx: key, a smi
+  __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
+  __ CheckMap(edi, Handle<Map>(Heap::MapForExternalArrayType(array_type)),
+              &slow, true);
 
   // Check that the index is in range.
-  __ sar(ebx, kSmiTagSize);  // Untag the index.
-  __ cmp(ebx, FieldOperand(ecx, ExternalArray::kLengthOffset));
+  __ mov(ebx, ecx);
+  __ SmiUntag(ebx);
+  __ cmp(ebx, FieldOperand(edi, ExternalArray::kLengthOffset));
   // Unsigned comparison catches both negative and too-large values.
   __ j(above_equal, &slow);
 
   // Handle both smis and HeapNumbers in the fast path. Go to the
   // runtime for all other kinds of values.
   // eax: value
-  // ecx: elements array
+  // edx: receiver
+  // ecx: key
+  // edi: elements array
   // ebx: untagged index
   __ test(eax, Immediate(kSmiTagMask));
   __ j(not_equal, &check_heap_number);
   // smi case
-  __ mov(edx, eax);  // Save the value.
-  __ sar(eax, kSmiTagSize);  // Untag the value.
-  __ mov(ecx, FieldOperand(ecx, ExternalArray::kExternalPointerOffset));
+  __ mov(ecx, eax);  // Preserve the value in eax.  Key is no longer needed.
+  __ SmiUntag(ecx);
+  __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
   // ecx: base pointer of external storage
   switch (array_type) {
     case kExternalByteArray:
     case kExternalUnsignedByteArray:
-      __ mov_b(Operand(ecx, ebx, times_1, 0), eax);
+      __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
       break;
     case kExternalShortArray:
     case kExternalUnsignedShortArray:
-      __ mov_w(Operand(ecx, ebx, times_2, 0), eax);
+      __ mov_w(Operand(edi, ebx, times_2, 0), ecx);
       break;
     case kExternalIntArray:
     case kExternalUnsignedIntArray:
-      __ mov(Operand(ecx, ebx, times_4, 0), eax);
+      __ mov(Operand(edi, ebx, times_4, 0), ecx);
       break;
     case kExternalFloatArray:
       // Need to perform int-to-float conversion.
-      __ push(eax);
+      __ push(ecx);
       __ fild_s(Operand(esp, 0));
-      __ pop(eax);
-      __ fstp_s(Operand(ecx, ebx, times_4, 0));
+      __ pop(ecx);
+      __ fstp_s(Operand(edi, ebx, times_4, 0));
       break;
     default:
       UNREACHABLE();
       break;
   }
-  __ mov(eax, edx);  // Return the original value.
-  __ ret(0);
+  __ ret(0);  // Return the original value.
 
   __ bind(&check_heap_number);
+  // eax: value
+  // edx: receiver
+  // ecx: key
+  // edi: elements array
+  // ebx: untagged index
   __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
          Immediate(Factory::heap_number_map()));
   __ j(not_equal, &slow);
@@ -853,14 +837,12 @@ void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm,
   // +/-Infinity into integer arrays basically undefined. For more
   // reproducible behavior, convert these to zero.
   __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
-  __ mov(edx, eax);  // Save the value.
-  __ mov(ecx, FieldOperand(ecx, ExternalArray::kExternalPointerOffset));
+  __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
   // ebx: untagged index
-  // ecx: base pointer of external storage
+  // edi: base pointer of external storage
   // top of FPU stack: value
   if (array_type == kExternalFloatArray) {
-    __ fstp_s(Operand(ecx, ebx, times_4, 0));
-    __ mov(eax, edx);  // Return the original value.
+    __ fstp_s(Operand(edi, ebx, times_4, 0));
     __ ret(0);
   } else {
     // Need to perform float-to-int conversion.
@@ -870,29 +852,27 @@ void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm,
     __ j(parity_even, &is_nan);
 
     if (array_type != kExternalUnsignedIntArray) {
-      __ push(eax);  // Make room on stack
+      __ push(ecx);  // Make room on stack
       __ fistp_s(Operand(esp, 0));
-      __ pop(eax);
+      __ pop(ecx);
     } else {
       // fistp stores values as signed integers.
       // To represent the entire range, we need to store as a 64-bit
       // int and discard the high 32 bits.
-      __ push(eax);  // Make room on stack
-      __ push(eax);  // Make room on stack
+      __ sub(Operand(esp), Immediate(2 * kPointerSize));
       __ fistp_d(Operand(esp, 0));
-      __ pop(eax);
-      __ mov(Operand(esp, 0), eax);
-      __ pop(eax);
+      __ pop(ecx);
+      __ add(Operand(esp), Immediate(kPointerSize));
     }
-    // eax: untagged integer value
+    // ecx: untagged integer value
     switch (array_type) {
       case kExternalByteArray:
       case kExternalUnsignedByteArray:
-        __ mov_b(Operand(ecx, ebx, times_1, 0), eax);
+        __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
         break;
       case kExternalShortArray:
       case kExternalUnsignedShortArray:
-        __ mov_w(Operand(ecx, ebx, times_2, 0), eax);
+        __ mov_w(Operand(edi, ebx, times_2, 0), ecx);
         break;
       case kExternalIntArray:
       case kExternalUnsignedIntArray: {
@@ -903,21 +883,20 @@ void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm,
         // This test would apparently detect both NaN and Infinity,
         // but we've already checked for NaN using the FPU hardware
         // above.
-        __ mov_w(edi, FieldOperand(edx, HeapNumber::kValueOffset + 6));
-        __ and_(edi, 0x7FF0);
-        __ cmp(edi, 0x7FF0);
+        __ mov_w(edx, FieldOperand(eax, HeapNumber::kValueOffset + 6));
+        __ and_(edx, 0x7FF0);
+        __ cmp(edx, 0x7FF0);
         __ j(not_equal, &not_infinity);
-        __ mov(eax, 0);
+        __ mov(ecx, 0);
         __ bind(&not_infinity);
-        __ mov(Operand(ecx, ebx, times_4, 0), eax);
+        __ mov(Operand(edi, ebx, times_4, 0), ecx);
         break;
       }
       default:
         UNREACHABLE();
         break;
     }
-    __ mov(eax, edx);  // Return the original value.
-    __ ret(0);
+    __ ret(0);  // Return original value.
 
     __ bind(&is_nan);
     __ ffree();
@@ -925,23 +904,22 @@ void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm,
     switch (array_type) {
       case kExternalByteArray:
       case kExternalUnsignedByteArray:
-        __ mov_b(Operand(ecx, ebx, times_1, 0), 0);
+        __ mov_b(Operand(edi, ebx, times_1, 0), 0);
         break;
       case kExternalShortArray:
       case kExternalUnsignedShortArray:
-        __ mov(eax, 0);
-        __ mov_w(Operand(ecx, ebx, times_2, 0), eax);
+        __ xor_(ecx, Operand(ecx));
+        __ mov_w(Operand(edi, ebx, times_2, 0), ecx);
         break;
       case kExternalIntArray:
       case kExternalUnsignedIntArray:
-        __ mov(Operand(ecx, ebx, times_4, 0), Immediate(0));
+        __ mov(Operand(edi, ebx, times_4, 0), Immediate(0));
         break;
       default:
         UNREACHABLE();
         break;
     }
-    __ mov(eax, edx);  // Return the original value.
-    __ ret(0);
+    __ ret(0);  // Return the original value.
   }
 
   // Slow case: call runtime.
@@ -1262,7 +1240,8 @@ void LoadIC::GenerateMiss(MacroAssembler* masm) {
   __ push(ebx);  // return address
 
   // Perform tail call to the entry.
-  __ TailCallRuntime(ExternalReference(IC_Utility(kLoadIC_Miss)), 2, 1);
+  ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss));
+  __ TailCallExternalReference(ref, 2, 1);
 }
 
 
@@ -1377,7 +1356,8 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
   __ push(ebx);  // return address
 
   // Perform tail call to the entry.
-  __ TailCallRuntime(ExternalReference(IC_Utility(kKeyedLoadIC_Miss)), 2, 1);
+  ExternalReference ref = ExternalReference(IC_Utility(kKeyedLoadIC_Miss));
+  __ TailCallExternalReference(ref, 2, 1);
 }
 
 
@@ -1394,7 +1374,7 @@ void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
   __ push(ebx);  // return address
 
   // Perform tail call to the entry.
-  __ TailCallRuntime(ExternalReference(Runtime::kKeyedGetProperty), 2, 1);
+  __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
 }
 
 
@@ -1431,7 +1411,8 @@ void StoreIC::GenerateMiss(MacroAssembler* masm) {
   __ push(ebx);
 
   // Perform tail call to the entry.
-  __ TailCallRuntime(ExternalReference(IC_Utility(kStoreIC_Miss)), 3, 1);
+  ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_Miss));
+  __ TailCallExternalReference(ref, 3, 1);
 }
 
 
@@ -1478,7 +1459,8 @@ void StoreIC::GenerateArrayLength(MacroAssembler* masm) {
   __ push(value);
   __ push(scratch);  // return address
 
-  __ TailCallRuntime(ExternalReference(IC_Utility(kStoreIC_ArrayLength)), 2, 1);
+  ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_ArrayLength));
+  __ TailCallExternalReference(ref, 2, 1);
 
   __ bind(&miss);
 
@@ -1492,38 +1474,39 @@ Object* KeyedStoreIC_Miss(Arguments args);
 void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm) {
   // ----------- S t a t e -------------
   //  -- eax    : value
+  //  -- ecx    : key
+  //  -- edx    : receiver
   //  -- esp[0] : return address
-  //  -- esp[4] : key
-  //  -- esp[8] : receiver
   // -----------------------------------
 
-  __ pop(ecx);
-  __ push(Operand(esp, 1 * kPointerSize));
-  __ push(Operand(esp, 1 * kPointerSize));
-  __ push(eax);
+  __ pop(ebx);
+  __ push(edx);
   __ push(ecx);
+  __ push(eax);
+  __ push(ebx);
 
   // Do tail-call to runtime routine.
-  __ TailCallRuntime(ExternalReference(Runtime::kSetProperty), 3, 1);
+  __ TailCallRuntime(Runtime::kSetProperty, 3, 1);
 }
 
 
 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
   // ----------- S t a t e -------------
   //  -- eax    : value
+  //  -- ecx    : key
+  //  -- edx    : receiver
   //  -- esp[0] : return address
-  //  -- esp[4] : key
-  //  -- esp[8] : receiver
   // -----------------------------------
 
-  __ pop(ecx);
-  __ push(Operand(esp, 1 * kPointerSize));
-  __ push(Operand(esp, 1 * kPointerSize));
-  __ push(eax);
+  __ pop(ebx);
+  __ push(edx);
   __ push(ecx);
+  __ push(eax);
+  __ push(ebx);
 
   // Do tail-call to runtime routine.
-  __ TailCallRuntime(ExternalReference(IC_Utility(kKeyedStoreIC_Miss)), 3, 1);
+  ExternalReference ref = ExternalReference(IC_Utility(kKeyedStoreIC_Miss));
+  __ TailCallExternalReference(ref, 3, 1);
 }
 
 #undef __
index 5ae3fe2..45e24fa 100644 (file)
@@ -164,7 +164,10 @@ void MacroAssembler::RecordWrite(Register object, int offset,
   if (Serializer::enabled()) {
     // Can't do arithmetic on external references if it might get serialized.
     mov(value, Operand(object));
-    and_(value, Heap::NewSpaceMask());
+    // The mask isn't really an address.  We load it as an external reference in
+    // case the size of the new space is different between the snapshot maker
+    // and the running system.
+    and_(Operand(value), Immediate(ExternalReference::new_space_mask()));
     cmp(Operand(value), Immediate(ExternalReference::new_space_start()));
     j(equal, &done);
   } else {
@@ -1186,15 +1189,22 @@ Object* MacroAssembler::TryCallRuntime(Runtime::Function* f,
 }
 
 
-void MacroAssembler::TailCallRuntime(const ExternalReference& ext,
-                                     int num_arguments,
-                                     int result_size) {
+void MacroAssembler::TailCallExternalReference(const ExternalReference& ext,
+                                               int num_arguments,
+                                               int result_size) {
   // TODO(1236192): Most runtime routines don't need the number of
   // arguments passed in because it is constant. At some point we
   // should remove this need and make the runtime routine entry code
   // smarter.
   Set(eax, Immediate(num_arguments));
-  JumpToRuntime(ext);
+  JumpToExternalReference(ext);
+}
+
+
+void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid,
+                                     int num_arguments,
+                                     int result_size) {
+  TailCallExternalReference(ExternalReference(fid), num_arguments, result_size);
 }
 
 
@@ -1264,7 +1274,7 @@ Object* MacroAssembler::TryPopHandleScope(Register saved, Register scratch) {
 }
 
 
-void MacroAssembler::JumpToRuntime(const ExternalReference& ext) {
+void MacroAssembler::JumpToExternalReference(const ExternalReference& ext) {
   // Set the entry point and jump to the C entry runtime stub.
   mov(ebx, Immediate(ext));
   CEntryStub ces(1);
@@ -1615,6 +1625,41 @@ void MacroAssembler::JumpIfNotBothSequentialAsciiStrings(Register object1,
 }
 
 
+void MacroAssembler::PrepareCallCFunction(int num_arguments, Register scratch) {
+  int frameAlignment = OS::ActivationFrameAlignment();
+  if (frameAlignment != 0) {
+    // Make stack end at alignment and make room for num_arguments words
+    // and the original value of esp.
+    mov(scratch, esp);
+    sub(Operand(esp), Immediate((num_arguments + 1) * kPointerSize));
+    ASSERT(IsPowerOf2(frameAlignment));
+    and_(esp, -frameAlignment);
+    mov(Operand(esp, num_arguments * kPointerSize), scratch);
+  } else {
+    sub(Operand(esp), Immediate(num_arguments * kPointerSize));
+  }
+}
+
+
+void MacroAssembler::CallCFunction(ExternalReference function,
+                                   int num_arguments) {
+  // Trashing eax is ok as it will be the return value.
+  mov(Operand(eax), Immediate(function));
+  CallCFunction(eax, num_arguments);
+}
+
+
+void MacroAssembler::CallCFunction(Register function,
+                                   int num_arguments) {
+  call(Operand(function));
+  if (OS::ActivationFrameAlignment() != 0) {
+    mov(esp, Operand(esp, num_arguments * kPointerSize));
+  } else {
+    add(Operand(esp), Immediate(num_arguments * sizeof(int32_t)));
+  }
+}
+
+
 CodePatcher::CodePatcher(byte* address, int size)
     : address_(address), size_(size), masm_(address, size + Assembler::kGap) {
   // Create a new macro assembler pointing to the address of the code to patch.
index 69dc54c..a284b63 100644 (file)
@@ -349,7 +349,6 @@ class MacroAssembler: public Assembler {
   void StubReturn(int argc);
 
   // Call a runtime routine.
-  // Eventually this should be used for all C calls.
   void CallRuntime(Runtime::Function* f, int num_arguments);
 
   // Call a runtime function, returning the CodeStub object called.
@@ -367,12 +366,34 @@ class MacroAssembler: public Assembler {
   Object* TryCallRuntime(Runtime::FunctionId id, int num_arguments);
 
   // Tail call of a runtime routine (jump).
-  // Like JumpToRuntime, but also takes care of passing the number
-  // of arguments.
-  void TailCallRuntime(const ExternalReference& ext,
+  // Like JumpToExternalReference, but also takes care of passing the number
+  // of parameters.
+  void TailCallExternalReference(const ExternalReference& ext,
+                                 int num_arguments,
+                                 int result_size);
+
+  // Convenience function: tail call a runtime routine (jump).
+  void TailCallRuntime(Runtime::FunctionId fid,
                        int num_arguments,
                        int result_size);
 
+  // Before calling a C-function from generated code, align arguments on stack.
+  // After aligning the frame, arguments must be stored in esp[0], esp[4],
+  // etc., not pushed. The argument count assumes all arguments are word sized.
+  // Some compilers/platforms require the stack to be aligned when calling
+  // C++ code.
+  // Needs a scratch register to do some arithmetic. This register will be
+  // trashed.
+  void PrepareCallCFunction(int num_arguments, Register scratch);
+
+  // Calls a C function and cleans up the space for arguments allocated
+  // by PrepareCallCFunction. The called function is not allowed to trigger a
+  // garbage collection, since that might move the code and invalidate the
+  // return address (unless this is somehow accounted for by the called
+  // function).
+  void CallCFunction(ExternalReference function, int num_arguments);
+  void CallCFunction(Register function, int num_arguments);
+
   void PushHandleScope(Register scratch);
 
   // Pops a handle scope using the specified scratch register and
@@ -384,7 +405,7 @@ class MacroAssembler: public Assembler {
   Object* TryPopHandleScope(Register saved, Register scratch);
 
   // Jump to a runtime routine.
-  void JumpToRuntime(const ExternalReference& ext);
+  void JumpToExternalReference(const ExternalReference& ext);
 
 
   // ---------------------------------------------------------------------------
index f6da693..74b9d12 100644 (file)
@@ -324,8 +324,8 @@ void RegExpMacroAssemblerIA32::CheckNotBackReferenceIgnoreCase(
     __ push(backtrack_stackpointer());
     __ push(ebx);
 
-    const int argument_count = 3;
-    FrameAlign(argument_count, ecx);
+    static const int argument_count = 3;
+    __ PrepareCallCFunction(argument_count, ecx);
     // Put arguments into allocated stack area, last argument highest on stack.
     // Parameters are
     //   Address byte_offset1 - Address captured substring's start.
@@ -346,7 +346,7 @@ void RegExpMacroAssemblerIA32::CheckNotBackReferenceIgnoreCase(
 
     ExternalReference compare =
         ExternalReference::re_case_insensitive_compare_uc16();
-    CallCFunction(compare, argument_count);
+    __ CallCFunction(compare, argument_count);
     // Pop original values before reacting on result value.
     __ pop(ebx);
     __ pop(backtrack_stackpointer());
@@ -784,13 +784,13 @@ Handle<Object> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
     __ push(edi);
 
     // Call GrowStack(backtrack_stackpointer())
-    int num_arguments = 2;
-    FrameAlign(num_arguments, ebx);
+    static const int num_arguments = 2;
+    __ PrepareCallCFunction(num_arguments, ebx);
     __ lea(eax, Operand(ebp, kStackHighEnd));
     __ mov(Operand(esp, 1 * kPointerSize), eax);
     __ mov(Operand(esp, 0 * kPointerSize), backtrack_stackpointer());
     ExternalReference grow_stack = ExternalReference::re_grow_stack();
-    CallCFunction(grow_stack, num_arguments);
+    __ CallCFunction(grow_stack, num_arguments);
     // If return NULL, we have failed to grow the stack, and
     // must exit with a stack-overflow exception.
     __ or_(eax, Operand(eax));
@@ -951,8 +951,8 @@ void RegExpMacroAssemblerIA32::WriteStackPointerToRegister(int reg) {
 // Private methods:
 
 void RegExpMacroAssemblerIA32::CallCheckStackGuardState(Register scratch) {
-  int num_arguments = 3;
-  FrameAlign(num_arguments, scratch);
+  static const int num_arguments = 3;
+  __ PrepareCallCFunction(num_arguments, scratch);
   // RegExp code frame pointer.
   __ mov(Operand(esp, 2 * kPointerSize), ebp);
   // Code* of self.
@@ -962,7 +962,7 @@ void RegExpMacroAssemblerIA32::CallCheckStackGuardState(Register scratch) {
   __ mov(Operand(esp, 0 * kPointerSize), eax);
   ExternalReference check_stack_guard =
       ExternalReference::re_check_stack_guard_state();
-  CallCFunction(check_stack_guard, num_arguments);
+  __ CallCFunction(check_stack_guard, num_arguments);
 }
 
 
@@ -1153,37 +1153,6 @@ void RegExpMacroAssemblerIA32::CheckStackLimit() {
 }
 
 
-void RegExpMacroAssemblerIA32::FrameAlign(int num_arguments, Register scratch) {
-  // TODO(lrn): Since we no longer use the system stack arbitrarily (but we do
-  // use it, e.g., for SafeCall), we know the number of elements on the stack
-  // since the last frame alignment. We might be able to do this simpler then.
-  int frameAlignment = OS::ActivationFrameAlignment();
-  if (frameAlignment != 0) {
-    // Make stack end at alignment and make room for num_arguments words
-    // and the original value of esp.
-    __ mov(scratch, esp);
-    __ sub(Operand(esp), Immediate((num_arguments + 1) * kPointerSize));
-    ASSERT(IsPowerOf2(frameAlignment));
-    __ and_(esp, -frameAlignment);
-    __ mov(Operand(esp, num_arguments * kPointerSize), scratch);
-  } else {
-    __ sub(Operand(esp), Immediate(num_arguments * kPointerSize));
-  }
-}
-
-
-void RegExpMacroAssemblerIA32::CallCFunction(ExternalReference function,
-                                             int num_arguments) {
-  __ mov(Operand(eax), Immediate(function));
-  __ call(Operand(eax));
-  if (OS::ActivationFrameAlignment() != 0) {
-    __ mov(esp, Operand(esp, num_arguments * kPointerSize));
-  } else {
-    __ add(Operand(esp), Immediate(num_arguments * sizeof(int32_t)));
-  }
-}
-
-
 void RegExpMacroAssemblerIA32::LoadCurrentCharacterUnchecked(int cp_offset,
                                                              int characters) {
   if (mode_ == ASCII) {
index d9866b7..0d5e272 100644 (file)
@@ -187,21 +187,6 @@ class RegExpMacroAssemblerIA32: public NativeRegExpMacroAssembler {
   // (ecx) and increments it by a word size.
   inline void Pop(Register target);
 
-  // Before calling a C-function from generated code, align arguments on stack.
-  // After aligning the frame, arguments must be stored in esp[0], esp[4],
-  // etc., not pushed. The argument count assumes all arguments are word sized.
-  // Some compilers/platforms require the stack to be aligned when calling
-  // C++ code.
-  // Needs a scratch register to do some arithmetic. This register will be
-  // trashed.
-  inline void FrameAlign(int num_arguments, Register scratch);
-
-  // Calls a C function and cleans up the space for arguments allocated
-  // by FrameAlign. The called function is not allowed to trigger a garbage
-  // collection, since that might move the code and invalidate the return
-  // address (unless this is somehow accounted for).
-  inline void CallCFunction(ExternalReference function, int num_arguments);
-
   MacroAssembler* masm_;
 
   // Which mode to generate code for (ASCII or UC16).
index 20539bf..3ccfe8c 100644 (file)
@@ -49,6 +49,7 @@ void Result::ToRegister() {
                                                  Immediate(handle()));
     }
     // This result becomes a copy of the fresh one.
+    fresh.set_number_info(number_info());
     *this = fresh;
   }
   ASSERT(is_register());
index ade324b..a7e9a69 100644 (file)
@@ -446,7 +446,7 @@ class LoadInterceptorCompiler BASE_EMBEDDED {
 
       ExternalReference ref =
           ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
-      __ TailCallRuntime(ref, 5, 1);
+      __ TailCallExternalReference(ref, 5, 1);
 
       __ bind(&cleanup);
       __ pop(scratch1);
@@ -468,7 +468,7 @@ class LoadInterceptorCompiler BASE_EMBEDDED {
 
     ExternalReference ref = ExternalReference(
         IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
-    __ TailCallRuntime(ref, 5, 1);
+    __ TailCallExternalReference(ref, 5, 1);
   }
 
  private:
@@ -907,7 +907,7 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
     __ push(Immediate(Handle<Map>(transition)));
     __ push(eax);
     __ push(scratch);
-    __ TailCallRuntime(
+    __ TailCallExternalReference(
         ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage)), 3, 1);
     return;
   }
@@ -1589,7 +1589,7 @@ Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
   // Do tail-call to the runtime system.
   ExternalReference store_callback_property =
       ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
-  __ TailCallRuntime(store_callback_property, 4, 1);
+  __ TailCallExternalReference(store_callback_property, 4, 1);
 
   // Handle store cache miss.
   __ bind(&miss);
@@ -1638,7 +1638,7 @@ Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
   // Do tail-call to the runtime system.
   ExternalReference store_ic_property =
       ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
-  __ TailCallRuntime(store_ic_property, 3, 1);
+  __ TailCallExternalReference(store_ic_property, 3, 1);
 
   // Handle store cache miss.
   __ bind(&miss);
@@ -1691,23 +1691,18 @@ Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
                                                   String* name) {
   // ----------- S t a t e -------------
   //  -- eax    : value
+  //  -- ecx    : key
+  //  -- edx    : receiver
   //  -- esp[0] : return address
-  //  -- esp[4] : key
-  //  -- esp[8] : receiver
   // -----------------------------------
   Label miss;
 
   __ IncrementCounter(&Counters::keyed_store_field, 1);
 
-  // Get the name from the stack.
-  __ mov(ecx, Operand(esp, 1 * kPointerSize));
   // Check that the name has not changed.
   __ cmp(Operand(ecx), Immediate(Handle<String>(name)));
   __ j(not_equal, &miss, not_taken);
 
-  // Get the object from the stack.
-  __ mov(edx, Operand(esp, 2 * kPointerSize));
-
   // Generate store field code.  Trashes the name register.
   GenerateStoreField(masm(),
                      object,
index 75ff670..7b03a5b 100644 (file)
@@ -37,23 +37,6 @@ namespace internal {
 
 #define __ ACCESS_MASM(masm())
 
-// -------------------------------------------------------------------------
-// VirtualFrame implementation.
-
-// On entry to a function, the virtual frame already contains the receiver,
-// the parameters, and a return address.  All frame elements are in memory.
-VirtualFrame::VirtualFrame()
-    : elements_(parameter_count() + local_count() + kPreallocatedElements),
-      stack_pointer_(parameter_count() + 1) {  // 0-based index of TOS.
-  for (int i = 0; i <= stack_pointer_; i++) {
-    elements_.Add(FrameElement::MemoryElement(NumberInfo::kUnknown));
-  }
-  for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
-    register_locations_[i] = kIllegalIndex;
-  }
-}
-
-
 void VirtualFrame::SyncElementBelowStackPointer(int index) {
   // Emit code to write elements below the stack pointer to their
   // (already allocated) stack address.
@@ -179,7 +162,7 @@ void VirtualFrame::MakeMergable() {
     if (element.is_constant() || element.is_copy()) {
       if (element.is_synced()) {
         // Just spill.
-        elements_[i] = FrameElement::MemoryElement(NumberInfo::kUnknown);
+        elements_[i] = FrameElement::MemoryElement(NumberInfo::Unknown());
       } else {
         // Allocate to a register.
         FrameElement backing_element;  // Invalid if not a copy.
@@ -191,7 +174,7 @@ void VirtualFrame::MakeMergable() {
         elements_[i] =
             FrameElement::RegisterElement(fresh.reg(),
                                           FrameElement::NOT_SYNCED,
-                                          NumberInfo::kUnknown);
+                                          NumberInfo::Unknown());
         Use(fresh.reg(), i);
 
         // Emit a move.
@@ -224,7 +207,7 @@ void VirtualFrame::MakeMergable() {
       // The copy flag is not relied on before the end of this loop,
       // including when registers are spilled.
       elements_[i].clear_copied();
-      elements_[i].set_number_info(NumberInfo::kUnknown);
+      elements_[i].set_number_info(NumberInfo::Unknown());
     }
   }
 }
@@ -896,30 +879,39 @@ Result VirtualFrame::RawCallCodeObject(Handle<Code> code,
 }
 
 
+// This function assumes that the only results that could be in a_reg or b_reg
+// are a and b.  Other results can be live, but must not be in a_reg or b_reg.
+void VirtualFrame::MoveResultsToRegisters(Result* a,
+                                          Result* b,
+                                          Register a_reg,
+                                          Register b_reg) {
+  if (a->is_register() && a->reg().is(a_reg)) {
+    b->ToRegister(b_reg);
+  } else if (!cgen()->allocator()->is_used(a_reg)) {
+    a->ToRegister(a_reg);
+    b->ToRegister(b_reg);
+  } else if (cgen()->allocator()->is_used(b_reg)) {
+    // a must be in b_reg, b in a_reg.
+    __ xchg(a_reg, b_reg);
+    // Results a and b will be invalidated, so it is ok if they are switched.
+  } else {
+    b->ToRegister(b_reg);
+    a->ToRegister(a_reg);
+  }
+  a->Unuse();
+  b->Unuse();
+}
+
+
 Result VirtualFrame::CallLoadIC(RelocInfo::Mode mode) {
   // Name and receiver are on the top of the frame.  The IC expects
   // name in ecx and receiver in eax.
-  Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
   Result name = Pop();
   Result receiver = Pop();
   PrepareForCall(0, 0);  // No stack arguments.
-  // Move results to the right registers:
-  if (name.is_register() && name.reg().is(eax)) {
-    if (receiver.is_register() && receiver.reg().is(ecx)) {
-      // Wrong registers.
-      __ xchg(eax, ecx);
-    } else {
-      // Register ecx is free for name, which frees eax for receiver.
-      name.ToRegister(ecx);
-      receiver.ToRegister(eax);
-    }
-  } else {
-    // Register eax is free for receiver, which frees ecx for name.
-    receiver.ToRegister(eax);
-    name.ToRegister(ecx);
-  }
-  name.Unuse();
-  receiver.Unuse();
+  MoveResultsToRegisters(&name, &receiver, ecx, eax);
+
+  Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
   return RawCallCodeObject(ic, mode);
 }
 
@@ -929,20 +921,7 @@ Result VirtualFrame::CallKeyedLoadIC(RelocInfo::Mode mode) {
   Result key = Pop();
   Result receiver = Pop();
   PrepareForCall(0, 0);
-
-  if (!key.is_register() || !key.reg().is(edx)) {
-    // Register edx is available for receiver.
-    receiver.ToRegister(edx);
-    key.ToRegister(eax);
-  } else if (!receiver.is_register() || !receiver.reg().is(eax)) {
-    // Register eax is available for key.
-    key.ToRegister(eax);
-    receiver.ToRegister(edx);
-  } else {
-    __ xchg(edx, eax);
-  }
-  key.Unuse();
-  receiver.Unuse();
+  MoveResultsToRegisters(&key, &receiver, eax, edx);
 
   Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
   return RawCallCodeObject(ic, mode);
@@ -958,42 +937,57 @@ Result VirtualFrame::CallStoreIC(Handle<String> name, bool is_contextual) {
     PrepareForCall(0, 0);
     value.ToRegister(eax);
     __ mov(edx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
-    __ mov(ecx, name);
+    value.Unuse();
   } else {
     Result receiver = Pop();
     PrepareForCall(0, 0);
-
-    if (value.is_register() && value.reg().is(edx)) {
-      if (receiver.is_register() && receiver.reg().is(eax)) {
-        // Wrong registers.
-        __ xchg(eax, edx);
-      } else {
-        // Register eax is free for value, which frees edx for receiver.
-        value.ToRegister(eax);
-        receiver.ToRegister(edx);
-      }
-    } else {
-      // Register edx is free for receiver, which guarantees eax is free for
-      // value.
-      receiver.ToRegister(edx);
-      value.ToRegister(eax);
-    }
+    MoveResultsToRegisters(&value, &receiver, eax, edx);
   }
   __ mov(ecx, name);
-  value.Unuse();
   return RawCallCodeObject(ic, RelocInfo::CODE_TARGET);
 }
 
 
 Result VirtualFrame::CallKeyedStoreIC() {
   // Value, key, and receiver are on the top of the frame.  The IC
-  // expects value in eax and key and receiver on the stack.  It does
-  // not drop the key and receiver.
-  Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
+  // expects value in eax, key in ecx, and receiver in edx.
   Result value = Pop();
-  PrepareForCall(2, 0);  // Two stack args, neither callee-dropped.
-  value.ToRegister(eax);
-  value.Unuse();
+  Result key = Pop();
+  Result receiver = Pop();
+  PrepareForCall(0, 0);
+  if (!cgen()->allocator()->is_used(eax) ||
+      (value.is_register() && value.reg().is(eax))) {
+    value.ToRegister(eax);  // No effect if value is in eax already.
+    MoveResultsToRegisters(&key, &receiver, ecx, edx);
+    value.Unuse();
+  } else if (!cgen()->allocator()->is_used(ecx) ||
+             (key.is_register() && key.reg().is(ecx))) {
+    // Receiver and/or key are in eax.
+    key.ToRegister(ecx);
+    MoveResultsToRegisters(&value, &receiver, eax, edx);
+    key.Unuse();
+  } else if (!cgen()->allocator()->is_used(edx) ||
+             (receiver.is_register() && receiver.reg().is(edx))) {
+    receiver.ToRegister(edx);
+    MoveResultsToRegisters(&key, &value, ecx, eax);
+    receiver.Unuse();
+  } else {
+    // All three registers are used, and no value is in the correct place.
+    // We have one of the two circular permutations of eax, ecx, edx.
+    ASSERT(value.is_register());
+    if (value.reg().is(ecx)) {
+      __ xchg(eax, edx);
+      __ xchg(eax, ecx);
+    } else {
+      __ xchg(eax, ecx);
+      __ xchg(eax, edx);
+    }
+    value.Unuse();
+    key.Unuse();
+    receiver.Unuse();
+  }
+
+  Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
   return RawCallCodeObject(ic, RelocInfo::CODE_TARGET);
 }
 
@@ -1068,7 +1062,7 @@ Result VirtualFrame::Pop() {
   ASSERT(element.is_valid());
 
   // Get number type information of the result.
-  NumberInfo::Type info;
+  NumberInfo info;
   if (!element.is_copy()) {
     info = element.number_info();
   } else {
@@ -1143,7 +1137,7 @@ void VirtualFrame::EmitPop(Operand operand) {
 }
 
 
-void VirtualFrame::EmitPush(Register reg, NumberInfo::Type info) {
+void VirtualFrame::EmitPush(Register reg, NumberInfo info) {
   ASSERT(stack_pointer_ == element_count() - 1);
   elements_.Add(FrameElement::MemoryElement(info));
   stack_pointer_++;
@@ -1151,7 +1145,7 @@ void VirtualFrame::EmitPush(Register reg, NumberInfo::Type info) {
 }
 
 
-void VirtualFrame::EmitPush(Operand operand, NumberInfo::Type info) {
+void VirtualFrame::EmitPush(Operand operand, NumberInfo info) {
   ASSERT(stack_pointer_ == element_count() - 1);
   elements_.Add(FrameElement::MemoryElement(info));
   stack_pointer_++;
@@ -1159,7 +1153,7 @@ void VirtualFrame::EmitPush(Operand operand, NumberInfo::Type info) {
 }
 
 
-void VirtualFrame::EmitPush(Immediate immediate, NumberInfo::Type info) {
+void VirtualFrame::EmitPush(Immediate immediate, NumberInfo info) {
   ASSERT(stack_pointer_ == element_count() - 1);
   elements_.Add(FrameElement::MemoryElement(info));
   stack_pointer_++;
index d4cc141..cd2d18f 100644 (file)
@@ -73,7 +73,7 @@ class VirtualFrame: public ZoneObject {
   static const int kIllegalIndex = -1;
 
   // Construct an initial virtual frame on entry to a JS function.
-  VirtualFrame();
+  inline VirtualFrame();
 
   // Construct a virtual frame as a clone of an existing one.
   explicit inline VirtualFrame(VirtualFrame* original);
@@ -84,7 +84,7 @@ class VirtualFrame: public ZoneObject {
 
   // Create a duplicate of an existing valid frame element.
   FrameElement CopyElementAt(int index,
-    NumberInfo::Type info = NumberInfo::kUninitialized);
+    NumberInfo info = NumberInfo::Uninitialized());
 
   // The number of elements on the virtual frame.
   int element_count() { return elements_.length(); }
@@ -388,14 +388,14 @@ class VirtualFrame: public ZoneObject {
   // Push an element on top of the expression stack and emit a
   // corresponding push instruction.
   void EmitPush(Register reg,
-                NumberInfo::Type info = NumberInfo::kUnknown);
+                NumberInfo info = NumberInfo::Unknown());
   void EmitPush(Operand operand,
-                NumberInfo::Type info = NumberInfo::kUnknown);
+                NumberInfo info = NumberInfo::Unknown());
   void EmitPush(Immediate immediate,
-                NumberInfo::Type info = NumberInfo::kUnknown);
+                NumberInfo info = NumberInfo::Unknown());
 
   // Push an element on the virtual frame.
-  inline void Push(Register reg, NumberInfo::Type info = NumberInfo::kUnknown);
+  inline void Push(Register reg, NumberInfo info = NumberInfo::Unknown());
   inline void Push(Handle<Object> value);
   inline void Push(Smi* value);
 
@@ -571,6 +571,14 @@ class VirtualFrame: public ZoneObject {
   // Register counts are correctly updated.
   int InvalidateFrameSlotAt(int index);
 
+  // This function assumes that a and b are the only results that could be in
+  // the registers a_reg or b_reg.  Other results can be live, but must not
+  //  be in the registers a_reg or b_reg.  The results a and b are invalidated.
+  void MoveResultsToRegisters(Result* a,
+                              Result* b,
+                              Register a_reg,
+                              Register b_reg);
+
   // Call a code stub that has already been prepared for calling (via
   // PrepareForCall).
   Result RawCallStub(CodeStub* stub);
index 107c3c0..f82e61e 100644 (file)
@@ -63,7 +63,9 @@ void IC::TraceIC(const char* type,
                  Code* new_target,
                  const char* extra_info) {
   if (FLAG_trace_ic) {
-    State new_state = StateFrom(new_target, Heap::undefined_value());
+    State new_state = StateFrom(new_target,
+                                Heap::undefined_value(),
+                                Heap::undefined_value());
     PrintF("[%s (%c->%c)%s", type,
            TransitionMarkFromState(old_state),
            TransitionMarkFromState(new_state),
@@ -132,7 +134,7 @@ Address IC::OriginalCodeAddress() {
 }
 #endif
 
-IC::State IC::StateFrom(Code* target, Object* receiver) {
+IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) {
   IC::State state = target->ic_state();
 
   if (state != MONOMORPHIC) return state;
@@ -148,7 +150,7 @@ IC::State IC::StateFrom(Code* target, Object* receiver) {
   // the receiver map's code cache.  Therefore, if the current target
   // is in the receiver map's code cache, the inline cache failed due
   // to prototype check failure.
-  int index = map->IndexInCodeCache(target);
+  int index = map->IndexInCodeCache(String::cast(name), target);
   if (index >= 0) {
     // For keyed load/store, the most likely cause of cache failure is
     // that the key has changed.  We do not distinguish between
@@ -160,7 +162,7 @@ IC::State IC::StateFrom(Code* target, Object* receiver) {
 
     // Remove the target from the code cache to avoid hitting the same
     // invalid stub again.
-    map->RemoveFromCodeCache(index);
+    map->RemoveFromCodeCache(String::cast(name), target, index);
 
     return MONOMORPHIC_PROTOTYPE_FAILURE;
   }
@@ -222,6 +224,7 @@ void IC::Clear(Address address) {
     case Code::STORE_IC: return StoreIC::Clear(address, target);
     case Code::KEYED_STORE_IC: return KeyedStoreIC::Clear(address, target);
     case Code::CALL_IC: return CallIC::Clear(address, target);
+    case Code::BINARY_OP_IC: return BinaryOpIC::Clear(address, target);
     default: UNREACHABLE();
   }
 }
@@ -1049,6 +1052,20 @@ Object* StoreIC::Store(State state,
     return *value;
   }
 
+
+  // Use specialized code for setting the length of arrays.
+  if (receiver->IsJSArray()
+      && name->Equals(Heap::length_symbol())
+      && receiver->AllowsSetElementsLength()) {
+#ifdef DEBUG
+    if (FLAG_trace_ic) PrintF("[StoreIC : +#length /array]\n");
+#endif
+    Code* target = Builtins::builtin(Builtins::StoreIC_ArrayLength);
+    set_target(target);
+    StubCache::Set(*name, HeapObject::cast(*object)->map(), target);
+    return receiver->SetProperty(*name, *value, NONE);
+  }
+
   // Lookup the property locally in the receiver.
   if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) {
     LookupResult lookup;
@@ -1285,7 +1302,7 @@ Object* CallIC_Miss(Arguments args) {
   NoHandleAllocation na;
   ASSERT(args.length() == 2);
   CallIC ic;
-  IC::State state = IC::StateFrom(ic.target(), args[0]);
+  IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
   Object* result =
       ic.LoadFunction(state, args.at<Object>(0), args.at<String>(1));
 
@@ -1318,7 +1335,7 @@ Object* LoadIC_Miss(Arguments args) {
   NoHandleAllocation na;
   ASSERT(args.length() == 2);
   LoadIC ic;
-  IC::State state = IC::StateFrom(ic.target(), args[0]);
+  IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
   return ic.Load(state, args.at<Object>(0), args.at<String>(1));
 }
 
@@ -1328,7 +1345,7 @@ Object* KeyedLoadIC_Miss(Arguments args) {
   NoHandleAllocation na;
   ASSERT(args.length() == 2);
   KeyedLoadIC ic;
-  IC::State state = IC::StateFrom(ic.target(), args[0]);
+  IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
   return ic.Load(state, args.at<Object>(0), args.at<Object>(1));
 }
 
@@ -1338,7 +1355,7 @@ Object* StoreIC_Miss(Arguments args) {
   NoHandleAllocation na;
   ASSERT(args.length() == 3);
   StoreIC ic;
-  IC::State state = IC::StateFrom(ic.target(), args[0]);
+  IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
   return ic.Store(state, args.at<Object>(0), args.at<String>(1),
                   args.at<Object>(2));
 }
@@ -1351,7 +1368,9 @@ Object* StoreIC_ArrayLength(Arguments args) {
   JSObject* receiver = JSObject::cast(args[0]);
   Object* len = args[1];
 
-  return receiver->SetElementsLength(len);
+  Object* result = receiver->SetElementsLength(len);
+  if (result->IsFailure()) return result;
+  return len;
 }
 
 
@@ -1394,12 +1413,118 @@ Object* KeyedStoreIC_Miss(Arguments args) {
   NoHandleAllocation na;
   ASSERT(args.length() == 3);
   KeyedStoreIC ic;
-  IC::State state = IC::StateFrom(ic.target(), args[0]);
+  IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
   return ic.Store(state, args.at<Object>(0), args.at<Object>(1),
                   args.at<Object>(2));
 }
 
 
+void BinaryOpIC::patch(Code* code) {
+  set_target(code);
+}
+
+
+void BinaryOpIC::Clear(Address address, Code* target) {
+  if (target->ic_state() == UNINITIALIZED) return;
+
+  // At the end of a fast case stub there should be a reference to
+  // a corresponding UNINITIALIZED stub, so look for the last reloc info item.
+  RelocInfo* rinfo = NULL;
+  for (RelocIterator it(target, RelocInfo::kCodeTargetMask);
+       !it.done(); it.next()) {
+    rinfo = it.rinfo();
+  }
+
+  ASSERT(rinfo != NULL);
+  Code* uninit_stub = Code::GetCodeFromTargetAddress(rinfo->target_address());
+  ASSERT(uninit_stub->ic_state() == UNINITIALIZED &&
+         uninit_stub->kind() == Code::BINARY_OP_IC);
+  SetTargetAtAddress(address, uninit_stub);
+}
+
+
+const char* BinaryOpIC::GetName(TypeInfo type_info) {
+  switch (type_info) {
+    case DEFAULT: return "Default";
+    case GENERIC: return "Generic";
+    case HEAP_NUMBERS: return "HeapNumbers";
+    case STRINGS: return "Strings";
+    default: return "Invalid";
+  }
+}
+
+
+BinaryOpIC::State BinaryOpIC::ToState(TypeInfo type_info) {
+  switch (type_info) {
+    // DEFAULT is mapped to UNINITIALIZED so that calls to DEFAULT stubs
+    // are not cleared at GC.
+    case DEFAULT: return UNINITIALIZED;
+
+    // Could have mapped GENERIC to MONOMORPHIC just as well but MEGAMORPHIC is
+    // conceptually closer.
+    case GENERIC: return MEGAMORPHIC;
+
+    default: return MONOMORPHIC;
+  }
+}
+
+
+BinaryOpIC::TypeInfo BinaryOpIC::GetTypeInfo(Object* left,
+                                             Object* right) {
+  // Patching is never requested for the two smis.
+  ASSERT(!left->IsSmi() || !right->IsSmi());
+
+  if (left->IsNumber() && right->IsNumber()) {
+    return HEAP_NUMBERS;
+  }
+
+  if (left->IsString() || right->IsString()) {
+    // Patching for fast string ADD makes sense even if only one of the
+    // arguments is a string.
+    return STRINGS;
+  }
+
+  return GENERIC;
+}
+
+
+// defined in codegen-<arch>.cc
+Handle<Code> GetBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info);
+
+
+Object* BinaryOp_Patch(Arguments args) {
+  ASSERT(args.length() == 6);
+
+  Handle<Object> left = args.at<Object>(0);
+  Handle<Object> right = args.at<Object>(1);
+  Handle<Object> result = args.at<Object>(2);
+  int key = Smi::cast(args[3])->value();
+#ifdef DEBUG
+  Token::Value op = static_cast<Token::Value>(Smi::cast(args[4])->value());
+  BinaryOpIC::TypeInfo prev_type_info =
+      static_cast<BinaryOpIC::TypeInfo>(Smi::cast(args[5])->value());
+#endif  // DEBUG
+  { HandleScope scope;
+    BinaryOpIC::TypeInfo type_info = BinaryOpIC::GetTypeInfo(*left, *right);
+    Handle<Code> code = GetBinaryOpStub(key, type_info);
+    if (!code.is_null()) {
+      BinaryOpIC ic;
+      ic.patch(*code);
+#ifdef DEBUG
+      if (FLAG_trace_ic) {
+        PrintF("[BinaryOpIC (%s->%s)#%s]\n",
+            BinaryOpIC::GetName(prev_type_info),
+            BinaryOpIC::GetName(type_info),
+            Token::Name(op));
+      }
+#endif  // DEBUG
+    }
+  }
+
+  return *result;
+}
+
+
 static Address IC_utilities[] = {
 #define ADDR(name) FUNCTION_ADDR(name),
     IC_UTIL_LIST(ADDR)
index d545989..7464a57 100644 (file)
@@ -55,7 +55,8 @@ enum DictionaryCheck { CHECK_DICTIONARY, DICTIONARY_CHECK_DONE };
   ICU(LoadPropertyWithInterceptorForLoad)             \
   ICU(LoadPropertyWithInterceptorForCall)             \
   ICU(KeyedLoadPropertyWithInterceptor)               \
-  ICU(StoreInterceptorProperty)
+  ICU(StoreInterceptorProperty)                       \
+  ICU(BinaryOp_Patch)
 
 //
 // IC is the base class for LoadIC, StoreIC, CallIC, KeyedLoadIC,
@@ -93,8 +94,8 @@ class IC {
   Code* target() { return GetTargetAtAddress(address()); }
   inline Address address();
 
-  // Compute the current IC state based on the target stub and the receiver.
-  static State StateFrom(Code* target, Object* receiver);
+  // Compute the current IC state based on the target stub, receiver and name.
+  static State StateFrom(Code* target, Object* receiver, Object* name);
 
   // Clear the inline cache to initial state.
   static void Clear(Address address);
@@ -444,6 +445,30 @@ class KeyedStoreIC: public IC {
 };
 
 
+class BinaryOpIC: public IC {
+ public:
+
+  enum TypeInfo {
+    DEFAULT,  // Initial state. When first executed, patches to one
+              // of the following states depending on the operands types.
+    HEAP_NUMBERS,  // Both arguments are HeapNumbers.
+    STRINGS,  // At least one of the arguments is String.
+    GENERIC   // Non-specialized case (processes any type combination).
+  };
+
+  BinaryOpIC() : IC(NO_EXTRA_FRAME) { }
+
+  void patch(Code* code);
+
+  static void Clear(Address address, Code* target);
+
+  static const char* GetName(TypeInfo type_info);
+
+  static State ToState(TypeInfo type_info);
+
+  static TypeInfo GetTypeInfo(Object* left, Object* right);
+};
+
 } }  // namespace v8::internal
 
 #endif  // V8_IC_H_
index b99a89e..46d53c2 100644 (file)
@@ -29,6 +29,7 @@
 #define V8_JSREGEXP_H_
 
 #include "macro-assembler.h"
+#include "zone-inl.h"
 
 namespace v8 {
 namespace internal {
index 12fabc3..6db0081 100644 (file)
@@ -46,7 +46,7 @@ void JumpTarget::InitializeEntryElement(int index, FrameElement* target) {
     entry_frame_->elements_[target->index()].set_copied();
   }
   if (direction_ == BIDIRECTIONAL && !target->is_copy()) {
-    element->set_number_info(NumberInfo::kUnknown);
+    element->set_number_info(NumberInfo::Unknown());
   }
 }
 
index ab09870..7b1ced7 100644 (file)
@@ -135,7 +135,7 @@ void JumpTarget::ComputeEntryFrame() {
     FrameElement* target = elements[index];
     if (target == NULL) {
       entry_frame_->elements_.Add(
-          FrameElement::MemoryElement(NumberInfo::kUninitialized));
+          FrameElement::MemoryElement(NumberInfo::Uninitialized()));
     } else {
       entry_frame_->elements_.Add(*target);
       InitializeEntryElement(index, target);
@@ -152,12 +152,12 @@ void JumpTarget::ComputeEntryFrame() {
       RegisterFile candidate_registers;
       int best_count = kMinInt;
       int best_reg_num = RegisterAllocator::kInvalidRegister;
-      NumberInfo::Type info = NumberInfo::kUninitialized;
+      NumberInfo info = NumberInfo::Uninitialized();
 
       for (int j = 0; j < reaching_frames_.length(); j++) {
         FrameElement element = reaching_frames_[j]->elements_[i];
         if (direction_ == BIDIRECTIONAL) {
-            info = NumberInfo::kUnknown;
+          info = NumberInfo::Unknown();
         } else if (!element.is_copy()) {
           info = NumberInfo::Combine(info, element.number_info());
         } else {
@@ -181,7 +181,7 @@ void JumpTarget::ComputeEntryFrame() {
 
       // We must have a number type information now (not for copied elements).
       ASSERT(entry_frame_->elements_[i].is_copy()
-             || info != NumberInfo::kUninitialized);
+             || !info.IsUninitialized());
 
       // If the value is synced on all frames, put it in memory.  This
       // costs nothing at the merge code but will incur a
@@ -211,7 +211,7 @@ void JumpTarget::ComputeEntryFrame() {
         Register reg = RegisterAllocator::ToRegister(best_reg_num);
         entry_frame_->elements_[i] =
             FrameElement::RegisterElement(reg, FrameElement::NOT_SYNCED,
-                                          NumberInfo::kUninitialized);
+                                          NumberInfo::Uninitialized());
         if (is_copied) entry_frame_->elements_[i].set_copied();
         entry_frame_->set_register_location(reg, i);
       }
@@ -225,8 +225,7 @@ void JumpTarget::ComputeEntryFrame() {
   if (direction_ == BIDIRECTIONAL) {
     for (int i = 0; i < length; ++i) {
       if (!entry_frame_->elements_[i].is_copy()) {
-        ASSERT(entry_frame_->elements_[i].number_info() ==
-               NumberInfo::kUnknown);
+        ASSERT(entry_frame_->elements_[i].number_info().IsUnknown());
       }
     }
   }
index dd291c6..db7c115 100644 (file)
@@ -29,6 +29,7 @@
 #define V8_JUMP_TARGET_H_
 
 #include "macro-assembler.h"
+#include "zone-inl.h"
 
 namespace v8 {
 namespace internal {
diff --git a/deps/v8/src/liveedit-delay.js b/deps/v8/src/liveedit-delay.js
new file mode 100644 (file)
index 0000000..12479b1
--- /dev/null
@@ -0,0 +1,426 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// LiveEdit feature implementation. The script should be executed after
+// debug-delay.js.
+
+
+// Changes script text and recompiles all relevant functions if possible.
+// The change is always a substring (change_pos, change_pos + change_len)
+// being replaced with a completely different string new_str.
+// 
+// Only one function will have its Code changed in result of this function.
+// All nested functions (should they have any instances at the moment) are left
+// unchanged and re-linked to a newly created script instance representing old
+// version of the source. (Generally speaking,
+// during the change all nested functions are erased and completely different
+// set of nested functions are introduced.) All other functions just have
+// their positions updated. 
+//
+// @param {Script} script that is being changed
+// @param {Array} change_log a list that collects engineer-readable description
+//     of what happened.
+Debug.LiveEditChangeScript = function(script, change_pos, change_len, new_str,
+    change_log) {
+
+  // So far the function works as namespace.
+  var liveedit = Debug.LiveEditChangeScript;
+  var Assert = liveedit.Assert;
+
+  // Fully compiles source string as a script. Returns Array of
+  // FunctionCompileInfo -- a descriptions of all functions of the script.
+  // Elements of array are ordered by start positions of functions (from top
+  // to bottom) in the source. Fields outer_index and next_sibling_index help
+  // to navigate the nesting structure of functions.
+  // 
+  // The script is used for compilation, because it produces code that 
+  // needs to be linked with some particular script (for nested functions). 
+  function DebugGatherCompileInfo(source) {
+    // Get function info, elements are partially sorted (it is a tree
+    // of nested functions serialized as parent followed by serialized children.
+    var raw_compile_info = %LiveEditGatherCompileInfo(script, source);
+
+    // Sort function infos by start position field.
+    var compile_info = new Array();
+    var old_index_map = new Array();
+    for (var i = 0; i < raw_compile_info.length; i++) {
+        compile_info.push(new liveedit.FunctionCompileInfo(raw_compile_info[i]));
+        old_index_map.push(i);
+    }
+    
+    for (var i = 0; i < compile_info.length; i++) {
+      var k = i;
+      for (var j = i + 1; j < compile_info.length; j++) {
+        if (compile_info[k].start_position > compile_info[j].start_position) {
+          k = j;
+        }
+      }
+      if (k != i) {
+        var temp_info = compile_info[k];
+        var temp_index = old_index_map[k];
+        compile_info[k] = compile_info[i];
+        old_index_map[k] = old_index_map[i];
+        compile_info[i] = temp_info;
+        old_index_map[i] = temp_index;
+      }
+    }
+
+    // After sorting update outer_inder field using old_index_map. Also
+    // set next_sibling_index field.
+    var current_index = 0;
+
+    // The recursive function, that goes over all children of a particular
+    // node (i.e. function info).
+    function ResetIndexes(new_parent_index, old_parent_index) {
+      var previous_sibling = -1;
+      while (current_index < compile_info.length &&
+          compile_info[current_index].outer_index == old_parent_index) {
+        var saved_index = current_index;
+        compile_info[saved_index].outer_index = new_parent_index;
+        if (previous_sibling != -1) {
+          compile_info[previous_sibling].next_sibling_index = saved_index;
+        }
+        previous_sibling = saved_index;
+        current_index++;
+        ResetIndexes(saved_index, old_index_map[saved_index]);
+      }
+      if (previous_sibling != -1) {
+        compile_info[previous_sibling].next_sibling_index = -1;
+      }
+    }
+    
+    ResetIndexes(-1, -1);
+    Assert(current_index == compile_info.length);
+    
+    return compile_info;
+  }  
+
+  // Given a positions, finds a function that fully includes the entire change.
+  function FindChangedFunction(compile_info, offset, len) {
+    // First condition: function should start before the change region.
+    // Function #0 (whole-script function) always does, but we want
+    // one, that is later in this list.
+    var index = 0;
+    while (index + 1 < compile_info.length &&
+        compile_info[index + 1].start_position <= offset) {
+      index++;
+    }
+    // Now we are at the last function that begins before the change
+    // region. The function that covers entire change region is either
+    // this function or the enclosing one.
+    for (; compile_info[index].end_position < offset + len;
+        index = compile_info[index].outer_index) {
+      Assert(index != -1);
+    }
+    return index;
+  }
+
+  // Variable forward declarations. Preprocessor "Minifier" needs them.
+  var old_compile_info;
+  var shared_infos;
+  // Finds SharedFunctionInfo that corresponds compile info with index
+  // in old version of the script.
+  function FindFunctionInfo(index) {
+    var old_info = old_compile_info[index];
+    for (var i = 0; i < shared_infos.length; i++) {
+      var info = shared_infos[i];
+      if (info.start_position == old_info.start_position && 
+          info.end_position == old_info.end_position) {
+        return info;
+      }
+    }
+  }
+
+  // Replaces function's Code.
+  function PatchCode(new_info, shared_info) {
+    %LiveEditReplaceFunctionCode(new_info.raw_array, shared_info.raw_array);
+
+    change_log.push( {function_patched: new_info.function_name} );
+  }
+  
+  var change_len_old;
+  var change_len_new;
+  // Translate position in old version of script into position in new
+  // version of script.
+  function PosTranslator(old_pos) {
+    if (old_pos <= change_pos) {
+      return old_pos;
+    }
+    if (old_pos >= change_pos + change_len_old) {
+      return old_pos + change_len_new - change_len_old;
+    }
+    return -1;
+  }
+  
+  var position_change_array;
+  var position_patch_report;
+  function PatchPositions(new_info, shared_info) {
+    if (!shared_info) {
+      // TODO: explain what is happening.
+      return;
+    }
+    %LiveEditPatchFunctionPositions(shared_info.raw_array,
+        position_change_array);
+    position_patch_report.push( { name: new_info.function_name } );
+  }
+  
+  var link_to_old_script_report;
+  var old_script;
+  // Makes a function associated with another instance of a script (the
+  // one representing its old version). This way the function still
+  // may access its own text.
+  function LinkToOldScript(shared_info) {
+    %LiveEditRelinkFunctionToScript(shared_info.raw_array, old_script);
+    
+    link_to_old_script_report.push( { name: shared_info.function_name } );
+  }
+
+
+  
+  var old_source = script.source;
+  var change_len_old = change_len;
+  var change_len_new = new_str.length;
+  
+  // Prepare new source string.
+  var new_source = old_source.substring(0, change_pos) +
+      new_str + old_source.substring(change_pos + change_len);
+
+  // Find all SharedFunctionInfo's that are compiled from this script.
+  var shared_raw_list = %LiveEditFindSharedFunctionInfosForScript(script);
+
+  var shared_infos = new Array();
+
+  for (var i = 0; i < shared_raw_list.length; i++) {
+    shared_infos.push(new liveedit.SharedInfoWrapper(shared_raw_list[i]));
+  }
+  
+  // Gather compile information about old version of script.
+  var old_compile_info = DebugGatherCompileInfo(old_source);
+  
+  // Gather compile information about new version of script.
+  var new_compile_info;
+  try {
+    new_compile_info = DebugGatherCompileInfo(new_source);
+  } catch (e) {
+    throw new liveedit.Failure("Failed to compile new version of script: " + e);
+  }
+
+  // An index of a single function, that is going to have its code replaced.
+  var function_being_patched =
+      FindChangedFunction(old_compile_info, change_pos, change_len_old);
+
+  // In old and new script versions function with a change should have the
+  // same indexes.
+  var function_being_patched2 =
+      FindChangedFunction(new_compile_info, change_pos, change_len_new);
+  Assert(function_being_patched == function_being_patched2,
+         "inconsistent old/new compile info");
+
+  // Check that function being patched has the same expectations in a new
+  // version. Otherwise we cannot safely patch its behavior and should
+  // choose the outer function instead.
+  while (!liveedit.CompareFunctionExpectations(
+      old_compile_info[function_being_patched],
+      new_compile_info[function_being_patched])) {
+
+    Assert(old_compile_info[function_being_patched].outer_index == 
+        new_compile_info[function_being_patched].outer_index);
+    function_being_patched =
+        old_compile_info[function_being_patched].outer_index;
+    Assert(function_being_patched != -1);
+  }
+  
+  // Check that function being patched is not currently on stack.
+  liveedit.CheckStackActivations(
+      [ FindFunctionInfo(function_being_patched) ], change_log );
+  
+
+  // Committing all changes.
+  var old_script_name = liveedit.CreateNameForOldScript(script); 
+
+  // Update the script text and create a new script representing an old
+  // version of the script.
+  var old_script = %LiveEditReplaceScript(script, new_source, old_script_name);
+
+  PatchCode(new_compile_info[function_being_patched],
+      FindFunctionInfo(function_being_patched));
+
+  var position_patch_report = new Array();
+  change_log.push( {position_patched: position_patch_report} );
+  
+  var position_change_array = [ change_pos,
+                                change_pos + change_len_old,
+                                change_pos + change_len_new ];
+  
+  // Update positions of all outer functions (i.e. all functions, that
+  // are partially below the function being patched).
+  for (var i = new_compile_info[function_being_patched].outer_index;
+      i != -1;
+      i = new_compile_info[i].outer_index) {
+    PatchPositions(new_compile_info[i], FindFunctionInfo(i));
+  }
+
+  // Update positions of all functions that are fully below the function
+  // being patched.
+  var old_next_sibling =
+      old_compile_info[function_being_patched].next_sibling_index;
+  var new_next_sibling =
+      new_compile_info[function_being_patched].next_sibling_index;
+
+  // We simply go over the tail of both old and new lists. Their tails should
+  // have an identical structure.
+  if (old_next_sibling == -1) {
+    Assert(new_next_sibling == -1);
+  } else {
+    Assert(old_compile_info.length - old_next_sibling ==
+        new_compile_info.length - new_next_sibling);
+
+    for (var i = old_next_sibling, j = new_next_sibling;
+        i < old_compile_info.length; i++, j++) {
+      PatchPositions(new_compile_info[j], FindFunctionInfo(i));
+    }
+  }
+
+  var link_to_old_script_report = new Array();
+  change_log.push( { linked_to_old_script: link_to_old_script_report } );
+
+  // We need to link to old script all former nested functions.  
+  for (var i = function_being_patched + 1; i < old_next_sibling; i++) {
+    LinkToOldScript(FindFunctionInfo(i), old_script);
+  }
+}
+
+Debug.LiveEditChangeScript.Assert = function(condition, message) {
+  if (!condition) {
+    if (message) {
+      throw "Assert " + message;
+    } else {
+      throw "Assert";
+    }
+  }
+}
+    
+// An object describing function compilation details. Its index fields
+// apply to indexes inside array that stores these objects.
+Debug.LiveEditChangeScript.FunctionCompileInfo = function(raw_array) {
+  this.function_name = raw_array[0];
+  this.start_position = raw_array[1];
+  this.end_position = raw_array[2];
+  this.param_num = raw_array[3];
+  this.code = raw_array[4];
+  this.scope_info = raw_array[5];
+  this.outer_index = raw_array[6];
+  this.next_sibling_index = null;
+  this.raw_array = raw_array;
+}
+  
+// A structure describing SharedFunctionInfo.
+Debug.LiveEditChangeScript.SharedInfoWrapper = function(raw_array) {
+  this.function_name = raw_array[0];
+  this.start_position = raw_array[1];
+  this.end_position = raw_array[2];
+  this.info = raw_array[3];
+  this.raw_array = raw_array;
+}
+
+// Adds a suffix to script name to mark that it is old version.
+Debug.LiveEditChangeScript.CreateNameForOldScript = function(script) {
+  // TODO(635): try better than this; support several changes.
+  return script.name + " (old)";
+}
+
+// Compares a function interface old and new version, whether it
+// changed or not.
+Debug.LiveEditChangeScript.CompareFunctionExpectations =
+    function(function_info1, function_info2) {
+  // Check that function has the same number of parameters (there may exist
+  // an adapter, that won't survive function parameter number change).
+  if (function_info1.param_num != function_info2.param_num) {
+    return false;
+  }
+  var scope_info1 = function_info1.scope_info;
+  var scope_info2 = function_info2.scope_info;
+  
+  if (!scope_info1) {
+    return !scope_info2;
+  }
+  
+  if (scope_info1.length != scope_info2.length) {
+    return false;
+  }
+
+  // Check that outer scope structure is not changed. Otherwise the function
+  // will not properly work with existing scopes.
+  return scope_info1.toString() == scope_info2.toString(); 
+}
+
+// For array of wrapped shared function infos checks that none of them
+// have activations on stack (of any thread). Throws a Failure exception
+// if this proves to be false.
+Debug.LiveEditChangeScript.CheckStackActivations = function(shared_wrapper_list,
+                                                            change_log) {
+  var liveedit = Debug.LiveEditChangeScript;
+      
+  var shared_list = new Array();
+  for (var i = 0; i < shared_wrapper_list.length; i++) {
+    shared_list[i] = shared_wrapper_list[i].info;
+  }
+  var result = %LiveEditCheckStackActivations(shared_list);
+  var problems = new Array();
+  for (var i = 0; i < shared_list.length; i++) {
+    if (result[i] == liveedit.FunctionPatchabilityStatus.FUNCTION_BLOCKED_ON_STACK) {
+      var shared = shared_list[i];
+      var description = {
+          name: shared.function_name,
+          start_pos: shared.start_position, 
+          end_pos: shared.end_position
+      };
+      problems.push(description);
+    }
+  }
+  if (problems.length > 0) {
+    change_log.push( { functions_on_stack: problems } );
+    throw new liveedit.Failure("Blocked by functions on stack");
+  }
+}
+
+// A copy of the FunctionPatchabilityStatus enum from liveedit.h
+Debug.LiveEditChangeScript.FunctionPatchabilityStatus = {
+    FUNCTION_AVAILABLE_FOR_PATCH: 0,
+    FUNCTION_BLOCKED_ON_STACK: 1
+}
+
+
+// A logical failure in liveedit process. This means that change_log
+// is valid and consistent description of what happened.
+Debug.LiveEditChangeScript.Failure = function(message) {
+  this.message = message;
+}
+
+Debug.LiveEditChangeScript.Failure.prototype.toString = function() {
+  return "LiveEdit Failure: " + this.message;     
+}
index c50e007..513cc02 100644 (file)
@@ -39,49 +39,445 @@ namespace v8 {
 namespace internal {
 
 
+#ifdef ENABLE_DEBUGGER_SUPPORT
+
+static void CompileScriptForTracker(Handle<Script> script) {
+  const bool is_eval = false;
+  const bool is_global = true;
+  // TODO(635): support extensions.
+  Extension* extension = NULL;
+
+  PostponeInterruptsScope postpone;
+
+  // Only allow non-global compiles for eval.
+  ASSERT(is_eval || is_global);
+
+  // Build AST.
+  ScriptDataImpl* pre_data = NULL;
+  FunctionLiteral* lit = MakeAST(is_global, script, extension, pre_data);
+
+  // Check for parse errors.
+  if (lit == NULL) {
+    ASSERT(Top::has_pending_exception());
+    return;
+  }
+
+  // Compile the code.
+  CompilationInfo info(lit, script, is_eval);
+  Handle<Code> code = MakeCodeForLiveEdit(&info);
+
+  // Check for stack-overflow exceptions.
+  if (code.is_null()) {
+    Top::StackOverflow();
+    return;
+  }
+}
+
+// Unwraps JSValue object, returning its field "value"
+static Handle<Object> UnwrapJSValue(Handle<JSValue> jsValue) {
+  return Handle<Object>(jsValue->value());
+}
+
+// Wraps any object into a OpaqueReference, that will hide the object
+// from JavaScript.
+static Handle<JSValue> WrapInJSValue(Object* object) {
+  Handle<JSFunction> constructor = Top::opaque_reference_function();
+  Handle<JSValue> result =
+      Handle<JSValue>::cast(Factory::NewJSObject(constructor));
+  result->set_value(object);
+  return result;
+}
+
+// Simple helper class that creates more or less typed structures over
+// JSArray object. This is an adhoc method of passing structures from C++
+// to JavaScript.
+template<typename S>
+class JSArrayBasedStruct {
+ public:
+  static S Create() {
+    Handle<JSArray> array = Factory::NewJSArray(S::kSize_);
+    return S(array);
+  }
+  static S cast(Object* object) {
+    JSArray* array = JSArray::cast(object);
+    Handle<JSArray> array_handle(array);
+    return S(array_handle);
+  }
+  explicit JSArrayBasedStruct(Handle<JSArray> array) : array_(array) {
+  }
+  Handle<JSArray> GetJSArray() {
+    return array_;
+  }
+ protected:
+  void SetField(int field_position, Handle<Object> value) {
+    SetElement(array_, field_position, value);
+  }
+  void SetSmiValueField(int field_position, int value) {
+    SetElement(array_, field_position, Handle<Smi>(Smi::FromInt(value)));
+  }
+  Object* GetField(int field_position) {
+    return array_->GetElement(field_position);
+  }
+  int GetSmiValueField(int field_position) {
+    Object* res = GetField(field_position);
+    return Smi::cast(res)->value();
+  }
+ private:
+  Handle<JSArray> array_;
+};
+
+
+// Represents some function compilation details. This structure will be used
+// from JavaScript. It contains Code object, which is kept wrapped
+// into a BlindReference for sanitizing reasons.
+class FunctionInfoWrapper : public JSArrayBasedStruct<FunctionInfoWrapper> {
+ public:
+  explicit FunctionInfoWrapper(Handle<JSArray> array)
+      : JSArrayBasedStruct<FunctionInfoWrapper>(array) {
+  }
+  void SetInitialProperties(Handle<String> name, int start_position,
+                            int end_position, int param_num, int parent_index) {
+    HandleScope scope;
+    this->SetField(kFunctionNameOffset_, name);
+    this->SetSmiValueField(kStartPositionOffset_, start_position);
+    this->SetSmiValueField(kEndPositionOffset_, end_position);
+    this->SetSmiValueField(kParamNumOffset_, param_num);
+    this->SetSmiValueField(kParentIndexOffset_, parent_index);
+  }
+  void SetFunctionCode(Handle<Code> function_code) {
+    Handle<JSValue> wrapper = WrapInJSValue(*function_code);
+    this->SetField(kCodeOffset_, wrapper);
+  }
+  void SetScopeInfo(Handle<JSArray> scope_info_array) {
+    this->SetField(kScopeInfoOffset_, scope_info_array);
+  }
+  int GetParentIndex() {
+    return this->GetSmiValueField(kParentIndexOffset_);
+  }
+  Handle<Code> GetFunctionCode() {
+    Handle<Object> raw_result = UnwrapJSValue(Handle<JSValue>(
+        JSValue::cast(this->GetField(kCodeOffset_))));
+    return Handle<Code>::cast(raw_result);
+  }
+  int GetStartPosition() {
+    return this->GetSmiValueField(kStartPositionOffset_);
+  }
+  int GetEndPosition() {
+    return this->GetSmiValueField(kEndPositionOffset_);
+  }
+
+ private:
+  static const int kFunctionNameOffset_ = 0;
+  static const int kStartPositionOffset_ = 1;
+  static const int kEndPositionOffset_ = 2;
+  static const int kParamNumOffset_ = 3;
+  static const int kCodeOffset_ = 4;
+  static const int kScopeInfoOffset_ = 5;
+  static const int kParentIndexOffset_ = 6;
+  static const int kSize_ = 7;
+
+  friend class JSArrayBasedStruct<FunctionInfoWrapper>;
+};
+
+// Wraps SharedFunctionInfo along with some of its fields for passing it
+// back to JavaScript. SharedFunctionInfo object itself is additionally
+// wrapped into BlindReference for sanitizing reasons.
+class SharedInfoWrapper : public JSArrayBasedStruct<SharedInfoWrapper> {
+ public:
+  explicit SharedInfoWrapper(Handle<JSArray> array)
+      : JSArrayBasedStruct<SharedInfoWrapper>(array) {
+  }
+
+  void SetProperties(Handle<String> name, int start_position, int end_position,
+                     Handle<SharedFunctionInfo> info) {
+    HandleScope scope;
+    this->SetField(kFunctionNameOffset_, name);
+    Handle<JSValue> info_holder = WrapInJSValue(*info);
+    this->SetField(kSharedInfoOffset_, info_holder);
+    this->SetSmiValueField(kStartPositionOffset_, start_position);
+    this->SetSmiValueField(kEndPositionOffset_, end_position);
+  }
+  Handle<SharedFunctionInfo> GetInfo() {
+    Object* element = this->GetField(kSharedInfoOffset_);
+    Handle<JSValue> value_wrapper(JSValue::cast(element));
+    Handle<Object> raw_result = UnwrapJSValue(value_wrapper);
+    return Handle<SharedFunctionInfo>::cast(raw_result);
+  }
+
+ private:
+  static const int kFunctionNameOffset_ = 0;
+  static const int kStartPositionOffset_ = 1;
+  static const int kEndPositionOffset_ = 2;
+  static const int kSharedInfoOffset_ = 3;
+  static const int kSize_ = 4;
+
+  friend class JSArrayBasedStruct<SharedInfoWrapper>;
+};
+
 class FunctionInfoListener {
  public:
+  FunctionInfoListener() {
+    current_parent_index_ = -1;
+    len_ = 0;
+    result_ = Factory::NewJSArray(10);
+  }
+
   void FunctionStarted(FunctionLiteral* fun) {
-    // Implementation follows.
+    HandleScope scope;
+    FunctionInfoWrapper info = FunctionInfoWrapper::Create();
+    info.SetInitialProperties(fun->name(), fun->start_position(),
+                              fun->end_position(), fun->num_parameters(),
+                              current_parent_index_);
+    current_parent_index_ = len_;
+    SetElement(result_, len_, info.GetJSArray());
+    len_++;
   }
 
   void FunctionDone() {
-    // Implementation follows.
+    HandleScope scope;
+    FunctionInfoWrapper info =
+        FunctionInfoWrapper::cast(result_->GetElement(current_parent_index_));
+    current_parent_index_ = info.GetParentIndex();
   }
 
   void FunctionScope(Scope* scope) {
-    // Implementation follows.
+    HandleScope handle_scope;
+
+    Handle<JSArray> scope_info_list = Factory::NewJSArray(10);
+    int scope_info_length = 0;
+
+    // Saves some description of scope. It stores name and indexes of
+    // variables in the whole scope chain. Null-named slots delimit
+    // scopes of this chain.
+    Scope* outer_scope = scope->outer_scope();
+    if (outer_scope == NULL) {
+      return;
+    }
+    do {
+      ZoneList<Variable*> list(10);
+      outer_scope->CollectUsedVariables(&list);
+      int j = 0;
+      for (int i = 0; i < list.length(); i++) {
+        Variable* var1 = list[i];
+        Slot* slot = var1->slot();
+        if (slot != NULL && slot->type() == Slot::CONTEXT) {
+          if (j != i) {
+            list[j] = var1;
+          }
+          j++;
+        }
+      }
+
+      // Sort it.
+      for (int k = 1; k < j; k++) {
+        int l = k;
+        for (int m = k + 1; m < j; m++) {
+          if (list[l]->slot()->index() > list[m]->slot()->index()) {
+            l = m;
+          }
+        }
+        list[k] = list[l];
+      }
+      for (int i = 0; i < j; i++) {
+        SetElement(scope_info_list, scope_info_length, list[i]->name());
+        scope_info_length++;
+        SetElement(scope_info_list, scope_info_length,
+                   Handle<Smi>(Smi::FromInt(list[i]->slot()->index())));
+        scope_info_length++;
+      }
+      SetElement(scope_info_list, scope_info_length,
+                 Handle<Object>(Heap::null_value()));
+      scope_info_length++;
+
+      outer_scope = outer_scope->outer_scope();
+    } while (outer_scope != NULL);
+
+    FunctionInfoWrapper info =
+        FunctionInfoWrapper::cast(result_->GetElement(current_parent_index_));
+    info.SetScopeInfo(scope_info_list);
   }
 
   void FunctionCode(Handle<Code> function_code) {
-    // Implementation follows.
+    FunctionInfoWrapper info =
+        FunctionInfoWrapper::cast(result_->GetElement(current_parent_index_));
+    info.SetFunctionCode(function_code);
   }
+
+  Handle<JSArray> GetResult() {
+    return result_;
+  }
+
+ private:
+  Handle<JSArray> result_;
+  int len_;
+  int current_parent_index_;
 };
 
 static FunctionInfoListener* active_function_info_listener = NULL;
 
+JSArray* LiveEdit::GatherCompileInfo(Handle<Script> script,
+                                     Handle<String> source) {
+  CompilationZoneScope zone_scope(DELETE_ON_EXIT);
+
+  FunctionInfoListener listener;
+  Handle<Object> original_source = Handle<Object>(script->source());
+  script->set_source(*source);
+  active_function_info_listener = &listener;
+  CompileScriptForTracker(script);
+  active_function_info_listener = NULL;
+  script->set_source(*original_source);
+
+  return *(listener.GetResult());
+}
+
+
+void LiveEdit::WrapSharedFunctionInfos(Handle<JSArray> array) {
+  HandleScope scope;
+  int len = Smi::cast(array->length())->value();
+  for (int i = 0; i < len; i++) {
+    Handle<SharedFunctionInfo> info(
+        SharedFunctionInfo::cast(array->GetElement(i)));
+    SharedInfoWrapper info_wrapper = SharedInfoWrapper::Create();
+    Handle<String> name_handle(String::cast(info->name()));
+    info_wrapper.SetProperties(name_handle, info->start_position(),
+                               info->end_position(), info);
+    array->SetElement(i, *(info_wrapper.GetJSArray()));
+  }
+}
+
+
+void LiveEdit::ReplaceFunctionCode(Handle<JSArray> new_compile_info_array,
+                                 Handle<JSArray> shared_info_array) {
+  HandleScope scope;
+
+  FunctionInfoWrapper compile_info_wrapper(new_compile_info_array);
+  SharedInfoWrapper shared_info_wrapper(shared_info_array);
+
+  Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo();
+
+  shared_info->set_code(*(compile_info_wrapper.GetFunctionCode()),
+                        UPDATE_WRITE_BARRIER);
+  shared_info->set_start_position(compile_info_wrapper.GetStartPosition());
+  shared_info->set_end_position(compile_info_wrapper.GetEndPosition());
+  // update breakpoints, original code, constructor stub
+}
+
+
+void LiveEdit::RelinkFunctionToScript(Handle<JSArray> shared_info_array,
+                                      Handle<Script> script_handle) {
+  SharedInfoWrapper shared_info_wrapper(shared_info_array);
+  Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo();
+
+  shared_info->set_script(*script_handle);
+}
+
+
+// For a script text change (defined as position_change_array), translates
+// position in unchanged text to position in changed text.
+// Text change is a set of non-overlapping regions in text, that have changed
+// their contents and length. It is specified as array of groups of 3 numbers:
+// (change_begin, change_end, change_end_new_position).
+// Each group describes a change in text; groups are sorted by change_begin.
+// Only position in text beyond any changes may be successfully translated.
+// If a positions is inside some region that changed, result is currently
+// undefined.
+static int TranslatePosition(int original_position,
+                             Handle<JSArray> position_change_array) {
+  int position_diff = 0;
+  int array_len = Smi::cast(position_change_array->length())->value();
+  // TODO(635): binary search may be used here
+  for (int i = 0; i < array_len; i += 3) {
+    int chunk_start =
+        Smi::cast(position_change_array->GetElement(i))->value();
+    int chunk_end =
+        Smi::cast(position_change_array->GetElement(i + 1))->value();
+    int chunk_changed_end =
+        Smi::cast(position_change_array->GetElement(i + 2))->value();
+    position_diff = chunk_changed_end - chunk_end;
+    if (original_position < chunk_start) {
+      break;
+    }
+    // Position mustn't be inside a chunk.
+    ASSERT(original_position >= chunk_end);
+  }
+
+  return original_position + position_diff;
+}
+
+
+void LiveEdit::PatchFunctionPositions(Handle<JSArray> shared_info_array,
+                                      Handle<JSArray> position_change_array) {
+  SharedInfoWrapper shared_info_wrapper(shared_info_array);
+  Handle<SharedFunctionInfo> info = shared_info_wrapper.GetInfo();
+
+  info->set_start_position(TranslatePosition(info->start_position(),
+                                             position_change_array));
+  info->set_end_position(TranslatePosition(info->end_position(),
+                                           position_change_array));
+
+  // Also patch rinfos (both in working code and original code), breakpoints.
+}
+
+
 LiveEditFunctionTracker::LiveEditFunctionTracker(FunctionLiteral* fun) {
   if (active_function_info_listener != NULL) {
     active_function_info_listener->FunctionStarted(fun);
   }
 }
+
+
 LiveEditFunctionTracker::~LiveEditFunctionTracker() {
   if (active_function_info_listener != NULL) {
     active_function_info_listener->FunctionDone();
   }
 }
+
+
 void LiveEditFunctionTracker::RecordFunctionCode(Handle<Code> code) {
   if (active_function_info_listener != NULL) {
     active_function_info_listener->FunctionCode(code);
   }
 }
+
+
 void LiveEditFunctionTracker::RecordFunctionScope(Scope* scope) {
   if (active_function_info_listener != NULL) {
     active_function_info_listener->FunctionScope(scope);
   }
 }
+
+
 bool LiveEditFunctionTracker::IsActive() {
   return active_function_info_listener != NULL;
 }
 
+
+#else  // ENABLE_DEBUGGER_SUPPORT
+
+// This ifdef-else-endif section provides working or stub implementation of
+// LiveEditFunctionTracker.
+LiveEditFunctionTracker::LiveEditFunctionTracker(FunctionLiteral* fun) {
+}
+
+
+LiveEditFunctionTracker::~LiveEditFunctionTracker() {
+}
+
+
+void LiveEditFunctionTracker::RecordFunctionCode(Handle<Code> code) {
+}
+
+
+void LiveEditFunctionTracker::RecordFunctionScope(Scope* scope) {
+}
+
+
+bool LiveEditFunctionTracker::IsActive() {
+  return false;
+}
+
+#endif  // ENABLE_DEBUGGER_SUPPORT
+
+
+
 } }  // namespace v8::internal
index 73aa7d3..efbcd74 100644 (file)
@@ -73,6 +73,34 @@ class LiveEditFunctionTracker {
   static bool IsActive();
 };
 
+#ifdef ENABLE_DEBUGGER_SUPPORT
+
+class LiveEdit : AllStatic {
+ public:
+  static JSArray* GatherCompileInfo(Handle<Script> script,
+                                    Handle<String> source);
+
+  static void WrapSharedFunctionInfos(Handle<JSArray> array);
+
+  static void ReplaceFunctionCode(Handle<JSArray> new_compile_info_array,
+                                  Handle<JSArray> shared_info_array);
+
+  static void RelinkFunctionToScript(Handle<JSArray> shared_info_array,
+                                     Handle<Script> script_handle);
+
+  static void PatchFunctionPositions(Handle<JSArray> shared_info_array,
+                                     Handle<JSArray> position_change_array);
+
+  // A copy of this is in liveedit-delay.js.
+  enum FunctionPatchabilityStatus {
+    FUNCTION_AVAILABLE_FOR_PATCH = 0,
+    FUNCTION_BLOCKED_ON_STACK = 1
+  };
+};
+
+#endif  // ENABLE_DEBUGGER_SUPPORT
+
+
 } }  // namespace v8::internal
 
 #endif /* V*_LIVEEDIT_H_ */
index a3fef73..588d345 100644 (file)
@@ -329,7 +329,7 @@ VMState Logger::bottom_state_(EXTERNAL);
 SlidingStateWindow* Logger::sliding_state_window_ = NULL;
 const char** Logger::log_events_ = NULL;
 CompressionHelper* Logger::compression_helper_ = NULL;
-bool Logger::is_logging_ = false;
+int Logger::logging_nesting_ = 0;
 int Logger::cpu_profiler_nesting_ = 0;
 int Logger::heap_profiler_nesting_ = 0;
 
@@ -389,12 +389,19 @@ void Logger::UncheckedStringEvent(const char* name, const char* value) {
 
 void Logger::IntEvent(const char* name, int value) {
 #ifdef ENABLE_LOGGING_AND_PROFILING
-  if (!Log::IsEnabled() || !FLAG_log) return;
+  if (FLAG_log) UncheckedIntEvent(name, value);
+#endif
+}
+
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+void Logger::UncheckedIntEvent(const char* name, int value) {
+  if (!Log::IsEnabled()) return;
   LogMessageBuilder msg;
   msg.Append("%s,%d\n", name, value);
   msg.WriteToLogFile();
-#endif
 }
+#endif
 
 
 void Logger::HandleEvent(const char* name, Object** location) {
@@ -1169,19 +1176,18 @@ void Logger::PauseProfiler(int flags, int tag) {
         // Must be the same message as Log::kDynamicBufferSeal.
         LOG(UncheckedStringEvent("profiler", "pause"));
       }
+      --logging_nesting_;
     }
   }
   if (flags &
       (PROFILER_MODULE_HEAP_STATS | PROFILER_MODULE_JS_CONSTRUCTORS)) {
     if (--heap_profiler_nesting_ == 0) {
       FLAG_log_gc = false;
+      --logging_nesting_;
     }
   }
   if (tag != 0) {
-    IntEvent("close-tag", tag);
-  }
-  if (GetActiveProfilerModules() == PROFILER_MODULE_NONE) {
-    is_logging_ = false;
+    UncheckedIntEvent("close-tag", tag);
   }
 }
 
@@ -1189,11 +1195,11 @@ void Logger::PauseProfiler(int flags, int tag) {
 void Logger::ResumeProfiler(int flags, int tag) {
   if (!Log::IsEnabled()) return;
   if (tag != 0) {
-    IntEvent("open-tag", tag);
+    UncheckedIntEvent("open-tag", tag);
   }
   if (flags & PROFILER_MODULE_CPU) {
     if (cpu_profiler_nesting_++ == 0) {
-      is_logging_ = true;
+      ++logging_nesting_;
       if (FLAG_prof_lazy) {
         profiler_->Engage();
         LOG(UncheckedStringEvent("profiler", "resume"));
@@ -1209,7 +1215,7 @@ void Logger::ResumeProfiler(int flags, int tag) {
   if (flags &
       (PROFILER_MODULE_HEAP_STATS | PROFILER_MODULE_JS_CONSTRUCTORS)) {
     if (heap_profiler_nesting_++ == 0) {
-      is_logging_ = true;
+      ++logging_nesting_;
       FLAG_log_gc = true;
     }
   }
@@ -1261,6 +1267,8 @@ void Logger::LogCodeObject(Object* object) {
     switch (code_object->kind()) {
       case Code::FUNCTION:
         return;  // We log this later using LogCompiledFunctions.
+      case Code::BINARY_OP_IC:
+        // fall through
       case Code::STUB:
         description = CodeStub::MajorName(code_object->major_key(), true);
         if (description == NULL)
@@ -1482,14 +1490,16 @@ bool Logger::Setup() {
     compression_helper_ = new CompressionHelper(kCompressionWindowSize);
   }
 
-  is_logging_ = start_logging;
+  if (start_logging) {
+    logging_nesting_ = 1;
+  }
 
   if (FLAG_prof) {
     profiler_ = new Profiler();
     if (!FLAG_prof_auto) {
       profiler_->pause();
     } else {
-      is_logging_ = true;
+      logging_nesting_ = 1;
     }
     if (!FLAG_prof_lazy) {
       profiler_->Engage();
index eb8369c..613a1e2 100644 (file)
@@ -265,7 +265,7 @@ class Logger {
   }
 
   static bool is_logging() {
-    return is_logging_;
+    return logging_nesting_ > 0;
   }
 
   // Pause/Resume collection of profiling data.
@@ -330,6 +330,9 @@ class Logger {
   // Logs a StringEvent regardless of whether FLAG_log is true.
   static void UncheckedStringEvent(const char* name, const char* value);
 
+  // Logs an IntEvent regardless of whether FLAG_log is true.
+  static void UncheckedIntEvent(const char* name, int value);
+
   // Stops logging and profiling in case of insufficient resources.
   static void StopLoggingAndProfiling();
 
@@ -372,7 +375,7 @@ class Logger {
 
   friend class LoggerTestHelper;
 
-  static bool is_logging_;
+  static int logging_nesting_;
   static int cpu_profiler_nesting_;
   static int heap_profiler_nesting_;
 #else
index ccc2037..9da2552 100644 (file)
@@ -73,6 +73,16 @@ const kDayMask            = 0x01f;
 const kYearShift          = 9;
 const kMonthShift         = 5;
 
+# Limits for parts of the date, so that we support all the dates that
+# ECMA 262 - 15.9.1.1 requires us to, but at the same time be sure that
+# the date (days since 1970) is in SMI range.
+const kMinYear  = -1000000;
+const kMaxYear  = 1000000;
+const kMinMonth = -10000000;
+const kMaxMonth = 10000000;
+const kMinDate  = -100000000;
+const kMaxDate  = 100000000;
+
 # Type query macros.
 #
 # Note: We have special support for typeof(foo) === 'bar' in the compiler.
index 5745e61..034f32d 100644 (file)
@@ -84,7 +84,7 @@ function MathCeil(x) {
 // ECMA 262 - 15.8.2.7
 function MathCos(x) {
   if (!IS_NUMBER(x)) x = ToNumber(x);
-  return %Math_cos(x);
+  return %_Math_cos(x);
 }
 
 // ECMA 262 - 15.8.2.8
@@ -159,7 +159,7 @@ function MathMin(arg1, arg2) {  // length == 2
 function MathPow(x, y) {
   if (!IS_NUMBER(x)) x = ToNumber(x);
   if (!IS_NUMBER(y)) y = ToNumber(y);
-  return %Math_pow(x, y);
+  return %_Math_pow(x, y);
 }
 
 // ECMA 262 - 15.8.2.14
@@ -176,13 +176,13 @@ function MathRound(x) {
 // ECMA 262 - 15.8.2.16
 function MathSin(x) {
   if (!IS_NUMBER(x)) x = ToNumber(x);
-  return %Math_sin(x);
+  return %_Math_sin(x);
 }
 
 // ECMA 262 - 15.8.2.17
 function MathSqrt(x) {
   if (!IS_NUMBER(x)) x = ToNumber(x);
-  return %Math_sqrt(x);
+  return %_Math_sqrt(x);
 }
 
 // ECMA 262 - 15.8.2.18
index e16b1b2..7cb1d20 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "api.h"
 #include "execution.h"
+#include "messages.h"
 #include "spaces-inl.h"
 #include "top.h"
 
index ca82afe..5848115 100644 (file)
@@ -127,6 +127,7 @@ function FormatMessage(message) {
       malformed_regexp:             "Invalid regular expression: /%0/: %1",
       unterminated_regexp:          "Invalid regular expression: missing /",
       regexp_flags:                 "Cannot supply flags when constructing one RegExp from another",
+      incompatible_method_receiver: "Method %0 called on incompatible receiver %1",
       invalid_lhs_in_assignment:    "Invalid left-hand side in assignment",
       invalid_lhs_in_for_in:        "Invalid left-hand side in for-in",
       invalid_lhs_in_postfix_op:    "Invalid left-hand side expression in postfix operation",
index 2de45f6..facccc2 100644 (file)
@@ -81,7 +81,7 @@ CodeGenerator::CodeGenerator(MacroAssembler* masm)
 // a1: called JS function
 // cp: callee's context
 
-void CodeGenerator::Generate(CompilationInfo* info, Mode mode) {
+void CodeGenerator::Generate(CompilationInfo* infomode) {
   UNIMPLEMENTED_MIPS();
 }
 
@@ -292,6 +292,16 @@ void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) {
 }
 
 
+void CodeGenerator::GenerateMathPow(ZoneList<Expression*>* args) {
+  UNIMPLEMENTED_MIPS();
+}
+
+
+void CodeGenerator::GenerateMathSqrt(ZoneList<Expression*>* args) {
+  UNIMPLEMENTED_MIPS();
+}
+
+
 // This should generate code that performs a charCodeAt() call or returns
 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt.
 // It is not yet implemented on ARM, so it always goes to the slow case.
@@ -300,6 +310,11 @@ void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
 }
 
 
+void CodeGenerator::GenerateCharFromCode(ZoneList<Expression*>* args) {
+  UNIMPLEMENTED_MIPS();
+}
+
+
 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
   UNIMPLEMENTED_MIPS();
 }
@@ -457,6 +472,34 @@ void CEntryStub::Generate(MacroAssembler* masm) {
 
 void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
   UNIMPLEMENTED_MIPS();
+
+  // Save callee saved registers on the stack.
+  __ MultiPush(kCalleeSaved | ra.bit());
+
+  // ********** State **********
+  //
+  // * Registers:
+  // a0: entry_address
+  // a1: function
+  // a2: reveiver_pointer
+  // a3: argc
+  //
+  // * Stack:
+  // ---------------------------
+  // args
+  // ---------------------------
+  // 4 args slots
+  // ---------------------------
+  // callee saved registers + ra
+  // ---------------------------
+  //
+  // ***************************
+
+  __ break_(0x1234);
+
+  // Restore callee saved registers from the stack.
+  __ MultiPop(kCalleeSaved | ra.bit());
+
   // Load a result.
   __ li(v0, Operand(0x1234));
   __ jr(ra);
index 147b872..987dcca 100644 (file)
@@ -157,11 +157,10 @@ class CodeGenerator: public AstVisitor {
  private:
   // Construction/Destruction.
   explicit CodeGenerator(MacroAssembler* masm);
-  virtual ~CodeGenerator() { delete masm_; }
 
   // Accessors.
   inline bool is_eval();
-  Scope* scope() const { return scope_; }
+  inline Scope* scope();
 
   // Generating deferred code.
   void ProcessDeferred();
@@ -184,7 +183,7 @@ class CodeGenerator: public AstVisitor {
 #undef DEF_VISIT
 
   // Main code generation function
-  void Generate(CompilationInfo* info, Mode mode);
+  void Generate(CompilationInfo* info);
 
   struct InlineRuntimeLUT {
     void (CodeGenerator::*method)(ZoneList<Expression*>*);
@@ -227,6 +226,9 @@ class CodeGenerator: public AstVisitor {
   // Fast support for charCodeAt(n).
   void GenerateFastCharCodeAt(ZoneList<Expression*>* args);
 
+  // Fast support for string.charAt(n) and string[n].
+  void GenerateCharFromCode(ZoneList<Expression*>* args);
+
   // Fast support for object equality testing.
   void GenerateObjectEquals(ZoneList<Expression*>* args);
 
@@ -244,6 +246,11 @@ class CodeGenerator: public AstVisitor {
   void GenerateRegExpExec(ZoneList<Expression*>* args);
   void GenerateNumberToString(ZoneList<Expression*>* args);
 
+  // Fast support for Math.pow().
+  void GenerateMathPow(ZoneList<Expression*>* args);
+  // Fast support for Math.sqrt().
+  void GenerateMathPow(ZoneList<Expression*>* args);
+
 
   // Fast support for Math.sin and Math.cos.
   inline void GenerateMathSin(ZoneList<Expression*>* args);
@@ -302,6 +309,7 @@ class CodeGenerator: public AstVisitor {
   friend class JumpTarget;
   friend class Reference;
   friend class FastCodeGenerator;
+  friend class FullCodeGenerator;
   friend class FullCodeGenSyntaxChecker;
 
   DISALLOW_COPY_AND_ASSIGN(CodeGenerator);
index c47f632..48a0ce6 100644 (file)
@@ -35,6 +35,14 @@ namespace internal {
 
 #define __ ACCESS_MASM(masm_)
 
+Register FastCodeGenerator::accumulator0() { return no_reg; }
+Register FastCodeGenerator::accumulator1() { return no_reg; }
+Register FastCodeGenerator::scratch0() { return no_reg; }
+Register FastCodeGenerator::scratch1() { return no_reg; }
+Register FastCodeGenerator::receiver_reg() { return no_reg; }
+Register FastCodeGenerator::context_reg() { return no_reg; }
+
+
 void FastCodeGenerator::Generate(CompilationInfo* info) {
   UNIMPLEMENTED_MIPS();
 }
@@ -45,7 +53,17 @@ void FastCodeGenerator::EmitThisPropertyStore(Handle<String> name) {
 }
 
 
-void FastCodeGenerator::EmitGlobalVariableLoad(Handle<String> name) {
+void FastCodeGenerator::EmitGlobalVariableLoad(Handle<Object> name) {
+  UNIMPLEMENTED_MIPS();
+}
+
+
+void FastCodeGenerator::EmitThisPropertyLoad(Handle<String> name) {
+  UNIMPLEMENTED_MIPS();
+}
+
+
+void FastCodeGenerator::EmitBitOr() {
   UNIMPLEMENTED_MIPS();
 }
 
index 920329e..3c29e99 100644 (file)
@@ -146,6 +146,11 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
 }
 
 
+void FullCodeGenerator::VisitAssignment(Assignment* expr) {
+  UNIMPLEMENTED_MIPS();
+}
+
+
 void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
   UNIMPLEMENTED_MIPS();
 }
index 5598cdf..6056166 100644 (file)
@@ -90,11 +90,6 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) {
 
 
 void LoadIC::GenerateMiss(MacroAssembler* masm) {
-  Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss)));
-}
-
-
-void LoadIC::Generate(MacroAssembler* masm, const ExternalReference& f) {
   UNIMPLEMENTED_MIPS();
 }
 
@@ -120,11 +115,6 @@ Object* KeyedLoadIC_Miss(Arguments args);
 
 
 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
-  Generate(masm, ExternalReference(IC_Utility(kKeyedLoadIC_Miss)));
-}
-
-
-void KeyedLoadIC::Generate(MacroAssembler* masm, const ExternalReference& f) {
   UNIMPLEMENTED_MIPS();
 }
 
@@ -145,24 +135,23 @@ void KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm,
 }
 
 
-void KeyedStoreIC::Generate(MacroAssembler* masm,
-                            const ExternalReference& f) {
+void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
   UNIMPLEMENTED_MIPS();
 }
 
 
-void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
+void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm,
+                                         ExternalArrayType array_type) {
   UNIMPLEMENTED_MIPS();
 }
 
 
-void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm,
-                                         ExternalArrayType array_type) {
+void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
   UNIMPLEMENTED_MIPS();
 }
 
 
-void KeyedStoreIC::GenerateExtendStorage(MacroAssembler* masm) {
+void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
   UNIMPLEMENTED_MIPS();
 }
 
@@ -172,12 +161,12 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
 }
 
 
-void StoreIC::GenerateExtendStorage(MacroAssembler* masm) {
+void StoreIC::GenerateMiss(MacroAssembler* masm) {
   UNIMPLEMENTED_MIPS();
 }
 
 
-void StoreIC::GenerateMiss(MacroAssembler* masm) {
+void StoreIC::GenerateArrayLength(MacroAssembler* masm) {
   UNIMPLEMENTED_MIPS();
 }
 
index 3301d19..e8398a8 100644 (file)
@@ -31,6 +31,7 @@
 #include "codegen-inl.h"
 #include "jump-target-inl.h"
 #include "register-allocator-inl.h"
+#include "virtual-frame-inl.h"
 
 namespace v8 {
 namespace internal {
index b733bdd..e49858b 100644 (file)
@@ -422,7 +422,7 @@ void MacroAssembler::MultiPopReversed(RegList regs) {
 // Trashes the at register if no scratch register is provided.
 void MacroAssembler::Branch(Condition cond, int16_t offset, Register rs,
                             const Operand& rt, Register scratch) {
-  Register r2;
+  Register r2 = no_reg;
   if (rt.is_reg()) {
     // We don't want any other register but scratch clobbered.
     ASSERT(!scratch.is(rs) && !scratch.is(rt.rm_));
@@ -489,7 +489,7 @@ void MacroAssembler::Branch(Condition cond, int16_t offset, Register rs,
 
 void MacroAssembler::Branch(Condition cond,  Label* L, Register rs,
                             const Operand& rt, Register scratch) {
-  Register r2;
+  Register r2 = no_reg;
   if (rt.is_reg()) {
     r2 = rt.rm_;
   } else if (cond != cc_always) {
@@ -559,7 +559,7 @@ void MacroAssembler::Branch(Condition cond,  Label* L, Register rs,
 // cases, so we keep slt and add an intermediate third instruction.
 void MacroAssembler::BranchAndLink(Condition cond, int16_t offset, Register rs,
                                    const Operand& rt, Register scratch) {
-  Register r2;
+  Register r2 = no_reg;
   if (rt.is_reg()) {
     r2 = rt.rm_;
   } else if (cond != cc_always) {
@@ -634,7 +634,7 @@ void MacroAssembler::BranchAndLink(Condition cond, int16_t offset, Register rs,
 
 void MacroAssembler::BranchAndLink(Condition cond, Label* L, Register rs,
                                    const Operand& rt, Register scratch) {
-  Register r2;
+  Register r2 = no_reg;
   if (rt.is_reg()) {
     r2 = rt.rm_;
   } else if (cond != cc_always) {
@@ -787,6 +787,16 @@ void MacroAssembler::Call(Label* target) {
 }
 
 
+#ifdef ENABLE_DEBUGGER_SUPPORT
+  // ---------------------------------------------------------------------------
+  // Debugger Support
+
+  void MacroAssembler::DebugBreak() {
+    UNIMPLEMENTED_MIPS();
+  }
+#endif
+
+
 // ---------------------------------------------------------------------------
 // Exception handling
 
@@ -826,14 +836,21 @@ void MacroAssembler::CallRuntime(Runtime::FunctionId fid, int num_arguments) {
 }
 
 
-void MacroAssembler::TailCallRuntime(const ExternalReference& ext,
+void MacroAssembler::TailCallExternalReference(const ExternalReference& ext,
+                                               int num_arguments,
+                                               int result_size) {
+  UNIMPLEMENTED_MIPS();
+}
+
+
+void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid,
                                      int num_arguments,
                                      int result_size) {
-  UNIMPLEMENTED_MIPS();
+  TailCallExternalReference(ExternalReference(fid), num_arguments, result_size);
 }
 
 
-void MacroAssembler::JumpToRuntime(const ExternalReference& builtin) {
+void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin) {
   UNIMPLEMENTED_MIPS();
 }
 
index aea9836..b34488c 100644 (file)
@@ -115,11 +115,7 @@ class MacroAssembler: public Assembler {
                 Heap::RootListIndex index,
                 Condition cond, Register src1, const Operand& src2);
 
-  // Sets the remembered set bit for [address+offset], where address is the
-  // address of the heap object 'object'.  The address must be in the first 8K
-  // of an allocated page. The 'scratch' register is used in the
-  // implementation and all 3 registers are clobbered by the operation, as
-  // well as the ip register.
+  // Sets the remembered set bit for [address+offset].
   void RecordWrite(Register object, Register offset, Register scratch);
 
 
@@ -182,19 +178,8 @@ class MacroAssembler: public Assembler {
 
 
   // Push multiple registers on the stack.
-  // With MultiPush, lower registers are pushed first on the stack.
-  // For example if you push t0, t1, s0, and ra you get:
-  // |                       |
-  // |-----------------------|
-  // |         t0            |                     +
-  // |-----------------------|                    |
-  // |         t1            |                    |
-  // |-----------------------|                    |
-  // |         s0            |                    v
-  // |-----------------------|                     -
-  // |         ra            |
-  // |-----------------------|
-  // |                       |
+  // Registers are saved in numerical order, with higher numbered registers
+  // saved in higher memory addresses
   void MultiPush(RegList regs);
   void MultiPushReversed(RegList regs);
   void Push(Register src) {
@@ -224,6 +209,20 @@ class MacroAssembler: public Assembler {
   }
 
 
+#ifdef ENABLE_DEBUGGER_SUPPORT
+  // ---------------------------------------------------------------------------
+  // Debugger Support
+
+  void SaveRegistersToMemory(RegList regs);
+  void RestoreRegistersFromMemory(RegList regs);
+  void CopyRegistersFromMemoryToStack(Register base, RegList regs);
+  void CopyRegistersFromStackToMemory(Register base,
+                                      Register scratch,
+                                      RegList regs);
+  void DebugBreak();
+#endif
+
+
   // ---------------------------------------------------------------------------
   // Exception handling
 
@@ -268,21 +267,25 @@ class MacroAssembler: public Assembler {
   void StubReturn(int argc);
 
   // Call a runtime routine.
-  // Eventually this should be used for all C calls.
   void CallRuntime(Runtime::Function* f, int num_arguments);
 
   // Convenience function: Same as above, but takes the fid instead.
   void CallRuntime(Runtime::FunctionId fid, int num_arguments);
 
   // Tail call of a runtime routine (jump).
-  // Like JumpToRuntime, but also takes care of passing the number
+  // Like JumpToExternalReference, but also takes care of passing the number
   // of parameters.
-  void TailCallRuntime(const ExternalReference& ext,
+  void TailCallExternalReference(const ExternalReference& ext,
+                                 int num_arguments,
+                                 int result_size);
+
+  // Convenience function: tail call a runtime routine (jump).
+  void TailCallRuntime(Runtime::FunctionId fid,
                        int num_arguments,
                        int result_size);
 
   // Jump to the builtin routine.
-  void JumpToRuntime(const ExternalReference& builtin);
+  void JumpToExternalReference(const ExternalReference& builtin);
 
   // Invoke specified builtin JavaScript function. Adds an entry to
   // the unresolved list if the name does not resolve.
index a87a49b..669fdaa 100644 (file)
@@ -72,20 +72,6 @@ void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
 }
 
 
-// Generate code to load the length from a string object and return the length.
-// If the receiver object is not a string or a wrapped string object the
-// execution continues at the miss label. The register containing the
-// receiver is potentially clobbered.
-void StubCompiler::GenerateLoadStringLength2(MacroAssembler* masm,
-                                             Register receiver,
-                                             Register scratch1,
-                                             Register scratch2,
-                                             Label* miss) {
-  UNIMPLEMENTED_MIPS();
-  __ break_(0x249);
-}
-
-
 void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
                                                  Register receiver,
                                                  Register scratch1,
@@ -99,7 +85,6 @@ void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
 // After executing generated code, the receiver_reg and name_reg
 // may be clobbered.
 void StubCompiler::GenerateStoreField(MacroAssembler* masm,
-                                      Builtins::Name storage_extend,
                                       JSObject* object,
                                       int index,
                                       Map* transition,
@@ -120,18 +105,6 @@ void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
 #define __ ACCESS_MASM(masm())
 
 
-Register StubCompiler::CheckPrototypes(JSObject* object,
-                                       Register object_reg,
-                                       JSObject* holder,
-                                       Register holder_reg,
-                                       Register scratch,
-                                       String* name,
-                                       Label* miss) {
-  UNIMPLEMENTED_MIPS();
-  return at;    // UNIMPLEMENTED RETURN
-}
-
-
 void StubCompiler::GenerateLoadField(JSObject* object,
                                      JSObject* holder,
                                      Register receiver,
@@ -192,7 +165,7 @@ Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
 }
 
 
-Object* CallStubCompiler::CompileCallField(Object* object,
+Object* CallStubCompiler::CompileCallField(JSObject* object,
                                            JSObject* holder,
                                            int index,
                                            String* name) {
@@ -211,7 +184,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
 }
 
 
-Object* CallStubCompiler::CompileCallInterceptor(Object* object,
+Object* CallStubCompiler::CompileCallInterceptor(JSObject* object,
                                                  JSObject* holder,
                                                  String* name) {
   UNIMPLEMENTED_MIPS();
index fad7ec4..e89882f 100644 (file)
@@ -32,6 +32,7 @@
 #include "codegen-inl.h"
 #include "register-allocator-inl.h"
 #include "scopes.h"
+#include "virtual-frame-inl.h"
 
 namespace v8 {
 namespace internal {
@@ -41,17 +42,6 @@ namespace internal {
 
 #define __ ACCESS_MASM(masm())
 
-
-// On entry to a function, the virtual frame already contains the
-// receiver and the parameters.  All initial frame elements are in
-// memory.
-VirtualFrame::VirtualFrame()
-    : elements_(parameter_count() + local_count() + kPreallocatedElements),
-      stack_pointer_(parameter_count()) {  // 0-based index of TOS.
-  UNIMPLEMENTED_MIPS();
-}
-
-
 void VirtualFrame::SyncElementBelowStackPointer(int index) {
   UNREACHABLE();
 }
index 79f973f..e5bc93f 100644 (file)
@@ -61,16 +61,17 @@ class VirtualFrame : public ZoneObject {
   static const int kIllegalIndex = -1;
 
   // Construct an initial virtual frame on entry to a JS function.
-  VirtualFrame();
+  inline VirtualFrame();
 
   // Construct a virtual frame as a clone of an existing one.
-  explicit VirtualFrame(VirtualFrame* original);
+  explicit inline VirtualFrame(VirtualFrame* original);
 
   CodeGenerator* cgen() { return CodeGeneratorScope::Current(); }
   MacroAssembler* masm() { return cgen()->masm(); }
 
   // Create a duplicate of an existing valid frame element.
-  FrameElement CopyElementAt(int index);
+  FrameElement CopyElementAt(int index,
+                             NumberInfo::Type info = NumberInfo::kUnknown);
 
   // The number of elements on the virtual frame.
   int element_count() { return elements_.length(); }
@@ -366,9 +367,9 @@ class VirtualFrame : public ZoneObject {
   void EmitMultiPushReversed(RegList regs);  // higher first
 
   // Push an element on the virtual frame.
-  void Push(Register reg);
-  void Push(Handle<Object> value);
-  void Push(Smi* value) { Push(Handle<Object>(value)); }
+  inline void Push(Register reg, NumberInfo::Type info = NumberInfo::kUnknown);
+  inline void Push(Handle<Object> value);
+  inline void Push(Smi* value);
 
   // Pushing a result invalidates it (its contents become owned by the frame).
   void Push(Result* result) {
@@ -384,7 +385,7 @@ class VirtualFrame : public ZoneObject {
   // Nip removes zero or more elements from immediately below the top
   // of the frame, leaving the previous top-of-frame value on top of
   // the frame.  Nip(k) is equivalent to x = Pop(), Drop(k), Push(x).
-  void Nip(int num_dropped);
+  inline void Nip(int num_dropped);
 
   // This pushes 4 arguments slots on the stack and saves asked 'a' registers
   // 'a' registers are arguments register a0 to a3.
@@ -483,7 +484,7 @@ class VirtualFrame : public ZoneObject {
 
   // Push a copy of a frame slot (typically a local or parameter) on top of
   // the frame.
-  void PushFrameSlotAt(int index);
+  inline void PushFrameSlotAt(int index);
 
   // Push a the value of a frame slot (typically a local or parameter) on
   // top of the frame and invalidate the slot.
@@ -534,7 +535,7 @@ class VirtualFrame : public ZoneObject {
   // (via PrepareForCall).
   void RawCallCodeObject(Handle<Code> code, RelocInfo::Mode rmode);
 
-  bool Equals(VirtualFrame* other);
+  inline bool Equals(VirtualFrame* other);
 
   // Classes that need raw access to the elements_ array.
   friend class DeferredCode;
index c6f32e4..bfc0d9f 100644 (file)
 namespace v8 {
 namespace internal {
 
-class NumberInfo : public AllStatic {
+//        Unknown
+//           |
+//         Number
+//         /    |
+//  HeapNumber Integer32
+//        |      |
+//        |     Smi
+//        |     /
+//      Uninitialized.
+
+class NumberInfo {
  public:
-  enum Type {
-    kUnknown = 0,
-    kNumber = 1,
-    kSmi = 3,
-    kHeapNumber = 5,
-    kUninitialized = 7
-  };
+  NumberInfo() { }
+
+  static inline NumberInfo Unknown();
+  // We know it's a number of some sort.
+  static inline NumberInfo Number();
+  // We know it's signed or unsigned 32 bit integer.
+  static inline NumberInfo Integer32();
+  // We know it's a Smi.
+  static inline NumberInfo Smi();
+  // We know it's a heap number.
+  static inline NumberInfo HeapNumber();
+  // We haven't started collecting info yet.
+  static inline NumberInfo Uninitialized();
+
+  // Return compact representation.  Very sensitive to enum values below!
+  int ThreeBitRepresentation() {
+    ASSERT(type_ != kUninitializedType);
+    int answer = type_ > 6 ? type_ -2 : type_;
+    ASSERT(answer >= 0);
+    ASSERT(answer <= 7);
+    return answer;
+  }
+
+  // Decode compact representation.  Very sensitive to enum values below!
+  static NumberInfo ExpandedRepresentation(int three_bit_representation) {
+    Type t = static_cast<Type>(three_bit_representation >= 6 ?
+                               three_bit_representation + 2 :
+                               three_bit_representation);
+    ASSERT(t == kUnknownType ||
+           t == kNumberType ||
+           t == kInteger32Type ||
+           t == kSmiType ||
+           t == kHeapNumberType);
+    return NumberInfo(t);
+  }
+
+  int ToInt() {
+    return type_;
+  }
+
+  static NumberInfo FromInt(int bit_representation) {
+    Type t = static_cast<Type>(bit_representation);
+    ASSERT(t == kUnknownType ||
+           t == kNumberType ||
+           t == kInteger32Type ||
+           t == kSmiType ||
+           t == kHeapNumberType);
+    return NumberInfo(t);
+  }
 
   // Return the weakest (least precise) common type.
-  static Type Combine(Type a, Type b) {
-    // Make use of the order of enum values.
-    return static_cast<Type>(a & b);
+  static NumberInfo Combine(NumberInfo a, NumberInfo b) {
+    return NumberInfo(static_cast<Type>(a.type_ & b.type_));
+  }
+
+  inline bool IsUnknown() {
+    return type_ == kUnknownType;
+  }
+
+  inline bool IsNumber() {
+    ASSERT(type_ != kUninitializedType);
+    return ((type_ & kNumberType) == kNumberType);
+  }
+
+  inline bool IsSmi() {
+    ASSERT(type_ != kUninitializedType);
+    return ((type_ & kSmiType) == kSmiType);
+  }
+
+  inline bool IsInteger32() {
+    ASSERT(type_ != kUninitializedType);
+    return ((type_ & kInteger32Type) == kInteger32Type);
+  }
+
+  inline bool IsHeapNumber() {
+    ASSERT(type_ != kUninitializedType);
+    return ((type_ & kHeapNumberType) == kHeapNumberType);
   }
 
-  static bool IsNumber(Type a) {
-    ASSERT(a != kUninitialized);
-    return ((a & kNumber) != 0);
+  inline bool IsUninitialized() {
+    return type_ == kUninitializedType;
   }
 
-  static const char* ToString(Type a) {
-    switch (a) {
-      case kUnknown: return "UnknownType";
-      case kNumber: return "NumberType";
-      case kSmi: return "SmiType";
-      case kHeapNumber: return "HeapNumberType";
-      case kUninitialized:
+  const char* ToString() {
+    switch (type_) {
+      case kUnknownType: return "UnknownType";
+      case kNumberType: return "NumberType";
+      case kSmiType: return "SmiType";
+      case kHeapNumberType: return "HeapNumberType";
+      case kInteger32Type: return "Integer32Type";
+      case kUninitializedType:
         UNREACHABLE();
         return "UninitializedType";
     }
     UNREACHABLE();
     return "Unreachable code";
   }
+
+ private:
+  enum Type {
+    kUnknownType = 0,
+    kNumberType = 1,
+    kInteger32Type = 3,
+    kSmiType = 7,
+    kHeapNumberType = 9,
+    kUninitializedType = 15
+  };
+  explicit inline NumberInfo(Type t) : type_(t) { }
+
+  Type type_;
 };
 
+
+NumberInfo NumberInfo::Unknown() {
+  return NumberInfo(kUnknownType);
+}
+
+
+NumberInfo NumberInfo::Number() {
+  return NumberInfo(kNumberType);
+}
+
+
+NumberInfo NumberInfo::Integer32() {
+  return NumberInfo(kInteger32Type);
+}
+
+
+NumberInfo NumberInfo::Smi() {
+  return NumberInfo(kSmiType);
+}
+
+
+NumberInfo NumberInfo::HeapNumber() {
+  return NumberInfo(kHeapNumberType);
+}
+
+
+NumberInfo NumberInfo::Uninitialized() {
+  return NumberInfo(kUninitializedType);
+}
+
 } }  // namespace v8::internal
 
 #endif  // V8_NUMBER_INFO_H_
index 9415bc1..492b492 100644 (file)
@@ -644,6 +644,24 @@ void Map::MapVerify() {
 }
 
 
+void CodeCache::CodeCachePrint() {
+  HeapObject::PrintHeader("CodeCache");
+  PrintF("\n - default_cache: ");
+  default_cache()->ShortPrint();
+  PrintF("\n - normal_type_cache: ");
+  normal_type_cache()->ShortPrint();
+}
+
+
+void CodeCache::CodeCacheVerify() {
+  VerifyHeapPointer(default_cache());
+  VerifyHeapPointer(normal_type_cache());
+  ASSERT(default_cache()->IsFixedArray());
+  ASSERT(normal_type_cache()->IsUndefined()
+         || normal_type_cache()->IsCodeCacheHashTable());
+}
+
+
 void FixedArray::FixedArrayPrint() {
   HeapObject::PrintHeader("FixedArray");
   PrintF(" - length: %d", length());
index 455a84c..18f45f3 100644 (file)
@@ -564,6 +564,11 @@ bool Object::IsCompilationCacheTable() {
 }
 
 
+bool Object::IsCodeCacheHashTable() {
+  return IsHashTable();
+}
+
+
 bool Object::IsMapCache() {
   return IsHashTable();
 }
@@ -840,15 +845,17 @@ Failure* Failure::OutOfMemoryException() {
 
 
 intptr_t Failure::value() const {
-  return reinterpret_cast<intptr_t>(this) >> kFailureTagSize;
+  return static_cast<intptr_t>(
+      reinterpret_cast<uintptr_t>(this) >> kFailureTagSize);
 }
 
 
 Failure* Failure::RetryAfterGC(int requested_bytes) {
   // Assert that the space encoding fits in the three bytes allotted for it.
   ASSERT((LAST_SPACE & ~kSpaceTagMask) == 0);
-  intptr_t requested = requested_bytes >> kObjectAlignmentBits;
-  int tag_bits = kSpaceTagSize + kFailureTypeTagSize;
+  uintptr_t requested =
+      static_cast<uintptr_t>(requested_bytes >> kObjectAlignmentBits);
+  int tag_bits = kSpaceTagSize + kFailureTypeTagSize + kFailureTagSize;
   if (((requested << tag_bits) >> tag_bits) != requested) {
     // No room for entire requested size in the bits. Round down to
     // maximally representable size.
@@ -861,7 +868,8 @@ Failure* Failure::RetryAfterGC(int requested_bytes) {
 
 
 Failure* Failure::Construct(Type type, intptr_t value) {
-  intptr_t info = (static_cast<intptr_t>(value) << kFailureTypeTagSize) | type;
+  uintptr_t info =
+      (static_cast<uintptr_t>(value) << kFailureTypeTagSize) | type;
   ASSERT(((info << kFailureTagSize) >> kFailureTagSize) == info);
   return reinterpret_cast<Failure*>((info << kFailureTagSize) | kFailureTag);
 }
@@ -1394,6 +1402,11 @@ void FixedArray::set_the_hole(int index) {
 }
 
 
+Object** FixedArray::data_start() {
+  return HeapObject::RawField(this, kHeaderSize);
+}
+
+
 bool DescriptorArray::IsEmpty() {
   ASSERT(this == Heap::empty_descriptor_array() ||
          this->length() > 2);
@@ -1560,6 +1573,7 @@ CAST_ACCESSOR(FixedArray)
 CAST_ACCESSOR(DescriptorArray)
 CAST_ACCESSOR(SymbolTable)
 CAST_ACCESSOR(CompilationCacheTable)
+CAST_ACCESSOR(CodeCacheHashTable)
 CAST_ACCESSOR(MapCache)
 CAST_ACCESSOR(String)
 CAST_ACCESSOR(SeqString)
@@ -1637,13 +1651,11 @@ bool String::Equals(String* other) {
 }
 
 
-Object* String::TryFlattenIfNotFlat() {
+Object* String::TryFlatten(PretenureFlag pretenure) {
   // We don't need to flatten strings that are already flat.  Since this code
   // is inlined, it can be helpful in the flat case to not call out to Flatten.
-  if (!IsFlat()) {
-    return TryFlatten();
-  }
-  return this;
+  if (IsFlat()) return this;
+  return SlowTryFlatten(pretenure);
 }
 
 
@@ -2143,14 +2155,14 @@ int Code::arguments_count() {
 
 
 CodeStub::Major Code::major_key() {
-  ASSERT(kind() == STUB);
+  ASSERT(kind() == STUB || kind() == BINARY_OP_IC);
   return static_cast<CodeStub::Major>(READ_BYTE_FIELD(this,
                                                       kStubMajorKeyOffset));
 }
 
 
 void Code::set_major_key(CodeStub::Major major) {
-  ASSERT(kind() == STUB);
+  ASSERT(kind() == STUB || kind() == BINARY_OP_IC);
   ASSERT(0 <= major && major < 256);
   WRITE_BYTE_FIELD(this, kStubMajorKeyOffset, major);
 }
@@ -2252,7 +2264,7 @@ void Map::set_prototype(Object* value, WriteBarrierMode mode) {
 
 ACCESSORS(Map, instance_descriptors, DescriptorArray,
           kInstanceDescriptorsOffset)
-ACCESSORS(Map, code_cache, FixedArray, kCodeCacheOffset)
+ACCESSORS(Map, code_cache, Object, kCodeCacheOffset)
 ACCESSORS(Map, constructor, Object, kConstructorOffset)
 
 ACCESSORS(JSFunction, shared, SharedFunctionInfo, kSharedFunctionInfoOffset)
@@ -2390,6 +2402,9 @@ INT_ACCESSORS(SharedFunctionInfo, this_property_assignments_count,
               kThisPropertyAssignmentsCountOffset)
 
 
+ACCESSORS(CodeCache, default_cache, FixedArray, kDefaultCacheOffset)
+ACCESSORS(CodeCache, normal_type_cache, Object, kNormalTypeCacheOffset)
+
 bool Script::HasValidSource() {
   Object* src = this->source();
   if (!src->IsString()) return true;
index 53423af..7f4ab0b 100644 (file)
@@ -673,7 +673,7 @@ static bool AnWord(String* str) {
 }
 
 
-Object* String::TryFlatten() {
+Object* String::SlowTryFlatten(PretenureFlag pretenure) {
 #ifdef DEBUG
   // Do not attempt to flatten in debug mode when allocation is not
   // allowed.  This is to avoid an assertion failure when allocating.
@@ -691,7 +691,7 @@ Object* String::TryFlatten() {
       // There's little point in putting the flat string in new space if the
       // cons string is in old space.  It can never get GCed until there is
       // an old space GC.
-      PretenureFlag tenure = Heap::InNewSpace(this) ? NOT_TENURED : TENURED;
+      PretenureFlag tenure = Heap::InNewSpace(this) ? pretenure : TENURED;
       int len = length();
       Object* object;
       String* result;
@@ -2180,7 +2180,7 @@ Object* JSObject::NormalizeProperties(PropertyNormalizationMode mode,
     property_count += 2;  // Make space for two more properties.
   }
   Object* obj =
-      StringDictionary::Allocate(property_count * 2);
+      StringDictionary::Allocate(property_count);
   if (obj->IsFailure()) return obj;
   StringDictionary* dictionary = StringDictionary::cast(obj);
 
@@ -2768,7 +2768,7 @@ Object* JSObject::DefineGetterSetter(String* name,
   }
 
   // Try to flatten before operating on the string.
-  name->TryFlattenIfNotFlat();
+  name->TryFlatten();
 
   // Check if there is an API defined callback object which prohibits
   // callback overwriting in this object or it's prototype chain.
@@ -3033,19 +3033,79 @@ Object* Map::CopyDropTransitions() {
 
 
 Object* Map::UpdateCodeCache(String* name, Code* code) {
+  // Allocate the code cache if not present.
+  if (code_cache()->IsFixedArray()) {
+    Object* result = Heap::AllocateCodeCache();
+    if (result->IsFailure()) return result;
+    set_code_cache(result);
+  }
+
+  // Update the code cache.
+  return CodeCache::cast(code_cache())->Update(name, code);
+}
+
+
+Object* Map::FindInCodeCache(String* name, Code::Flags flags) {
+  // Do a lookup if a code cache exists.
+  if (!code_cache()->IsFixedArray()) {
+    return CodeCache::cast(code_cache())->Lookup(name, flags);
+  } else {
+    return Heap::undefined_value();
+  }
+}
+
+
+int Map::IndexInCodeCache(String* name, Code* code) {
+  // Get the internal index if a code cache exists.
+  if (!code_cache()->IsFixedArray()) {
+    return CodeCache::cast(code_cache())->GetIndex(name, code);
+  }
+  return -1;
+}
+
+
+void Map::RemoveFromCodeCache(String* name, Code* code, int index) {
+  // No GC is supposed to happen between a call to IndexInCodeCache and
+  // RemoveFromCodeCache so the code cache must be there.
+  ASSERT(!code_cache()->IsFixedArray());
+  CodeCache::cast(code_cache())->RemoveByIndex(name, code, index);
+}
+
+
+Object* CodeCache::Update(String* name, Code* code) {
   ASSERT(code->ic_state() == MONOMORPHIC);
-  FixedArray* cache = code_cache();
 
-  // When updating the code cache we disregard the type encoded in the
+  // The number of monomorphic stubs for normal load/store/call IC's can grow to
+  // a large number and therefore they need to go into a hash table. They are
+  // used to load global properties from cells.
+  if (code->type() == NORMAL) {
+    // Make sure that a hash table is allocated for the normal load code cache.
+    if (normal_type_cache()->IsUndefined()) {
+      Object* result =
+          CodeCacheHashTable::Allocate(CodeCacheHashTable::kInitialSize);
+      if (result->IsFailure()) return result;
+      set_normal_type_cache(result);
+    }
+    return UpdateNormalTypeCache(name, code);
+  } else {
+    ASSERT(default_cache()->IsFixedArray());
+    return UpdateDefaultCache(name, code);
+  }
+}
+
+
+Object* CodeCache::UpdateDefaultCache(String* name, Code* code) {
+  // When updating the default code cache we disregard the type encoded in the
   // flags. This allows call constant stubs to overwrite call field
   // stubs, etc.
   Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
 
   // First check whether we can update existing code cache without
   // extending it.
+  FixedArray* cache = default_cache();
   int length = cache->length();
   int deleted_index = -1;
-  for (int i = 0; i < length; i += 2) {
+  for (int i = 0; i < length; i += kCodeCacheEntrySize) {
     Object* key = cache->get(i);
     if (key->IsNull()) {
       if (deleted_index < 0) deleted_index = i;
@@ -3053,14 +3113,15 @@ Object* Map::UpdateCodeCache(String* name, Code* code) {
     }
     if (key->IsUndefined()) {
       if (deleted_index >= 0) i = deleted_index;
-      cache->set(i + 0, name);
-      cache->set(i + 1, code);
+      cache->set(i + kCodeCacheEntryNameOffset, name);
+      cache->set(i + kCodeCacheEntryCodeOffset, code);
       return this;
     }
     if (name->Equals(String::cast(key))) {
-      Code::Flags found = Code::cast(cache->get(i + 1))->flags();
+      Code::Flags found =
+          Code::cast(cache->get(i + kCodeCacheEntryCodeOffset))->flags();
       if (Code::RemoveTypeFromFlags(found) == flags) {
-        cache->set(i + 1, code);
+        cache->set(i + kCodeCacheEntryCodeOffset, code);
         return this;
       }
     }
@@ -3069,61 +3130,207 @@ Object* Map::UpdateCodeCache(String* name, Code* code) {
   // Reached the end of the code cache.  If there were deleted
   // elements, reuse the space for the first of them.
   if (deleted_index >= 0) {
-    cache->set(deleted_index + 0, name);
-    cache->set(deleted_index + 1, code);
+    cache->set(deleted_index + kCodeCacheEntryNameOffset, name);
+    cache->set(deleted_index + kCodeCacheEntryCodeOffset, code);
     return this;
   }
 
-  // Extend the code cache with some new entries (at least one).
-  int new_length = length + ((length >> 1) & ~1) + 2;
-  ASSERT((new_length & 1) == 0);  // must be a multiple of two
+  // Extend the code cache with some new entries (at least one). Must be a
+  // multiple of the entry size.
+  int new_length = length + ((length >> 1)) + kCodeCacheEntrySize;
+  new_length = new_length - new_length % kCodeCacheEntrySize;
+  ASSERT((new_length % kCodeCacheEntrySize) == 0);
   Object* result = cache->CopySize(new_length);
   if (result->IsFailure()) return result;
 
   // Add the (name, code) pair to the new cache.
   cache = FixedArray::cast(result);
-  cache->set(length + 0, name);
-  cache->set(length + 1, code);
-  set_code_cache(cache);
+  cache->set(length + kCodeCacheEntryNameOffset, name);
+  cache->set(length + kCodeCacheEntryCodeOffset, code);
+  set_default_cache(cache);
   return this;
 }
 
 
-Object* Map::FindInCodeCache(String* name, Code::Flags flags) {
-  FixedArray* cache = code_cache();
+Object* CodeCache::UpdateNormalTypeCache(String* name, Code* code) {
+  // Adding a new entry can cause a new cache to be allocated.
+  CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
+  Object* new_cache = cache->Put(name, code);
+  if (new_cache->IsFailure()) return new_cache;
+  set_normal_type_cache(new_cache);
+  return this;
+}
+
+
+Object* CodeCache::Lookup(String* name, Code::Flags flags) {
+  if (Code::ExtractTypeFromFlags(flags) == NORMAL) {
+    return LookupNormalTypeCache(name, flags);
+  } else {
+    return LookupDefaultCache(name, flags);
+  }
+}
+
+
+Object* CodeCache::LookupDefaultCache(String* name, Code::Flags flags) {
+  FixedArray* cache = default_cache();
   int length = cache->length();
-  for (int i = 0; i < length; i += 2) {
-    Object* key = cache->get(i);
+  for (int i = 0; i < length; i += kCodeCacheEntrySize) {
+    Object* key = cache->get(i + kCodeCacheEntryNameOffset);
     // Skip deleted elements.
     if (key->IsNull()) continue;
     if (key->IsUndefined()) return key;
     if (name->Equals(String::cast(key))) {
-      Code* code = Code::cast(cache->get(i + 1));
-      if (code->flags() == flags) return code;
+      Code* code = Code::cast(cache->get(i + kCodeCacheEntryCodeOffset));
+      if (code->flags() == flags) {
+        return code;
+      }
     }
   }
   return Heap::undefined_value();
 }
 
 
-int Map::IndexInCodeCache(Code* code) {
-  FixedArray* array = code_cache();
+Object* CodeCache::LookupNormalTypeCache(String* name, Code::Flags flags) {
+  if (!normal_type_cache()->IsUndefined()) {
+    CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
+    return cache->Lookup(name, flags);
+  } else {
+    return Heap::undefined_value();
+  }
+}
+
+
+int CodeCache::GetIndex(String* name, Code* code) {
+  // This is not used for normal load/store/call IC's.
+  if (code->type() == NORMAL) {
+    if (normal_type_cache()->IsUndefined()) return -1;
+    CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
+    return cache->GetIndex(name, code->flags());
+  }
+
+  FixedArray* array = default_cache();
   int len = array->length();
-  for (int i = 0; i < len; i += 2) {
-    if (array->get(i + 1) == code) return i + 1;
+  for (int i = 0; i < len; i += kCodeCacheEntrySize) {
+    if (array->get(i + kCodeCacheEntryCodeOffset) == code) return i + 1;
   }
   return -1;
 }
 
 
-void Map::RemoveFromCodeCache(int index) {
-  FixedArray* array = code_cache();
-  ASSERT(array->length() >= index && array->get(index)->IsCode());
-  // Use null instead of undefined for deleted elements to distinguish
-  // deleted elements from unused elements.  This distinction is used
-  // when looking up in the cache and when updating the cache.
-  array->set_null(index - 1);  // key
-  array->set_null(index);  // code
+void CodeCache::RemoveByIndex(String* name, Code* code, int index) {
+  if (code->type() == NORMAL) {
+    ASSERT(!normal_type_cache()->IsUndefined());
+    CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
+    ASSERT(cache->GetIndex(name, code->flags()) == index);
+    cache->RemoveByIndex(index);
+  } else {
+    FixedArray* array = default_cache();
+    ASSERT(array->length() >= index && array->get(index)->IsCode());
+    // Use null instead of undefined for deleted elements to distinguish
+    // deleted elements from unused elements.  This distinction is used
+    // when looking up in the cache and when updating the cache.
+    ASSERT_EQ(1, kCodeCacheEntryCodeOffset - kCodeCacheEntryNameOffset);
+    array->set_null(index - 1);  // Name.
+    array->set_null(index);  // Code.
+  }
+}
+
+
+// The key in the code cache hash table consists of the property name and the
+// code object. The actual match is on the name and the code flags. If a key
+// is created using the flags and not a code object it can only be used for
+// lookup not to create a new entry.
+class CodeCacheHashTableKey : public HashTableKey {
+ public:
+  CodeCacheHashTableKey(String* name, Code::Flags flags)
+      : name_(name), flags_(flags), code_(NULL) { }
+
+  CodeCacheHashTableKey(String* name, Code* code)
+      : name_(name),
+        flags_(code->flags()),
+        code_(code) { }
+
+
+  bool IsMatch(Object* other) {
+    if (!other->IsFixedArray()) return false;
+    FixedArray* pair = FixedArray::cast(other);
+    String* name = String::cast(pair->get(0));
+    Code::Flags flags = Code::cast(pair->get(1))->flags();
+    if (flags != flags_) {
+      return false;
+    }
+    return name_->Equals(name);
+  }
+
+  static uint32_t NameFlagsHashHelper(String* name, Code::Flags flags) {
+    return name->Hash() ^ flags;
+  }
+
+  uint32_t Hash() { return NameFlagsHashHelper(name_, flags_); }
+
+  uint32_t HashForObject(Object* obj) {
+    FixedArray* pair = FixedArray::cast(obj);
+    String* name = String::cast(pair->get(0));
+    Code* code = Code::cast(pair->get(1));
+    return NameFlagsHashHelper(name, code->flags());
+  }
+
+  Object* AsObject() {
+    ASSERT(code_ != NULL);
+    Object* obj = Heap::AllocateFixedArray(2);
+    if (obj->IsFailure()) return obj;
+    FixedArray* pair = FixedArray::cast(obj);
+    pair->set(0, name_);
+    pair->set(1, code_);
+    return pair;
+  }
+
+ private:
+  String* name_;
+  Code::Flags flags_;
+  Code* code_;
+};
+
+
+Object* CodeCacheHashTable::Lookup(String* name, Code::Flags flags) {
+  CodeCacheHashTableKey key(name, flags);
+  int entry = FindEntry(&key);
+  if (entry == kNotFound) return Heap::undefined_value();
+  return get(EntryToIndex(entry) + 1);
+}
+
+
+Object* CodeCacheHashTable::Put(String* name, Code* code) {
+  CodeCacheHashTableKey key(name, code);
+  Object* obj = EnsureCapacity(1, &key);
+  if (obj->IsFailure()) return obj;
+
+  // Don't use this, as the table might have grown.
+  CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj);
+
+  int entry = cache->FindInsertionEntry(key.Hash());
+  Object* k = key.AsObject();
+  if (k->IsFailure()) return k;
+
+  cache->set(EntryToIndex(entry), k);
+  cache->set(EntryToIndex(entry) + 1, code);
+  cache->ElementAdded();
+  return cache;
+}
+
+
+int CodeCacheHashTable::GetIndex(String* name, Code::Flags flags) {
+  CodeCacheHashTableKey key(name, flags);
+  int entry = FindEntry(&key);
+  return (entry == kNotFound) ? -1 : entry;
+}
+
+
+void CodeCacheHashTable::RemoveByIndex(int index) {
+  ASSERT(index >= 0);
+  set(EntryToIndex(index), Heap::null_value());
+  set(EntryToIndex(index) + 1, Heap::null_value());
+  ElementRemoved();
 }
 
 
@@ -3430,18 +3637,25 @@ void DescriptorArray::Sort() {
   int len = number_of_descriptors();
 
   // Bottom-up max-heap construction.
-  for (int i = 1; i < len; ++i) {
-    int child_index = i;
-    while (child_index > 0) {
-      int parent_index = ((child_index + 1) >> 1) - 1;
-      uint32_t parent_hash = GetKey(parent_index)->Hash();
+  // Index of the last node with children
+  const int max_parent_index = (len / 2) - 1;
+  for (int i = max_parent_index; i >= 0; --i) {
+    int parent_index = i;
+    const uint32_t parent_hash = GetKey(i)->Hash();
+    while (parent_index <= max_parent_index) {
+      int child_index = 2 * parent_index + 1;
       uint32_t child_hash = GetKey(child_index)->Hash();
-      if (parent_hash < child_hash) {
-        Swap(parent_index, child_index);
-      } else {
-        break;
+      if (child_index + 1 < len) {
+        uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
+        if (right_child_hash > child_hash) {
+          child_index++;
+          child_hash = right_child_hash;
+        }
       }
-      child_index = parent_index;
+      if (child_hash <= parent_hash) break;
+      Swap(parent_index, child_index);
+      // Now element at child_index could be < its children.
+      parent_index = child_index;  // parent_hash remains correct.
     }
   }
 
@@ -3451,21 +3665,21 @@ void DescriptorArray::Sort() {
     Swap(0, i);
     // Sift down the new top element.
     int parent_index = 0;
-    while (true) {
-      int child_index = ((parent_index + 1) << 1) - 1;
-      if (child_index >= i) break;
-      uint32_t child1_hash = GetKey(child_index)->Hash();
-      uint32_t child2_hash = GetKey(child_index + 1)->Hash();
-      uint32_t parent_hash = GetKey(parent_index)->Hash();
-      if (child_index + 1 >= i || child1_hash > child2_hash) {
-        if (parent_hash > child1_hash) break;
-        Swap(parent_index, child_index);
-        parent_index = child_index;
-      } else {
-        if (parent_hash > child2_hash) break;
-        Swap(parent_index, child_index + 1);
-        parent_index = child_index + 1;
+    const uint32_t parent_hash = GetKey(parent_index)->Hash();
+    const int max_parent_index = (i / 2) - 1;
+    while (parent_index <= max_parent_index) {
+      int child_index = parent_index * 2 + 1;
+      uint32_t child_hash = GetKey(child_index)->Hash();
+      if (child_index + 1 < i) {
+        uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
+        if (right_child_hash > child_hash) {
+          child_index++;
+          child_hash = right_child_hash;
+        }
       }
+      if (child_hash <= parent_hash) break;
+      Swap(parent_index, child_index);
+      parent_index = child_index;
     }
   }
 
@@ -3546,7 +3760,7 @@ int String::Utf8Length() {
   // doesn't make Utf8Length faster, but it is very likely that
   // the string will be accessed later (for example by WriteUtf8)
   // so it's still a good idea.
-  TryFlattenIfNotFlat();
+  TryFlatten();
   Access<StringInputBuffer> buffer(&string_input_buffer);
   buffer->Reset(0, this);
   int result = 0;
@@ -4637,9 +4851,9 @@ uint32_t String::ComputeHashField(unibrow::CharacterStream* buffer,
 }
 
 
-Object* String::SubString(int start, int end) {
+Object* String::SubString(int start, int end, PretenureFlag pretenure) {
   if (start == 0 && end == length()) return this;
-  Object* result = Heap::AllocateSubString(this, start, end);
+  Object* result = Heap::AllocateSubString(this, start, end, pretenure);
   return result;
 }
 
@@ -4951,11 +5165,9 @@ void SharedFunctionInfo::SourceCodePrint(StringStream* accumulator,
 
 
 void SharedFunctionInfo::SharedFunctionInfoIterateBody(ObjectVisitor* v) {
-  IteratePointers(v, kNameOffset, kConstructStubOffset + kPointerSize);
-  IteratePointers(v, kInstanceClassNameOffset, kScriptOffset + kPointerSize);
-  IteratePointers(v, kDebugInfoOffset, kInferredNameOffset + kPointerSize);
-  IteratePointers(v, kThisPropertyAssignmentsOffset,
-      kThisPropertyAssignmentsOffset + kPointerSize);
+  IteratePointers(v,
+                  kNameOffset,
+                  kThisPropertyAssignmentsOffset + kPointerSize);
 }
 
 
@@ -5126,6 +5338,7 @@ const char* Code::Kind2String(Kind kind) {
     case STORE_IC: return "STORE_IC";
     case KEYED_STORE_IC: return "KEYED_STORE_IC";
     case CALL_IC: return "CALL_IC";
+    case BINARY_OP_IC: return "BINARY_OP_IC";
   }
   UNREACHABLE();
   return NULL;
@@ -5247,7 +5460,7 @@ Object* JSObject::SetSlowElements(Object* len) {
     case DICTIONARY_ELEMENTS: {
       if (IsJSArray()) {
         uint32_t old_length =
-        static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
+            static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
         element_dictionary()->RemoveNumberEntries(new_length, old_length),
         JSArray::cast(this)->set_length(len);
       }
@@ -6903,15 +7116,17 @@ void HashTable<Shape, Key>::IterateElements(ObjectVisitor* v) {
 
 
 template<typename Shape, typename Key>
-Object* HashTable<Shape, Key>::Allocate(int at_least_space_for) {
-  int capacity = RoundUpToPowerOf2(at_least_space_for);
-  if (capacity < 4) {
-    capacity = 4;  // Guarantee min capacity.
+Object* HashTable<Shape, Key>::Allocate(int at_least_space_for,
+                                        PretenureFlag pretenure) {
+  const int kMinCapacity = 32;
+  int capacity = RoundUpToPowerOf2(at_least_space_for * 2);
+  if (capacity < kMinCapacity) {
+    capacity = kMinCapacity;  // Guarantee min capacity.
   } else if (capacity > HashTable::kMaxCapacity) {
     return Failure::OutOfMemoryException();
   }
 
-  Object* obj = Heap::AllocateHashTable(EntryToIndex(capacity));
+  Object* obj = Heap::AllocateHashTable(EntryToIndex(capacity), pretenure);
   if (!obj->IsFailure()) {
     HashTable::cast(obj)->SetNumberOfElements(0);
     HashTable::cast(obj)->SetNumberOfDeletedElements(0);
@@ -6946,10 +7161,15 @@ Object* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) {
   // Return if:
   //   50% is still free after adding n elements and
   //   at most 50% of the free elements are deleted elements.
-  if ((nof + (nof >> 1) <= capacity) &&
-      (nod <= (capacity - nof) >> 1)) return this;
+  if (nod <= (capacity - nof) >> 1) {
+    int needed_free = nof >> 1;
+    if (nof + needed_free <= capacity) return this;
+  }
 
-  Object* obj = Allocate(nof * 2);
+  const int kMinCapacityForPretenure = 256;
+  bool pretenure =
+      (capacity > kMinCapacityForPretenure) && !Heap::InNewSpace(this);
+  Object* obj = Allocate(nof * 2, pretenure ? TENURED : NOT_TENURED);
   if (obj->IsFailure()) return obj;
 
   AssertNoAllocation no_gc;
@@ -6981,7 +7201,6 @@ Object* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) {
 }
 
 
-
 template<typename Shape, typename Key>
 uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) {
   uint32_t capacity = Capacity();
@@ -7091,8 +7310,7 @@ Object* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
     result_double = HeapNumber::cast(new_double);
   }
 
-  int capacity = dict->Capacity();
-  Object* obj = NumberDictionary::Allocate(dict->Capacity());
+  Object* obj = NumberDictionary::Allocate(dict->NumberOfElements());
   if (obj->IsFailure()) return obj;
   NumberDictionary* new_dict = NumberDictionary::cast(obj);
 
@@ -7100,6 +7318,7 @@ Object* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
 
   uint32_t pos = 0;
   uint32_t undefs = 0;
+  int capacity = dict->Capacity();
   for (int i = 0; i < capacity; i++) {
     Object* k = dict->KeyAt(i);
     if (dict->IsKey(k)) {
index 7533892..826fcae 100644 (file)
@@ -72,6 +72,7 @@
 //             - Dictionary
 //             - SymbolTable
 //             - CompilationCacheTable
+//             - CodeCacheHashTable
 //             - MapCache
 //           - Context
 //           - GlobalContext
 //         - TypeSwitchInfo
 //         - DebugInfo
 //         - BreakPointInfo
+//         - CodeCache
 //
 // Formats of Object*:
 //  Smi:        [31 bit signed int] 0
@@ -269,6 +271,7 @@ enum PropertyNormalizationMode {
   V(SIGNATURE_INFO_TYPE)                                                       \
   V(TYPE_SWITCH_INFO_TYPE)                                                     \
   V(SCRIPT_TYPE)                                                               \
+  V(CODE_CACHE_TYPE)                                                           \
                                                                                \
   V(JS_VALUE_TYPE)                                                             \
   V(JS_OBJECT_TYPE)                                                            \
@@ -364,7 +367,8 @@ enum PropertyNormalizationMode {
   V(OBJECT_TEMPLATE_INFO, ObjectTemplateInfo, object_template_info)            \
   V(SIGNATURE_INFO, SignatureInfo, signature_info)                             \
   V(TYPE_SWITCH_INFO, TypeSwitchInfo, type_switch_info)                        \
-  V(SCRIPT, Script, script)
+  V(SCRIPT, Script, script)                                                    \
+  V(CODE_CACHE, CodeCache, code_cache)
 
 #ifdef ENABLE_DEBUGGER_SUPPORT
 #define STRUCT_LIST_DEBUGGER(V)                                                \
@@ -468,6 +472,7 @@ enum InstanceType {
   SIGNATURE_INFO_TYPE,
   TYPE_SWITCH_INFO_TYPE,
   SCRIPT_TYPE,
+  CODE_CACHE_TYPE,
 #ifdef ENABLE_DEBUGGER_SUPPORT
   DEBUG_INFO_TYPE,
   BREAK_POINT_INFO_TYPE,
@@ -601,6 +606,7 @@ class Object BASE_EMBEDDED {
   inline bool IsDictionary();
   inline bool IsSymbolTable();
   inline bool IsCompilationCacheTable();
+  inline bool IsCodeCacheHashTable();
   inline bool IsMapCache();
   inline bool IsPrimitive();
   inline bool IsGlobalObject();
@@ -1626,6 +1632,9 @@ class FixedArray: public Array {
   inline void set_null(int index);
   inline void set_the_hole(int index);
 
+  // Gives access to raw memory which stores the array's data.
+  inline Object** data_start();
+
   // Copy operations.
   inline Object* Copy();
   Object* CopySize(int new_length);
@@ -1933,7 +1942,8 @@ class HashTable: public FixedArray {
   }
 
   // Returns a new HashTable object. Might return Failure.
-  static Object* Allocate(int at_least_space_for);
+  static Object* Allocate(int at_least_space_for,
+                          PretenureFlag pretenure = NOT_TENURED);
 
   // Returns the key at entry.
   Object* KeyAt(int entry) { return get(EntryToIndex(entry)); }
@@ -1965,6 +1975,8 @@ class HashTable: public FixedArray {
   static const int kEntrySize = Shape::kEntrySize;
   static const int kElementsStartOffset =
       kHeaderSize + kElementsStartIndex * kPointerSize;
+  static const int kCapacityOffset =
+      kHeaderSize + kCapacityIndex * kPointerSize;
 
   // Constant used for denoting a absent entry.
   static const int kNotFound = -1;
@@ -2615,13 +2627,14 @@ class Code: public HeapObject {
     CALL_IC,
     STORE_IC,
     KEYED_STORE_IC,
-    // No more than eight kinds. The value currently encoded in three bits in
+    BINARY_OP_IC,
+    // No more than 16 kinds. The value currently encoded in four bits in
     // Flags.
 
     // Pseudo-kinds.
     REGEXP = BUILTIN,
     FIRST_IC_KIND = LOAD_IC,
-    LAST_IC_KIND = KEYED_STORE_IC
+    LAST_IC_KIND = BINARY_OP_IC
   };
 
   enum {
@@ -2667,7 +2680,7 @@ class Code: public HeapObject {
   inline bool is_keyed_store_stub() { return kind() == KEYED_STORE_IC; }
   inline bool is_call_stub() { return kind() == CALL_IC; }
 
-  // [major_key]: For kind STUB, the major key.
+  // [major_key]: For kind STUB or BINARY_OP_IC, the major key.
   inline CodeStub::Major major_key();
   inline void set_major_key(CodeStub::Major major);
 
@@ -2774,14 +2787,14 @@ class Code: public HeapObject {
   static const int kFlagsICStateShift        = 0;
   static const int kFlagsICInLoopShift       = 3;
   static const int kFlagsKindShift           = 4;
-  static const int kFlagsTypeShift           = 7;
-  static const int kFlagsArgumentsCountShift = 10;
+  static const int kFlagsTypeShift           = 8;
+  static const int kFlagsArgumentsCountShift = 11;
 
-  static const int kFlagsICStateMask        = 0x00000007;  // 0000000111
-  static const int kFlagsICInLoopMask       = 0x00000008;  // 0000001000
-  static const int kFlagsKindMask           = 0x00000070;  // 0001110000
-  static const int kFlagsTypeMask           = 0x00000380;  // 1110000000
-  static const int kFlagsArgumentsCountMask = 0xFFFFFC00;
+  static const int kFlagsICStateMask        = 0x00000007;  // 00000000111
+  static const int kFlagsICInLoopMask       = 0x00000008;  // 00000001000
+  static const int kFlagsKindMask           = 0x000000F0;  // 00011110000
+  static const int kFlagsTypeMask           = 0x00000700;  // 11100000000
+  static const int kFlagsArgumentsCountMask = 0xFFFFF800;
 
   static const int kFlagsNotUsedInLookup =
       (kFlagsICInLoopMask | kFlagsTypeMask);
@@ -2922,7 +2935,7 @@ class Map: public HeapObject {
   DECL_ACCESSORS(instance_descriptors, DescriptorArray)
 
   // [stub cache]: contains stubs compiled for this map.
-  DECL_ACCESSORS(code_cache, FixedArray)
+  DECL_ACCESSORS(code_cache, Object)
 
   Object* CopyDropDescriptors();
 
@@ -2958,10 +2971,10 @@ class Map: public HeapObject {
 
   // Returns the non-negative index of the code object if it is in the
   // cache and -1 otherwise.
-  int IndexInCodeCache(Code* code);
+  int IndexInCodeCache(String* name, Code* code);
 
   // Removes a code object from the code cache at the given index.
-  void RemoveFromCodeCache(int index);
+  void RemoveFromCodeCache(String* name, Code* code, int index);
 
   // For every transition in this map, makes the transition's
   // target's prototype pointer point back to this map.
@@ -3026,6 +3039,11 @@ class Map: public HeapObject {
   static const int kNeedsLoading = 0;
   static const int kIsExtensible = 1;
 
+  // Layout of the default cache. It holds alternating name and code objects.
+  static const int kCodeCacheEntrySize = 2;
+  static const int kCodeCacheEntryNameOffset = 0;
+  static const int kCodeCacheEntryCodeOffset = 1;
+
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(Map);
 };
@@ -3275,11 +3293,22 @@ class SharedFunctionInfo: public HeapObject {
   static const int kDontAdaptArgumentsSentinel = -1;
 
   // Layout description.
-  // (An even number of integers has a size that is a multiple of a pointer.)
+  // Pointer fields.
   static const int kNameOffset = HeapObject::kHeaderSize;
   static const int kCodeOffset = kNameOffset + kPointerSize;
   static const int kConstructStubOffset = kCodeOffset + kPointerSize;
-  static const int kLengthOffset = kConstructStubOffset + kPointerSize;
+  static const int kInstanceClassNameOffset =
+      kConstructStubOffset + kPointerSize;
+  static const int kExternalReferenceDataOffset =
+      kInstanceClassNameOffset + kPointerSize;
+  static const int kScriptOffset = kExternalReferenceDataOffset + kPointerSize;
+  static const int kDebugInfoOffset = kScriptOffset + kPointerSize;
+  static const int kInferredNameOffset = kDebugInfoOffset + kPointerSize;
+  static const int kThisPropertyAssignmentsOffset =
+      kInferredNameOffset + kPointerSize;
+  // Integer fields.
+  static const int kLengthOffset =
+      kThisPropertyAssignmentsOffset + kPointerSize;
   static const int kFormalParameterCountOffset = kLengthOffset + kIntSize;
   static const int kExpectedNofPropertiesOffset =
       kFormalParameterCountOffset + kIntSize;
@@ -3287,27 +3316,14 @@ class SharedFunctionInfo: public HeapObject {
       kExpectedNofPropertiesOffset + kIntSize;
   static const int kEndPositionOffset = kStartPositionAndTypeOffset + kIntSize;
   static const int kFunctionTokenPositionOffset = kEndPositionOffset + kIntSize;
-  static const int kInstanceClassNameOffset =
+  static const int kCompilerHintsOffset =
       kFunctionTokenPositionOffset + kIntSize;
-  static const int kExternalReferenceDataOffset =
-      kInstanceClassNameOffset + kPointerSize;
-  static const int kScriptOffset = kExternalReferenceDataOffset + kPointerSize;
-  static const int kDebugInfoOffset = kScriptOffset + kPointerSize;
-  static const int kInferredNameOffset = kDebugInfoOffset + kPointerSize;
-  static const int kCompilerHintsOffset = kInferredNameOffset + kPointerSize;
-  static const int kThisPropertyAssignmentsOffset =
-      kCompilerHintsOffset + kPointerSize;
   static const int kThisPropertyAssignmentsCountOffset =
-      kThisPropertyAssignmentsOffset + kPointerSize;
-  static const int kSize = kThisPropertyAssignmentsCountOffset + kPointerSize;
+      kCompilerHintsOffset + kIntSize;
+  // Total size.
+  static const int kSize = kThisPropertyAssignmentsCountOffset + kIntSize;
 
  private:
-  // Bit positions in length_and_flg.
-  // The least significant bit is used as the flag.
-  static const int kFlagBit         = 0;
-  static const int kLengthShift     = 1;
-  static const int kLengthMask      = ~((1 << kLengthShift) - 1);
-
   // Bit positions in start_position_and_type.
   // The source code start position is in the 30 most significant bits of
   // the start_position_and_type field.
@@ -3711,6 +3727,97 @@ class CompilationCacheTable: public HashTable<CompilationCacheShape,
 };
 
 
+class CodeCache: public Struct {
+ public:
+  DECL_ACCESSORS(default_cache, FixedArray)
+  DECL_ACCESSORS(normal_type_cache, Object)
+
+  // Add the code object to the cache.
+  Object* Update(String* name, Code* code);
+
+  // Lookup code object in the cache. Returns code object if found and undefined
+  // if not.
+  Object* Lookup(String* name, Code::Flags flags);
+
+  // Get the internal index of a code object in the cache. Returns -1 if the
+  // code object is not in that cache. This index can be used to later call
+  // RemoveByIndex. The cache cannot be modified between a call to GetIndex and
+  // RemoveByIndex.
+  int GetIndex(String* name, Code* code);
+
+  // Remove an object from the cache with the provided internal index.
+  void RemoveByIndex(String* name, Code* code, int index);
+
+  static inline CodeCache* cast(Object* obj);
+
+#ifdef DEBUG
+  void CodeCachePrint();
+  void CodeCacheVerify();
+#endif
+
+  static const int kDefaultCacheOffset = HeapObject::kHeaderSize;
+  static const int kNormalTypeCacheOffset =
+      kDefaultCacheOffset + kPointerSize;
+  static const int kSize = kNormalTypeCacheOffset + kPointerSize;
+
+ private:
+  Object* UpdateDefaultCache(String* name, Code* code);
+  Object* UpdateNormalTypeCache(String* name, Code* code);
+  Object* LookupDefaultCache(String* name, Code::Flags flags);
+  Object* LookupNormalTypeCache(String* name, Code::Flags flags);
+
+  // Code cache layout of the default cache. Elements are alternating name and
+  // code objects for non normal load/store/call IC's.
+  static const int kCodeCacheEntrySize = 2;
+  static const int kCodeCacheEntryNameOffset = 0;
+  static const int kCodeCacheEntryCodeOffset = 1;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(CodeCache);
+};
+
+
+class CodeCacheHashTableShape {
+ public:
+  static inline bool IsMatch(HashTableKey* key, Object* value) {
+    return key->IsMatch(value);
+  }
+
+  static inline uint32_t Hash(HashTableKey* key) {
+    return key->Hash();
+  }
+
+  static inline uint32_t HashForObject(HashTableKey* key, Object* object) {
+    return key->HashForObject(object);
+  }
+
+  static Object* AsObject(HashTableKey* key) {
+    return key->AsObject();
+  }
+
+  static const int kPrefixSize = 0;
+  static const int kEntrySize = 2;
+};
+
+
+class CodeCacheHashTable: public HashTable<CodeCacheHashTableShape,
+                                           HashTableKey*> {
+ public:
+  Object* Lookup(String* name, Code::Flags flags);
+  Object* Put(String* name, Code* code);
+
+  int GetIndex(String* name, Code::Flags flags);
+  void RemoveByIndex(int index);
+
+  static inline CodeCacheHashTable* cast(Object* obj);
+
+  // Initial size of the fixed array backing the hash table.
+  static const int kInitialSize = 64;
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(CodeCacheHashTable);
+};
+
+
 enum AllowNullsFlag {ALLOW_NULLS, DISALLOW_NULLS};
 enum RobustnessFlag {ROBUST_STRING_TRAVERSAL, FAST_STRING_TRAVERSAL};
 
@@ -3837,13 +3944,13 @@ class String: public HeapObject {
   // Try to flatten the top level ConsString that is hiding behind this
   // string.  This is a no-op unless the string is a ConsString.  Flatten
   // mutates the ConsString and might return a failure.
-  Object* TryFlatten();
+  Object* SlowTryFlatten(PretenureFlag pretenure);
 
   // Try to flatten the string.  Checks first inline to see if it is necessary.
-  // Do not handle allocation failures.  After calling TryFlattenIfNotFlat, the
+  // Do not handle allocation failures.  After calling TryFlatten, the
   // string could still be a ConsString, in which case a failure is returned.
   // Use FlattenString from Handles.cc to be sure to flatten.
-  inline Object* TryFlattenIfNotFlat();
+  inline Object* TryFlatten(PretenureFlag pretenure = NOT_TENURED);
 
   Vector<const char> ToAsciiVector();
   Vector<const uc16> ToUC16Vector();
@@ -3853,7 +3960,7 @@ class String: public HeapObject {
   bool MarkAsUndetectable();
 
   // Return a substring.
-  Object* SubString(int from, int to);
+  Object* SubString(int from, int to, PretenureFlag pretenure = NOT_TENURED);
 
   // String equality operations.
   inline bool Equals(String* other);
@@ -4051,10 +4158,6 @@ class SeqString: public String {
   // Casting.
   static inline SeqString* cast(Object* obj);
 
-  // Dispatched behaviour.
-  // For regexp code.
-  uint16_t* SeqStringGetTwoByteAddress();
-
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(SeqString);
 };
index 5058296..dd72669 100644 (file)
@@ -31,6 +31,7 @@
 #include "ast.h"
 #include "bootstrapper.h"
 #include "compiler.h"
+#include "messages.h"
 #include "platform.h"
 #include "runtime.h"
 #include "parser.h"
@@ -107,13 +108,13 @@ class Parser {
 
   // Returns NULL if parsing failed.
   FunctionLiteral* ParseProgram(Handle<String> source,
-                                unibrow::CharacterStream* stream,
                                 bool in_global_context);
   FunctionLiteral* ParseLazy(Handle<String> source,
                              Handle<String> name,
-                             int start_position, bool is_expression);
-  FunctionLiteral* ParseJson(Handle<String> source,
-                             unibrow::CharacterStream* stream);
+                             int start_position,
+                             int end_position,
+                             bool is_expression);
+  FunctionLiteral* ParseJson(Handle<String> source);
 
   // The minimum number of contiguous assignment that will
   // be treated as an initialization block. Benchmarks show that
@@ -1212,7 +1213,7 @@ bool Parser::PreParseProgram(Handle<String> source,
   AssertNoZoneAllocation assert_no_zone_allocation;
   AssertNoAllocation assert_no_allocation;
   NoHandleAllocation no_handle_allocation;
-  scanner_.Init(source, stream, 0, JAVASCRIPT);
+  scanner_.Initialize(source, stream, JAVASCRIPT);
   ASSERT(target_stack_ == NULL);
   mode_ = PARSE_EAGERLY;
   DummyScope top_scope;
@@ -1226,7 +1227,6 @@ bool Parser::PreParseProgram(Handle<String> source,
 
 
 FunctionLiteral* Parser::ParseProgram(Handle<String> source,
-                                      unibrow::CharacterStream* stream,
                                       bool in_global_context) {
   CompilationZoneScope zone_scope(DONT_DELETE_ON_EXIT);
 
@@ -1234,8 +1234,8 @@ FunctionLiteral* Parser::ParseProgram(Handle<String> source,
   Counters::total_parse_size.Increment(source->length());
 
   // Initialize parser state.
-  source->TryFlattenIfNotFlat();
-  scanner_.Init(source, stream, 0, JAVASCRIPT);
+  source->TryFlatten();
+  scanner_.Initialize(source, JAVASCRIPT);
   ASSERT(target_stack_ == NULL);
 
   // Compute the parsing mode.
@@ -1286,15 +1286,15 @@ FunctionLiteral* Parser::ParseProgram(Handle<String> source,
 FunctionLiteral* Parser::ParseLazy(Handle<String> source,
                                    Handle<String> name,
                                    int start_position,
+                                   int end_position,
                                    bool is_expression) {
   CompilationZoneScope zone_scope(DONT_DELETE_ON_EXIT);
   HistogramTimerScope timer(&Counters::parse_lazy);
-  source->TryFlattenIfNotFlat();
   Counters::total_parse_size.Increment(source->length());
-  SafeStringInputBuffer buffer(source.location());
 
   // Initialize parser state.
-  scanner_.Init(source, &buffer, start_position, JAVASCRIPT);
+  source->TryFlatten();
+  scanner_.Initialize(source, start_position, end_position, JAVASCRIPT);
   ASSERT(target_stack_ == NULL);
   mode_ = PARSE_EAGERLY;
 
@@ -1330,16 +1330,15 @@ FunctionLiteral* Parser::ParseLazy(Handle<String> source,
   return result;
 }
 
-FunctionLiteral* Parser::ParseJson(Handle<String> source,
-                                   unibrow::CharacterStream* stream) {
+FunctionLiteral* Parser::ParseJson(Handle<String> source) {
   CompilationZoneScope zone_scope(DONT_DELETE_ON_EXIT);
 
   HistogramTimerScope timer(&Counters::parse);
   Counters::total_parse_size.Increment(source->length());
 
   // Initialize parser state.
-  source->TryFlattenIfNotFlat();
-  scanner_.Init(source, stream, 0, JSON);
+  source->TryFlatten(TENURED);
+  scanner_.Initialize(source, JSON);
   ASSERT(target_stack_ == NULL);
 
   FunctionLiteral* result = NULL;
@@ -3258,7 +3257,6 @@ Expression* Parser::ParsePrimaryExpression(bool* ok) {
         result = VariableProxySentinel::this_proxy();
       } else {
         VariableProxy* recv = top_scope_->receiver();
-        recv->var_uses()->RecordRead(1);
         result = recv;
       }
       break;
@@ -5065,13 +5063,12 @@ FunctionLiteral* MakeAST(bool compile_in_global_context,
     return NULL;
   }
   Handle<String> source = Handle<String>(String::cast(script->source()));
-  SafeStringInputBuffer input(source.location());
   FunctionLiteral* result;
   if (is_json) {
     ASSERT(compile_in_global_context);
-    result = parser.ParseJson(source, &input);
+    result = parser.ParseJson(source);
   } else {
-    result = parser.ParseProgram(source, &input, compile_in_global_context);
+    result = parser.ParseProgram(source, compile_in_global_context);
   }
   return result;
 }
@@ -5086,13 +5083,11 @@ FunctionLiteral* MakeLazyAST(Handle<Script> script,
   always_allow_natives_syntax = true;
   AstBuildingParser parser(script, true, NULL, NULL);  // always allow
   always_allow_natives_syntax = allow_natives_syntax_before;
-  // Parse the function by pulling the function source from the script source.
+  // Parse the function by pointing to the function source in the script source.
   Handle<String> script_source(String::cast(script->source()));
   FunctionLiteral* result =
-      parser.ParseLazy(SubString(script_source, start_position, end_position),
-                       name,
-                       start_position,
-                       is_expression);
+      parser.ParseLazy(script_source, name,
+                       start_position, end_position, is_expression);
   return result;
 }
 
index ff75776..3617e8a 100644 (file)
@@ -567,6 +567,9 @@ static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
 
   TickSample sample;
 
+  // We always sample the VM state.
+  sample.state = Logger::state();
+
   // If profiling, we extract the current pc and sp.
   if (active_sampler_->IsProfiling()) {
     // Extracting the sample from the context is extremely machine dependent.
@@ -588,9 +591,6 @@ static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
     active_sampler_->SampleStack(&sample);
   }
 
-  // We always sample the VM state.
-  sample.state = Logger::state();
-
   active_sampler_->Tick(&sample);
 }
 
index e890f94..f1812ff 100644 (file)
@@ -331,8 +331,8 @@ void OS::LogSharedLibraryAddresses() {
     if (fscanf(fp, " %c%c%c%c", &attr_r, &attr_w, &attr_x, &attr_p) != 4) break;
 
     int c;
-    if (attr_r == 'r' && attr_x == 'x') {
-      // Found a readable and executable entry. Skip characters until we reach
+    if (attr_r == 'r' && attr_w != 'w' && attr_x == 'x') {
+      // Found a read-only executable entry. Skip characters until we reach
       // the beginning of the filename or the end of the line.
       do {
         c = getc(fp);
@@ -728,6 +728,9 @@ static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
 
   TickSample sample;
 
+  // We always sample the VM state.
+  sample.state = Logger::state();
+
   // If profiling, we extract the current pc and sp.
   if (active_sampler_->IsProfiling()) {
     // Extracting the sample from the context is extremely machine dependent.
@@ -760,9 +763,6 @@ static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
       active_sampler_->SampleStack(&sample);
   }
 
-  // We always sample the VM state.
-  sample.state = Logger::state();
-
   active_sampler_->Tick(&sample);
 #endif
 }
index e379ae2..4502987 100644 (file)
@@ -548,6 +548,9 @@ class Sampler::PlatformData : public Malloced {
     while (sampler_->IsActive()) {
       TickSample sample;
 
+      // We always sample the VM state.
+      sample.state = Logger::state();
+
       // If profiling, we record the pc and sp of the profiled thread.
       if (sampler_->IsProfiling()
           && KERN_SUCCESS == thread_suspend(profiled_thread_)) {
@@ -585,8 +588,6 @@ class Sampler::PlatformData : public Malloced {
         thread_resume(profiled_thread_);
       }
 
-      // We always sample the VM state.
-      sample.state = Logger::state();
       // Invoke tick handler with program counter and stack pointer.
       sampler_->Tick(&sample);
 
index 81b0d4c..04ffea9 100644 (file)
@@ -1807,6 +1807,9 @@ class Sampler::PlatformData : public Malloced {
     while (sampler_->IsActive()) {
       TickSample sample;
 
+      // We always sample the VM state.
+      sample.state = Logger::state();
+
       // If profiling, we record the pc and sp of the profiled thread.
       if (sampler_->IsProfiling()
           && SuspendThread(profiled_thread_) != (DWORD)-1) {
@@ -1826,8 +1829,6 @@ class Sampler::PlatformData : public Malloced {
         ResumeThread(profiled_thread_);
       }
 
-      // We always sample the VM state.
-      sample.state = Logger::state();
       // Invoke tick handler with program counter and stack pointer.
       sampler_->Tick(&sample);
 
index ca570a6..6e2a60e 100644 (file)
@@ -604,7 +604,7 @@ class IndentedScope BASE_EMBEDDED {
         ast_printer_->Print(StaticType::Type2String(expr->type()));
         printed_first = true;
       }
-      if (expr->num() != Expression::kNoLabel) {
+      if (expr->num() != AstNode::kNoNumber) {
         ast_printer_->Print(printed_first ? ", num = " : " (num = ");
         ast_printer_->Print("%d", expr->num());
         printed_first = true;
@@ -679,7 +679,7 @@ void AstPrinter::PrintLiteralWithModeIndented(const char* info,
       pos += OS::SNPrintF(buf + pos, ", type = %s",
                           StaticType::Type2String(type));
     }
-    if (num != Expression::kNoLabel) {
+    if (num != AstNode::kNoNumber) {
       pos += OS::SNPrintF(buf + pos, ", num = %d", num);
     }
     OS::SNPrintF(buf + pos, ")");
@@ -740,7 +740,7 @@ void AstPrinter::PrintParameters(Scope* scope) {
       PrintLiteralWithModeIndented("VAR", scope->parameter(i),
                                    scope->parameter(i)->name(),
                                    scope->parameter(i)->type(),
-                                   Expression::kNoLabel);
+                                   AstNode::kNoNumber);
     }
   }
 }
@@ -786,7 +786,7 @@ void AstPrinter::VisitDeclaration(Declaration* node) {
                                  node->proxy()->AsVariable(),
                                  node->proxy()->name(),
                                  node->proxy()->AsVariable()->type(),
-                                 Expression::kNoLabel);
+                                 AstNode::kNoNumber);
   } else {
     // function declarations
     PrintIndented("FUNCTION ");
index 7bec455..843d0aa 100644 (file)
@@ -142,7 +142,7 @@ function DoRegExpExec(regexp, string, index) {
 
 function RegExpExec(string) {
   if (!IS_REGEXP(this)) {
-    throw MakeTypeError('method_called_on_incompatible',
+    throw MakeTypeError('incompatible_method_receiver',
                         ['RegExp.prototype.exec', this]);
   }
   if (%_ArgumentsLength() == 0) {
@@ -152,8 +152,12 @@ function RegExpExec(string) {
     }
     string = regExpInput;
   }
-  var s = ToString(string);
-  var length = s.length;
+  var s;
+  if (IS_STRING(string)) {
+    s = string;
+  } else {
+    s = ToString(string);
+  }
   var lastIndex = this.lastIndex;
   var i = this.global ? TO_INTEGER(lastIndex) : 0;
 
@@ -172,16 +176,23 @@ function RegExpExec(string) {
   }
 
   var numResults = NUMBER_OF_CAPTURES(lastMatchInfo) >> 1;
-  var result = new $Array(numResults);
-  for (var i = 0; i < numResults; i++) {
-    var matchStart = lastMatchInfo[CAPTURE(i << 1)];
-    var matchEnd = lastMatchInfo[CAPTURE((i << 1) + 1)];
-    if (matchStart != -1 && matchEnd != -1) {
-      result[i] = SubString(s, matchStart, matchEnd);
-    } else {
-      // Make sure the element is present. Avoid reading the undefined
-      // property from the global object since this may change.
-      result[i] = void 0;
+  var result;
+  if (numResults === 1) {
+    var matchStart = lastMatchInfo[CAPTURE(0)];
+    var matchEnd = lastMatchInfo[CAPTURE(1)];
+    result = [SubString(s, matchStart, matchEnd)];
+  } else {
+    result = new $Array(numResults);
+    for (var i = 0; i < numResults; i++) {
+      var matchStart = lastMatchInfo[CAPTURE(i << 1)];
+      var matchEnd = lastMatchInfo[CAPTURE((i << 1) + 1)];
+      if (matchStart != -1 && matchEnd != -1) {
+        result[i] = SubString(s, matchStart, matchEnd);
+      } else {
+        // Make sure the element is present. Avoid reading the undefined
+        // property from the global object since this may change.
+        result[i] = void 0;
+      }
     }
   }
 
@@ -199,7 +210,7 @@ function RegExpExec(string) {
 // else implements.
 function RegExpTest(string) {
   if (!IS_REGEXP(this)) {
-    throw MakeTypeError('method_called_on_incompatible',
+    throw MakeTypeError('incompatible_method_receiver',
                         ['RegExp.prototype.test', this]);
   }
   if (%_ArgumentsLength() == 0) {
index 718da36..8453104 100644 (file)
@@ -103,6 +103,45 @@ void RegisterAllocator::Unuse(Register reg) {
   registers_.Unuse(ToNumber(reg));
 }
 
+
+NumberInfo Result::number_info() const {
+  ASSERT(is_valid());
+  if (!is_constant()) {
+    return NumberInfo::FromInt(NumberInfoField::decode(value_));
+  }
+  Handle<Object> value = handle();
+  if (value->IsSmi()) return NumberInfo::Smi();
+  if (value->IsHeapNumber()) return NumberInfo::HeapNumber();
+  return NumberInfo::Unknown();
+}
+
+
+void Result::set_number_info(NumberInfo info) {
+  ASSERT(is_valid());
+  value_ &= ~NumberInfoField::mask();
+  value_ |= NumberInfoField::encode(info.ToInt());
+}
+
+
+bool Result::is_number() const {
+  return number_info().IsNumber();
+}
+
+
+bool Result::is_smi() const {
+  return number_info().IsSmi();
+}
+
+
+bool Result::is_integer32() const {
+  return number_info().IsInteger32();
+}
+
+
+bool Result::is_heap_number() const {
+  return number_info().IsHeapNumber();
+}
+
 } }  // namespace v8::internal
 
 #endif  // V8_REGISTER_ALLOCATOR_INL_H_
index 1655b4a..64e4428 100644 (file)
@@ -38,11 +38,11 @@ namespace internal {
 // Result implementation.
 
 
-Result::Result(Register reg, NumberInfo::Type info) {
+Result::Result(Register reg, NumberInfo info) {
   ASSERT(reg.is_valid() && !RegisterAllocator::IsReserved(reg));
   CodeGeneratorScope::Current()->allocator()->Use(reg);
   value_ = TypeField::encode(REGISTER)
-      | NumberInfoField::encode(info)
+      | NumberInfoField::encode(info.ToInt())
       | DataField::encode(reg.code_);
 }
 
@@ -53,23 +53,6 @@ Result::ZoneObjectList* Result::ConstantList() {
 }
 
 
-NumberInfo::Type Result::number_info() {
-  ASSERT(is_valid());
-  if (!is_constant()) return NumberInfoField::decode(value_);
-  Handle<Object> value = handle();
-  if (value->IsSmi()) return NumberInfo::kSmi;
-  if (value->IsHeapNumber()) return NumberInfo::kHeapNumber;
-  return NumberInfo::kUnknown;
-}
-
-
-void Result::set_number_info(NumberInfo::Type info) {
-  ASSERT(is_valid());
-  value_ = value_ & ~NumberInfoField::mask();
-  value_ = value_ | NumberInfoField::encode(info);
-}
-
-
 // -------------------------------------------------------------------------
 // RegisterAllocator implementation.
 
index 747200a..2a7b820 100644 (file)
@@ -65,12 +65,12 @@ class Result BASE_EMBEDDED {
   Result() { invalidate(); }
 
   // Construct a register Result.
-  explicit Result(Register reg, NumberInfo::Type info = NumberInfo::kUnknown);
+  explicit Result(Register reg, NumberInfo info = NumberInfo::Unknown());
 
   // Construct a Result whose value is a compile-time constant.
   explicit Result(Handle<Object> value) {
     value_ = TypeField::encode(CONSTANT)
-        | NumberInfoField::encode(NumberInfo::kUninitialized)
+        | NumberInfoField::encode(NumberInfo::Uninitialized().ToInt())
         | DataField::encode(ConstantList()->length());
     ConstantList()->Add(value);
   }
@@ -101,13 +101,12 @@ class Result BASE_EMBEDDED {
 
   void invalidate() { value_ = TypeField::encode(INVALID); }
 
-  NumberInfo::Type number_info();
-  void set_number_info(NumberInfo::Type info);
-  bool is_number() {
-    return (number_info() & NumberInfo::kNumber) != 0;
-  }
-  bool is_smi() { return number_info() == NumberInfo::kSmi; }
-  bool is_heap_number() { return number_info() == NumberInfo::kHeapNumber; }
+  inline NumberInfo number_info() const;
+  inline void set_number_info(NumberInfo info);
+  inline bool is_number() const;
+  inline bool is_smi() const;
+  inline bool is_integer32() const;
+  inline bool is_heap_number() const;
 
   bool is_valid() const { return type() != INVALID; }
   bool is_register() const { return type() == REGISTER; }
@@ -140,8 +139,8 @@ class Result BASE_EMBEDDED {
   uint32_t value_;
 
   class TypeField: public BitField<Type, 0, 2> {};
-  class NumberInfoField : public BitField<NumberInfo::Type, 2, 3> {};
-  class DataField: public BitField<uint32_t, 5, 32 - 5> {};
+  class NumberInfoField : public BitField<int, 2, 4> {};
+  class DataField: public BitField<uint32_t, 6, 32 - 6> {};
 
   inline void CopyTo(Result* destination) const;
 
index b05cfae..8a32212 100644 (file)
@@ -244,6 +244,12 @@ void AstOptimizer::VisitVariableProxy(VariableProxy* node) {
         !Heap::result_symbol()->Equals(*var->name())) {
       func_name_inferrer_.PushName(var->name());
     }
+
+    if (FLAG_safe_int32_compiler) {
+      if (var->IsStackAllocated() && !var->is_arguments()) {
+        node->set_side_effect_free(true);
+      }
+    }
   }
 }
 
@@ -252,11 +258,14 @@ void AstOptimizer::VisitLiteral(Literal* node) {
   Handle<Object> literal = node->handle();
   if (literal->IsSmi()) {
     node->type()->SetAsLikelySmi();
+    node->set_side_effect_free(true);
   } else if (literal->IsString()) {
     Handle<String> lit_str(Handle<String>::cast(literal));
     if (!Heap::prototype_symbol()->Equals(*lit_str)) {
       func_name_inferrer_.PushName(lit_str);
     }
+  } else if (literal->IsHeapNumber()) {
+    node->set_side_effect_free(true);
   }
 }
 
@@ -414,6 +423,27 @@ void AstOptimizer::VisitCallRuntime(CallRuntime* node) {
 
 void AstOptimizer::VisitUnaryOperation(UnaryOperation* node) {
   Visit(node->expression());
+  if (FLAG_safe_int32_compiler) {
+    switch (node->op()) {
+      case Token::BIT_NOT:
+        node->expression()->set_to_int32(true);
+        // Fall through.
+      case Token::ADD:
+      case Token::SUB:
+      case Token::NOT:
+        node->set_side_effect_free(node->expression()->side_effect_free());
+        break;
+      case Token::DELETE:
+      case Token::TYPEOF:
+      case Token::VOID:
+        break;
+      default:
+        UNREACHABLE();
+        break;
+    }
+  } else if (node->op() == Token::BIT_NOT) {
+    node->expression()->set_to_int32(true);
+  }
 }
 
 
@@ -442,6 +472,8 @@ void AstOptimizer::VisitBinaryOperation(BinaryOperation* node) {
       node->type()->SetAsLikelySmiIfUnknown();
       node->left()->type()->SetAsLikelySmiIfUnknown();
       node->right()->type()->SetAsLikelySmiIfUnknown();
+      node->left()->set_to_int32(true);
+      node->right()->set_to_int32(true);
       break;
     case Token::ADD:
     case Token::SUB:
@@ -483,6 +515,32 @@ void AstOptimizer::VisitBinaryOperation(BinaryOperation* node) {
       }
     }
   }
+
+  if (FLAG_safe_int32_compiler) {
+    switch (node->op()) {
+      case Token::COMMA:
+      case Token::OR:
+      case Token::AND:
+        break;
+      case Token::BIT_OR:
+      case Token::BIT_XOR:
+      case Token::BIT_AND:
+      case Token::SHL:
+      case Token::SAR:
+      case Token::SHR:
+      case Token::ADD:
+      case Token::SUB:
+      case Token::MUL:
+      case Token::DIV:
+      case Token::MOD:
+        node->set_side_effect_free(node->left()->side_effect_free() &&
+                                   node->right()->side_effect_free());
+        break;
+      default:
+        UNREACHABLE();
+        break;
+    }
+  }
 }
 
 
index 6459aa7..6d3a158 100644 (file)
@@ -38,6 +38,7 @@
 #include "debug.h"
 #include "execution.h"
 #include "jsregexp.h"
+#include "liveedit.h"
 #include "parser.h"
 #include "platform.h"
 #include "runtime.h"
@@ -1230,6 +1231,17 @@ static Object* Runtime_RegExpExec(Arguments args) {
 }
 
 
+static Object* Runtime_FinishArrayPrototypeSetup(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 1);
+  CONVERT_ARG_CHECKED(JSArray, prototype, 0);
+  // This is necessary to enable fast checks for absence of elements
+  // on Array.prototype and below.
+  prototype->set_elements(Heap::empty_fixed_array());
+  return Smi::FromInt(0);
+}
+
+
 static Object* Runtime_MaterializeRegExpLiteral(Arguments args) {
   HandleScope scope;
   ASSERT(args.length() == 4);
@@ -2608,8 +2620,8 @@ static Object* Runtime_StringLocaleCompare(Arguments args) {
   int d = str1->Get(0) - str2->Get(0);
   if (d != 0) return Smi::FromInt(d);
 
-  str1->TryFlattenIfNotFlat();
-  str2->TryFlattenIfNotFlat();
+  str1->TryFlatten();
+  str2->TryFlatten();
 
   static StringInputBuffer buf1;
   static StringInputBuffer buf2;
@@ -2818,7 +2830,7 @@ static Object* Runtime_NumberToPrecision(Arguments args) {
 // string->Get(index).
 static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
   if (index < static_cast<uint32_t>(string->length())) {
-    string->TryFlattenIfNotFlat();
+    string->TryFlatten();
     return LookupSingleCharacterStringFromCode(
         string->Get(index));
   }
@@ -2846,6 +2858,11 @@ Object* Runtime::GetElementOrCharAt(Handle<Object> object, uint32_t index) {
     return prototype->GetElement(index);
   }
 
+  return GetElement(object, index);
+}
+
+
+Object* Runtime::GetElement(Handle<Object> object, uint32_t index) {
   return object->GetElement(index);
 }
 
@@ -3072,7 +3089,7 @@ Object* Runtime::SetObjectProperty(Handle<Object> object,
       result = SetElement(js_object, index, value);
     } else {
       Handle<String> key_string = Handle<String>::cast(key);
-      key_string->TryFlattenIfNotFlat();
+      key_string->TryFlatten();
       result = SetProperty(js_object, key_string, value, attr);
     }
     if (result.is_null()) return Failure::Exception();
@@ -3121,7 +3138,7 @@ Object* Runtime::ForceSetObjectProperty(Handle<JSObject> js_object,
       return js_object->SetElement(index, *value);
     } else {
       Handle<String> key_string = Handle<String>::cast(key);
-      key_string->TryFlattenIfNotFlat();
+      key_string->TryFlatten();
       return js_object->IgnoreAttributesAndSetLocalProperty(*key_string,
                                                             *value,
                                                             attr);
@@ -3173,7 +3190,7 @@ Object* Runtime::ForceDeleteObjectProperty(Handle<JSObject> js_object,
     key_string = Handle<String>::cast(converted);
   }
 
-  key_string->TryFlattenIfNotFlat();
+  key_string->TryFlatten();
   return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
 }
 
@@ -3669,7 +3686,7 @@ static Object* Runtime_StringToNumber(Arguments args) {
   NoHandleAllocation ha;
   ASSERT(args.length() == 1);
   CONVERT_CHECKED(String, subject, args[0]);
-  subject->TryFlattenIfNotFlat();
+  subject->TryFlatten();
   return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
 }
 
@@ -3751,7 +3768,7 @@ static Object* Runtime_URIEscape(Arguments args) {
   ASSERT(args.length() == 1);
   CONVERT_CHECKED(String, source, args[0]);
 
-  source->TryFlattenIfNotFlat();
+  source->TryFlatten();
 
   int escaped_length = 0;
   int length = source->length();
@@ -3864,7 +3881,7 @@ static Object* Runtime_URIUnescape(Arguments args) {
   ASSERT(args.length() == 1);
   CONVERT_CHECKED(String, source, args[0]);
 
-  source->TryFlattenIfNotFlat();
+  source->TryFlatten();
 
   bool ascii = true;
   int length = source->length();
@@ -3904,7 +3921,7 @@ static Object* Runtime_StringParseInt(Arguments args) {
   CONVERT_CHECKED(String, s, args[0]);
   CONVERT_SMI_CHECKED(radix, args[1]);
 
-  s->TryFlattenIfNotFlat();
+  s->TryFlatten();
 
   int len = s->length();
   int i;
@@ -4068,18 +4085,83 @@ static Object* ConvertCaseHelper(String* s,
 }
 
 
-template <class Converter>
-static Object* ConvertCase(Arguments args,
-                           unibrow::Mapping<Converter, 128>* mapping) {
-  NoHandleAllocation ha;
+static inline SeqAsciiString* TryGetSeqAsciiString(String* s) {
+  if (!s->IsFlat() || !s->IsAsciiRepresentation()) return NULL;
+  if (s->IsConsString()) {
+    ASSERT(ConsString::cast(s)->second()->length() == 0);
+    return SeqAsciiString::cast(ConsString::cast(s)->first());
+  }
+  return SeqAsciiString::cast(s);
+}
+
+
+namespace {
+
+struct ToLowerTraits {
+  typedef unibrow::ToLowercase UnibrowConverter;
+
+  static bool ConvertAscii(char* dst, char* src, int length) {
+    bool changed = false;
+    for (int i = 0; i < length; ++i) {
+      char c = src[i];
+      if ('A' <= c && c <= 'Z') {
+        c += ('a' - 'A');
+        changed = true;
+      }
+      dst[i] = c;
+    }
+    return changed;
+  }
+};
+
+
+struct ToUpperTraits {
+  typedef unibrow::ToUppercase UnibrowConverter;
+
+  static bool ConvertAscii(char* dst, char* src, int length) {
+    bool changed = false;
+    for (int i = 0; i < length; ++i) {
+      char c = src[i];
+      if ('a' <= c && c <= 'z') {
+        c -= ('a' - 'A');
+        changed = true;
+      }
+      dst[i] = c;
+    }
+    return changed;
+  }
+};
+
+}  // namespace
 
+
+template <typename ConvertTraits>
+static Object* ConvertCase(
+    Arguments args,
+    unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
+  NoHandleAllocation ha;
   CONVERT_CHECKED(String, s, args[0]);
-  s->TryFlattenIfNotFlat();
+  s->TryFlatten();
 
-  int input_string_length = s->length();
+  const int length = s->length();
   // Assume that the string is not empty; we need this assumption later
-  if (input_string_length == 0) return s;
-  int length = input_string_length;
+  if (length == 0) return s;
+
+  // Simpler handling of ascii strings.
+  //
+  // NOTE: This assumes that the upper/lower case of an ascii
+  // character is also ascii.  This is currently the case, but it
+  // might break in the future if we implement more context and locale
+  // dependent upper/lower conversions.
+  SeqAsciiString* seq_ascii = TryGetSeqAsciiString(s);
+  if (seq_ascii != NULL) {
+    Object* o = Heap::AllocateRawAsciiString(length);
+    if (o->IsFailure()) return o;
+    SeqAsciiString* result = SeqAsciiString::cast(o);
+    bool has_changed_character = ConvertTraits::ConvertAscii(
+        result->GetChars(), seq_ascii->GetChars(), length);
+    return has_changed_character ? result : s;
+  }
 
   Object* answer = ConvertCaseHelper(s, length, length, mapping);
   if (answer->IsSmi()) {
@@ -4091,18 +4173,20 @@ static Object* ConvertCase(Arguments args,
 
 
 static Object* Runtime_StringToLowerCase(Arguments args) {
-  return ConvertCase<unibrow::ToLowercase>(args, &to_lower_mapping);
+  return ConvertCase<ToLowerTraits>(args, &to_lower_mapping);
 }
 
 
 static Object* Runtime_StringToUpperCase(Arguments args) {
-  return ConvertCase<unibrow::ToUppercase>(args, &to_upper_mapping);
+  return ConvertCase<ToUpperTraits>(args, &to_upper_mapping);
 }
 
+
 static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
   return unibrow::WhiteSpace::Is(c) || c == 0x200b;
 }
 
+
 static Object* Runtime_StringTrim(Arguments args) {
   NoHandleAllocation ha;
   ASSERT(args.length() == 3);
@@ -4111,7 +4195,7 @@ static Object* Runtime_StringTrim(Arguments args) {
   CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
   CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
 
-  s->TryFlattenIfNotFlat();
+  s->TryFlatten();
   int length = s->length();
 
   int left = 0;
@@ -4130,6 +4214,82 @@ static Object* Runtime_StringTrim(Arguments args) {
   return s->SubString(left, right);
 }
 
+
+// Copies ascii characters to the given fixed array looking up
+// one-char strings in the cache. Gives up on the first char that is
+// not in the cache and fills the remainder with smi zeros. Returns
+// the length of the successfully copied prefix.
+static int CopyCachedAsciiCharsToArray(const char* chars,
+                                       FixedArray* elements,
+                                       int length) {
+  AssertNoAllocation nogc;
+  FixedArray* ascii_cache = Heap::single_character_string_cache();
+  Object* undefined = Heap::undefined_value();
+  int i;
+  for (i = 0; i < length; ++i) {
+    Object* value = ascii_cache->get(chars[i]);
+    if (value == undefined) break;
+    ASSERT(!Heap::InNewSpace(value));
+    elements->set(i, value, SKIP_WRITE_BARRIER);
+  }
+  if (i < length) {
+    ASSERT(Smi::FromInt(0) == 0);
+    memset(elements->data_start() + i, 0, kPointerSize * (length - i));
+  }
+#ifdef DEBUG
+  for (int j = 0; j < length; ++j) {
+    Object* element = elements->get(j);
+    ASSERT(element == Smi::FromInt(0) ||
+           (element->IsString() && String::cast(element)->LooksValid()));
+  }
+#endif
+  return i;
+}
+
+
+// Converts a String to JSArray.
+// For example, "foo" => ["f", "o", "o"].
+static Object* Runtime_StringToArray(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 1);
+  CONVERT_ARG_CHECKED(String, s, 0);
+
+  s->TryFlatten();
+  const int length = s->length();
+
+  Handle<FixedArray> elements;
+  if (s->IsFlat() && s->IsAsciiRepresentation()) {
+    Object* obj = Heap::AllocateUninitializedFixedArray(length);
+    if (obj->IsFailure()) return obj;
+    elements = Handle<FixedArray>(FixedArray::cast(obj));
+
+    Vector<const char> chars = s->ToAsciiVector();
+    // Note, this will initialize all elements (not only the prefix)
+    // to prevent GC from seeing partially initialized array.
+    int num_copied_from_cache = CopyCachedAsciiCharsToArray(chars.start(),
+                                                            *elements,
+                                                            length);
+
+    for (int i = num_copied_from_cache; i < length; ++i) {
+      elements->set(i, *LookupSingleCharacterStringFromCode(chars[i]));
+    }
+  } else {
+    elements = Factory::NewFixedArray(length);
+    for (int i = 0; i < length; ++i) {
+      elements->set(i, *LookupSingleCharacterStringFromCode(s->Get(i)));
+    }
+  }
+
+#ifdef DEBUG
+  for (int i = 0; i < length; ++i) {
+    ASSERT(String::cast(elements->get(i))->length() == 1);
+  }
+#endif
+
+  return *Factory::NewJSArrayWithElements(elements);
+}
+
+
 bool Runtime::IsUpperCaseChar(uint16_t ch) {
   unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
   int char_length = to_upper_mapping.get(ch, 0, chars);
@@ -4152,9 +4312,12 @@ static Object* Runtime_NumberToInteger(Arguments args) {
   NoHandleAllocation ha;
   ASSERT(args.length() == 1);
 
-  Object* obj = args[0];
-  if (obj->IsSmi()) return obj;
-  CONVERT_DOUBLE_CHECKED(number, obj);
+  CONVERT_DOUBLE_CHECKED(number, args[0]);
+
+  // We do not include 0 so that we don't have to treat +0 / -0 cases.
+  if (number > 0 && number <= Smi::kMaxValue) {
+    return Smi::FromInt(static_cast<int>(number));
+  }
   return Heap::NumberFromDouble(DoubleToInteger(number));
 }
 
@@ -4163,9 +4326,7 @@ static Object* Runtime_NumberToJSUint32(Arguments args) {
   NoHandleAllocation ha;
   ASSERT(args.length() == 1);
 
-  Object* obj = args[0];
-  if (obj->IsSmi() && Smi::cast(obj)->value() >= 0) return obj;
-  CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, obj);
+  CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
   return Heap::NumberFromUint32(number);
 }
 
@@ -4174,9 +4335,12 @@ static Object* Runtime_NumberToJSInt32(Arguments args) {
   NoHandleAllocation ha;
   ASSERT(args.length() == 1);
 
-  Object* obj = args[0];
-  if (obj->IsSmi()) return obj;
-  CONVERT_DOUBLE_CHECKED(number, obj);
+  CONVERT_DOUBLE_CHECKED(number, args[0]);
+
+  // We do not include 0 so that we don't have to treat +0 / -0 cases.
+  if (number > 0 && number <= Smi::kMaxValue) {
+    return Smi::FromInt(static_cast<int>(number));
+  }
   return Heap::NumberFromInt32(DoubleToInt32(number));
 }
 
@@ -4593,6 +4757,66 @@ static Object* Runtime_SmiLexicographicCompare(Arguments args) {
 }
 
 
+static Object* StringInputBufferCompare(String* x, String* y) {
+  static StringInputBuffer bufx;
+  static StringInputBuffer bufy;
+  bufx.Reset(x);
+  bufy.Reset(y);
+  while (bufx.has_more() && bufy.has_more()) {
+    int d = bufx.GetNext() - bufy.GetNext();
+    if (d < 0) return Smi::FromInt(LESS);
+    else if (d > 0) return Smi::FromInt(GREATER);
+  }
+
+  // x is (non-trivial) prefix of y:
+  if (bufy.has_more()) return Smi::FromInt(LESS);
+  // y is prefix of x:
+  return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
+}
+
+
+static Object* FlatStringCompare(String* x, String* y) {
+  ASSERT(x->IsFlat());
+  ASSERT(y->IsFlat());
+  Object* equal_prefix_result = Smi::FromInt(EQUAL);
+  int prefix_length = x->length();
+  if (y->length() < prefix_length) {
+    prefix_length = y->length();
+    equal_prefix_result = Smi::FromInt(GREATER);
+  } else if (y->length() > prefix_length) {
+    equal_prefix_result = Smi::FromInt(LESS);
+  }
+  int r;
+  if (x->IsAsciiRepresentation()) {
+    Vector<const char> x_chars = x->ToAsciiVector();
+    if (y->IsAsciiRepresentation()) {
+      Vector<const char> y_chars = y->ToAsciiVector();
+      r = memcmp(x_chars.start(), y_chars.start(), prefix_length);
+    } else {
+      Vector<const uc16> y_chars = y->ToUC16Vector();
+      r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
+    }
+  } else {
+    Vector<const uc16> x_chars = x->ToUC16Vector();
+    if (y->IsAsciiRepresentation()) {
+      Vector<const char> y_chars = y->ToAsciiVector();
+      r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
+    } else {
+      Vector<const uc16> y_chars = y->ToUC16Vector();
+      r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
+    }
+  }
+  Object* result;
+  if (r == 0) {
+    result = equal_prefix_result;
+  } else {
+    result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
+  }
+  ASSERT(result == StringInputBufferCompare(x, y));
+  return result;
+}
+
+
 static Object* Runtime_StringCompare(Arguments args) {
   NoHandleAllocation ha;
   ASSERT(args.length() == 2);
@@ -4615,29 +4839,18 @@ static Object* Runtime_StringCompare(Arguments args) {
   if (d < 0) return Smi::FromInt(LESS);
   else if (d > 0) return Smi::FromInt(GREATER);
 
-  x->TryFlattenIfNotFlat();
-  y->TryFlattenIfNotFlat();
-
-  static StringInputBuffer bufx;
-  static StringInputBuffer bufy;
-  bufx.Reset(x);
-  bufy.Reset(y);
-  while (bufx.has_more() && bufy.has_more()) {
-    int d = bufx.GetNext() - bufy.GetNext();
-    if (d < 0) return Smi::FromInt(LESS);
-    else if (d > 0) return Smi::FromInt(GREATER);
-  }
+  x->TryFlatten();
+  y->TryFlatten();
 
-  // x is (non-trivial) prefix of y:
-  if (bufy.has_more()) return Smi::FromInt(LESS);
-  // y is prefix of x:
-  return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
+  return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
+                                      : StringInputBufferCompare(x, y);
 }
 
 
 static Object* Runtime_Math_abs(Arguments args) {
   NoHandleAllocation ha;
   ASSERT(args.length() == 1);
+  Counters::math_abs.Increment();
 
   CONVERT_DOUBLE_CHECKED(x, args[0]);
   return Heap::AllocateHeapNumber(fabs(x));
@@ -4647,6 +4860,7 @@ static Object* Runtime_Math_abs(Arguments args) {
 static Object* Runtime_Math_acos(Arguments args) {
   NoHandleAllocation ha;
   ASSERT(args.length() == 1);
+  Counters::math_acos.Increment();
 
   CONVERT_DOUBLE_CHECKED(x, args[0]);
   return TranscendentalCache::Get(TranscendentalCache::ACOS, x);
@@ -4656,6 +4870,7 @@ static Object* Runtime_Math_acos(Arguments args) {
 static Object* Runtime_Math_asin(Arguments args) {
   NoHandleAllocation ha;
   ASSERT(args.length() == 1);
+  Counters::math_asin.Increment();
 
   CONVERT_DOUBLE_CHECKED(x, args[0]);
   return TranscendentalCache::Get(TranscendentalCache::ASIN, x);
@@ -4665,6 +4880,7 @@ static Object* Runtime_Math_asin(Arguments args) {
 static Object* Runtime_Math_atan(Arguments args) {
   NoHandleAllocation ha;
   ASSERT(args.length() == 1);
+  Counters::math_atan.Increment();
 
   CONVERT_DOUBLE_CHECKED(x, args[0]);
   return TranscendentalCache::Get(TranscendentalCache::ATAN, x);
@@ -4674,6 +4890,7 @@ static Object* Runtime_Math_atan(Arguments args) {
 static Object* Runtime_Math_atan2(Arguments args) {
   NoHandleAllocation ha;
   ASSERT(args.length() == 2);
+  Counters::math_atan2.Increment();
 
   CONVERT_DOUBLE_CHECKED(x, args[0]);
   CONVERT_DOUBLE_CHECKED(y, args[1]);
@@ -4697,6 +4914,7 @@ static Object* Runtime_Math_atan2(Arguments args) {
 static Object* Runtime_Math_ceil(Arguments args) {
   NoHandleAllocation ha;
   ASSERT(args.length() == 1);
+  Counters::math_ceil.Increment();
 
   CONVERT_DOUBLE_CHECKED(x, args[0]);
   return Heap::NumberFromDouble(ceiling(x));
@@ -4706,6 +4924,7 @@ static Object* Runtime_Math_ceil(Arguments args) {
 static Object* Runtime_Math_cos(Arguments args) {
   NoHandleAllocation ha;
   ASSERT(args.length() == 1);
+  Counters::math_cos.Increment();
 
   CONVERT_DOUBLE_CHECKED(x, args[0]);
   return TranscendentalCache::Get(TranscendentalCache::COS, x);
@@ -4715,6 +4934,7 @@ static Object* Runtime_Math_cos(Arguments args) {
 static Object* Runtime_Math_exp(Arguments args) {
   NoHandleAllocation ha;
   ASSERT(args.length() == 1);
+  Counters::math_exp.Increment();
 
   CONVERT_DOUBLE_CHECKED(x, args[0]);
   return TranscendentalCache::Get(TranscendentalCache::EXP, x);
@@ -4724,6 +4944,7 @@ static Object* Runtime_Math_exp(Arguments args) {
 static Object* Runtime_Math_floor(Arguments args) {
   NoHandleAllocation ha;
   ASSERT(args.length() == 1);
+  Counters::math_floor.Increment();
 
   CONVERT_DOUBLE_CHECKED(x, args[0]);
   return Heap::NumberFromDouble(floor(x));
@@ -4733,6 +4954,7 @@ static Object* Runtime_Math_floor(Arguments args) {
 static Object* Runtime_Math_log(Arguments args) {
   NoHandleAllocation ha;
   ASSERT(args.length() == 1);
+  Counters::math_log.Increment();
 
   CONVERT_DOUBLE_CHECKED(x, args[0]);
   return TranscendentalCache::Get(TranscendentalCache::LOG, x);
@@ -4773,6 +4995,7 @@ static double powi(double x, int y) {
 static Object* Runtime_Math_pow(Arguments args) {
   NoHandleAllocation ha;
   ASSERT(args.length() == 2);
+  Counters::math_pow.Increment();
 
   CONVERT_DOUBLE_CHECKED(x, args[0]);
 
@@ -4807,10 +5030,27 @@ static Object* Runtime_Math_pow(Arguments args) {
   }
 }
 
+// Fast version of Math.pow if we know that y is not an integer and
+// y is not -0.5 or 0.5. Used as slowcase from codegen.
+static Object* Runtime_Math_pow_cfunction(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+  CONVERT_DOUBLE_CHECKED(x, args[0]);
+  CONVERT_DOUBLE_CHECKED(y, args[1]);
+  if (y == 0) {
+      return Smi::FromInt(1);
+  } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
+      return Heap::nan_value();
+  } else {
+      return Heap::AllocateHeapNumber(pow(x, y));
+  }
+}
+
 
 static Object* Runtime_Math_round(Arguments args) {
   NoHandleAllocation ha;
   ASSERT(args.length() == 1);
+  Counters::math_round.Increment();
 
   CONVERT_DOUBLE_CHECKED(x, args[0]);
   if (signbit(x) && x >= -0.5) return Heap::minus_zero_value();
@@ -4823,6 +5063,7 @@ static Object* Runtime_Math_round(Arguments args) {
 static Object* Runtime_Math_sin(Arguments args) {
   NoHandleAllocation ha;
   ASSERT(args.length() == 1);
+  Counters::math_sin.Increment();
 
   CONVERT_DOUBLE_CHECKED(x, args[0]);
   return TranscendentalCache::Get(TranscendentalCache::SIN, x);
@@ -4832,6 +5073,7 @@ static Object* Runtime_Math_sin(Arguments args) {
 static Object* Runtime_Math_sqrt(Arguments args) {
   NoHandleAllocation ha;
   ASSERT(args.length() == 1);
+  Counters::math_sqrt.Increment();
 
   CONVERT_DOUBLE_CHECKED(x, args[0]);
   return Heap::AllocateHeapNumber(sqrt(x));
@@ -4841,12 +5083,65 @@ static Object* Runtime_Math_sqrt(Arguments args) {
 static Object* Runtime_Math_tan(Arguments args) {
   NoHandleAllocation ha;
   ASSERT(args.length() == 1);
+  Counters::math_tan.Increment();
 
   CONVERT_DOUBLE_CHECKED(x, args[0]);
   return TranscendentalCache::Get(TranscendentalCache::TAN, x);
 }
 
 
+static Object* Runtime_DateMakeDay(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 3);
+
+  CONVERT_SMI_CHECKED(year, args[0]);
+  CONVERT_SMI_CHECKED(month, args[1]);
+  CONVERT_SMI_CHECKED(date, args[2]);
+
+  static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
+                                       181, 212, 243, 273, 304, 334};
+  static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
+                                            182, 213, 244, 274, 305, 335};
+
+  year += month / 12;
+  month %= 12;
+  if (month < 0) {
+    year--;
+    month += 12;
+  }
+
+  ASSERT(month >= 0);
+  ASSERT(month < 12);
+
+  // year_delta is an arbitrary number such that:
+  // a) year_delta = -1 (mod 400)
+  // b) year + year_delta > 0 for years in the range defined by
+  //    ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
+  //    Jan 1 1970. This is required so that we don't run into integer
+  //    division of negative numbers.
+  // c) there shouldn't be overflow for 32-bit integers in the following
+  //    operations.
+  static const int year_delta = 399999;
+  static const int base_day = 365 * (1970 + year_delta) +
+                              (1970 + year_delta) / 4 -
+                              (1970 + year_delta) / 100 +
+                              (1970 + year_delta) / 400;
+
+  int year1 = year + year_delta;
+  int day_from_year = 365 * year1 +
+                      year1 / 4 -
+                      year1 / 100 +
+                      year1 / 400 -
+                      base_day;
+
+  if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
+    return Smi::FromInt(day_from_year + day_from_month[month] + date - 1);
+  }
+
+  return Smi::FromInt(day_from_year + day_from_month_leap[month] + date - 1);
+}
+
+
 static Object* Runtime_NewArgumentsFast(Arguments args) {
   NoHandleAllocation ha;
   ASSERT(args.length() == 3);
@@ -5448,6 +5743,7 @@ static Object* Runtime_DebugPrint(Arguments args) {
   }
   args[0]->Print();
   if (args[0]->IsHeapObject()) {
+    PrintF("\n");
     HeapObject::cast(args[0])->map()->Print();
   }
 #else
@@ -7996,6 +8292,195 @@ static Object* Runtime_FunctionGetInferredName(Arguments args) {
   return f->shared()->inferred_name();
 }
 
+
+static int FindSharedFunctionInfosForScript(Script* script,
+                                     FixedArray* buffer) {
+  AssertNoAllocation no_allocations;
+
+  int counter = 0;
+  int buffer_size = buffer->length();
+  HeapIterator iterator;
+  for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
+    ASSERT(obj != NULL);
+    if (!obj->IsSharedFunctionInfo()) {
+      continue;
+    }
+    SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
+    if (shared->script() != script) {
+      continue;
+    }
+    if (counter < buffer_size) {
+      buffer->set(counter, shared);
+    }
+    counter++;
+  }
+  return counter;
+}
+
+// For a script finds all SharedFunctionInfo's in the heap that points
+// to this script. Returns JSArray of SharedFunctionInfo wrapped
+// in OpaqueReferences.
+static Object* Runtime_LiveEditFindSharedFunctionInfosForScript(
+    Arguments args) {
+  ASSERT(args.length() == 1);
+  HandleScope scope;
+  CONVERT_CHECKED(JSValue, script_value, args[0]);
+
+  Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
+
+  const int kBufferSize = 32;
+
+  Handle<FixedArray> array;
+  array = Factory::NewFixedArray(kBufferSize);
+  int number = FindSharedFunctionInfosForScript(*script, *array);
+  if (number > kBufferSize) {
+    array = Factory::NewFixedArray(number);
+    FindSharedFunctionInfosForScript(*script, *array);
+  }
+
+  Handle<JSArray> result = Factory::NewJSArrayWithElements(array);
+  result->set_length(Smi::FromInt(number));
+
+  LiveEdit::WrapSharedFunctionInfos(result);
+
+  return *result;
+}
+
+// For a script calculates compilation information about all its functions.
+// The script source is explicitly specified by the second argument.
+// The source of the actual script is not used, however it is important that
+// all generated code keeps references to this particular instance of script.
+// Returns a JSArray of compilation infos. The array is ordered so that
+// each function with all its descendant is always stored in a continues range
+// with the function itself going first. The root function is a script function.
+static Object* Runtime_LiveEditGatherCompileInfo(Arguments args) {
+  ASSERT(args.length() == 2);
+  HandleScope scope;
+  CONVERT_CHECKED(JSValue, script, args[0]);
+  CONVERT_ARG_CHECKED(String, source, 1);
+  Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
+
+  JSArray* result =  LiveEdit::GatherCompileInfo(script_handle, source);
+
+  if (Top::has_pending_exception()) {
+    return Failure::Exception();
+  }
+
+  return result;
+}
+
+// Changes the source of the script to a new_source and creates a new
+// script representing the old version of the script source.
+static Object* Runtime_LiveEditReplaceScript(Arguments args) {
+  ASSERT(args.length() == 3);
+  HandleScope scope;
+  CONVERT_CHECKED(JSValue, original_script_value, args[0]);
+  CONVERT_ARG_CHECKED(String, new_source, 1);
+  CONVERT_ARG_CHECKED(String, old_script_name, 2);
+  Handle<Script> original_script =
+      Handle<Script>(Script::cast(original_script_value->value()));
+
+  Handle<String> original_source(String::cast(original_script->source()));
+
+  original_script->set_source(*new_source);
+  Handle<Script> old_script = Factory::NewScript(original_source);
+  old_script->set_name(*old_script_name);
+  old_script->set_line_offset(original_script->line_offset());
+  old_script->set_column_offset(original_script->column_offset());
+  old_script->set_data(original_script->data());
+  old_script->set_type(original_script->type());
+  old_script->set_context_data(original_script->context_data());
+  old_script->set_compilation_type(original_script->compilation_type());
+  old_script->set_eval_from_shared(original_script->eval_from_shared());
+  old_script->set_eval_from_instructions_offset(
+      original_script->eval_from_instructions_offset());
+
+
+  Debugger::OnAfterCompile(old_script, Debugger::SEND_WHEN_DEBUGGING);
+
+  return *(GetScriptWrapper(old_script));
+}
+
+// Replaces code of SharedFunctionInfo with a new one.
+static Object* Runtime_LiveEditReplaceFunctionCode(Arguments args) {
+  ASSERT(args.length() == 2);
+  HandleScope scope;
+  CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
+  CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
+
+  LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
+
+  return Heap::undefined_value();
+}
+
+// Connects SharedFunctionInfo to another script.
+static Object* Runtime_LiveEditRelinkFunctionToScript(Arguments args) {
+  ASSERT(args.length() == 2);
+  HandleScope scope;
+  CONVERT_ARG_CHECKED(JSArray, shared_info_array, 0);
+  CONVERT_ARG_CHECKED(JSValue, script_value, 1);
+  Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
+
+  LiveEdit::RelinkFunctionToScript(shared_info_array, script);
+
+  return Heap::undefined_value();
+}
+
+// Updates positions of a shared function info (first parameter) according
+// to script source change. Text change is described in second parameter as
+// array of groups of 3 numbers:
+// (change_begin, change_end, change_end_new_position).
+// Each group describes a change in text; groups are sorted by change_begin.
+static Object* Runtime_LiveEditPatchFunctionPositions(Arguments args) {
+  ASSERT(args.length() == 2);
+  HandleScope scope;
+  CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
+  CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
+
+  LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
+
+  return Heap::undefined_value();
+}
+
+
+static LiveEdit::FunctionPatchabilityStatus FindFunctionCodeOnStacks(
+    Handle<SharedFunctionInfo> shared) {
+  // TODO(635): check all threads, not only the current one.
+  for (StackFrameIterator it; !it.done(); it.Advance()) {
+    StackFrame* frame = it.frame();
+    if (frame->code() == shared->code()) {
+      return LiveEdit::FUNCTION_BLOCKED_ON_STACK;
+    }
+  }
+  return LiveEdit::FUNCTION_AVAILABLE_FOR_PATCH;
+}
+
+// For array of SharedFunctionInfo's (each wrapped in JSValue)
+// checks that none of them have activations on stacks (of any thread).
+// Returns array of the same length with corresponding results of
+// LiveEdit::FunctionPatchabilityStatus type.
+static Object* Runtime_LiveEditCheckStackActivations(Arguments args) {
+  ASSERT(args.length() == 1);
+  HandleScope scope;
+  CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
+
+
+  int len = Smi::cast(shared_array->length())->value();
+  Handle<JSArray> result = Factory::NewJSArray(len);
+
+  for (int i = 0; i < len; i++) {
+    JSValue* wrapper = JSValue::cast(shared_array->GetElement(i));
+    Handle<SharedFunctionInfo> shared(
+        SharedFunctionInfo::cast(wrapper->value()));
+    LiveEdit::FunctionPatchabilityStatus check_res =
+        FindFunctionCodeOnStacks(shared);
+    SetElement(result, i, Handle<Smi>(Smi::FromInt(check_res)));
+  }
+
+  return *result;
+}
+
+
 #endif  // ENABLE_DEBUGGER_SUPPORT
 
 #ifdef ENABLE_LOGGING_AND_PROFILING
index e2e5c22..8c2f86d 100644 (file)
@@ -60,6 +60,7 @@ namespace internal {
   F(GetArgumentsProperty, 1, 1) \
   F(ToFastProperties, 1, 1) \
   F(ToSlowProperties, 1, 1) \
+  F(FinishArrayPrototypeSetup, 1, 1) \
   \
   F(IsInPrototypeChain, 2, 1) \
   F(SetHiddenPrototype, 2, 1) \
@@ -142,6 +143,7 @@ namespace internal {
   F(Math_floor, 1, 1) \
   F(Math_log, 1, 1) \
   F(Math_pow, 2, 1) \
+  F(Math_pow_cfunction, 2, 1) \
   F(Math_round, 1, 1) \
   F(Math_sin, 1, 1) \
   F(Math_sqrt, 1, 1) \
@@ -161,6 +163,7 @@ namespace internal {
   F(StringReplaceRegExpWithString, 4, 1) \
   F(StringMatch, 3, 1) \
   F(StringTrim, 3, 1) \
+  F(StringToArray, 1, 1) \
   \
   /* Numbers */ \
   F(NumberToRadixString, 2, 1) \
@@ -200,6 +203,7 @@ namespace internal {
   F(DateLocalTimezone, 1, 1) \
   F(DateLocalTimeOffset, 0, 1) \
   F(DateDaylightSavingsOffset, 1, 1) \
+  F(DateMakeDay, 3, 1) \
   \
   /* Numbers */ \
   F(NumberIsFinite, 1, 1) \
@@ -321,7 +325,14 @@ namespace internal {
   F(SystemBreak, 0, 1) \
   F(DebugDisassembleFunction, 1, 1) \
   F(DebugDisassembleConstructor, 1, 1) \
-  F(FunctionGetInferredName, 1, 1)
+  F(FunctionGetInferredName, 1, 1) \
+  F(LiveEditFindSharedFunctionInfosForScript, 1, 1) \
+  F(LiveEditGatherCompileInfo, 2, 1) \
+  F(LiveEditReplaceScript, 3, 1) \
+  F(LiveEditReplaceFunctionCode, 2, 1) \
+  F(LiveEditRelinkFunctionToScript, 2, 1) \
+  F(LiveEditPatchFunctionPositions, 2, 1) \
+  F(LiveEditCheckStackActivations, 1, 1)
 #else
 #define RUNTIME_FUNCTION_LIST_DEBUGGER_SUPPORT(F)
 #endif
@@ -400,6 +411,7 @@ class Runtime : public AllStatic {
   // Support getting the characters in a string using [] notation as
   // in Firefox/SpiderMonkey, Safari and Opera.
   static Object* GetElementOrCharAt(Handle<Object> object, uint32_t index);
+  static Object* GetElement(Handle<Object> object, uint32_t index);
 
   static Object* SetObjectProperty(Handle<Object> object,
                                    Handle<Object> key,
index e9d9848..d777041 100644 (file)
@@ -478,7 +478,7 @@ function STRING_CHAR_AT(pos) {
   if (!%_IsSmi(char_code)) {
     return %StringCharAt(this, pos);
   }
-  return %CharFromCode(char_code);
+  return %_CharFromCode(char_code);
 }
 
 
index cf7e49f..8943119 100755 (executable)
@@ -28,6 +28,7 @@
 #include "v8.h"
 
 #include "ast.h"
+#include "handles.h"
 #include "scanner.h"
 
 namespace v8 {
@@ -86,12 +87,7 @@ void UTF8Buffer::AddCharSlow(uc32 c) {
 
 
 UTF16Buffer::UTF16Buffer()
-    : pos_(0), size_(0) { }
-
-
-Handle<String> UTF16Buffer::SubString(int start, int end) {
-  return internal::SubString(data_, start, end);
-}
+    : pos_(0), end_(Scanner::kNoEndPosition) { }
 
 
 // CharacterStreamUTF16Buffer
@@ -100,10 +96,14 @@ CharacterStreamUTF16Buffer::CharacterStreamUTF16Buffer()
 
 
 void CharacterStreamUTF16Buffer::Initialize(Handle<String> data,
-                                            unibrow::CharacterStream* input) {
-  data_ = data;
-  pos_ = 0;
+                                            unibrow::CharacterStream* input,
+                                            int start_position,
+                                            int end_position) {
   stream_ = input;
+  if (start_position > 0) {
+    SeekForward(start_position);
+  }
+  end_ = end_position != Scanner::kNoEndPosition ? end_position : kMaxInt;
 }
 
 
@@ -115,6 +115,8 @@ void CharacterStreamUTF16Buffer::PushBack(uc32 ch) {
 
 
 uc32 CharacterStreamUTF16Buffer::Advance() {
+  ASSERT(end_ != Scanner::kNoEndPosition);
+  ASSERT(end_ >= 0);
   // NOTE: It is of importance to Persian / Farsi resources that we do
   // *not* strip format control characters in the scanner; see
   //
@@ -126,7 +128,7 @@ uc32 CharacterStreamUTF16Buffer::Advance() {
   if (!pushback_buffer()->is_empty()) {
     pos_++;
     return last_ = pushback_buffer()->RemoveLast();
-  } else if (stream_->has_more()) {
+  } else if (stream_->has_more() && pos_ < end_) {
     pos_++;
     uc32 next = stream_->GetNext();
     return last_ = next;
@@ -146,25 +148,32 @@ void CharacterStreamUTF16Buffer::SeekForward(int pos) {
 }
 
 
-// TwoByteStringUTF16Buffer
-TwoByteStringUTF16Buffer::TwoByteStringUTF16Buffer()
+// ExternalStringUTF16Buffer
+template <typename StringType, typename CharType>
+ExternalStringUTF16Buffer<StringType, CharType>::ExternalStringUTF16Buffer()
     : raw_data_(NULL) { }
 
 
-void TwoByteStringUTF16Buffer::Initialize(
-     Handle<ExternalTwoByteString> data) {
+template <typename StringType, typename CharType>
+void ExternalStringUTF16Buffer<StringType, CharType>::Initialize(
+     Handle<StringType> data,
+     int start_position,
+     int end_position) {
   ASSERT(!data.is_null());
-
-  data_ = data;
-  pos_ = 0;
-
   raw_data_ = data->resource()->data();
-  size_ = data->length();
+
+  ASSERT(end_position <= data->length());
+  if (start_position > 0) {
+    SeekForward(start_position);
+  }
+  end_ =
+      end_position != Scanner::kNoEndPosition ? end_position : data->length();
 }
 
 
-uc32 TwoByteStringUTF16Buffer::Advance() {
-  if (pos_ < size_) {
+template <typename StringType, typename CharType>
+uc32 ExternalStringUTF16Buffer<StringType, CharType>::Advance() {
+  if (pos_ < end_) {
     return raw_data_[pos_++];
   } else {
     // note: currently the following increment is necessary to avoid a
@@ -175,14 +184,16 @@ uc32 TwoByteStringUTF16Buffer::Advance() {
 }
 
 
-void TwoByteStringUTF16Buffer::PushBack(uc32 ch) {
+template <typename StringType, typename CharType>
+void ExternalStringUTF16Buffer<StringType, CharType>::PushBack(uc32 ch) {
   pos_--;
   ASSERT(pos_ >= Scanner::kCharacterLookaheadBufferSize);
   ASSERT(raw_data_[pos_ - Scanner::kCharacterLookaheadBufferSize] == ch);
 }
 
 
-void TwoByteStringUTF16Buffer::SeekForward(int pos) {
+template <typename StringType, typename CharType>
+void ExternalStringUTF16Buffer<StringType, CharType>::SeekForward(int pos) {
   pos_ = pos;
 }
 
@@ -327,21 +338,56 @@ Scanner::Scanner(ParserMode pre)
     : stack_overflow_(false), is_pre_parsing_(pre == PREPARSE) { }
 
 
+void Scanner::Initialize(Handle<String> source,
+                         ParserLanguage language) {
+  safe_string_input_buffer_.Reset(source.location());
+  Init(source, &safe_string_input_buffer_, 0, source->length(), language);
+}
+
+
+void Scanner::Initialize(Handle<String> source,
+                         unibrow::CharacterStream* stream,
+                         ParserLanguage language) {
+  Init(source, stream, 0, kNoEndPosition, language);
+}
+
+
+void Scanner::Initialize(Handle<String> source,
+                         int start_position,
+                         int end_position,
+                         ParserLanguage language) {
+  safe_string_input_buffer_.Reset(source.location());
+  Init(source, &safe_string_input_buffer_,
+       start_position, end_position, language);
+}
+
+
 void Scanner::Init(Handle<String> source,
                    unibrow::CharacterStream* stream,
-                   int position,
+                   int start_position,
+                   int end_position,
                    ParserLanguage language) {
   // Initialize the source buffer.
   if (!source.is_null() && StringShape(*source).IsExternalTwoByte()) {
     two_byte_string_buffer_.Initialize(
-        Handle<ExternalTwoByteString>::cast(source));
+        Handle<ExternalTwoByteString>::cast(source),
+        start_position,
+        end_position);
     source_ = &two_byte_string_buffer_;
+  } else if (!source.is_null() && StringShape(*source).IsExternalAscii()) {
+    ascii_string_buffer_.Initialize(
+        Handle<ExternalAsciiString>::cast(source),
+        start_position,
+        end_position);
+    source_ = &ascii_string_buffer_;
   } else {
-    char_stream_buffer_.Initialize(source, stream);
+    char_stream_buffer_.Initialize(source,
+                                   stream,
+                                   start_position,
+                                   end_position);
     source_ = &char_stream_buffer_;
   }
 
-  position_ = position;
   is_parsing_json_ = (language == JSON);
 
   // Set c0_ (one character ahead)
@@ -358,11 +404,6 @@ void Scanner::Init(Handle<String> source,
 }
 
 
-Handle<String> Scanner::SubString(int start, int end) {
-  return source_->SubString(start - position_, end - position_);
-}
-
-
 Token::Value Scanner::Next() {
   // BUG 1215673: Find a thread safe way to set a stack limit in
   // pre-parse mode. Otherwise, we cannot safely pre-parse from other
index f0035c0..d5efdff 100644 (file)
@@ -84,32 +84,34 @@ class UTF8Buffer {
 };
 
 
+// Interface through which the scanner reads characters from the input source.
 class UTF16Buffer {
  public:
   UTF16Buffer();
   virtual ~UTF16Buffer() {}
 
   virtual void PushBack(uc32 ch) = 0;
-  // returns a value < 0 when the buffer end is reached
+  // Returns a value < 0 when the buffer end is reached.
   virtual uc32 Advance() = 0;
   virtual void SeekForward(int pos) = 0;
 
   int pos() const { return pos_; }
-  int size() const { return size_; }
-  Handle<String> SubString(int start, int end);
 
  protected:
-  Handle<String> data_;
-  int pos_;
-  int size_;
+  int pos_;  // Current position in the buffer.
+  int end_;  // Position where scanning should stop (EOF).
 };
 
 
+// UTF16 buffer to read characters from a character stream.
 class CharacterStreamUTF16Buffer: public UTF16Buffer {
  public:
   CharacterStreamUTF16Buffer();
   virtual ~CharacterStreamUTF16Buffer() {}
-  void Initialize(Handle<String> data, unibrow::CharacterStream* stream);
+  void Initialize(Handle<String> data,
+                  unibrow::CharacterStream* stream,
+                  int start_position,
+                  int end_position);
   virtual void PushBack(uc32 ch);
   virtual uc32 Advance();
   virtual void SeekForward(int pos);
@@ -123,17 +125,21 @@ class CharacterStreamUTF16Buffer: public UTF16Buffer {
 };
 
 
-class TwoByteStringUTF16Buffer: public UTF16Buffer {
+// UTF16 buffer to read characters from an external string.
+template <typename StringType, typename CharType>
+class ExternalStringUTF16Buffer: public UTF16Buffer {
  public:
-  TwoByteStringUTF16Buffer();
-  virtual ~TwoByteStringUTF16Buffer() {}
-  void Initialize(Handle<ExternalTwoByteString> data);
+  ExternalStringUTF16Buffer();
+  virtual ~ExternalStringUTF16Buffer() {}
+  void Initialize(Handle<StringType> data,
+                  int start_position,
+                  int end_position);
   virtual void PushBack(uc32 ch);
   virtual uc32 Advance();
   virtual void SeekForward(int pos);
 
  private:
-  const uint16_t* raw_data_;
+  const CharType* raw_data_;  // Pointer to the actual array of characters.
 };
 
 
@@ -263,11 +269,15 @@ class Scanner {
   // Construction
   explicit Scanner(ParserMode parse_mode);
 
-  // Initialize the Scanner to scan source:
-  void Init(Handle<String> source,
-            unibrow::CharacterStream* stream,
-            int position,
-            ParserLanguage language);
+  // Initialize the Scanner to scan source.
+  void Initialize(Handle<String> source,
+                  ParserLanguage language);
+  void Initialize(Handle<String> source,
+                  unibrow::CharacterStream* stream,
+                  ParserLanguage language);
+  void Initialize(Handle<String> source,
+                  int start_position, int end_position,
+                  ParserLanguage language);
 
   // Returns the next token.
   Token::Value Next();
@@ -335,7 +345,6 @@ class Scanner {
   // tokens, which is what it is used for.
   void SeekForward(int pos);
 
-  Handle<String> SubString(int start_pos, int end_pos);
   bool stack_overflow() { return stack_overflow_; }
 
   static StaticResource<Utf8Decoder>* utf8_decoder() { return &utf8_decoder_; }
@@ -350,14 +359,28 @@ class Scanner {
   static unibrow::Predicate<unibrow::WhiteSpace, 128> kIsWhiteSpace;
 
   static const int kCharacterLookaheadBufferSize = 1;
+  static const int kNoEndPosition = 1;
 
  private:
+  void Init(Handle<String> source,
+            unibrow::CharacterStream* stream,
+            int start_position, int end_position,
+            ParserLanguage language);
+
+
+  // Different UTF16 buffers used to pull characters from. Based on input one of
+  // these will be initialized as the actual data source.
   CharacterStreamUTF16Buffer char_stream_buffer_;
-  TwoByteStringUTF16Buffer two_byte_string_buffer_;
+  ExternalStringUTF16Buffer<ExternalTwoByteString, uint16_t>
+      two_byte_string_buffer_;
+  ExternalStringUTF16Buffer<ExternalAsciiString, char> ascii_string_buffer_;
 
-  // Source.
+  // Source. Will point to one of the buffers declared above.
   UTF16Buffer* source_;
-  int position_;
+
+  // Used to convert the source string into a character stream when a stream
+  // is not passed to the scanner.
+  SafeStringInputBuffer safe_string_input_buffer_;
 
   // Buffer to hold literal values (identifiers, strings, numbers)
   // using 0-terminated UTF-8 encoding.
@@ -460,7 +483,7 @@ class Scanner {
 
   // Return the current source position.
   int source_pos() {
-    return source_->pos() - kCharacterLookaheadBufferSize + position_;
+    return source_->pos() - kCharacterLookaheadBufferSize;
   }
 
   // Decodes a unicode escape-sequence which is part of an identifier.
index de1841b..8b7e2ad 100644 (file)
@@ -82,7 +82,7 @@ ScopeInfo<Allocator>::ScopeInfo(Scope* scope)
   List<Variable*, Allocator> heap_locals(locals.length());
   for (int i = 0; i < locals.length(); i++) {
     Variable* var = locals[i];
-    if (var->var_uses()->is_used()) {
+    if (var->is_used()) {
       Slot* slot = var->slot();
       if (slot != NULL) {
         switch (slot->type()) {
@@ -130,7 +130,7 @@ ScopeInfo<Allocator>::ScopeInfo(Scope* scope)
   if (scope->is_function_scope()) {
     Variable* var = scope->function();
     if (var != NULL &&
-        var->var_uses()->is_used() &&
+        var->is_used() &&
         var->slot()->type() == Slot::CONTEXT) {
       function_name_ = var->name();
       // Note that we must not find the function name in the context slot
index 28d169a..927ac66 100644 (file)
@@ -29,6 +29,7 @@
 #define V8_SCOPEINFO_H_
 
 #include "variables.h"
+#include "zone-inl.h"
 
 namespace v8 {
 namespace internal {
index 701e5e3..b55e5d5 100644 (file)
@@ -309,7 +309,7 @@ void Scope::CollectUsedVariables(List<Variable*, Allocator>* locals) {
   // which is the current user of this function).
   for (int i = 0; i < temps_.length(); i++) {
     Variable* var = temps_[i];
-    if (var->var_uses()->is_used()) {
+    if (var->is_used()) {
       locals->Add(var);
     }
   }
@@ -317,7 +317,7 @@ void Scope::CollectUsedVariables(List<Variable*, Allocator>* locals) {
        p != NULL;
        p = variables_.Next(p)) {
     Variable* var = reinterpret_cast<Variable*>(p->value);
-    if (var->var_uses()->is_used()) {
+    if (var->is_used()) {
       locals->Add(var);
     }
   }
@@ -418,17 +418,16 @@ static void PrintName(Handle<String> name) {
 
 
 static void PrintVar(PrettyPrinter* printer, int indent, Variable* var) {
-  if (var->var_uses()->is_used() || var->rewrite() != NULL) {
+  if (var->is_used() || var->rewrite() != NULL) {
     Indent(indent, Variable::Mode2String(var->mode()));
     PrintF(" ");
     PrintName(var->name());
     PrintF(";  // ");
-    if (var->rewrite() != NULL) PrintF("%s, ", printer->Print(var->rewrite()));
-    if (var->is_accessed_from_inner_scope()) PrintF("inner scope access, ");
-    PrintF("var ");
-    var->var_uses()->Print();
-    PrintF(", obj ");
-    var->obj_uses()->Print();
+    if (var->rewrite() != NULL) {
+      PrintF("%s, ", printer->Print(var->rewrite()));
+      if (var->is_accessed_from_inner_scope()) PrintF(", ");
+    }
+    if (var->is_accessed_from_inner_scope()) PrintF("inner scope access");
     PrintF("\n");
   }
 }
@@ -738,10 +737,10 @@ bool Scope::MustAllocate(Variable* var) {
       (var->is_accessed_from_inner_scope_ ||
        scope_calls_eval_ || inner_scope_calls_eval_ ||
        scope_contains_with_)) {
-    var->var_uses()->RecordAccess(1);
+    var->set_is_used(true);
   }
   // Global variables do not need to be allocated.
-  return !var->is_global() && var->var_uses()->is_used();
+  return !var->is_global() && var->is_used();
 }
 
 
@@ -847,7 +846,7 @@ void Scope::AllocateParameterLocals() {
                        new Literal(Handle<Object>(Smi::FromInt(i))),
                        RelocInfo::kNoPosition,
                        Property::SYNTHETIC);
-        arguments_shadow->var_uses()->RecordUses(var->var_uses());
+        if (var->is_used()) arguments_shadow->set_is_used(true);
       }
     }
 
index 0819ec2..a95a7d6 100644 (file)
@@ -359,79 +359,87 @@ void ExternalReferenceTable::PopulateTable() {
       UNCLASSIFIED,
       7,
       "Heap::NewSpaceStart()");
-  Add(ExternalReference::heap_always_allocate_scope_depth().address(),
+  Add(ExternalReference::new_space_mask().address(),
       UNCLASSIFIED,
       8,
+      "Heap::NewSpaceMask()");
+  Add(ExternalReference::heap_always_allocate_scope_depth().address(),
+      UNCLASSIFIED,
+      9,
       "Heap::always_allocate_scope_depth()");
   Add(ExternalReference::new_space_allocation_limit_address().address(),
       UNCLASSIFIED,
-      9,
+      10,
       "Heap::NewSpaceAllocationLimitAddress()");
   Add(ExternalReference::new_space_allocation_top_address().address(),
       UNCLASSIFIED,
-      10,
+      11,
       "Heap::NewSpaceAllocationTopAddress()");
 #ifdef ENABLE_DEBUGGER_SUPPORT
   Add(ExternalReference::debug_break().address(),
       UNCLASSIFIED,
-      11,
+      12,
       "Debug::Break()");
   Add(ExternalReference::debug_step_in_fp_address().address(),
       UNCLASSIFIED,
-      12,
+      13,
       "Debug::step_in_fp_addr()");
 #endif
   Add(ExternalReference::double_fp_operation(Token::ADD).address(),
       UNCLASSIFIED,
-      13,
+      14,
       "add_two_doubles");
   Add(ExternalReference::double_fp_operation(Token::SUB).address(),
       UNCLASSIFIED,
-      14,
+      15,
       "sub_two_doubles");
   Add(ExternalReference::double_fp_operation(Token::MUL).address(),
       UNCLASSIFIED,
-      15,
+      16,
       "mul_two_doubles");
   Add(ExternalReference::double_fp_operation(Token::DIV).address(),
       UNCLASSIFIED,
-      16,
+      17,
       "div_two_doubles");
   Add(ExternalReference::double_fp_operation(Token::MOD).address(),
       UNCLASSIFIED,
-      17,
+      18,
       "mod_two_doubles");
   Add(ExternalReference::compare_doubles().address(),
       UNCLASSIFIED,
-      18,
+      19,
       "compare_doubles");
 #ifdef V8_NATIVE_REGEXP
   Add(ExternalReference::re_case_insensitive_compare_uc16().address(),
       UNCLASSIFIED,
-      19,
+      20,
       "NativeRegExpMacroAssembler::CaseInsensitiveCompareUC16()");
   Add(ExternalReference::re_check_stack_guard_state().address(),
       UNCLASSIFIED,
-      20,
+      21,
       "RegExpMacroAssembler*::CheckStackGuardState()");
   Add(ExternalReference::re_grow_stack().address(),
       UNCLASSIFIED,
-      21,
+      22,
       "NativeRegExpMacroAssembler::GrowStack()");
   Add(ExternalReference::re_word_character_map().address(),
       UNCLASSIFIED,
-      22,
+      23,
       "NativeRegExpMacroAssembler::word_character_map");
 #endif
   // Keyed lookup cache.
   Add(ExternalReference::keyed_lookup_cache_keys().address(),
       UNCLASSIFIED,
-      23,
+      24,
       "KeyedLookupCache::keys()");
   Add(ExternalReference::keyed_lookup_cache_field_offsets().address(),
       UNCLASSIFIED,
-      24,
+      25,
       "KeyedLookupCache::field_offsets()");
+  Add(ExternalReference::transcendental_cache_array_address().address(),
+      UNCLASSIFIED,
+      26,
+      "TranscendentalCache::caches()");
 }
 
 
index 2c495d8..08399ee 100644 (file)
@@ -1379,6 +1379,7 @@ static void ReportCodeKindStatistics() {
       CASE(STORE_IC);
       CASE(KEYED_STORE_IC);
       CASE(CALL_IC);
+      CASE(BINARY_OP_IC);
     }
   }
 
@@ -1413,7 +1414,7 @@ static void ReportHistogram(bool print_spill) {
   PrintF("\n  Object Histogram:\n");
   for (int i = 0; i <= LAST_TYPE; i++) {
     if (heap_histograms[i].number() > 0) {
-      PrintF("    %-33s%10d (%10d bytes)\n",
+      PrintF("    %-34s%10d (%10d bytes)\n",
              heap_histograms[i].name(),
              heap_histograms[i].number(),
              heap_histograms[i].bytes());
@@ -1430,7 +1431,7 @@ static void ReportHistogram(bool print_spill) {
   STRING_TYPE_LIST(INCREMENT)
 #undef INCREMENT
   if (string_number > 0) {
-    PrintF("    %-33s%10d (%10d bytes)\n\n", "STRING_TYPE", string_number,
+    PrintF("    %-34s%10d (%10d bytes)\n\n", "STRING_TYPE", string_number,
            string_bytes);
   }
 
@@ -1499,7 +1500,7 @@ void NewSpace::ReportStatistics() {
     PrintF("\n  Object Histogram:\n");
     for (int i = 0; i <= LAST_TYPE; i++) {
       if (allocated_histogram_[i].number() > 0) {
-        PrintF("    %-33s%10d (%10d bytes)\n",
+        PrintF("    %-34s%10d (%10d bytes)\n",
                allocated_histogram_[i].name(),
                allocated_histogram_[i].number(),
                allocated_histogram_[i].bytes());
diff --git a/deps/v8/src/splay-tree-inl.h b/deps/v8/src/splay-tree-inl.h
new file mode 100644 (file)
index 0000000..16fe25e
--- /dev/null
@@ -0,0 +1,276 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_SPLAY_TREE_INL_H_
+#define V8_SPLAY_TREE_INL_H_
+
+#include "splay-tree.h"
+
+namespace v8 {
+namespace internal {
+
+
+template<typename Config, class Allocator>
+SplayTree<Config, Allocator>::~SplayTree() {
+  NodeDeleter deleter;
+  ForEachNode(&deleter);
+}
+
+
+template<typename Config, class Allocator>
+bool SplayTree<Config, Allocator>::Insert(const Key& key, Locator* locator) {
+  if (is_empty()) {
+    // If the tree is empty, insert the new node.
+    root_ = new Node(key, Config::kNoValue);
+  } else {
+    // Splay on the key to move the last node on the search path
+    // for the key to the root of the tree.
+    Splay(key);
+    // Ignore repeated insertions with the same key.
+    int cmp = Config::Compare(key, root_->key_);
+    if (cmp == 0) {
+      locator->bind(root_);
+      return false;
+    }
+    // Insert the new node.
+    Node* node = new Node(key, Config::kNoValue);
+    if (cmp > 0) {
+      node->left_ = root_;
+      node->right_ = root_->right_;
+      root_->right_ = NULL;
+    } else {
+      node->right_ = root_;
+      node->left_ = root_->left_;
+      root_->left_ = NULL;
+    }
+    root_ = node;
+  }
+  locator->bind(root_);
+  return true;
+}
+
+
+template<typename Config, class Allocator>
+bool SplayTree<Config, Allocator>::Find(const Key& key, Locator* locator) {
+  if (is_empty())
+    return false;
+  Splay(key);
+  if (Config::Compare(key, root_->key_) == 0) {
+    locator->bind(root_);
+    return true;
+  } else {
+    return false;
+  }
+}
+
+
+template<typename Config, class Allocator>
+bool SplayTree<Config, Allocator>::FindGreatestLessThan(const Key& key,
+                                                        Locator* locator) {
+  if (is_empty())
+    return false;
+  // Splay on the key to move the node with the given key or the last
+  // node on the search path to the top of the tree.
+  Splay(key);
+  // Now the result is either the root node or the greatest node in
+  // the left subtree.
+  int cmp = Config::Compare(root_->key_, key);
+  if (cmp <= 0) {
+    locator->bind(root_);
+    return true;
+  } else {
+    Node* temp = root_;
+    root_ = root_->left_;
+    bool result = FindGreatest(locator);
+    root_ = temp;
+    return result;
+  }
+}
+
+
+template<typename Config, class Allocator>
+bool SplayTree<Config, Allocator>::FindLeastGreaterThan(const Key& key,
+                                                        Locator* locator) {
+  if (is_empty())
+    return false;
+  // Splay on the key to move the node with the given key or the last
+  // node on the search path to the top of the tree.
+  Splay(key);
+  // Now the result is either the root node or the least node in
+  // the right subtree.
+  int cmp = Config::Compare(root_->key_, key);
+  if (cmp >= 0) {
+    locator->bind(root_);
+    return true;
+  } else {
+    Node* temp = root_;
+    root_ = root_->right_;
+    bool result = FindLeast(locator);
+    root_ = temp;
+    return result;
+  }
+}
+
+
+template<typename Config, class Allocator>
+bool SplayTree<Config, Allocator>::FindGreatest(Locator* locator) {
+  if (is_empty())
+    return false;
+  Node* current = root_;
+  while (current->right_ != NULL)
+    current = current->right_;
+  locator->bind(current);
+  return true;
+}
+
+
+template<typename Config, class Allocator>
+bool SplayTree<Config, Allocator>::FindLeast(Locator* locator) {
+  if (is_empty())
+    return false;
+  Node* current = root_;
+  while (current->left_ != NULL)
+    current = current->left_;
+  locator->bind(current);
+  return true;
+}
+
+
+template<typename Config, class Allocator>
+bool SplayTree<Config, Allocator>::Remove(const Key& key) {
+  // Bail if the tree is empty
+  if (is_empty())
+    return false;
+  // Splay on the key to move the node with the given key to the top.
+  Splay(key);
+  // Bail if the key is not in the tree
+  if (Config::Compare(key, root_->key_) != 0)
+    return false;
+  if (root_->left_ == NULL) {
+    // No left child, so the new tree is just the right child.
+    root_ = root_->right_;
+  } else {
+    // Left child exists.
+    Node* right = root_->right_;
+    // Make the original left child the new root.
+    root_ = root_->left_;
+    // Splay to make sure that the new root has an empty right child.
+    Splay(key);
+    // Insert the original right child as the right child of the new
+    // root.
+    root_->right_ = right;
+  }
+  return true;
+}
+
+
+template<typename Config, class Allocator>
+void SplayTree<Config, Allocator>::Splay(const Key& key) {
+  if (is_empty())
+    return;
+  Node dummy_node(Config::kNoKey, Config::kNoValue);
+  // Create a dummy node.  The use of the dummy node is a bit
+  // counter-intuitive: The right child of the dummy node will hold
+  // the L tree of the algorithm.  The left child of the dummy node
+  // will hold the R tree of the algorithm.  Using a dummy node, left
+  // and right will always be nodes and we avoid special cases.
+  Node* dummy = &dummy_node;
+  Node* left = dummy;
+  Node* right = dummy;
+  Node* current = root_;
+  while (true) {
+    int cmp = Config::Compare(key, current->key_);
+    if (cmp < 0) {
+      if (current->left_ == NULL)
+        break;
+      if (Config::Compare(key, current->left_->key_) < 0) {
+        // Rotate right.
+        Node* temp = current->left_;
+        current->left_ = temp->right_;
+        temp->right_ = current;
+        current = temp;
+        if (current->left_ == NULL)
+          break;
+      }
+      // Link right.
+      right->left_ = current;
+      right = current;
+      current = current->left_;
+    } else if (cmp > 0) {
+      if (current->right_ == NULL)
+        break;
+      if (Config::Compare(key, current->right_->key_) > 0) {
+        // Rotate left.
+        Node* temp = current->right_;
+        current->right_ = temp->left_;
+        temp->left_ = current;
+        current = temp;
+        if (current->right_ == NULL)
+          break;
+      }
+      // Link left.
+      left->right_ = current;
+      left = current;
+      current = current->right_;
+    } else {
+      break;
+    }
+  }
+  // Assemble.
+  left->right_ = current->left_;
+  right->left_ = current->right_;
+  current->left_ = dummy->right_;
+  current->right_ = dummy->left_;
+  root_ = current;
+}
+
+
+template <typename Config, class Allocator> template <class Callback>
+void SplayTree<Config, Allocator>::ForEach(Callback* callback) {
+  NodeToPairAdaptor<Callback> callback_adaptor(callback);
+  ForEachNode(&callback_adaptor);
+}
+
+
+template <typename Config, class Allocator> template <class Callback>
+void SplayTree<Config, Allocator>::ForEachNode(Callback* callback) {
+  // Pre-allocate some space for tiny trees.
+  List<Node*, Allocator> nodes_to_visit(10);
+  if (root_ != NULL) nodes_to_visit.Add(root_);
+  int pos = 0;
+  while (pos < nodes_to_visit.length()) {
+    Node* node = nodes_to_visit[pos++];
+    if (node->left() != NULL) nodes_to_visit.Add(node->left());
+    if (node->right() != NULL) nodes_to_visit.Add(node->right());
+    callback->Call(node);
+  }
+}
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_SPLAY_TREE_INL_H_
diff --git a/deps/v8/src/splay-tree.h b/deps/v8/src/splay-tree.h
new file mode 100644 (file)
index 0000000..b0f415d
--- /dev/null
@@ -0,0 +1,191 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_SPLAY_TREE_H_
+#define V8_SPLAY_TREE_H_
+
+namespace v8 {
+namespace internal {
+
+
+// A splay tree.  The config type parameter encapsulates the different
+// configurations of a concrete splay tree:
+//
+//   typedef Key: the key type
+//   typedef Value: the value type
+//   static const kNoKey: the dummy key used when no key is set
+//   static const kNoValue: the dummy value used to initialize nodes
+//   int (Compare)(Key& a, Key& b) -> {-1, 0, 1}: comparison function
+//
+// The tree is also parameterized by an allocation policy
+// (Allocator). The policy is used for allocating lists in the C free
+// store or the zone; see zone.h.
+
+// Forward defined as
+// template <typename Config, class Allocator = FreeStoreAllocationPolicy>
+//     class SplayTree;
+template <typename Config, class Allocator>
+class SplayTree {
+ public:
+  typedef typename Config::Key Key;
+  typedef typename Config::Value Value;
+
+  class Locator;
+
+  SplayTree() : root_(NULL) { }
+  ~SplayTree();
+
+  INLINE(void* operator new(size_t size)) {
+    return Allocator::New(static_cast<int>(size));
+  }
+  INLINE(void operator delete(void* p, size_t)) { return Allocator::Delete(p); }
+
+  // Inserts the given key in this tree with the given value.  Returns
+  // true if a node was inserted, otherwise false.  If found the locator
+  // is enabled and provides access to the mapping for the key.
+  bool Insert(const Key& key, Locator* locator);
+
+  // Looks up the key in this tree and returns true if it was found,
+  // otherwise false.  If the node is found the locator is enabled and
+  // provides access to the mapping for the key.
+  bool Find(const Key& key, Locator* locator);
+
+  // Finds the mapping with the greatest key less than or equal to the
+  // given key.
+  bool FindGreatestLessThan(const Key& key, Locator* locator);
+
+  // Find the mapping with the greatest key in this tree.
+  bool FindGreatest(Locator* locator);
+
+  // Finds the mapping with the least key greater than or equal to the
+  // given key.
+  bool FindLeastGreaterThan(const Key& key, Locator* locator);
+
+  // Find the mapping with the least key in this tree.
+  bool FindLeast(Locator* locator);
+
+  // Remove the node with the given key from the tree.
+  bool Remove(const Key& key);
+
+  bool is_empty() { return root_ == NULL; }
+
+  // Perform the splay operation for the given key. Moves the node with
+  // the given key to the top of the tree.  If no node has the given
+  // key, the last node on the search path is moved to the top of the
+  // tree.
+  void Splay(const Key& key);
+
+  class Node {
+   public:
+    Node(const Key& key, const Value& value)
+        : key_(key),
+          value_(value),
+          left_(NULL),
+          right_(NULL) { }
+
+    INLINE(void* operator new(size_t size)) {
+      return Allocator::New(static_cast<int>(size));
+    }
+    INLINE(void operator delete(void* p, size_t)) {
+      return Allocator::Delete(p);
+    }
+
+    Key key() { return key_; }
+    Value value() { return value_; }
+    Node* left() { return left_; }
+    Node* right() { return right_; }
+   private:
+
+    friend class SplayTree;
+    friend class Locator;
+    Key key_;
+    Value value_;
+    Node* left_;
+    Node* right_;
+  };
+
+  // A locator provides access to a node in the tree without actually
+  // exposing the node.
+  class Locator BASE_EMBEDDED {
+   public:
+    explicit Locator(Node* node) : node_(node) { }
+    Locator() : node_(NULL) { }
+    const Key& key() { return node_->key_; }
+    Value& value() { return node_->value_; }
+    void set_value(const Value& value) { node_->value_ = value; }
+    inline void bind(Node* node) { node_ = node; }
+   private:
+    Node* node_;
+  };
+
+  template <class Callback>
+  void ForEach(Callback* callback);
+
+ protected:
+
+  // Resets tree root. Existing nodes become unreachable.
+  void ResetRoot() { root_ = NULL; }
+
+ private:
+
+  template<class Callback>
+  class NodeToPairAdaptor BASE_EMBEDDED {
+   public:
+    explicit NodeToPairAdaptor(Callback* callback)
+        : callback_(callback) { }
+    void Call(Node* node) {
+      callback_->Call(node->key(), node->value());
+    }
+
+   private:
+    Callback* callback_;
+
+    DISALLOW_COPY_AND_ASSIGN(NodeToPairAdaptor);
+  };
+
+  class NodeDeleter BASE_EMBEDDED {
+   public:
+    NodeDeleter() { }
+    void Call(Node* node) { delete node; }
+
+   private:
+
+    DISALLOW_COPY_AND_ASSIGN(NodeDeleter);
+  };
+
+  template <class Callback>
+  void ForEachNode(Callback* callback);
+
+  Node* root_;
+
+  DISALLOW_COPY_AND_ASSIGN(SplayTree);
+};
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_SPLAY_TREE_H_
index 49f403d..067578c 100644 (file)
@@ -69,7 +69,7 @@ function StringCharAt(pos) {
     if (index >= subject.length || index < 0) return "";
     char_code = %StringCharCodeAt(subject, index);
   }
-  return %CharFromCode(char_code);
+  return %_CharFromCode(char_code);
 }
 
 
@@ -184,7 +184,7 @@ function SubString(string, start, end) {
     if (!%_IsSmi(char_code)) {
       char_code = %StringCharCodeAt(string, start);
     }
-    return %CharFromCode(char_code);
+    return %_CharFromCode(char_code);
   }
   return %_SubString(string, start, end);
 }
@@ -530,11 +530,7 @@ function StringSplit(separator, limit) {
     var separator_length = separator.length;
 
     // If the separator string is empty then return the elements in the subject.
-    if (separator_length === 0) {
-      var result = $Array(length);
-      for (var i = 0; i < length; i++) result[i] = subject[i];
-      return result;
-    }
+    if (separator_length === 0) return %StringToArray(subject);
 
     var result = [];
     var start_index = 0;
@@ -726,7 +722,7 @@ function StringTrimRight() {
 // ECMA-262, section 15.5.3.2
 function StringFromCharCode(code) {
   var n = %_ArgumentsLength();
-  if (n == 1) return %CharFromCode(ToNumber(code) & 0xffff)
+  if (n == 1) return %_CharFromCode(ToNumber(code) & 0xffff)
 
   // NOTE: This is not super-efficient, but it is necessary because we
   // want to avoid converting to numbers from within the virtual
index b9db4be..7c8a1c9 100644 (file)
@@ -31,6 +31,7 @@
 #include "bootstrapper.h"
 #include "debug.h"
 #include "execution.h"
+#include "messages.h"
 #include "platform.h"
 #include "simulator.h"
 #include "string-stream.h"
diff --git a/deps/v8/src/usage-analyzer.cc b/deps/v8/src/usage-analyzer.cc
deleted file mode 100644 (file)
index 74cf982..0000000
+++ /dev/null
@@ -1,426 +0,0 @@
-// Copyright 2006-2008 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-//       notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-//       copyright notice, this list of conditions and the following
-//       disclaimer in the documentation and/or other materials provided
-//       with the distribution.
-//     * Neither the name of Google Inc. nor the names of its
-//       contributors may be used to endorse or promote products derived
-//       from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include "v8.h"
-
-#include "ast.h"
-#include "scopes.h"
-#include "usage-analyzer.h"
-
-namespace v8 {
-namespace internal {
-
-// Weight boundaries
-static const int MinWeight = 1;
-static const int MaxWeight = 1000000;
-static const int InitialWeight = 100;
-
-
-class UsageComputer: public AstVisitor {
- public:
-  static bool Traverse(AstNode* node);
-
-  // AST node visit functions.
-#define DECLARE_VISIT(type) void Visit##type(type* node);
-  AST_NODE_LIST(DECLARE_VISIT)
-#undef DECLARE_VISIT
-
-  void VisitVariable(Variable* var);
-
- private:
-  int weight_;
-  bool is_write_;
-
-  UsageComputer(int weight, bool is_write);
-  virtual ~UsageComputer();
-
-  // Helper functions
-  void RecordUses(UseCount* uses);
-  void Read(Expression* x);
-  void Write(Expression* x);
-  void ReadList(ZoneList<Expression*>* list);
-  void ReadList(ZoneList<ObjectLiteral::Property*>* list);
-
-  friend class WeightScaler;
-};
-
-
-class WeightScaler BASE_EMBEDDED {
- public:
-  WeightScaler(UsageComputer* uc, float scale);
-  ~WeightScaler();
-
- private:
-  UsageComputer* uc_;
-  int old_weight_;
-};
-
-
-// ----------------------------------------------------------------------------
-// Implementation of UsageComputer
-
-bool UsageComputer::Traverse(AstNode* node) {
-  UsageComputer uc(InitialWeight, false);
-  uc.Visit(node);
-  return !uc.HasStackOverflow();
-}
-
-
-void UsageComputer::VisitBlock(Block* node) {
-  VisitStatements(node->statements());
-}
-
-
-void UsageComputer::VisitDeclaration(Declaration* node) {
-  Write(node->proxy());
-  if (node->fun() != NULL)
-    VisitFunctionLiteral(node->fun());
-}
-
-
-void UsageComputer::VisitExpressionStatement(ExpressionStatement* node) {
-  Visit(node->expression());
-}
-
-
-void UsageComputer::VisitEmptyStatement(EmptyStatement* node) {
-  // nothing to do
-}
-
-
-void UsageComputer::VisitIfStatement(IfStatement* node) {
-  Read(node->condition());
-  { WeightScaler ws(this, 0.5);  // executed 50% of the time
-    Visit(node->then_statement());
-    Visit(node->else_statement());
-  }
-}
-
-
-void UsageComputer::VisitContinueStatement(ContinueStatement* node) {
-  // nothing to do
-}
-
-
-void UsageComputer::VisitBreakStatement(BreakStatement* node) {
-  // nothing to do
-}
-
-
-void UsageComputer::VisitReturnStatement(ReturnStatement* node) {
-  Read(node->expression());
-}
-
-
-void UsageComputer::VisitWithEnterStatement(WithEnterStatement* node) {
-  Read(node->expression());
-}
-
-
-void UsageComputer::VisitWithExitStatement(WithExitStatement* node) {
-  // nothing to do
-}
-
-
-void UsageComputer::VisitSwitchStatement(SwitchStatement* node) {
-  Read(node->tag());
-  ZoneList<CaseClause*>* cases = node->cases();
-  for (int i = cases->length(); i-- > 0;) {
-    WeightScaler ws(this, static_cast<float>(1.0 / cases->length()));
-    CaseClause* clause = cases->at(i);
-    if (!clause->is_default())
-      Read(clause->label());
-    VisitStatements(clause->statements());
-  }
-}
-
-
-void UsageComputer::VisitDoWhileStatement(DoWhileStatement* node) {
-  WeightScaler ws(this, 10.0);
-  Read(node->cond());
-  Visit(node->body());
-}
-
-
-void UsageComputer::VisitWhileStatement(WhileStatement* node) {
-  WeightScaler ws(this, 10.0);
-  Read(node->cond());
-  Visit(node->body());
-}
-
-
-void UsageComputer::VisitForStatement(ForStatement* node) {
-  if (node->init() != NULL) Visit(node->init());
-  { WeightScaler ws(this, 10.0);  // executed in each iteration
-    if (node->cond() != NULL) Read(node->cond());
-    if (node->next() != NULL) Visit(node->next());
-    Visit(node->body());
-  }
-}
-
-
-void UsageComputer::VisitForInStatement(ForInStatement* node) {
-  WeightScaler ws(this, 10.0);
-  Write(node->each());
-  Read(node->enumerable());
-  Visit(node->body());
-}
-
-
-void UsageComputer::VisitTryCatchStatement(TryCatchStatement* node) {
-  Visit(node->try_block());
-  { WeightScaler ws(this, 0.25);
-    Write(node->catch_var());
-    Visit(node->catch_block());
-  }
-}
-
-
-void UsageComputer::VisitTryFinallyStatement(TryFinallyStatement* node) {
-  Visit(node->try_block());
-  Visit(node->finally_block());
-}
-
-
-void UsageComputer::VisitDebuggerStatement(DebuggerStatement* node) {
-}
-
-
-void UsageComputer::VisitFunctionLiteral(FunctionLiteral* node) {
-  ZoneList<Declaration*>* decls = node->scope()->declarations();
-  for (int i = 0; i < decls->length(); i++) VisitDeclaration(decls->at(i));
-  VisitStatements(node->body());
-}
-
-
-void UsageComputer::VisitFunctionBoilerplateLiteral(
-    FunctionBoilerplateLiteral* node) {
-  // Do nothing.
-}
-
-
-void UsageComputer::VisitConditional(Conditional* node) {
-  Read(node->condition());
-  { WeightScaler ws(this, 0.5);
-    Read(node->then_expression());
-    Read(node->else_expression());
-  }
-}
-
-
-void UsageComputer::VisitSlot(Slot* node) {
-  UNREACHABLE();
-}
-
-
-void UsageComputer::VisitVariable(Variable* node) {
-  RecordUses(node->var_uses());
-}
-
-
-void UsageComputer::VisitVariableProxy(VariableProxy* node) {
-  // The proxy may refer to a variable in which case it was bound via
-  // VariableProxy::BindTo.
-  RecordUses(node->var_uses());
-}
-
-
-void UsageComputer::VisitLiteral(Literal* node) {
-  // nothing to do
-}
-
-void UsageComputer::VisitRegExpLiteral(RegExpLiteral* node) {
-  // nothing to do
-}
-
-
-void UsageComputer::VisitObjectLiteral(ObjectLiteral* node) {
-  ReadList(node->properties());
-}
-
-
-void UsageComputer::VisitArrayLiteral(ArrayLiteral* node) {
-  ReadList(node->values());
-}
-
-
-void UsageComputer::VisitCatchExtensionObject(CatchExtensionObject* node) {
-  Read(node->value());
-}
-
-
-void UsageComputer::VisitAssignment(Assignment* node) {
-  if (node->op() != Token::ASSIGN)
-    Read(node->target());
-  Write(node->target());
-  Read(node->value());
-}
-
-
-void UsageComputer::VisitThrow(Throw* node) {
-  Read(node->exception());
-}
-
-
-void UsageComputer::VisitProperty(Property* node) {
-  // In any case (read or write) we read both the
-  // node's object and the key.
-  Read(node->obj());
-  Read(node->key());
-  // If the node's object is a variable proxy,
-  // we have a 'simple' object property access. We count
-  // the access via the variable or proxy's object uses.
-  VariableProxy* proxy = node->obj()->AsVariableProxy();
-  if (proxy != NULL) {
-    RecordUses(proxy->obj_uses());
-  }
-}
-
-
-void UsageComputer::VisitCall(Call* node) {
-  Read(node->expression());
-  ReadList(node->arguments());
-}
-
-
-void UsageComputer::VisitCallNew(CallNew* node) {
-  Read(node->expression());
-  ReadList(node->arguments());
-}
-
-
-void UsageComputer::VisitCallRuntime(CallRuntime* node) {
-  ReadList(node->arguments());
-}
-
-
-void UsageComputer::VisitUnaryOperation(UnaryOperation* node) {
-  Read(node->expression());
-}
-
-
-void UsageComputer::VisitCountOperation(CountOperation* node) {
-  Read(node->expression());
-  Write(node->expression());
-}
-
-
-void UsageComputer::VisitBinaryOperation(BinaryOperation* node) {
-  Read(node->left());
-  Read(node->right());
-}
-
-
-void UsageComputer::VisitCompareOperation(CompareOperation* node) {
-  Read(node->left());
-  Read(node->right());
-}
-
-
-void UsageComputer::VisitThisFunction(ThisFunction* node) {
-}
-
-
-UsageComputer::UsageComputer(int weight, bool is_write) {
-  weight_ = weight;
-  is_write_ = is_write;
-}
-
-
-UsageComputer::~UsageComputer() {
-  // nothing to do
-}
-
-
-void UsageComputer::RecordUses(UseCount* uses) {
-  if (is_write_)
-    uses->RecordWrite(weight_);
-  else
-    uses->RecordRead(weight_);
-}
-
-
-void UsageComputer::Read(Expression* x) {
-  if (is_write_) {
-    UsageComputer uc(weight_, false);
-    uc.Visit(x);
-  } else {
-    Visit(x);
-  }
-}
-
-
-void UsageComputer::Write(Expression* x) {
-  if (!is_write_) {
-    UsageComputer uc(weight_, true);
-    uc.Visit(x);
-  } else {
-    Visit(x);
-  }
-}
-
-
-void UsageComputer::ReadList(ZoneList<Expression*>* list) {
-  for (int i = list->length(); i-- > 0; )
-    Read(list->at(i));
-}
-
-
-void UsageComputer::ReadList(ZoneList<ObjectLiteral::Property*>* list) {
-  for (int i = list->length(); i-- > 0; )
-    Read(list->at(i)->value());
-}
-
-
-// ----------------------------------------------------------------------------
-// Implementation of WeightScaler
-
-WeightScaler::WeightScaler(UsageComputer* uc, float scale) {
-  uc_ = uc;
-  old_weight_ = uc->weight_;
-  int new_weight = static_cast<int>(uc->weight_ * scale);
-  if (new_weight <= 0) new_weight = MinWeight;
-  else if (new_weight > MaxWeight) new_weight = MaxWeight;
-  uc->weight_ = new_weight;
-}
-
-
-WeightScaler::~WeightScaler() {
-  uc_->weight_ = old_weight_;
-}
-
-
-// ----------------------------------------------------------------------------
-// Interface to variable usage analysis
-
-bool AnalyzeVariableUsage(FunctionLiteral* lit) {
-  if (!FLAG_usage_computation) return true;
-  HistogramTimerScope timer(&Counters::usage_analysis);
-  return UsageComputer::Traverse(lit);
-}
-
-} }  // namespace v8::internal
index 2fcd241..deab09f 100644 (file)
@@ -528,11 +528,11 @@ static inline void CopyChars(sinkchar* dest, const sourcechar* src, int chars) {
   sinkchar* limit = dest + chars;
 #ifdef V8_HOST_CAN_READ_UNALIGNED
   if (sizeof(*dest) == sizeof(*src)) {
-    // Number of characters in a uint32_t.
-    static const int kStepSize = sizeof(uint32_t) / sizeof(*dest);  // NOLINT
+    // Number of characters in a uintptr_t.
+    static const int kStepSize = sizeof(uintptr_t) / sizeof(*dest);  // NOLINT
     while (dest <= limit - kStepSize) {
-      *reinterpret_cast<uint32_t*>(dest) =
-          *reinterpret_cast<const uint32_t*>(src);
+      *reinterpret_cast<uintptr_t*>(dest) =
+          *reinterpret_cast<const uintptr_t*>(src);
       dest += kStepSize;
       src += kStepSize;
     }
@@ -544,6 +544,58 @@ static inline void CopyChars(sinkchar* dest, const sourcechar* src, int chars) {
 }
 
 
+// Compare ASCII/16bit chars to ASCII/16bit chars.
+template <typename lchar, typename rchar>
+static inline int CompareChars(const lchar* lhs, const rchar* rhs, int chars) {
+  const lchar* limit = lhs + chars;
+#ifdef V8_HOST_CAN_READ_UNALIGNED
+  if (sizeof(*lhs) == sizeof(*rhs)) {
+    // Number of characters in a uintptr_t.
+    static const int kStepSize = sizeof(uintptr_t) / sizeof(*lhs);  // NOLINT
+    while (lhs <= limit - kStepSize) {
+      if (*reinterpret_cast<const uintptr_t*>(lhs) !=
+          *reinterpret_cast<const uintptr_t*>(rhs)) {
+        break;
+      }
+      lhs += kStepSize;
+      rhs += kStepSize;
+    }
+  }
+#endif
+  while (lhs < limit) {
+    int r = static_cast<int>(*lhs) - static_cast<int>(*rhs);
+    if (r != 0) return r;
+    ++lhs;
+    ++rhs;
+  }
+  return 0;
+}
+
+
+template <typename T>
+static inline void MemsetPointer(T** dest, T* value, int counter) {
+#if defined(V8_HOST_ARCH_IA32)
+#define STOS "stosl"
+#elif defined(V8_HOST_ARCH_X64)
+#define STOS "stosq"
+#endif
+
+#if defined(__GNUC__) && defined(STOS)
+  asm("cld;"
+      "rep ; " STOS
+      : /* no output */
+      : "c" (counter), "a" (value), "D" (dest)
+      : /* no clobbered list as all inputs are considered clobbered */);
+#else
+  for (int i = 0; i < counter; i++) {
+    dest[i] = value;
+  }
+#endif
+
+#undef STOS
+}
+
+
 // Calculate 10^exponent.
 int TenToThe(int exponent);
 
index eaac2db..2b493fb 100644 (file)
@@ -169,7 +169,24 @@ namespace internal {
   SC(regexp_entry_runtime, V8.RegExpEntryRuntime)                     \
   SC(regexp_entry_native, V8.RegExpEntryNative)                       \
   SC(number_to_string_native, V8.NumberToStringNative)                \
-  SC(number_to_string_runtime, V8.NumberToStringRuntime)
+  SC(number_to_string_runtime, V8.NumberToStringRuntime)              \
+  SC(math_abs, V8.MathAbs)                                            \
+  SC(math_acos, V8.MathAcos)                                          \
+  SC(math_asin, V8.MathAsin)                                          \
+  SC(math_atan, V8.MathAtan)                                          \
+  SC(math_atan2, V8.MathAtan2)                                        \
+  SC(math_ceil, V8.MathCeil)                                          \
+  SC(math_cos, V8.MathCos)                                            \
+  SC(math_exp, V8.MathExp)                                            \
+  SC(math_floor, V8.MathFloor)                                        \
+  SC(math_log, V8.MathLog)                                            \
+  SC(math_pow, V8.MathPow)                                            \
+  SC(math_round, V8.MathRound)                                        \
+  SC(math_sin, V8.MathSin)                                            \
+  SC(math_sqrt, V8.MathSqrt)                                          \
+  SC(math_tan, V8.MathTan)                                            \
+  SC(transcendental_cache_hit, V8.TranscendentalCacheHit)             \
+  SC(transcendental_cache_miss, V8.TranscendentalCacheMiss)
 
 // This file contains all the v8 counters that are in use.
 class Counters : AllStatic {
index b3624c5..d58f30f 100644 (file)
@@ -67,7 +67,7 @@
 #include "spaces-inl.h"
 #include "heap-inl.h"
 #include "log-inl.h"
-#include "messages.h"
+#include "handles-inl.h"
 
 namespace v8 {
 namespace internal {
index 3bcd48a..f46a54d 100644 (file)
@@ -35,57 +35,6 @@ namespace v8 {
 namespace internal {
 
 // ----------------------------------------------------------------------------
-// Implementation UseCount.
-
-UseCount::UseCount()
-  : nreads_(0),
-    nwrites_(0) {
-}
-
-
-void UseCount::RecordRead(int weight) {
-  ASSERT(weight > 0);
-  nreads_ += weight;
-  // We must have a positive nreads_ here. Handle
-  // any kind of overflow by setting nreads_ to
-  // some large-ish value.
-  if (nreads_ <= 0) nreads_ = 1000000;
-  ASSERT(is_read() & is_used());
-}
-
-
-void UseCount::RecordWrite(int weight) {
-  ASSERT(weight > 0);
-  nwrites_ += weight;
-  // We must have a positive nwrites_ here. Handle
-  // any kind of overflow by setting nwrites_ to
-  // some large-ish value.
-  if (nwrites_ <= 0) nwrites_ = 1000000;
-  ASSERT(is_written() && is_used());
-}
-
-
-void UseCount::RecordAccess(int weight) {
-  RecordRead(weight);
-  RecordWrite(weight);
-}
-
-
-void UseCount::RecordUses(UseCount* uses) {
-  if (uses->nreads() > 0) RecordRead(uses->nreads());
-  if (uses->nwrites() > 0) RecordWrite(uses->nwrites());
-}
-
-
-#ifdef DEBUG
-void UseCount::Print() {
-  // PrintF("r = %d, w = %d", nreads_, nwrites_);
-  PrintF("%du = %dr + %dw", nuses(), nreads(), nwrites());
-}
-#endif
-
-
-// ----------------------------------------------------------------------------
 // Implementation StaticType.
 
 
@@ -136,6 +85,12 @@ Slot* Variable::slot() const {
 }
 
 
+bool Variable::IsStackAllocated() const {
+  Slot* s = slot();
+  return s != NULL && s->IsStackAllocated();
+}
+
+
 Variable::Variable(Scope* scope,
                    Handle<String> name,
                    Mode mode,
@@ -148,6 +103,7 @@ Variable::Variable(Scope* scope,
     kind_(kind),
     local_if_not_shadowed_(NULL),
     is_accessed_from_inner_scope_(false),
+    is_used_(false),
     rewrite_(NULL) {
   // names must be canonicalized for fast equality checks
   ASSERT(name->IsSymbol());
index ac7f294..a68aa33 100644 (file)
 namespace v8 {
 namespace internal {
 
-class UseCount BASE_EMBEDDED {
- public:
-  UseCount();
-
-  // Inform the node of a "use". The weight can be used to indicate
-  // heavier use, for instance if the variable is accessed inside a loop.
-  void RecordRead(int weight);
-  void RecordWrite(int weight);
-  void RecordAccess(int weight);  // records a read & write
-  void RecordUses(UseCount* uses);
-
-  int nreads() const  { return nreads_; }
-  int nwrites() const  { return nwrites_; }
-  int nuses() const  { return nreads_ + nwrites_; }
-
-  bool is_read() const  { return nreads() > 0; }
-  bool is_written() const  { return nwrites() > 0; }
-  bool is_used() const  { return nuses() > 0; }
-
-#ifdef DEBUG
-  void Print();
-#endif
-
- private:
-  int nreads_;
-  int nwrites_;
-};
-
-
 // Variables and AST expression nodes can track their "type" to enable
 // optimizations and removal of redundant checks when generating code.
 
@@ -168,13 +139,15 @@ class Variable: public ZoneObject {
   bool is_accessed_from_inner_scope() const  {
     return is_accessed_from_inner_scope_;
   }
-  UseCount* var_uses()  { return &var_uses_; }
-  UseCount* obj_uses()  { return &obj_uses_; }
+  bool is_used() { return is_used_; }
+  void set_is_used(bool flag) { is_used_ = flag; }
 
   bool IsVariable(Handle<String> n) const {
     return !is_this() && name().is_identical_to(n);
   }
 
+  bool IsStackAllocated() const;
+
   bool is_dynamic() const {
     return (mode_ == DYNAMIC ||
             mode_ == DYNAMIC_GLOBAL ||
@@ -216,8 +189,7 @@ class Variable: public ZoneObject {
 
   // Usage info.
   bool is_accessed_from_inner_scope_;  // set by variable resolver
-  UseCount var_uses_;  // uses of the variable value
-  UseCount obj_uses_;  // uses of the object the variable points to
+  bool is_used_;
 
   // Static type information
   StaticType type_;
index a9d9d04..79832ea 100644 (file)
@@ -34,8 +34,8 @@
 // cannot be changed without changing the SCons build script.
 #define MAJOR_VERSION     2
 #define MINOR_VERSION     1
-#define BUILD_NUMBER      2
-#define PATCH_LEVEL       6
+#define BUILD_NUMBER      3
+#define PATCH_LEVEL       0
 #define CANDIDATE_VERSION false
 
 // Define SONAME to have the SCons build the put a specific SONAME into the
index 3476e41..9aa88fe 100644 (file)
 namespace v8 {
 namespace internal {
 
+
+// On entry to a function, the virtual frame already contains the receiver,
+// the parameters, and a return address.  All frame elements are in memory.
+VirtualFrame::VirtualFrame()
+    : elements_(parameter_count() + local_count() + kPreallocatedElements),
+      stack_pointer_(parameter_count() + 1) {  // 0-based index of TOS.
+  for (int i = 0; i <= stack_pointer_; i++) {
+    elements_.Add(FrameElement::MemoryElement(NumberInfo::Unknown()));
+  }
+  for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
+    register_locations_[i] = kIllegalIndex;
+  }
+}
+
+
 // When cloned, a frame is a deep copy of the original.
 VirtualFrame::VirtualFrame(VirtualFrame* original)
     : elements_(original->element_count()),
@@ -50,7 +65,7 @@ void VirtualFrame::PushFrameSlotAt(int index) {
 }
 
 
-void VirtualFrame::Push(Register reg, NumberInfo::Type info) {
+void VirtualFrame::Push(Register reg, NumberInfo info) {
   if (is_used(reg)) {
     int index = register_location(reg);
     FrameElement element = CopyElementAt(index, info);
index d5b5f42..8c13a6a 100644 (file)
@@ -43,7 +43,7 @@ namespace internal {
 // not conflict with the existing type information and must be equally or
 // more precise. The default parameter value kUninitialized means that there
 // is no additional information.
-FrameElement VirtualFrame::CopyElementAt(int index, NumberInfo::Type info) {
+FrameElement VirtualFrame::CopyElementAt(int index, NumberInfo info) {
   ASSERT(index >= 0);
   ASSERT(index < element_count());
 
@@ -74,14 +74,14 @@ FrameElement VirtualFrame::CopyElementAt(int index, NumberInfo::Type info) {
       result.set_index(index);
       elements_[index].set_copied();
       // Update backing element's number information.
-      NumberInfo::Type existing = elements_[index].number_info();
-      ASSERT(existing != NumberInfo::kUninitialized);
+      NumberInfo existing = elements_[index].number_info();
+      ASSERT(!existing.IsUninitialized());
       // Assert that the new type information (a) does not conflict with the
       // existing one and (b) is equally or more precise.
-      ASSERT((info == NumberInfo::kUninitialized) ||
-             (existing | info) != NumberInfo::kUninitialized);
-      ASSERT(existing <= info);
-      elements_[index].set_number_info(info != NumberInfo::kUninitialized
+      ASSERT((info.ToInt() & existing.ToInt()) == existing.ToInt());
+      ASSERT((info.ToInt() | existing.ToInt()) == info.ToInt());
+
+      elements_[index].set_number_info(!info.IsUninitialized()
                                        ? info
                                        : existing);
       break;
@@ -104,7 +104,7 @@ void VirtualFrame::Adjust(int count) {
   ASSERT(stack_pointer_ == element_count() - 1);
 
   for (int i = 0; i < count; i++) {
-    elements_.Add(FrameElement::MemoryElement(NumberInfo::kUnknown));
+    elements_.Add(FrameElement::MemoryElement(NumberInfo::Unknown()));
   }
   stack_pointer_ += count;
 }
@@ -152,7 +152,7 @@ void VirtualFrame::SpillElementAt(int index) {
   SyncElementAt(index);
   // Number type information is preserved.
   // Copies get their number information from their backing element.
-  NumberInfo::Type info;
+  NumberInfo info;
   if (!elements_[index].is_copy()) {
     info = elements_[index].number_info();
   } else {
index b3c5e33..0c5d481 100644 (file)
@@ -61,10 +61,10 @@ void Builtins::Generate_Adaptor(MacroAssembler* masm,
     ASSERT(extra_args == NO_EXTRA_ARGUMENTS);
   }
 
-  // JumpToRuntime expects rax to contain the number of arguments
+  // JumpToExternalReference expects rax to contain the number of arguments
   // including the receiver and the extra arguments.
   __ addq(rax, Immediate(num_extra_args + 1));
-  __ JumpToRuntime(ExternalReference(id), 1);
+  __ JumpToExternalReference(ExternalReference(id), 1);
 }
 
 
index 6ffb5ac..b10c3f9 100644 (file)
@@ -278,6 +278,7 @@ void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
 void CodeGenerator::Generate(CompilationInfo* info) {
   // Record the position for debugging purposes.
   CodeForFunctionPosition(info->function());
+  Comment cmnt(masm_, "[ function compiled by virtual frame code generator");
 
   // Initialize state.
   info_ = info;
@@ -3876,6 +3877,49 @@ void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
 }
 
 
+void CodeGenerator::GenerateCharFromCode(ZoneList<Expression*>* args) {
+  Comment(masm_, "[ GenerateCharFromCode");
+  ASSERT(args->length() == 1);
+
+  Load(args->at(0));
+  Result code = frame_->Pop();
+  code.ToRegister();
+  ASSERT(code.is_valid());
+
+  Result temp = allocator()->Allocate();
+  ASSERT(temp.is_valid());
+
+  JumpTarget slow_case;
+  JumpTarget exit;
+
+  // Fast case of Heap::LookupSingleCharacterStringFromCode.
+  Condition is_smi = __ CheckSmi(code.reg());
+  slow_case.Branch(NegateCondition(is_smi), &code, not_taken);
+
+  __ SmiToInteger32(kScratchRegister, code.reg());
+  __ cmpl(kScratchRegister, Immediate(String::kMaxAsciiCharCode));
+  slow_case.Branch(above, &code, not_taken);
+
+  __ Move(temp.reg(), Factory::single_character_string_cache());
+  __ movq(temp.reg(), FieldOperand(temp.reg(),
+                                   kScratchRegister, times_pointer_size,
+                                   FixedArray::kHeaderSize));
+  __ CompareRoot(temp.reg(), Heap::kUndefinedValueRootIndex);
+  slow_case.Branch(equal, &code, not_taken);
+  code.Unuse();
+
+  frame_->Push(&temp);
+  exit.Jump();
+
+  slow_case.Bind(&code);
+  frame_->Push(&code);
+  Result result = frame_->CallRuntime(Runtime::kCharFromCode, 1);
+  frame_->Push(&result);
+
+  exit.Bind();
+}
+
+
 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) {
   ASSERT(args->length() == 1);
   Load(args->at(0));
@@ -3888,6 +3932,25 @@ void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) {
 }
 
 
+// Generates the Math.pow method - currently just calls runtime.
+void CodeGenerator::GenerateMathPow(ZoneList<Expression*>* args) {
+  ASSERT(args->length() == 2);
+  Load(args->at(0));
+  Load(args->at(1));
+  Result res = frame_->CallRuntime(Runtime::kMath_pow, 2);
+  frame_->Push(&res);
+}
+
+
+// Generates the Math.sqrt method - currently just calls runtime.
+void CodeGenerator::GenerateMathSqrt(ZoneList<Expression*>* args) {
+  ASSERT(args->length() == 1);
+  Load(args->at(0));
+  Result res = frame_->CallRuntime(Runtime::kMath_sqrt, 1);
+  frame_->Push(&res);
+}
+
+
 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) {
   ASSERT(args->length() == 1);
   Load(args->at(0));
@@ -3955,21 +4018,12 @@ void CodeGenerator::GenerateRandomPositiveSmi(ZoneList<Expression*>* args) {
   frame_->SpillAll();
   __ push(rsi);
 
-  // Make sure the frame is aligned like the OS expects.
-  static const int kFrameAlignment = OS::ActivationFrameAlignment();
-  if (kFrameAlignment > 0) {
-    ASSERT(IsPowerOf2(kFrameAlignment));
-    __ movq(rbx, rsp);  // Save in AMD-64 abi callee-saved register.
-    __ and_(rsp, Immediate(-kFrameAlignment));
-  }
+  static const int num_arguments = 0;
+  __ PrepareCallCFunction(num_arguments);
 
   // Call V8::RandomPositiveSmi().
-  __ Call(FUNCTION_ADDR(V8::RandomPositiveSmi), RelocInfo::RUNTIME_ENTRY);
-
-  // Restore stack pointer from callee-saved register.
-  if (kFrameAlignment > 0) {
-    __ movq(rsp, rbx);
-  }
+  __ CallCFunction(ExternalReference::random_positive_smi_function(),
+                   num_arguments);
 
   __ pop(rsi);
   Result result = allocator_->Allocate(rax);
@@ -4002,6 +4056,24 @@ void CodeGenerator::GenerateNumberToString(ZoneList<Expression*>* args) {
 }
 
 
+void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) {
+  ASSERT_EQ(args->length(), 1);
+  // Load the argument on the stack and jump to the runtime.
+  Load(args->at(0));
+  Result answer = frame_->CallRuntime(Runtime::kMath_sin, 1);
+  frame_->Push(&answer);
+}
+
+
+void CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) {
+  ASSERT_EQ(args->length(), 1);
+  // Load the argument on the stack and jump to the runtime.
+  Load(args->at(0));
+  Result answer = frame_->CallRuntime(Runtime::kMath_cos, 1);
+  frame_->Push(&answer);
+}
+
+
 void CodeGenerator::GenerateStringAdd(ZoneList<Expression*>* args) {
   ASSERT_EQ(2, args->length());
 
@@ -5217,7 +5289,7 @@ void CodeGenerator::GenericBinaryOperation(Token::Value op,
   }
 
   // Get number type of left and right sub-expressions.
-  NumberInfo::Type operands_type =
+  NumberInfo operands_type =
       NumberInfo::Combine(left.number_info(), right.number_info());
 
   Result answer;
@@ -5253,7 +5325,7 @@ void CodeGenerator::GenericBinaryOperation(Token::Value op,
   // Set NumberInfo of result according to the operation performed.
   // We rely on the fact that smis have a 32 bit payload on x64.
   ASSERT(kSmiValueSize == 32);
-  NumberInfo::Type result_type = NumberInfo::kUnknown;
+  NumberInfo result_type = NumberInfo::Unknown();
   switch (op) {
     case Token::COMMA:
       result_type = right.number_info();
@@ -5267,32 +5339,32 @@ void CodeGenerator::GenericBinaryOperation(Token::Value op,
     case Token::BIT_XOR:
     case Token::BIT_AND:
       // Result is always a smi.
-      result_type = NumberInfo::kSmi;
+      result_type = NumberInfo::Smi();
       break;
     case Token::SAR:
     case Token::SHL:
       // Result is always a smi.
-      result_type = NumberInfo::kSmi;
+      result_type = NumberInfo::Smi();
       break;
     case Token::SHR:
       // Result of x >>> y is always a smi if y >= 1, otherwise a number.
       result_type = (right.is_constant() && right.handle()->IsSmi()
                      && Smi::cast(*right.handle())->value() >= 1)
-          ? NumberInfo::kSmi
-          : NumberInfo::kNumber;
+          ? NumberInfo::Smi()
+          : NumberInfo::Number();
       break;
     case Token::ADD:
       // Result could be a string or a number. Check types of inputs.
-      result_type = NumberInfo::IsNumber(operands_type)
-          ? NumberInfo::kNumber
-          : NumberInfo::kUnknown;
+      result_type = operands_type.IsNumber()
+          ? NumberInfo::Number()
+          : NumberInfo::Unknown();
       break;
     case Token::SUB:
     case Token::MUL:
     case Token::DIV:
     case Token::MOD:
       // Result is always a number.
-      result_type = NumberInfo::kNumber;
+      result_type = NumberInfo::Number();
       break;
     default:
       UNREACHABLE();
@@ -6324,7 +6396,7 @@ void FastNewClosureStub::Generate(MacroAssembler* masm) {
   __ push(rsi);
   __ push(rdx);
   __ push(rcx);  // Restore return address.
-  __ TailCallRuntime(ExternalReference(Runtime::kNewClosure), 2, 1);
+  __ TailCallRuntime(Runtime::kNewClosure, 2, 1);
 }
 
 
@@ -6366,7 +6438,7 @@ void FastNewContextStub::Generate(MacroAssembler* masm) {
 
   // Need to collect. Call into runtime system.
   __ bind(&gc);
-  __ TailCallRuntime(ExternalReference(Runtime::kNewContext), 1, 1);
+  __ TailCallRuntime(Runtime::kNewContext, 1, 1);
 }
 
 
@@ -6422,8 +6494,7 @@ void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) {
   __ ret(3 * kPointerSize);
 
   __ bind(&slow_case);
-  ExternalReference runtime(Runtime::kCreateArrayLiteralShallow);
-  __ TailCallRuntime(runtime, 3, 1);
+  __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1);
 }
 
 
@@ -6782,10 +6853,10 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
   // time or if regexp entry in generated code is turned off runtime switch or
   // at compilation.
 #ifndef V8_NATIVE_REGEXP
-  __ TailCallRuntime(ExternalReference(Runtime::kRegExpExec), 4, 1);
+  __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
 #else  // V8_NATIVE_REGEXP
   if (!FLAG_regexp_entry_native) {
-    __ TailCallRuntime(ExternalReference(Runtime::kRegExpExec), 4, 1);
+    __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
     return;
   }
 
@@ -7129,7 +7200,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
 
   // Do the runtime call to execute the regexp.
   __ bind(&runtime);
-  __ TailCallRuntime(ExternalReference(Runtime::kRegExpExec), 4, 1);
+  __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
 #endif  // V8_NATIVE_REGEXP
 }
 
@@ -7540,7 +7611,7 @@ void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) {
 
   // Do the runtime call to allocate the arguments object.
   __ bind(&runtime);
-  __ TailCallRuntime(ExternalReference(Runtime::kNewArgumentsFast), 3, 1);
+  __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1);
 }
 
 
@@ -7597,9 +7668,7 @@ void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
   __ pop(rbx);  // Return address.
   __ push(rdx);
   __ push(rbx);
-  Runtime::Function* f =
-      Runtime::FunctionForId(Runtime::kGetArgumentsProperty);
-  __ TailCallRuntime(ExternalReference(f), 1, f->result_size);
+  __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1);
 }
 
 
@@ -8088,8 +8157,7 @@ void StackCheckStub::Generate(MacroAssembler* masm) {
   __ push(rax);
 
   // Do tail-call to runtime routine.
-  Runtime::Function* f = Runtime::FunctionForId(Runtime::kStackGuard);
-  __ TailCallRuntime(ExternalReference(f), 1, f->result_size);
+  __ TailCallRuntime(Runtime::kStackGuard, 1, 1);
 }
 
 
@@ -8273,7 +8341,7 @@ const char* GenericBinaryOpStub::GetName() {
                args_in_registers_ ? "RegArgs" : "StackArgs",
                args_reversed_ ? "_R" : "",
                use_sse3_ ? "SSE3" : "SSE2",
-               NumberInfo::ToString(operands_type_));
+               operands_type_.ToString());
   return name_;
 }
 
@@ -8597,7 +8665,7 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
     case Token::DIV: {
       // rax: y
       // rdx: x
-      if (NumberInfo::IsNumber(operands_type_)) {
+      if (operands_type_.IsNumber()) {
         if (FLAG_debug_code) {
           // Assert at runtime that inputs are only numbers.
           __ AbortIfNotNumber(rdx, "GenericBinaryOpStub operand not a number.");
@@ -8839,6 +8907,11 @@ void GenericBinaryOpStub::GenerateReturn(MacroAssembler* masm) {
 }
 
 
+Handle<Code> GetBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info) {
+  return Handle<Code>::null();
+}
+
+
 int CompareStub::MinorKey() {
   // Encode the three parameters in a unique 16 bit value.
   ASSERT(static_cast<unsigned>(cc_) < (1 << 14));
@@ -8936,16 +9009,11 @@ void StringAddStub::Generate(MacroAssembler* masm) {
   // rbx: length of first string
   // rcx: length of second string
   // rdx: second string
-  // r8: instance type of first string if string check was performed above
-  // r9: instance type of first string if string check was performed above
-  Label string_add_flat_result;
+  // r8: map of first string if string check was performed above
+  // r9: map of second string if string check was performed above
+  Label string_add_flat_result, longer_than_two;
   __ bind(&both_not_zero_length);
-  // Look at the length of the result of adding the two strings.
-  __ addl(rbx, rcx);
-  // Use the runtime system when adding two one character strings, as it
-  // contains optimizations for this specific case using the symbol table.
-  __ cmpl(rbx, Immediate(2));
-  __ j(equal, &string_add_runtime);
+
   // If arguments where known to be strings, maps are not loaded to r8 and r9
   // by the code above.
   if (!string_check_) {
@@ -8955,6 +9023,35 @@ void StringAddStub::Generate(MacroAssembler* masm) {
   // Get the instance types of the two strings as they will be needed soon.
   __ movzxbl(r8, FieldOperand(r8, Map::kInstanceTypeOffset));
   __ movzxbl(r9, FieldOperand(r9, Map::kInstanceTypeOffset));
+
+  // Look at the length of the result of adding the two strings.
+  __ addl(rbx, rcx);
+  // Use the runtime system when adding two one character strings, as it
+  // contains optimizations for this specific case using the symbol table.
+  __ cmpl(rbx, Immediate(2));
+  __ j(not_equal, &longer_than_two);
+
+  // Check that both strings are non-external ascii strings.
+  __ JumpIfBothInstanceTypesAreNotSequentialAscii(r8, r9, rbx, rcx,
+                                                 &string_add_runtime);
+
+  // Get the two characters forming the sub string.
+  __ movzxbq(rbx, FieldOperand(rax, SeqAsciiString::kHeaderSize));
+  __ movzxbq(rcx, FieldOperand(rdx, SeqAsciiString::kHeaderSize));
+
+  // Try to lookup two character string in symbol table. If it is not found
+  // just allocate a new one.
+  Label make_two_character_string, make_flat_ascii_string;
+  GenerateTwoCharacterSymbolTableProbe(masm, rbx, rcx, r14, r12, rdi, r15,
+                                       &make_two_character_string);
+  __ IncrementCounter(&Counters::string_add_native, 1);
+  __ ret(2 * kPointerSize);
+
+  __ bind(&make_two_character_string);
+  __ Set(rbx, 2);
+  __ jmp(&make_flat_ascii_string);
+
+  __ bind(&longer_than_two);
   // Check if resulting string will be flat.
   __ cmpl(rbx, Immediate(String::kMinNonFlatLength));
   __ j(below, &string_add_flat_result);
@@ -9021,6 +9118,8 @@ void StringAddStub::Generate(MacroAssembler* masm) {
   __ j(zero, &non_ascii_string_add_flat_result);
   __ testl(r9, Immediate(kAsciiStringTag));
   __ j(zero, &string_add_runtime);
+
+  __ bind(&make_flat_ascii_string);
   // Both strings are ascii strings. As they are short they are both flat.
   __ AllocateAsciiString(rcx, rbx, rdi, r14, r15, &string_add_runtime);
   // rcx: result string
@@ -9087,7 +9186,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
 
   // Just jump to runtime to add the two strings.
   __ bind(&string_add_runtime);
-  __ TailCallRuntime(ExternalReference(Runtime::kStringAdd), 2, 1);
+  __ TailCallRuntime(Runtime::kStringAdd, 2, 1);
 }
 
 
@@ -9171,6 +9270,179 @@ void StringStubBase::GenerateCopyCharactersREP(MacroAssembler* masm,
   __ bind(&done);
 }
 
+void StringStubBase::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
+                                                          Register c1,
+                                                          Register c2,
+                                                          Register scratch1,
+                                                          Register scratch2,
+                                                          Register scratch3,
+                                                          Register scratch4,
+                                                          Label* not_found) {
+  // Register scratch3 is the general scratch register in this function.
+  Register scratch = scratch3;
+
+  // Make sure that both characters are not digits as such strings has a
+  // different hash algorithm. Don't try to look for these in the symbol table.
+  Label not_array_index;
+  __ movq(scratch, c1);
+  __ subq(scratch, Immediate(static_cast<int>('0')));
+  __ cmpq(scratch, Immediate(static_cast<int>('9' - '0')));
+  __ j(above, &not_array_index);
+  __ movq(scratch, c2);
+  __ subq(scratch, Immediate(static_cast<int>('0')));
+  __ cmpq(scratch, Immediate(static_cast<int>('9' - '0')));
+  __ j(below_equal, not_found);
+
+  __ bind(&not_array_index);
+  // Calculate the two character string hash.
+  Register hash = scratch1;
+  GenerateHashInit(masm, hash, c1, scratch);
+  GenerateHashAddCharacter(masm, hash, c2, scratch);
+  GenerateHashGetHash(masm, hash, scratch);
+
+  // Collect the two characters in a register.
+  Register chars = c1;
+  __ shl(c2, Immediate(kBitsPerByte));
+  __ orl(chars, c2);
+
+  // chars: two character string, char 1 in byte 0 and char 2 in byte 1.
+  // hash:  hash of two character string.
+
+  // Load the symbol table.
+  Register symbol_table = c2;
+  __ LoadRoot(symbol_table, Heap::kSymbolTableRootIndex);
+
+  // Calculate capacity mask from the symbol table capacity.
+  Register mask = scratch2;
+  __ movq(mask, FieldOperand(symbol_table, SymbolTable::kCapacityOffset));
+  __ SmiToInteger32(mask, mask);
+  __ decl(mask);
+
+  Register undefined = scratch4;
+  __ LoadRoot(undefined, Heap::kUndefinedValueRootIndex);
+
+  // Registers
+  // chars:        two character string, char 1 in byte 0 and char 2 in byte 1.
+  // hash:         hash of two character string (32-bit int)
+  // symbol_table: symbol table
+  // mask:         capacity mask (32-bit int)
+  // undefined:    undefined value
+  // scratch:      -
+
+  // Perform a number of probes in the symbol table.
+  static const int kProbes = 4;
+  Label found_in_symbol_table;
+  Label next_probe[kProbes];
+  for (int i = 0; i < kProbes; i++) {
+    // Calculate entry in symbol table.
+    __ movl(scratch, hash);
+    if (i > 0) {
+      __ addl(scratch, Immediate(SymbolTable::GetProbeOffset(i)));
+    }
+    __ andl(scratch, mask);
+
+    // Load the entry from the symble table.
+    Register candidate = scratch;  // Scratch register contains candidate.
+    ASSERT_EQ(1, SymbolTable::kEntrySize);
+    __ movq(candidate,
+           FieldOperand(symbol_table,
+                        scratch,
+                        times_pointer_size,
+                        SymbolTable::kElementsStartOffset));
+
+    // If entry is undefined no string with this hash can be found.
+    __ cmpq(candidate, undefined);
+    __ j(equal, not_found);
+
+    // If length is not 2 the string is not a candidate.
+    __ cmpl(FieldOperand(candidate, String::kLengthOffset), Immediate(2));
+    __ j(not_equal, &next_probe[i]);
+
+    // We use kScratchRegister as a temporary register in assumption that
+    // JumpIfInstanceTypeIsNotSequentialAscii does not use it implicitly
+    Register temp = kScratchRegister;
+
+    // Check that the candidate is a non-external ascii string.
+    __ movq(temp, FieldOperand(candidate, HeapObject::kMapOffset));
+    __ movzxbl(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
+    __ JumpIfInstanceTypeIsNotSequentialAscii(
+        temp, temp, &next_probe[i]);
+
+    // Check if the two characters match.
+    __ movl(temp, FieldOperand(candidate, SeqAsciiString::kHeaderSize));
+    __ andl(temp, Immediate(0x0000ffff));
+    __ cmpl(chars, temp);
+    __ j(equal, &found_in_symbol_table);
+    __ bind(&next_probe[i]);
+  }
+
+  // No matching 2 character string found by probing.
+  __ jmp(not_found);
+
+  // Scratch register contains result when we fall through to here.
+  Register result = scratch;
+  __ bind(&found_in_symbol_table);
+  if (!result.is(rax)) {
+    __ movq(rax, result);
+  }
+}
+
+
+void StringStubBase::GenerateHashInit(MacroAssembler* masm,
+                                      Register hash,
+                                      Register character,
+                                      Register scratch) {
+  // hash = character + (character << 10);
+  __ movl(hash, character);
+  __ shll(hash, Immediate(10));
+  __ addl(hash, character);
+  // hash ^= hash >> 6;
+  __ movl(scratch, hash);
+  __ sarl(scratch, Immediate(6));
+  __ xorl(hash, scratch);
+}
+
+
+void StringStubBase::GenerateHashAddCharacter(MacroAssembler* masm,
+                                              Register hash,
+                                              Register character,
+                                              Register scratch) {
+  // hash += character;
+  __ addl(hash, character);
+  // hash += hash << 10;
+  __ movl(scratch, hash);
+  __ shll(scratch, Immediate(10));
+  __ addl(hash, scratch);
+  // hash ^= hash >> 6;
+  __ movl(scratch, hash);
+  __ sarl(scratch, Immediate(6));
+  __ xorl(hash, scratch);
+}
+
+
+void StringStubBase::GenerateHashGetHash(MacroAssembler* masm,
+                                         Register hash,
+                                         Register scratch) {
+  // hash += hash << 3;
+  __ movl(scratch, hash);
+  __ shll(scratch, Immediate(3));
+  __ addl(hash, scratch);
+  // hash ^= hash >> 11;
+  __ movl(scratch, hash);
+  __ sarl(scratch, Immediate(11));
+  __ xorl(hash, scratch);
+  // hash += hash << 15;
+  __ movl(scratch, hash);
+  __ shll(scratch, Immediate(15));
+  __ addl(hash, scratch);
+
+  // if (hash == 0) hash = 27;
+  Label hash_not_zero;
+  __ testl(hash, hash);
+  __ j(not_zero, &hash_not_zero);
+  __ movl(hash, Immediate(27));
+  __ bind(&hash_not_zero);
+}
 
 void SubStringStub::Generate(MacroAssembler* masm) {
   Label runtime;
@@ -9197,25 +9469,55 @@ void SubStringStub::Generate(MacroAssembler* masm) {
   // rax: string
   // rbx: instance type
   // Calculate length of sub string using the smi values.
+  Label result_longer_than_two;
   __ movq(rcx, Operand(rsp, kToOffset));
   __ movq(rdx, Operand(rsp, kFromOffset));
   __ JumpIfNotBothPositiveSmi(rcx, rdx, &runtime);
 
   __ SmiSub(rcx, rcx, rdx, NULL);  // Overflow doesn't happen.
   __ j(negative, &runtime);
-  // Handle sub-strings of length 2 and less in the runtime system.
+  // Special handling of sub-strings of length 1 and 2. One character strings
+  // are handled in the runtime system (looked up in the single character
+  // cache). Two character strings are looked for in the symbol cache.
   __ SmiToInteger32(rcx, rcx);
   __ cmpl(rcx, Immediate(2));
-  __ j(below_equal, &runtime);
+  __ j(greater, &result_longer_than_two);
+  __ j(less, &runtime);
+
+  // Sub string of length 2 requested.
+  // rax: string
+  // rbx: instance type
+  // rcx: sub string length (value is 2)
+  // rdx: from index (smi)
+  __ JumpIfInstanceTypeIsNotSequentialAscii(rbx, rbx, &runtime);
+
+  // Get the two characters forming the sub string.
+  __ SmiToInteger32(rdx, rdx);  // From index is no longer smi.
+  __ movzxbq(rbx, FieldOperand(rax, rdx, times_1, SeqAsciiString::kHeaderSize));
+  __ movzxbq(rcx,
+             FieldOperand(rax, rdx, times_1, SeqAsciiString::kHeaderSize + 1));
+
+  // Try to lookup two character string in symbol table.
+  Label make_two_character_string;
+  GenerateTwoCharacterSymbolTableProbe(masm, rbx, rcx, rax, rdx, rdi, r14,
+                                       &make_two_character_string);
+  __ ret(3 * kPointerSize);
+
+  __ bind(&make_two_character_string);
+  // Setup registers for allocating the two character string.
+  __ movq(rax, Operand(rsp, kStringOffset));
+  __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
+  __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset));
+  __ Set(rcx, 2);
+
+  __ bind(&result_longer_than_two);
 
   // rax: string
   // rbx: instance type
   // rcx: result string length
   // Check for flat ascii string
   Label non_ascii_flat;
-  __ and_(rbx, Immediate(kStringRepresentationMask | kStringEncodingMask));
-  __ cmpb(rbx, Immediate(kSeqStringTag | kAsciiStringTag));
-  __ j(not_equal, &non_ascii_flat);
+  __ JumpIfInstanceTypeIsNotSequentialAscii(rbx, rbx, &non_ascii_flat);
 
   // Allocate the result.
   __ AllocateAsciiString(rax, rcx, rbx, rdx, rdi, &runtime);
@@ -9281,7 +9583,7 @@ void SubStringStub::Generate(MacroAssembler* masm) {
 
   // Just jump to runtime to create the sub string.
   __ bind(&runtime);
-  __ TailCallRuntime(ExternalReference(Runtime::kSubString), 3, 1);
+  __ TailCallRuntime(Runtime::kSubString, 3, 1);
 }
 
 
@@ -9401,7 +9703,7 @@ void StringCompareStub::Generate(MacroAssembler* masm) {
   // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
   // tagged as a small integer.
   __ bind(&runtime);
-  __ TailCallRuntime(ExternalReference(Runtime::kStringCompare), 2, 1);
+  __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
 }
 
 #undef __
index 309e294..8f5fdc1 100644 (file)
@@ -547,6 +547,9 @@ class CodeGenerator: public AstVisitor {
   // Fast support for charCodeAt(n).
   void GenerateFastCharCodeAt(ZoneList<Expression*>* args);
 
+  // Fast support for string.charAt(n) and string[n].
+  void GenerateCharFromCode(ZoneList<Expression*>* args);
+
   // Fast support for object equality testing.
   void GenerateObjectEquals(ZoneList<Expression*>* args);
 
@@ -572,7 +575,17 @@ class CodeGenerator: public AstVisitor {
   // Fast support for number to string.
   void GenerateNumberToString(ZoneList<Expression*>* args);
 
-  // Simple condition analysis.
+  // Fast support for Math.pow().
+  void GenerateMathPow(ZoneList<Expression*>* args);
+
+  // Fast call to math functions.
+  void GenerateMathSin(ZoneList<Expression*>* args);
+  void GenerateMathCos(ZoneList<Expression*>* args);
+
+  // Fast case for sqrt
+  void GenerateMathSqrt(ZoneList<Expression*>* args);
+
+// Simple condition analysis.
   enum ConditionAnalysis {
     ALWAYS_TRUE,
     ALWAYS_FALSE,
@@ -651,7 +664,7 @@ class GenericBinaryOpStub: public CodeStub {
   GenericBinaryOpStub(Token::Value op,
                       OverwriteMode mode,
                       GenericBinaryFlags flags,
-                      NumberInfo::Type operands_type = NumberInfo::kUnknown)
+                      NumberInfo operands_type = NumberInfo::Unknown())
       : op_(op),
         mode_(mode),
         flags_(flags),
@@ -683,7 +696,7 @@ class GenericBinaryOpStub: public CodeStub {
   bool args_reversed_;  // Left and right argument are swapped.
   bool use_sse3_;
   char* name_;
-  NumberInfo::Type operands_type_;
+  NumberInfo operands_type_;
 
   const char* GetName();
 
@@ -697,7 +710,7 @@ class GenericBinaryOpStub: public CodeStub {
            static_cast<int>(flags_),
            static_cast<int>(args_in_registers_),
            static_cast<int>(args_reversed_),
-           NumberInfo::ToString(operands_type_));
+           operands_type_.ToString());
   }
 #endif
 
@@ -708,7 +721,7 @@ class GenericBinaryOpStub: public CodeStub {
   class ArgsInRegistersBits: public BitField<bool, 10, 1> {};
   class ArgsReversedBits: public BitField<bool, 11, 1> {};
   class FlagBits: public BitField<GenericBinaryFlags, 12, 1> {};
-  class NumberInfoBits: public BitField<NumberInfo::Type, 13, 3> {};
+  class NumberInfoBits: public BitField<int, 13, 3> {};
 
   Major MajorKey() { return GenericBinaryOp; }
   int MinorKey() {
@@ -719,7 +732,7 @@ class GenericBinaryOpStub: public CodeStub {
            | SSE3Bits::encode(use_sse3_)
            | ArgsInRegistersBits::encode(args_in_registers_)
            | ArgsReversedBits::encode(args_reversed_)
-           | NumberInfoBits::encode(operands_type_);
+           | NumberInfoBits::encode(operands_type_.ThreeBitRepresentation());
   }
 
   void Generate(MacroAssembler* masm);
@@ -763,6 +776,33 @@ class StringStubBase: public CodeStub {
                                  Register src,      // Must be rsi.
                                  Register count,    // Must be rcx.
                                  bool ascii);
+
+
+  // Probe the symbol table for a two character string. If the string is
+  // not found by probing a jump to the label not_found is performed. This jump
+  // does not guarantee that the string is not in the symbol table. If the
+  // string is found the code falls through with the string in register rax.
+  void GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
+                                            Register c1,
+                                            Register c2,
+                                            Register scratch1,
+                                            Register scratch2,
+                                            Register scratch3,
+                                            Register scratch4,
+                                            Label* not_found);
+
+  // Generate string hash.
+  void GenerateHashInit(MacroAssembler* masm,
+                        Register hash,
+                        Register character,
+                        Register scratch);
+  void GenerateHashAddCharacter(MacroAssembler* masm,
+                                Register hash,
+                                Register character,
+                                Register scratch);
+  void GenerateHashGetHash(MacroAssembler* masm,
+                           Register hash,
+                           Register scratch);
 };
 
 
index af2a1ff..5e76901 100644 (file)
@@ -189,6 +189,7 @@ void FastCodeGenerator::EmitBitOr() {
 void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
   ASSERT(info_ == NULL);
   info_ = compilation_info;
+  Comment cmnt(masm_, "[ function compiled by fast code generator");
 
   // Save the caller's frame pointer and set up our own.
   Comment prologue_cmnt(masm(), ";; Prologue");
index 669e175..bfa1a44 100644 (file)
@@ -56,6 +56,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info, Mode mode) {
   ASSERT(info_ == NULL);
   info_ = info;
   SetFunctionPosition(function());
+  Comment cmnt(masm_, "[ function compiled by full code generator");
 
   if (mode == PRIMARY) {
     __ push(rbp);  // Caller's frame pointer.
index 0e93637..e05f68d 100644 (file)
@@ -241,7 +241,8 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
   __ push(rbx);  // return address
 
   // Perform tail call to the entry.
-  __ TailCallRuntime(ExternalReference(IC_Utility(kKeyedLoadIC_Miss)), 2, 1);
+  ExternalReference ref = ExternalReference(IC_Utility(kKeyedLoadIC_Miss));
+  __ TailCallExternalReference(ref, 2, 1);
 }
 
 
@@ -258,7 +259,7 @@ void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
   __ push(rbx);  // return address
 
   // Perform tail call to the entry.
-  __ TailCallRuntime(ExternalReference(Runtime::kKeyedGetProperty), 2, 1);
+  __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
 }
 
 
@@ -608,7 +609,7 @@ void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
   __ push(rdx);  // return address
 
   // Perform tail call to the entry.
-  __ TailCallRuntime(ExternalReference(
+  __ TailCallExternalReference(ExternalReference(
         IC_Utility(kKeyedLoadPropertyWithInterceptor)), 2, 1);
 
   __ bind(&slow);
@@ -631,7 +632,8 @@ void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
   __ push(rcx);  // return address
 
   // Do tail-call to runtime routine.
-  __ TailCallRuntime(ExternalReference(IC_Utility(kKeyedStoreIC_Miss)), 3, 1);
+  ExternalReference ref = ExternalReference(IC_Utility(kKeyedStoreIC_Miss));
+  __ TailCallExternalReference(ref, 3, 1);
 }
 
 
@@ -650,7 +652,7 @@ void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm) {
   __ push(rcx);  // return address
 
   // Do tail-call to runtime routine.
-  __ TailCallRuntime(ExternalReference(Runtime::kSetProperty), 3, 1);
+  __ TailCallRuntime(Runtime::kSetProperty, 3, 1);
 }
 
 
@@ -1223,7 +1225,8 @@ void LoadIC::GenerateMiss(MacroAssembler* masm) {
   __ push(rbx);  // return address
 
   // Perform tail call to the entry.
-  __ TailCallRuntime(ExternalReference(IC_Utility(kLoadIC_Miss)), 2, 1);
+  ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss));
+  __ TailCallExternalReference(ref, 2, 1);
 }
 
 
@@ -1385,7 +1388,8 @@ void StoreIC::GenerateMiss(MacroAssembler* masm) {
   __ push(rbx);  // return address
 
   // Perform tail call to the entry.
-  __ TailCallRuntime(ExternalReference(IC_Utility(kStoreIC_Miss)), 3, 1);
+  ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_Miss));
+  __ TailCallExternalReference(ref, 3, 1);
 }
 
 
@@ -1449,7 +1453,8 @@ void StoreIC::GenerateArrayLength(MacroAssembler* masm) {
   __ push(value);
   __ push(scratch);  // return address
 
-  __ TailCallRuntime(ExternalReference(IC_Utility(kStoreIC_ArrayLength)), 2, 1);
+  ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_ArrayLength));
+  __ TailCallExternalReference(ref, 2, 1);
 
   __ bind(&miss);
 
index 90a9c75..dca2780 100644 (file)
@@ -396,9 +396,9 @@ void MacroAssembler::CallExternalReference(const ExternalReference& ext,
 }
 
 
-void MacroAssembler::TailCallRuntime(ExternalReference const& ext,
-                                     int num_arguments,
-                                     int result_size) {
+void MacroAssembler::TailCallExternalReference(const ExternalReference& ext,
+                                               int num_arguments,
+                                               int result_size) {
   // ----------- S t a t e -------------
   //  -- rsp[0] : return address
   //  -- rsp[8] : argument num_arguments - 1
@@ -411,12 +411,19 @@ void MacroAssembler::TailCallRuntime(ExternalReference const& ext,
   // should remove this need and make the runtime routine entry code
   // smarter.
   movq(rax, Immediate(num_arguments));
-  JumpToRuntime(ext, result_size);
+  JumpToExternalReference(ext, result_size);
 }
 
 
-void MacroAssembler::JumpToRuntime(const ExternalReference& ext,
-                                   int result_size) {
+void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid,
+                                     int num_arguments,
+                                     int result_size) {
+  TailCallExternalReference(ExternalReference(fid), num_arguments, result_size);
+}
+
+
+void MacroAssembler::JumpToExternalReference(const ExternalReference& ext,
+                                             int result_size) {
   // Set the entry point and jump to the C entry runtime stub.
   movq(rbx, ext);
   CEntryStub ces(result_size);
@@ -1393,6 +1400,50 @@ void MacroAssembler::JumpIfNotBothSequentialAsciiStrings(Register first_object,
 }
 
 
+void MacroAssembler::JumpIfInstanceTypeIsNotSequentialAscii(
+    Register instance_type,
+    Register scratch,
+    Label *failure) {
+  if (!scratch.is(instance_type)) {
+    movl(scratch, instance_type);
+  }
+
+  const int kFlatAsciiStringMask =
+      kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask;
+
+  andl(scratch, Immediate(kFlatAsciiStringMask));
+  cmpl(scratch, Immediate(kStringTag | kSeqStringTag | kAsciiStringTag));
+  j(not_equal, failure);
+}
+
+
+void MacroAssembler::JumpIfBothInstanceTypesAreNotSequentialAscii(
+    Register first_object_instance_type,
+    Register second_object_instance_type,
+    Register scratch1,
+    Register scratch2,
+    Label* on_fail) {
+  // Load instance type for both strings.
+  movq(scratch1, first_object_instance_type);
+  movq(scratch2, second_object_instance_type);
+
+  // Check that both are flat ascii strings.
+  ASSERT(kNotStringTag != 0);
+  const int kFlatAsciiStringMask =
+      kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask;
+  const int kFlatAsciiStringTag = ASCII_STRING_TYPE;
+
+  andl(scratch1, Immediate(kFlatAsciiStringMask));
+  andl(scratch2, Immediate(kFlatAsciiStringMask));
+  // Interleave the bits to check both scratch1 and scratch2 in one test.
+  ASSERT_EQ(0, kFlatAsciiStringMask & (kFlatAsciiStringMask << 3));
+  lea(scratch1, Operand(scratch1, scratch2, times_8, 0));
+  cmpl(scratch1,
+       Immediate(kFlatAsciiStringTag + (kFlatAsciiStringTag << 3)));
+  j(not_equal, on_fail);
+}
+
+
 void MacroAssembler::Move(Register dst, Handle<Object> source) {
   ASSERT(!source->IsFailure());
   if (source->IsSmi()) {
index 2673086..bbb6e21 100644 (file)
@@ -426,6 +426,20 @@ class MacroAssembler: public Assembler {
                                            Register scratch2,
                                            Label* on_not_both_flat_ascii);
 
+  // Check whether the instance type represents a flat ascii string. Jump to the
+  // label if not. If the instance type can be scratched specify same register
+  // for both instance type and scratch.
+  void JumpIfInstanceTypeIsNotSequentialAscii(Register instance_type,
+                                              Register scratch,
+                                              Label *on_not_flat_ascii_string);
+
+  void JumpIfBothInstanceTypesAreNotSequentialAscii(
+      Register first_object_instance_type,
+      Register second_object_instance_type,
+      Register scratch1,
+      Register scratch2,
+      Label* on_fail);
+
   // ---------------------------------------------------------------------------
   // Macro instructions.
 
@@ -645,7 +659,6 @@ class MacroAssembler: public Assembler {
   void StubReturn(int argc);
 
   // Call a runtime routine.
-  // Eventually this should be used for all C calls.
   void CallRuntime(Runtime::Function* f, int num_arguments);
 
   // Convenience function: Same as above, but takes the fid instead.
@@ -656,14 +669,19 @@ class MacroAssembler: public Assembler {
                              int num_arguments);
 
   // Tail call of a runtime routine (jump).
-  // Like JumpToRuntime, but also takes care of passing the number
-  // of arguments.
-  void TailCallRuntime(const ExternalReference& ext,
+  // Like JumpToExternalReference, but also takes care of passing the number
+  // of parameters.
+  void TailCallExternalReference(const ExternalReference& ext,
+                                 int num_arguments,
+                                 int result_size);
+
+  // Convenience function: tail call a runtime routine (jump).
+  void TailCallRuntime(Runtime::FunctionId fid,
                        int num_arguments,
                        int result_size);
 
   // Jump to a runtime routine.
-  void JumpToRuntime(const ExternalReference& ext, int result_size);
+  void JumpToExternalReference(const ExternalReference& ext, int result_size);
 
   // Before calling a C-function from generated code, align arguments on stack.
   // After aligning the frame, arguments must be stored in esp[0], esp[4],
index 026301b..6e7d9c9 100644 (file)
@@ -335,7 +335,7 @@ void RegExpMacroAssemblerX64::CheckNotBackReferenceIgnoreCase(
 #endif
     __ push(backtrack_stackpointer());
 
-    int num_arguments = 3;
+    static const int num_arguments = 3;
     __ PrepareCallCFunction(num_arguments);
 
     // Put arguments into parameter registers. Parameters are
@@ -849,7 +849,7 @@ Handle<Object> RegExpMacroAssemblerX64::GetCode(Handle<String> source) {
 #endif
 
     // Call GrowStack(backtrack_stackpointer())
-    int num_arguments = 2;
+    static const int num_arguments = 2;
     __ PrepareCallCFunction(num_arguments);
 #ifdef _WIN64
     // Microsoft passes parameters in rcx, rdx.
@@ -1029,7 +1029,7 @@ void RegExpMacroAssemblerX64::WriteStackPointerToRegister(int reg) {
 void RegExpMacroAssemblerX64::CallCheckStackGuardState() {
   // This function call preserves no register values. Caller should
   // store anything volatile in a C call or overwritten by this function.
-  int num_arguments = 3;
+  static const int num_arguments = 3;
   __ PrepareCallCFunction(num_arguments);
 #ifdef _WIN64
   // Second argument: Code* of self. (Do this before overwriting r8).
index 9c8b4f7..5d73b5f 100644 (file)
@@ -236,7 +236,7 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
     __ Push(Handle<Map>(transition));
     __ push(rax);
     __ push(scratch);
-    __ TailCallRuntime(
+    __ TailCallExternalReference(
         ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage)), 3, 1);
     return;
   }
@@ -526,7 +526,7 @@ class LoadInterceptorCompiler BASE_EMBEDDED {
 
       ExternalReference ref =
           ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
-      __ TailCallRuntime(ref, 5, 1);
+      __ TailCallExternalReference(ref, 5, 1);
 
       __ bind(&cleanup);
       __ pop(scratch1);
@@ -548,7 +548,7 @@ class LoadInterceptorCompiler BASE_EMBEDDED {
 
     ExternalReference ref = ExternalReference(
         IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
-    __ TailCallRuntime(ref, 5, 1);
+    __ TailCallExternalReference(ref, 5, 1);
   }
 
  private:
@@ -1360,7 +1360,7 @@ Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
   // Do tail-call to the runtime system.
   ExternalReference store_callback_property =
       ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
-  __ TailCallRuntime(store_callback_property, 4, 1);
+  __ TailCallExternalReference(store_callback_property, 4, 1);
 
   // Handle store cache miss.
   __ bind(&miss);
@@ -1438,7 +1438,7 @@ Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
   // Do tail-call to the runtime system.
   ExternalReference store_ic_property =
       ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
-  __ TailCallRuntime(store_ic_property, 3, 1);
+  __ TailCallExternalReference(store_ic_property, 3, 1);
 
   // Handle store cache miss.
   __ bind(&miss);
@@ -1637,7 +1637,7 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object,
   // Do tail-call to the runtime system.
   ExternalReference load_callback_property =
       ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
-  __ TailCallRuntime(load_callback_property, 5, 1);
+  __ TailCallExternalReference(load_callback_property, 5, 1);
 
   return true;
 }
index e322c61..79be20b 100644 (file)
@@ -37,23 +37,6 @@ namespace internal {
 
 #define __ ACCESS_MASM(masm())
 
-// -------------------------------------------------------------------------
-// VirtualFrame implementation.
-
-// On entry to a function, the virtual frame already contains the receiver,
-// the parameters, and a return address.  All frame elements are in memory.
-VirtualFrame::VirtualFrame()
-    : elements_(parameter_count() + local_count() + kPreallocatedElements),
-      stack_pointer_(parameter_count() + 1) {  // 0-based index of TOS.
-  for (int i = 0; i <= stack_pointer_; i++) {
-    elements_.Add(FrameElement::MemoryElement(NumberInfo::kUnknown));
-  }
-  for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
-    register_locations_[i] = kIllegalIndex;
-  }
-}
-
-
 void VirtualFrame::Enter() {
   // Registers live on entry to a JS frame:
   //   rsp: stack pointer, points to return address from this function.
@@ -194,7 +177,7 @@ void VirtualFrame::EmitPop(const Operand& operand) {
 }
 
 
-void VirtualFrame::EmitPush(Register reg, NumberInfo::Type info) {
+void VirtualFrame::EmitPush(Register reg, NumberInfo info) {
   ASSERT(stack_pointer_ == element_count() - 1);
   elements_.Add(FrameElement::MemoryElement(info));
   stack_pointer_++;
@@ -202,7 +185,7 @@ void VirtualFrame::EmitPush(Register reg, NumberInfo::Type info) {
 }
 
 
-void VirtualFrame::EmitPush(const Operand& operand, NumberInfo::Type info) {
+void VirtualFrame::EmitPush(const Operand& operand, NumberInfo info) {
   ASSERT(stack_pointer_ == element_count() - 1);
   elements_.Add(FrameElement::MemoryElement(info));
   stack_pointer_++;
@@ -210,7 +193,7 @@ void VirtualFrame::EmitPush(const Operand& operand, NumberInfo::Type info) {
 }
 
 
-void VirtualFrame::EmitPush(Immediate immediate, NumberInfo::Type info) {
+void VirtualFrame::EmitPush(Immediate immediate, NumberInfo info) {
   ASSERT(stack_pointer_ == element_count() - 1);
   elements_.Add(FrameElement::MemoryElement(info));
   stack_pointer_++;
@@ -220,7 +203,7 @@ void VirtualFrame::EmitPush(Immediate immediate, NumberInfo::Type info) {
 
 void VirtualFrame::EmitPush(Smi* smi_value) {
   ASSERT(stack_pointer_ == element_count() - 1);
-  elements_.Add(FrameElement::MemoryElement(NumberInfo::kSmi));
+  elements_.Add(FrameElement::MemoryElement(NumberInfo::Smi()));
   stack_pointer_++;
   __ Push(smi_value);
 }
@@ -228,11 +211,11 @@ void VirtualFrame::EmitPush(Smi* smi_value) {
 
 void VirtualFrame::EmitPush(Handle<Object> value) {
   ASSERT(stack_pointer_ == element_count() - 1);
-  NumberInfo::Type info = NumberInfo::kUnknown;
+  NumberInfo info = NumberInfo::Unknown();
   if (value->IsSmi()) {
-    info = NumberInfo::kSmi;
+    info = NumberInfo::Smi();
   } else if (value->IsHeapNumber()) {
-    info = NumberInfo::kHeapNumber;
+    info = NumberInfo::HeapNumber();
   }
   elements_.Add(FrameElement::MemoryElement(info));
   stack_pointer_++;
@@ -240,7 +223,7 @@ void VirtualFrame::EmitPush(Handle<Object> value) {
 }
 
 
-void VirtualFrame::EmitPush(Heap::RootListIndex index, NumberInfo::Type info) {
+void VirtualFrame::EmitPush(Heap::RootListIndex index, NumberInfo info) {
   ASSERT(stack_pointer_ == element_count() - 1);
   elements_.Add(FrameElement::MemoryElement(info));
   stack_pointer_++;
@@ -497,7 +480,7 @@ void VirtualFrame::MakeMergable() {
     if (element.is_constant() || element.is_copy()) {
       if (element.is_synced()) {
         // Just spill.
-        elements_[i] = FrameElement::MemoryElement(NumberInfo::kUnknown);
+        elements_[i] = FrameElement::MemoryElement(NumberInfo::Unknown());
       } else {
         // Allocate to a register.
         FrameElement backing_element;  // Invalid if not a copy.
@@ -509,7 +492,7 @@ void VirtualFrame::MakeMergable() {
         elements_[i] =
             FrameElement::RegisterElement(fresh.reg(),
                                           FrameElement::NOT_SYNCED,
-                                          NumberInfo::kUnknown);
+                                          NumberInfo::Unknown());
         Use(fresh.reg(), i);
 
         // Emit a move.
@@ -538,7 +521,7 @@ void VirtualFrame::MakeMergable() {
       // The copy flag is not relied on before the end of this loop,
       // including when registers are spilled.
       elements_[i].clear_copied();
-      elements_[i].set_number_info(NumberInfo::kUnknown);
+      elements_[i].set_number_info(NumberInfo::Unknown());
     }
   }
 }
@@ -745,7 +728,7 @@ Result VirtualFrame::Pop() {
   ASSERT(element.is_valid());
 
   // Get number type information of the result.
-  NumberInfo::Type info;
+  NumberInfo info;
   if (!element.is_copy()) {
     info = element.number_info();
   } else {
index d4df484..ddd606b 100644 (file)
@@ -73,7 +73,7 @@ class VirtualFrame : public ZoneObject {
   static const int kIllegalIndex = -1;
 
   // Construct an initial virtual frame on entry to a JS function.
-  VirtualFrame();
+  inline VirtualFrame();
 
   // Construct a virtual frame as a clone of an existing one.
   explicit inline VirtualFrame(VirtualFrame* original);
@@ -83,7 +83,7 @@ class VirtualFrame : public ZoneObject {
 
   // Create a duplicate of an existing valid frame element.
   FrameElement CopyElementAt(int index,
-    NumberInfo::Type info = NumberInfo::kUninitialized);
+    NumberInfo info = NumberInfo::Uninitialized());
 
   // The number of elements on the virtual frame.
   int element_count() { return elements_.length(); }
@@ -383,19 +383,19 @@ class VirtualFrame : public ZoneObject {
   // Push an element on top of the expression stack and emit a
   // corresponding push instruction.
   void EmitPush(Register reg,
-                NumberInfo::Type info = NumberInfo::kUnknown);
+                NumberInfo info = NumberInfo::Unknown());
   void EmitPush(const Operand& operand,
-                NumberInfo::Type info = NumberInfo::kUnknown);
+                NumberInfo info = NumberInfo::Unknown());
   void EmitPush(Heap::RootListIndex index,
-                NumberInfo::Type info = NumberInfo::kUnknown);
+                NumberInfo info = NumberInfo::Unknown());
   void EmitPush(Immediate immediate,
-                NumberInfo::Type info = NumberInfo::kUnknown);
+                NumberInfo info = NumberInfo::Unknown());
   void EmitPush(Smi* value);
   // Uses kScratchRegister, emits appropriate relocation info.
   void EmitPush(Handle<Object> value);
 
   // Push an element on the virtual frame.
-  inline void Push(Register reg, NumberInfo::Type info = NumberInfo::kUnknown);
+  inline void Push(Register reg, NumberInfo info = NumberInfo::Unknown());
   inline void Push(Handle<Object> value);
   inline void Push(Smi* value);
 
index 121ba19..5893a2f 100644 (file)
@@ -68,227 +68,12 @@ void Zone::adjust_segment_bytes_allocated(int delta) {
 }
 
 
-template <typename C>
-bool ZoneSplayTree<C>::Insert(const Key& key, Locator* locator) {
-  if (is_empty()) {
-    // If the tree is empty, insert the new node.
-    root_ = new Node(key, C::kNoValue);
-  } else {
-    // Splay on the key to move the last node on the search path
-    // for the key to the root of the tree.
-    Splay(key);
-    // Ignore repeated insertions with the same key.
-    int cmp = C::Compare(key, root_->key_);
-    if (cmp == 0) {
-      locator->bind(root_);
-      return false;
-    }
-    // Insert the new node.
-    Node* node = new Node(key, C::kNoValue);
-    if (cmp > 0) {
-      node->left_ = root_;
-      node->right_ = root_->right_;
-      root_->right_ = NULL;
-    } else {
-      node->right_ = root_;
-      node->left_ = root_->left_;
-      root_->left_ = NULL;
-    }
-    root_ = node;
-  }
-  locator->bind(root_);
-  return true;
-}
-
-
-template <typename C>
-bool ZoneSplayTree<C>::Find(const Key& key, Locator* locator) {
-  if (is_empty())
-    return false;
-  Splay(key);
-  if (C::Compare(key, root_->key_) == 0) {
-    locator->bind(root_);
-    return true;
-  } else {
-    return false;
-  }
-}
-
-
-template <typename C>
-bool ZoneSplayTree<C>::FindGreatestLessThan(const Key& key,
-                                            Locator* locator) {
-  if (is_empty())
-    return false;
-  // Splay on the key to move the node with the given key or the last
-  // node on the search path to the top of the tree.
-  Splay(key);
-  // Now the result is either the root node or the greatest node in
-  // the left subtree.
-  int cmp = C::Compare(root_->key_, key);
-  if (cmp <= 0) {
-    locator->bind(root_);
-    return true;
-  } else {
-    Node* temp = root_;
-    root_ = root_->left_;
-    bool result = FindGreatest(locator);
-    root_ = temp;
-    return result;
-  }
-}
-
-
-template <typename C>
-bool ZoneSplayTree<C>::FindLeastGreaterThan(const Key& key,
-                                            Locator* locator) {
-  if (is_empty())
-    return false;
-  // Splay on the key to move the node with the given key or the last
-  // node on the search path to the top of the tree.
-  Splay(key);
-  // Now the result is either the root node or the least node in
-  // the right subtree.
-  int cmp = C::Compare(root_->key_, key);
-  if (cmp >= 0) {
-    locator->bind(root_);
-    return true;
-  } else {
-    Node* temp = root_;
-    root_ = root_->right_;
-    bool result = FindLeast(locator);
-    root_ = temp;
-    return result;
-  }
-}
-
-
-template <typename C>
-bool ZoneSplayTree<C>::FindGreatest(Locator* locator) {
-  if (is_empty())
-    return false;
-  Node* current = root_;
-  while (current->right_ != NULL)
-    current = current->right_;
-  locator->bind(current);
-  return true;
-}
-
-
-template <typename C>
-bool ZoneSplayTree<C>::FindLeast(Locator* locator) {
-  if (is_empty())
-    return false;
-  Node* current = root_;
-  while (current->left_ != NULL)
-    current = current->left_;
-  locator->bind(current);
-  return true;
-}
-
-
-template <typename C>
-bool ZoneSplayTree<C>::Remove(const Key& key) {
-  // Bail if the tree is empty
-  if (is_empty())
-    return false;
-  // Splay on the key to move the node with the given key to the top.
-  Splay(key);
-  // Bail if the key is not in the tree
-  if (C::Compare(key, root_->key_) != 0)
-    return false;
-  if (root_->left_ == NULL) {
-    // No left child, so the new tree is just the right child.
-    root_ = root_->right_;
-  } else {
-    // Left child exists.
-    Node* right = root_->right_;
-    // Make the original left child the new root.
-    root_ = root_->left_;
-    // Splay to make sure that the new root has an empty right child.
-    Splay(key);
-    // Insert the original right child as the right child of the new
-    // root.
-    root_->right_ = right;
-  }
-  return true;
-}
-
-
-template <typename C>
-void ZoneSplayTree<C>::Splay(const Key& key) {
-  if (is_empty())
-    return;
-  Node dummy_node(C::kNoKey, C::kNoValue);
-  // Create a dummy node.  The use of the dummy node is a bit
-  // counter-intuitive: The right child of the dummy node will hold
-  // the L tree of the algorithm.  The left child of the dummy node
-  // will hold the R tree of the algorithm.  Using a dummy node, left
-  // and right will always be nodes and we avoid special cases.
-  Node* dummy = &dummy_node;
-  Node* left = dummy;
-  Node* right = dummy;
-  Node* current = root_;
-  while (true) {
-    int cmp = C::Compare(key, current->key_);
-    if (cmp < 0) {
-      if (current->left_ == NULL)
-        break;
-      if (C::Compare(key, current->left_->key_) < 0) {
-        // Rotate right.
-        Node* temp = current->left_;
-        current->left_ = temp->right_;
-        temp->right_ = current;
-        current = temp;
-        if (current->left_ == NULL)
-          break;
-      }
-      // Link right.
-      right->left_ = current;
-      right = current;
-      current = current->left_;
-    } else if (cmp > 0) {
-      if (current->right_ == NULL)
-        break;
-      if (C::Compare(key, current->right_->key_) > 0) {
-        // Rotate left.
-        Node* temp = current->right_;
-        current->right_ = temp->left_;
-        temp->left_ = current;
-        current = temp;
-        if (current->right_ == NULL)
-          break;
-      }
-      // Link left.
-      left->right_ = current;
-      left = current;
-      current = current->right_;
-    } else {
-      break;
-    }
-  }
-  // Assemble.
-  left->right_ = current->left_;
-  right->left_ = current->right_;
-  current->left_ = dummy->right_;
-  current->right_ = dummy->left_;
-  root_ = current;
-}
-
-
-template <typename Config> template <class Callback>
-void ZoneSplayTree<Config>::ForEach(Callback* callback) {
-  // Pre-allocate some space for tiny trees.
-  ZoneList<Node*> nodes_to_visit(10);
-  nodes_to_visit.Add(root_);
-  int pos = 0;
-  while (pos < nodes_to_visit.length()) {
-    Node* node = nodes_to_visit[pos++];
-    if (node == NULL) continue;
-    callback->Call(node->key(), node->value());
-    nodes_to_visit.Add(node->left());
-    nodes_to_visit.Add(node->right());
-  }
+template <typename Config>
+ZoneSplayTree<Config>::~ZoneSplayTree() {
+  // Reset the root to avoid unneeded iteration over all tree nodes
+  // in the destructor.  For a zone-allocated tree, nodes will be
+  // freed by the Zone.
+  SplayTree<Config, ZoneListAllocationPolicy>::ResetRoot();
 }
 
 
index 33fe557..01df450 100644 (file)
@@ -28,6 +28,7 @@
 #include "v8.h"
 
 #include "zone-inl.h"
+#include "splay-tree-inl.h"
 
 namespace v8 {
 namespace internal {
index 0d006dd..3397356 100644 (file)
@@ -205,98 +205,14 @@ class ZoneScope BASE_EMBEDDED {
 
 
 // A zone splay tree.  The config type parameter encapsulates the
-// different configurations of a concrete splay tree:
-//
-//   typedef Key: the key type
-//   typedef Value: the value type
-//   static const kNoKey: the dummy key used when no key is set
-//   static const kNoValue: the dummy value used to initialize nodes
-//   int (Compare)(Key& a, Key& b) -> {-1, 0, 1}: comparison function
-//
+// different configurations of a concrete splay tree (see splay-tree.h).
+// The tree itself and all its elements are allocated in the Zone.
 template <typename Config>
-class ZoneSplayTree : public ZoneObject {
+class ZoneSplayTree: public SplayTree<Config, ZoneListAllocationPolicy> {
  public:
-  typedef typename Config::Key Key;
-  typedef typename Config::Value Value;
-
-  class Locator;
-
-  ZoneSplayTree() : root_(NULL) { }
-
-  // Inserts the given key in this tree with the given value.  Returns
-  // true if a node was inserted, otherwise false.  If found the locator
-  // is enabled and provides access to the mapping for the key.
-  bool Insert(const Key& key, Locator* locator);
-
-  // Looks up the key in this tree and returns true if it was found,
-  // otherwise false.  If the node is found the locator is enabled and
-  // provides access to the mapping for the key.
-  bool Find(const Key& key, Locator* locator);
-
-  // Finds the mapping with the greatest key less than or equal to the
-  // given key.
-  bool FindGreatestLessThan(const Key& key, Locator* locator);
-
-  // Find the mapping with the greatest key in this tree.
-  bool FindGreatest(Locator* locator);
-
-  // Finds the mapping with the least key greater than or equal to the
-  // given key.
-  bool FindLeastGreaterThan(const Key& key, Locator* locator);
-
-  // Find the mapping with the least key in this tree.
-  bool FindLeast(Locator* locator);
-
-  // Remove the node with the given key from the tree.
-  bool Remove(const Key& key);
-
-  bool is_empty() { return root_ == NULL; }
-
-  // Perform the splay operation for the given key. Moves the node with
-  // the given key to the top of the tree.  If no node has the given
-  // key, the last node on the search path is moved to the top of the
-  // tree.
-  void Splay(const Key& key);
-
-  class Node : public ZoneObject {
-   public:
-    Node(const Key& key, const Value& value)
-        : key_(key),
-          value_(value),
-          left_(NULL),
-          right_(NULL) { }
-    Key key() { return key_; }
-    Value value() { return value_; }
-    Node* left() { return left_; }
-    Node* right() { return right_; }
-   private:
-    friend class ZoneSplayTree;
-    friend class Locator;
-    Key key_;
-    Value value_;
-    Node* left_;
-    Node* right_;
-  };
-
-  // A locator provides access to a node in the tree without actually
-  // exposing the node.
-  class Locator {
-   public:
-    explicit Locator(Node* node) : node_(node) { }
-    Locator() : node_(NULL) { }
-    const Key& key() { return node_->key_; }
-    Value& value() { return node_->value_; }
-    void set_value(const Value& value) { node_->value_ = value; }
-    inline void bind(Node* node) { node_ = node; }
-   private:
-    Node* node_;
-  };
-
-  template <class Callback>
-  void ForEach(Callback* callback);
-
- private:
-  Node* root_;
+  ZoneSplayTree()
+      : SplayTree<Config, ZoneListAllocationPolicy>() {}
+  ~ZoneSplayTree();
 };
 
 
index acd567e..7335b7a 100644 (file)
@@ -40,6 +40,7 @@ SOURCES = {
     'test-ast.cc',
     'test-compiler.cc',
     'test-conversions.cc',
+    'test-dataflow.cc',
     'test-debug.cc',
     'test-decls.cc',
     'test-flags.cc',
index ecbafa0..eefe71c 100644 (file)
@@ -27,6 +27,8 @@
 
 prefix cctest
 
+test-api/Bug*: FAIL
+
 # BUG(281): This test fails on some Linuxes.
 test-debug/DebuggerAgent: PASS, (PASS || FAIL) if $system == linux
 
index 10a92c3..e996a07 100644 (file)
@@ -264,6 +264,25 @@ THREADED_TEST(Access) {
 }
 
 
+THREADED_TEST(AccessElement) {
+  v8::HandleScope scope;
+  LocalContext env;
+  Local<v8::Object> obj = v8::Object::New();
+  Local<Value> before = obj->Get(1);
+  CHECK(before->IsUndefined());
+  Local<String> bar_str = v8_str("bar");
+  obj->Set(1, bar_str);
+  Local<Value> after = obj->Get(1);
+  CHECK(!after->IsUndefined());
+  CHECK(after->IsString());
+  CHECK_EQ(bar_str, after);
+
+  Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
+  CHECK_EQ(v8_str("a"), value->Get(0));
+  CHECK_EQ(v8_str("b"), value->Get(1));
+}
+
+
 THREADED_TEST(Script) {
   v8::HandleScope scope;
   LocalContext env;
@@ -1254,7 +1273,7 @@ static v8::Handle<Value> CallFunctionRecursivelyCall(
   args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
   v8::Handle<Value> function =
       args.This()->Get(v8_str("callFunctionRecursively"));
-  return v8::Handle<Function>::Cast(function)->Call(args.This(), 0, NULL);
+  return function.As<Function>()->Call(args.This(), 0, NULL);
 }
 
 
@@ -1334,6 +1353,20 @@ THREADED_TEST(InternalFields) {
 }
 
 
+THREADED_TEST(GlobalObjectInternalFields) {
+  v8::HandleScope scope;
+  Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
+  global_template->SetInternalFieldCount(1);
+  LocalContext env(NULL, global_template);
+  v8::Handle<v8::Object> global_proxy = env->Global();
+  v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
+  CHECK_EQ(1, global->InternalFieldCount());
+  CHECK(global->GetInternalField(0)->IsUndefined());
+  global->SetInternalField(0, v8_num(17));
+  CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
+}
+
+
 THREADED_TEST(InternalFieldsNativePointers) {
   v8::HandleScope scope;
   LocalContext env;
@@ -1514,7 +1547,7 @@ THREADED_TEST(External) {
   LocalContext env;
   env->Global()->Set(v8_str("ext"), ext);
   Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
-  v8::Handle<v8::External> reext = v8::Handle<v8::External>::Cast(reext_obj);
+  v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
   int* ptr = static_cast<int*>(reext->Value());
   CHECK_EQ(x, 3);
   *ptr = 10;
@@ -1646,22 +1679,22 @@ THREADED_TEST(Array) {
   LocalContext context;
   Local<v8::Array> array = v8::Array::New();
   CHECK_EQ(0, array->Length());
-  CHECK(array->Get(v8::Integer::New(0))->IsUndefined());
+  CHECK(array->Get(0)->IsUndefined());
   CHECK(!array->Has(0));
-  CHECK(array->Get(v8::Integer::New(100))->IsUndefined());
+  CHECK(array->Get(100)->IsUndefined());
   CHECK(!array->Has(100));
-  array->Set(v8::Integer::New(2), v8_num(7));
+  array->Set(2, v8_num(7));
   CHECK_EQ(3, array->Length());
   CHECK(!array->Has(0));
   CHECK(!array->Has(1));
   CHECK(array->Has(2));
-  CHECK_EQ(7, array->Get(v8::Integer::New(2))->Int32Value());
+  CHECK_EQ(7, array->Get(2)->Int32Value());
   Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
-  Local<v8::Array> arr = Local<v8::Array>::Cast(obj);
+  Local<v8::Array> arr = obj.As<v8::Array>();
   CHECK_EQ(3, arr->Length());
-  CHECK_EQ(1, arr->Get(v8::Integer::New(0))->Int32Value());
-  CHECK_EQ(2, arr->Get(v8::Integer::New(1))->Int32Value());
-  CHECK_EQ(3, arr->Get(v8::Integer::New(2))->Int32Value());
+  CHECK_EQ(1, arr->Get(0)->Int32Value());
+  CHECK_EQ(2, arr->Get(1)->Int32Value());
+  CHECK_EQ(3, arr->Get(2)->Int32Value());
 }
 
 
@@ -1670,7 +1703,7 @@ v8::Handle<Value> HandleF(const v8::Arguments& args) {
   ApiTestFuzzer::Fuzz();
   Local<v8::Array> result = v8::Array::New(args.Length());
   for (int i = 0; i < args.Length(); i++)
-    result->Set(v8::Integer::New(i), args[i]);
+    result->Set(i, args[i]);
   return scope.Close(result);
 }
 
@@ -1682,39 +1715,34 @@ THREADED_TEST(Vector) {
   LocalContext context(0, global);
 
   const char* fun = "f()";
-  Local<v8::Array> a0 =
-      Local<v8::Array>::Cast(Script::Compile(String::New(fun))->Run());
+  Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
   CHECK_EQ(0, a0->Length());
 
   const char* fun2 = "f(11)";
-  Local<v8::Array> a1 =
-      Local<v8::Array>::Cast(Script::Compile(String::New(fun2))->Run());
+  Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
   CHECK_EQ(1, a1->Length());
-  CHECK_EQ(11, a1->Get(v8::Integer::New(0))->Int32Value());
+  CHECK_EQ(11, a1->Get(0)->Int32Value());
 
   const char* fun3 = "f(12, 13)";
-  Local<v8::Array> a2 =
-      Local<v8::Array>::Cast(Script::Compile(String::New(fun3))->Run());
+  Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
   CHECK_EQ(2, a2->Length());
-  CHECK_EQ(12, a2->Get(v8::Integer::New(0))->Int32Value());
-  CHECK_EQ(13, a2->Get(v8::Integer::New(1))->Int32Value());
+  CHECK_EQ(12, a2->Get(0)->Int32Value());
+  CHECK_EQ(13, a2->Get(1)->Int32Value());
 
   const char* fun4 = "f(14, 15, 16)";
-  Local<v8::Array> a3 =
-      Local<v8::Array>::Cast(Script::Compile(String::New(fun4))->Run());
+  Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
   CHECK_EQ(3, a3->Length());
-  CHECK_EQ(14, a3->Get(v8::Integer::New(0))->Int32Value());
-  CHECK_EQ(15, a3->Get(v8::Integer::New(1))->Int32Value());
-  CHECK_EQ(16, a3->Get(v8::Integer::New(2))->Int32Value());
+  CHECK_EQ(14, a3->Get(0)->Int32Value());
+  CHECK_EQ(15, a3->Get(1)->Int32Value());
+  CHECK_EQ(16, a3->Get(2)->Int32Value());
 
   const char* fun5 = "f(17, 18, 19, 20)";
-  Local<v8::Array> a4 =
-      Local<v8::Array>::Cast(Script::Compile(String::New(fun5))->Run());
+  Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
   CHECK_EQ(4, a4->Length());
-  CHECK_EQ(17, a4->Get(v8::Integer::New(0))->Int32Value());
-  CHECK_EQ(18, a4->Get(v8::Integer::New(1))->Int32Value());
-  CHECK_EQ(19, a4->Get(v8::Integer::New(2))->Int32Value());
-  CHECK_EQ(20, a4->Get(v8::Integer::New(3))->Int32Value());
+  CHECK_EQ(17, a4->Get(0)->Int32Value());
+  CHECK_EQ(18, a4->Get(1)->Int32Value());
+  CHECK_EQ(19, a4->Get(2)->Int32Value());
+  CHECK_EQ(20, a4->Get(3)->Int32Value());
 }
 
 
@@ -1932,6 +1960,95 @@ static void CheckUncle(v8::TryCatch* try_catch) {
 }
 
 
+THREADED_TEST(ConversionNumber) {
+  v8::HandleScope scope;
+  LocalContext env;
+  // Very large number.
+  CompileRun("var obj = Math.pow(2,32) * 1237;");
+  Local<Value> obj = env->Global()->Get(v8_str("obj"));
+  CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
+  CHECK_EQ(0, obj->ToInt32()->Value());
+  CHECK(0u == obj->ToUint32()->Value());  // NOLINT - no CHECK_EQ for unsigned.
+  // Large number.
+  CompileRun("var obj = -1234567890123;");
+  obj = env->Global()->Get(v8_str("obj"));
+  CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
+  CHECK_EQ(-1912276171, obj->ToInt32()->Value());
+  CHECK(2382691125u == obj->ToUint32()->Value());  // NOLINT
+  // Small positive integer.
+  CompileRun("var obj = 42;");
+  obj = env->Global()->Get(v8_str("obj"));
+  CHECK_EQ(42.0, obj->ToNumber()->Value());
+  CHECK_EQ(42, obj->ToInt32()->Value());
+  CHECK(42u == obj->ToUint32()->Value());  // NOLINT
+  // Negative integer.
+  CompileRun("var obj = -37;");
+  obj = env->Global()->Get(v8_str("obj"));
+  CHECK_EQ(-37.0, obj->ToNumber()->Value());
+  CHECK_EQ(-37, obj->ToInt32()->Value());
+  CHECK(4294967259u == obj->ToUint32()->Value());  // NOLINT
+  // Positive non-int32 integer.
+  CompileRun("var obj = 0x81234567;");
+  obj = env->Global()->Get(v8_str("obj"));
+  CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
+  CHECK_EQ(-2128394905, obj->ToInt32()->Value());
+  CHECK(2166572391u == obj->ToUint32()->Value());  // NOLINT
+  // Fraction.
+  CompileRun("var obj = 42.3;");
+  obj = env->Global()->Get(v8_str("obj"));
+  CHECK_EQ(42.3, obj->ToNumber()->Value());
+  CHECK_EQ(42, obj->ToInt32()->Value());
+  CHECK(42u == obj->ToUint32()->Value());  // NOLINT
+  // Large negative fraction.
+  CompileRun("var obj = -5726623061.75;");
+  obj = env->Global()->Get(v8_str("obj"));
+  CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
+  CHECK_EQ(-1431655765, obj->ToInt32()->Value());
+  CHECK(2863311531u == obj->ToUint32()->Value());  // NOLINT
+}
+
+
+THREADED_TEST(isNumberType) {
+  v8::HandleScope scope;
+  LocalContext env;
+  // Very large number.
+  CompileRun("var obj = Math.pow(2,32) * 1237;");
+  Local<Value> obj = env->Global()->Get(v8_str("obj"));
+  CHECK(!obj->IsInt32());
+  CHECK(!obj->IsUint32());
+  // Large negative number.
+  CompileRun("var obj = -1234567890123;");
+  obj = env->Global()->Get(v8_str("obj"));
+  CHECK(!obj->IsInt32());
+  CHECK(!obj->IsUint32());
+  // Small positive integer.
+  CompileRun("var obj = 42;");
+  obj = env->Global()->Get(v8_str("obj"));
+  CHECK(obj->IsInt32());
+  CHECK(obj->IsUint32());
+  // Negative integer.
+  CompileRun("var obj = -37;");
+  obj = env->Global()->Get(v8_str("obj"));
+  CHECK(obj->IsInt32());
+  CHECK(!obj->IsUint32());
+  // Positive non-int32 integer.
+  CompileRun("var obj = 0x81234567;");
+  obj = env->Global()->Get(v8_str("obj"));
+  CHECK(!obj->IsInt32());
+  CHECK(obj->IsUint32());
+  // Fraction.
+  CompileRun("var obj = 42.3;");
+  obj = env->Global()->Get(v8_str("obj"));
+  CHECK(!obj->IsInt32());
+  CHECK(!obj->IsUint32());
+  // Large negative fraction.
+  CompileRun("var obj = -5726623061.75;");
+  obj = env->Global()->Get(v8_str("obj"));
+  CHECK(!obj->IsInt32());
+  CHECK(!obj->IsUint32());
+}
+
+
 THREADED_TEST(ConversionException) {
   v8::HandleScope scope;
   LocalContext env;
@@ -2130,8 +2247,7 @@ v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
                                  args[3] };
     if (count % cInterval == 0) {
       v8::TryCatch try_catch;
-      Local<Value> result =
-          v8::Handle<Function>::Cast(fun)->Call(global, 4, argv);
+      Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
       int expected = args[3]->Int32Value();
       if (try_catch.HasCaught()) {
         CHECK_EQ(expected, count);
@@ -2142,7 +2258,7 @@ v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
       }
       return result;
     } else {
-      return v8::Handle<Function>::Cast(fun)->Call(global, 4, argv);
+      return fun.As<Function>()->Call(global, 4, argv);
     }
   }
 }
@@ -2532,7 +2648,7 @@ static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
                                                const AccessorInfo& info) {
   // Set x on the prototype object and do not handle the get request.
   v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
-  v8::Handle<v8::Object>::Cast(proto)->Set(v8_str("x"), v8::Integer::New(23));
+  proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
   return v8::Handle<Value>();
 }
 
@@ -2868,22 +2984,22 @@ THREADED_TEST(FunctionPrototypeAcrossContexts) {
   v8::Handle<v8::Object> global0 =
       env0->Global();
   v8::Handle<v8::Object> object0 =
-      v8::Handle<v8::Object>::Cast(global0->Get(v8_str("Object")));
+      global0->Get(v8_str("Object")).As<v8::Object>();
   v8::Handle<v8::Object> tostring0 =
-      v8::Handle<v8::Object>::Cast(object0->Get(v8_str("toString")));
+      object0->Get(v8_str("toString")).As<v8::Object>();
   v8::Handle<v8::Object> proto0 =
-      v8::Handle<v8::Object>::Cast(tostring0->Get(v8_str("__proto__")));
+      tostring0->Get(v8_str("__proto__")).As<v8::Object>();
   proto0->Set(v8_str("custom"), v8_num(1234));
 
   LocalContext env1;
   v8::Handle<v8::Object> global1 =
       env1->Global();
   v8::Handle<v8::Object> object1 =
-      v8::Handle<v8::Object>::Cast(global1->Get(v8_str("Object")));
+      global1->Get(v8_str("Object")).As<v8::Object>();
   v8::Handle<v8::Object> tostring1 =
-      v8::Handle<v8::Object>::Cast(object1->Get(v8_str("toString")));
+      object1->Get(v8_str("toString")).As<v8::Object>();
   v8::Handle<v8::Object> proto1 =
-      v8::Handle<v8::Object>::Cast(tostring1->Get(v8_str("__proto__")));
+      tostring1->Get(v8_str("__proto__")).As<v8::Object>();
   CHECK(!proto1->Has(v8_str("custom")));
 }
 
@@ -3505,7 +3621,7 @@ THREADED_TEST(Arguments) {
   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
   global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
   LocalContext context(NULL, global);
-  args_fun = v8::Handle<Function>::Cast(context->Global()->Get(v8_str("f")));
+  args_fun = context->Global()->Get(v8_str("f")).As<Function>();
   v8_compile("f(1, 2, 3)")->Run();
 }
 
@@ -3843,21 +3959,20 @@ THREADED_TEST(ErrorConstruction) {
   v8::Handle<String> message = v8_str("message");
   v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
   CHECK(range_error->IsObject());
-  v8::Handle<v8::Object> range_obj(v8::Handle<v8::Object>::Cast(range_error));
-  CHECK(v8::Handle<v8::Object>::Cast(range_error)->Get(message)->Equals(foo));
+  v8::Handle<v8::Object> range_obj = range_error.As<v8::Object>();
+  CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
   v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
   CHECK(reference_error->IsObject());
-  CHECK(
-      v8::Handle<v8::Object>::Cast(reference_error)->Get(message)->Equals(foo));
+  CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
   v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
   CHECK(syntax_error->IsObject());
-  CHECK(v8::Handle<v8::Object>::Cast(syntax_error)->Get(message)->Equals(foo));
+  CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
   v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
   CHECK(type_error->IsObject());
-  CHECK(v8::Handle<v8::Object>::Cast(type_error)->Get(message)->Equals(foo));
+  CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
   v8::Handle<Value> error = v8::Exception::Error(foo);
   CHECK(error->IsObject());
-  CHECK(v8::Handle<v8::Object>::Cast(error)->Get(message)->Equals(foo));
+  CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
 }
 
 
@@ -4780,13 +4895,13 @@ static bool NamedAccessFlatten(Local<v8::Object> global,
   CHECK(name->IsString());
 
   memset(buf, 0x1, sizeof(buf));
-  len = Local<String>::Cast(name)->WriteAscii(buf);
+  len = name.As<String>()->WriteAscii(buf);
   CHECK_EQ(4, len);
 
   uint16_t buf2[100];
 
   memset(buf, 0x1, sizeof(buf));
-  len = Local<String>::Cast(name)->Write(buf2);
+  len = name.As<String>()->Write(buf2);
   CHECK_EQ(4, len);
 
   return true;
@@ -5135,7 +5250,7 @@ THREADED_TEST(HiddenPrototype) {
   // object.
   Local<Value> proto = o0->Get(v8_str("__proto__"));
   CHECK(proto->IsObject());
-  CHECK(Local<v8::Object>::Cast(proto)->Get(v8_str("z"))->IsUndefined());
+  CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
 }
 
 
@@ -5179,20 +5294,20 @@ THREADED_TEST(SetPrototype) {
   // object.
   Local<Value> proto = o0->Get(v8_str("__proto__"));
   CHECK(proto->IsObject());
-  CHECK_EQ(v8::Handle<v8::Object>::Cast(proto), o3);
+  CHECK_EQ(proto.As<v8::Object>(), o3);
 
   // However, Object::GetPrototype ignores hidden prototype.
   Local<Value> proto0 = o0->GetPrototype();
   CHECK(proto0->IsObject());
-  CHECK_EQ(v8::Handle<v8::Object>::Cast(proto0), o1);
+  CHECK_EQ(proto0.As<v8::Object>(), o1);
 
   Local<Value> proto1 = o1->GetPrototype();
   CHECK(proto1->IsObject());
-  CHECK_EQ(v8::Handle<v8::Object>::Cast(proto1), o2);
+  CHECK_EQ(proto1.As<v8::Object>(), o2);
 
   Local<Value> proto2 = o2->GetPrototype();
   CHECK(proto2->IsObject());
-  CHECK_EQ(v8::Handle<v8::Object>::Cast(proto2), o3);
+  CHECK_EQ(proto2.As<v8::Object>(), o3);
 }
 
 
@@ -6904,7 +7019,7 @@ THREADED_TEST(ObjectProtoToString) {
 
   // Check ordinary object
   Local<Value> object = v8_compile("new Object()")->Run();
-  value = Local<v8::Object>::Cast(object)->ObjectProtoToString();
+  value = object.As<v8::Object>()->ObjectProtoToString();
   CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
 }
 
@@ -7524,12 +7639,12 @@ THREADED_TEST(DateAccess) {
   LocalContext context;
   v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
   CHECK(date->IsDate());
-  CHECK_EQ(1224744689038.0, v8::Handle<v8::Date>::Cast(date)->NumberValue());
+  CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
 }
 
 
 void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
-  v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(val);
+  v8::Handle<v8::Object> obj = val.As<v8::Object>();
   v8::Handle<v8::Array> props = obj->GetPropertyNames();
   CHECK_EQ(elmc, props->Length());
   for (int i = 0; i < elmc; i++) {
@@ -7551,7 +7666,7 @@ THREADED_TEST(PropertyEnumeration) {
       "var x = { __proto__: proto, w: 0, z: 1 };"
       "result[3] = x;"
       "result;"))->Run();
-  v8::Handle<v8::Array> elms = v8::Handle<v8::Array>::Cast(obj);
+  v8::Handle<v8::Array> elms = obj.As<v8::Array>();
   CHECK_EQ(4, elms->Length());
   int elmc0 = 0;
   const char** elmv0 = NULL;
@@ -8073,7 +8188,7 @@ TEST(ObjectClone) {
   // Create an object, verify basics.
   Local<Value> val = CompileRun(sample);
   CHECK(val->IsObject());
-  Local<v8::Object> obj = Local<v8::Object>::Cast(val);
+  Local<v8::Object> obj = val.As<v8::Object>();
   obj->Set(v8_str("gamma"), v8_str("cloneme"));
 
   CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
@@ -9714,7 +9829,7 @@ static void SetterWhichSetsYOnThisTo23(Local<String> name,
 }
 
 
-THREADED_TEST(SetterOnConstructorPrototype) {
+TEST(SetterOnConstructorPrototype) {
   v8::HandleScope scope;
   Local<ObjectTemplate> templ = ObjectTemplate::New();
   templ->SetAccessor(v8_str("x"),
@@ -9796,3 +9911,47 @@ THREADED_TEST(InterceptorOnConstructorPrototype) {
     CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
   }
 }
+
+
+TEST(Bug618) {
+  const char* source = "function C1() {"
+                       "  this.x = 23;"
+                       "};"
+                       "C1.prototype = P;";
+
+  v8::HandleScope scope;
+  LocalContext context;
+  v8::Local<v8::Script> script;
+
+  // Use a simple object as prototype.
+  v8::Local<v8::Object> prototype = v8::Object::New();
+  prototype->Set(v8_str("y"), v8_num(42));
+  context->Global()->Set(v8_str("P"), prototype);
+
+  // This compile will add the code to the compilation cache.
+  CompileRun(source);
+
+  script = v8::Script::Compile(v8_str("new C1();"));
+  for (int i = 0; i < 10; i++) {
+    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
+    CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
+    CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
+  }
+
+  // Use an API object with accessors as prototype.
+  Local<ObjectTemplate> templ = ObjectTemplate::New();
+  templ->SetAccessor(v8_str("x"),
+                     GetterWhichReturns42,
+                     SetterWhichSetsYOnThisTo23);
+  context->Global()->Set(v8_str("P"), templ->NewInstance());
+
+  // This compile will get the code from the compilation cache.
+  CompileRun(source);
+
+  script = v8::Script::Compile(v8_str("new C1();"));
+  for (int i = 0; i < 10; i++) {
+    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
+    CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
+    CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
+  }
+}
diff --git a/deps/v8/test/cctest/test-dataflow.cc b/deps/v8/test/cctest/test-dataflow.cc
new file mode 100644 (file)
index 0000000..003ac66
--- /dev/null
@@ -0,0 +1,103 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdlib.h>
+
+#include "v8.h"
+
+#include "data-flow.h"
+#include "cctest.h"
+
+using namespace v8::internal;
+
+TEST(BitVector) {
+  ZoneScope zone(DELETE_ON_EXIT);
+  {
+    BitVector v(15);
+    v.Add(1);
+    CHECK(v.Contains(1));
+    v.Remove(0);
+    CHECK(!v.Contains(0));
+    v.Add(0);
+    v.Add(1);
+    BitVector w(15);
+    w.Add(1);
+    v.Intersect(w);
+    CHECK(!v.Contains(0));
+    CHECK(v.Contains(1));
+  }
+
+  {
+    BitVector v(15);
+    v.Add(0);
+    BitVector w(15);
+    w.Add(1);
+    v.Union(w);
+    CHECK(v.Contains(0));
+    CHECK(v.Contains(1));
+  }
+
+  {
+    BitVector v(15);
+    v.Add(0);
+    BitVector w(15);
+    w = v;
+    CHECK(w.Contains(0));
+    w.Add(1);
+    BitVector u(w);
+    CHECK(u.Contains(0));
+    CHECK(u.Contains(1));
+    v.Union(w);
+    CHECK(v.Contains(0));
+    CHECK(v.Contains(1));
+  }
+
+  {
+    BitVector v(35);
+    v.Add(0);
+    BitVector w(35);
+    w.Add(33);
+    v.Union(w);
+    CHECK(v.Contains(0));
+    CHECK(v.Contains(33));
+  }
+
+  {
+    BitVector v(35);
+    v.Add(32);
+    v.Add(33);
+    BitVector w(35);
+    w.Add(33);
+    v.Intersect(w);
+    CHECK(!v.Contains(32));
+    CHECK(v.Contains(33));
+    BitVector r(35);
+    r.CopyFrom(v);
+    CHECK(!r.Contains(32));
+    CHECK(r.Contains(33));
+  }
+}
index b7c39b2..d0726b9 100644 (file)
@@ -5958,7 +5958,7 @@ TEST(ProcessDebugMessages) {
 }
 
 
-struct BracktraceData {
+struct BacktraceData {
   static int frame_counter;
   static void MessageHandler(const v8::Debug::Message& message) {
     char print_buffer[1000];
@@ -5972,7 +5972,7 @@ struct BracktraceData {
   }
 };
 
-int BracktraceData::frame_counter;
+int BacktraceData::frame_counter;
 
 
 // Test that debug messages get processed when ProcessDebugMessages is called.
@@ -5980,7 +5980,7 @@ TEST(Backtrace) {
   v8::HandleScope scope;
   DebugLocalContext env;
 
-  v8::Debug::SetMessageHandler2(BracktraceData::MessageHandler);
+  v8::Debug::SetMessageHandler2(BacktraceData::MessageHandler);
 
   const int kBufferSize = 1000;
   uint16_t buffer[kBufferSize];
@@ -5990,19 +5990,19 @@ TEST(Backtrace) {
      "\"command\":\"backtrace\"}";
 
   // Check backtrace from ProcessDebugMessages.
-  BracktraceData::frame_counter = -10;
+  BacktraceData::frame_counter = -10;
   v8::Debug::SendCommand(buffer, AsciiToUtf16(scripts_command, buffer));
   v8::Debug::ProcessDebugMessages();
-  CHECK_EQ(BracktraceData::frame_counter, 0);
+  CHECK_EQ(BacktraceData::frame_counter, 0);
 
   v8::Handle<v8::String> void0 = v8::String::New("void(0)");
   v8::Handle<v8::Script> script = v8::Script::Compile(void0, void0);
 
   // Check backtrace from "void(0)" script.
-  BracktraceData::frame_counter = -10;
+  BacktraceData::frame_counter = -10;
   v8::Debug::SendCommand(buffer, AsciiToUtf16(scripts_command, buffer));
   script->Run();
-  CHECK_EQ(BracktraceData::frame_counter, 1);
+  CHECK_EQ(BacktraceData::frame_counter, 1);
 
   // Get rid of the debug message handler.
   v8::Debug::SetMessageHandler2(NULL);
index 7b0ad99..5a64f0f 100644 (file)
@@ -234,7 +234,9 @@ TEST(DisasmIa320) {
   __ imul(edx, ecx, 12);
   __ imul(edx, ecx, 1000);
 
+  __ cld();
   __ rep_movs();
+  __ rep_stos();
 
   __ sub(edx, Operand(ebx, ecx, times_4, 10000));
   __ sub(edx, Operand(ebx));
index 295b0ee..2e56894 100644 (file)
@@ -8,6 +8,7 @@
 #include "heap-profiler.h"
 #include "string-stream.h"
 #include "cctest.h"
+#include "zone-inl.h"
 
 namespace i = v8::internal;
 using i::ClustersCoarser;
index d36286b..45c5160 100644 (file)
@@ -149,14 +149,9 @@ TEST(HeapObjects) {
   CHECK(Heap::nan_value()->IsNumber());
   CHECK(isnan(Heap::nan_value()->Number()));
 
-  Object* str = Heap::AllocateStringFromAscii(CStrVector("fisk hest "));
-  if (!str->IsFailure()) {
-    String* s =  String::cast(str);
-    CHECK(s->IsString());
-    CHECK_EQ(10, s->length());
-  } else {
-    CHECK(false);
-  }
+  Handle<String> s = Factory::NewStringFromAscii(CStrVector("fisk hest "));
+  CHECK(s->IsString());
+  CHECK_EQ(10, s->length());
 
   String* object_symbol = String::cast(Heap::Object_symbol());
   CHECK(Top::context()->global()->HasLocalProperty(object_symbol));
@@ -201,69 +196,68 @@ TEST(GarbageCollection) {
   InitializeVM();
 
   v8::HandleScope sc;
-  // check GC when heap is empty
+  // Check GC.
   int free_bytes = Heap::MaxObjectSizeInPagedSpace();
   CHECK(Heap::CollectGarbage(free_bytes, NEW_SPACE));
 
-  // allocate a function and keep it in global object's property
-  String* func_name  = String::cast(Heap::LookupAsciiSymbol("theFunction"));
-  SharedFunctionInfo* function_share =
-    SharedFunctionInfo::cast(Heap::AllocateSharedFunctionInfo(func_name));
-  JSFunction* function =
-      JSFunction::cast(Heap::AllocateFunction(*Top::function_map(),
-                                              function_share,
-                                              Heap::undefined_value()));
-  Map* initial_map =
-      Map::cast(Heap::AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize));
-  function->set_initial_map(initial_map);
-  Top::context()->global()->SetProperty(func_name, function, NONE);
-
-  // allocate an object, but it is unrooted
-  String* prop_name = String::cast(Heap::LookupAsciiSymbol("theSlot"));
-  String* prop_namex = String::cast(Heap::LookupAsciiSymbol("theSlotx"));
-  JSObject* obj = JSObject::cast(Heap::AllocateJSObject(function));
-  obj->SetProperty(prop_name, Smi::FromInt(23), NONE);
-  obj->SetProperty(prop_namex, Smi::FromInt(24), NONE);
-
-  CHECK_EQ(Smi::FromInt(23), obj->GetProperty(prop_name));
-  CHECK_EQ(Smi::FromInt(24), obj->GetProperty(prop_namex));
+  Handle<String> name = Factory::LookupAsciiSymbol("theFunction");
+  Handle<String> prop_name = Factory::LookupAsciiSymbol("theSlot");
+  Handle<String> prop_namex = Factory::LookupAsciiSymbol("theSlotx");
+  Handle<String> obj_name = Factory::LookupAsciiSymbol("theObject");
+
+  {
+    v8::HandleScope inner_scope;
+    // Allocate a function and keep it in global object's property.
+    Handle<JSFunction> function =
+        Factory::NewFunction(name, Factory::undefined_value());
+    Handle<Map> initial_map =
+        Factory::NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
+    function->set_initial_map(*initial_map);
+    Top::context()->global()->SetProperty(*name, *function, NONE);
+    // Allocate an object.  Unrooted after leaving the scope.
+    Handle<JSObject> obj = Factory::NewJSObject(function);
+    obj->SetProperty(*prop_name, Smi::FromInt(23), NONE);
+    obj->SetProperty(*prop_namex, Smi::FromInt(24), NONE);
+
+    CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
+    CHECK_EQ(Smi::FromInt(24), obj->GetProperty(*prop_namex));
+  }
 
   CHECK(Heap::CollectGarbage(free_bytes, NEW_SPACE));
 
-  // function should be alive, func_name might be invalid after GC
-  func_name  = String::cast(Heap::LookupAsciiSymbol("theFunction"));
-  CHECK(Top::context()->global()->HasLocalProperty(func_name));
-  // check function is retained
-  Object* func_value = Top::context()->global()->GetProperty(func_name);
+  // Function should be alive.
+  CHECK(Top::context()->global()->HasLocalProperty(*name));
+  // Check function is retained.
+  Object* func_value = Top::context()->global()->GetProperty(*name);
   CHECK(func_value->IsJSFunction());
-  // old function pointer may not be valid
-  function = JSFunction::cast(func_value);
-
-  // allocate another object, make it reachable from global
-  obj = JSObject::cast(Heap::AllocateJSObject(function));
-  String* obj_name = String::cast(Heap::LookupAsciiSymbol("theObject"));
-  Top::context()->global()->SetProperty(obj_name, obj, NONE);
-  // set property
-  prop_name = String::cast(Heap::LookupAsciiSymbol("theSlot"));
-  obj->SetProperty(prop_name, Smi::FromInt(23), NONE);
+  Handle<JSFunction> function(JSFunction::cast(func_value));
+
+  {
+    HandleScope inner_scope;
+    // Allocate another object, make it reachable from global.
+    Handle<JSObject> obj = Factory::NewJSObject(function);
+    Top::context()->global()->SetProperty(*obj_name, *obj, NONE);
+    obj->SetProperty(*prop_name, Smi::FromInt(23), NONE);
+  }
 
-  // after gc, it should survive
+  // After gc, it should survive.
   CHECK(Heap::CollectGarbage(free_bytes, NEW_SPACE));
 
-  obj_name = String::cast(Heap::LookupAsciiSymbol("theObject"));
-  CHECK(Top::context()->global()->HasLocalProperty(obj_name));
-  CHECK(Top::context()->global()->GetProperty(obj_name)->IsJSObject());
-  obj = JSObject::cast(Top::context()->global()->GetProperty(obj_name));
-  prop_name = String::cast(Heap::LookupAsciiSymbol("theSlot"));
-  CHECK_EQ(Smi::FromInt(23), obj->GetProperty(prop_name));
+  CHECK(Top::context()->global()->HasLocalProperty(*obj_name));
+  CHECK(Top::context()->global()->GetProperty(*obj_name)->IsJSObject());
+  JSObject* obj =
+      JSObject::cast(Top::context()->global()->GetProperty(*obj_name));
+  CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
 }
 
 
 static void VerifyStringAllocation(const char* string) {
-  String* s = String::cast(Heap::AllocateStringFromUtf8(CStrVector(string)));
+  v8::HandleScope scope;
+  Handle<String> s = Factory::NewStringFromUtf8(CStrVector(string));
   CHECK_EQ(StrLength(string), s->length());
   for (int index = 0; index < s->length(); index++) {
-    CHECK_EQ(static_cast<uint16_t>(string[index]), s->Get(index));  }
+    CHECK_EQ(static_cast<uint16_t>(string[index]), s->Get(index));
+  }
 }
 
 
@@ -291,13 +285,22 @@ TEST(LocalHandles) {
 TEST(GlobalHandles) {
   InitializeVM();
 
-  Object* i = Heap::AllocateStringFromAscii(CStrVector("fisk"));
-  Object* u = Heap::AllocateHeapNumber(1.12344);
+  Handle<Object> h1;
+  Handle<Object> h2;
+  Handle<Object> h3;
+  Handle<Object> h4;
+
+  {
+    HandleScope scope;
 
-  Handle<Object> h1 = GlobalHandles::Create(i);
-  Handle<Object> h2 = GlobalHandles::Create(u);
-  Handle<Object> h3 = GlobalHandles::Create(i);
-  Handle<Object> h4 = GlobalHandles::Create(u);
+    Handle<Object> i = Factory::NewStringFromAscii(CStrVector("fisk"));
+    Handle<Object> u = Factory::NewNumber(1.12344);
+
+    h1 = GlobalHandles::Create(*i);
+    h2 = GlobalHandles::Create(*u);
+    h3 = GlobalHandles::Create(*i);
+    h4 = GlobalHandles::Create(*u);
+  }
 
   // after gc, it should survive
   CHECK(Heap::CollectGarbage(0, NEW_SPACE));
@@ -331,11 +334,18 @@ TEST(WeakGlobalHandlesScavenge) {
 
   WeakPointerCleared = false;
 
-  Object* i = Heap::AllocateStringFromAscii(CStrVector("fisk"));
-  Object* u = Heap::AllocateHeapNumber(1.12344);
+  Handle<Object> h1;
+  Handle<Object> h2;
+
+  {
+    HandleScope scope;
 
-  Handle<Object> h1 = GlobalHandles::Create(i);
-  Handle<Object> h2 = GlobalHandles::Create(u);
+    Handle<Object> i = Factory::NewStringFromAscii(CStrVector("fisk"));
+    Handle<Object> u = Factory::NewNumber(1.12344);
+
+    h1 = GlobalHandles::Create(*i);
+    h2 = GlobalHandles::Create(*u);
+  }
 
   GlobalHandles::MakeWeak(h2.location(),
                           reinterpret_cast<void*>(1234),
@@ -361,11 +371,18 @@ TEST(WeakGlobalHandlesMark) {
 
   WeakPointerCleared = false;
 
-  Object* i = Heap::AllocateStringFromAscii(CStrVector("fisk"));
-  Object* u = Heap::AllocateHeapNumber(1.12344);
+  Handle<Object> h1;
+  Handle<Object> h2;
+
+  {
+    HandleScope scope;
 
-  Handle<Object> h1 = GlobalHandles::Create(i);
-  Handle<Object> h2 = GlobalHandles::Create(u);
+    Handle<Object> i = Factory::NewStringFromAscii(CStrVector("fisk"));
+    Handle<Object> u = Factory::NewNumber(1.12344);
+
+    h1 = GlobalHandles::Create(*i);
+    h2 = GlobalHandles::Create(*u);
+  }
 
   CHECK(Heap::CollectGarbage(0, OLD_POINTER_SPACE));
   CHECK(Heap::CollectGarbage(0, NEW_SPACE));
@@ -401,8 +418,14 @@ TEST(DeleteWeakGlobalHandle) {
 
   WeakPointerCleared = false;
 
-  Object* i = Heap::AllocateStringFromAscii(CStrVector("fisk"));
-  Handle<Object> h = GlobalHandles::Create(i);
+  Handle<Object> h;
+
+  {
+    HandleScope scope;
+
+    Handle<Object> i = Factory::NewStringFromAscii(CStrVector("fisk"));
+    h = GlobalHandles::Create(*i);
+  }
 
   GlobalHandles::MakeWeak(h.location(),
                           reinterpret_cast<void*>(1234),
@@ -509,24 +532,20 @@ TEST(FunctionAllocation) {
   InitializeVM();
 
   v8::HandleScope sc;
-  String* name  = String::cast(Heap::LookupAsciiSymbol("theFunction"));
-  SharedFunctionInfo* function_share =
-    SharedFunctionInfo::cast(Heap::AllocateSharedFunctionInfo(name));
-  JSFunction* function =
-    JSFunction::cast(Heap::AllocateFunction(*Top::function_map(),
-                                            function_share,
-                                            Heap::undefined_value()));
-  Map* initial_map =
-      Map::cast(Heap::AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize));
-  function->set_initial_map(initial_map);
-
-  String* prop_name = String::cast(Heap::LookupAsciiSymbol("theSlot"));
-  JSObject* obj = JSObject::cast(Heap::AllocateJSObject(function));
-  obj->SetProperty(prop_name, Smi::FromInt(23), NONE);
-  CHECK_EQ(Smi::FromInt(23), obj->GetProperty(prop_name));
+  Handle<String> name = Factory::LookupAsciiSymbol("theFunction");
+  Handle<JSFunction> function =
+      Factory::NewFunction(name, Factory::undefined_value());
+  Handle<Map> initial_map =
+      Factory::NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
+  function->set_initial_map(*initial_map);
+
+  Handle<String> prop_name = Factory::LookupAsciiSymbol("theSlot");
+  Handle<JSObject> obj = Factory::NewJSObject(function);
+  obj->SetProperty(*prop_name, Smi::FromInt(23), NONE);
+  CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
   // Check that we can add properties to function objects.
-  function->SetProperty(prop_name, Smi::FromInt(24), NONE);
-  CHECK_EQ(Smi::FromInt(24), function->GetProperty(prop_name));
+  function->SetProperty(*prop_name, Smi::FromInt(24), NONE);
+  CHECK_EQ(Smi::FromInt(24), function->GetProperty(*prop_name));
 }
 
 
@@ -534,64 +553,64 @@ TEST(ObjectProperties) {
   InitializeVM();
 
   v8::HandleScope sc;
-  JSFunction* constructor =
-      JSFunction::cast(
-          Top::context()->global()->GetProperty(String::cast(
-                                                    Heap::Object_symbol())));
-  JSObject* obj = JSObject::cast(Heap::AllocateJSObject(constructor));
-  String* first = String::cast(Heap::LookupAsciiSymbol("first"));
-  String* second = String::cast(Heap::LookupAsciiSymbol("second"));
+  String* object_symbol = String::cast(Heap::Object_symbol());
+  JSFunction* object_function =
+      JSFunction::cast(Top::context()->global()->GetProperty(object_symbol));
+  Handle<JSFunction> constructor(object_function);
+  Handle<JSObject> obj = Factory::NewJSObject(constructor);
+  Handle<String> first = Factory::LookupAsciiSymbol("first");
+  Handle<String> second = Factory::LookupAsciiSymbol("second");
 
   // check for empty
-  CHECK(!obj->HasLocalProperty(first));
+  CHECK(!obj->HasLocalProperty(*first));
 
   // add first
-  obj->SetProperty(first, Smi::FromInt(1), NONE);
-  CHECK(obj->HasLocalProperty(first));
+  obj->SetProperty(*first, Smi::FromInt(1), NONE);
+  CHECK(obj->HasLocalProperty(*first));
 
   // delete first
-  CHECK(obj->DeleteProperty(first, JSObject::NORMAL_DELETION));
-  CHECK(!obj->HasLocalProperty(first));
+  CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
+  CHECK(!obj->HasLocalProperty(*first));
 
   // add first and then second
-  obj->SetProperty(first, Smi::FromInt(1), NONE);
-  obj->SetProperty(second, Smi::FromInt(2), NONE);
-  CHECK(obj->HasLocalProperty(first));
-  CHECK(obj->HasLocalProperty(second));
+  obj->SetProperty(*first, Smi::FromInt(1), NONE);
+  obj->SetProperty(*second, Smi::FromInt(2), NONE);
+  CHECK(obj->HasLocalProperty(*first));
+  CHECK(obj->HasLocalProperty(*second));
 
   // delete first and then second
-  CHECK(obj->DeleteProperty(first, JSObject::NORMAL_DELETION));
-  CHECK(obj->HasLocalProperty(second));
-  CHECK(obj->DeleteProperty(second, JSObject::NORMAL_DELETION));
-  CHECK(!obj->HasLocalProperty(first));
-  CHECK(!obj->HasLocalProperty(second));
+  CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
+  CHECK(obj->HasLocalProperty(*second));
+  CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION));
+  CHECK(!obj->HasLocalProperty(*first));
+  CHECK(!obj->HasLocalProperty(*second));
 
   // add first and then second
-  obj->SetProperty(first, Smi::FromInt(1), NONE);
-  obj->SetProperty(second, Smi::FromInt(2), NONE);
-  CHECK(obj->HasLocalProperty(first));
-  CHECK(obj->HasLocalProperty(second));
+  obj->SetProperty(*first, Smi::FromInt(1), NONE);
+  obj->SetProperty(*second, Smi::FromInt(2), NONE);
+  CHECK(obj->HasLocalProperty(*first));
+  CHECK(obj->HasLocalProperty(*second));
 
   // delete second and then first
-  CHECK(obj->DeleteProperty(second, JSObject::NORMAL_DELETION));
-  CHECK(obj->HasLocalProperty(first));
-  CHECK(obj->DeleteProperty(first, JSObject::NORMAL_DELETION));
-  CHECK(!obj->HasLocalProperty(first));
-  CHECK(!obj->HasLocalProperty(second));
+  CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION));
+  CHECK(obj->HasLocalProperty(*first));
+  CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
+  CHECK(!obj->HasLocalProperty(*first));
+  CHECK(!obj->HasLocalProperty(*second));
 
   // check string and symbol match
   static const char* string1 = "fisk";
-  String* s1 =
-      String::cast(Heap::AllocateStringFromAscii(CStrVector(string1)));
-  obj->SetProperty(s1, Smi::FromInt(1), NONE);
-  CHECK(obj->HasLocalProperty(String::cast(Heap::LookupAsciiSymbol(string1))));
+  Handle<String> s1 = Factory::NewStringFromAscii(CStrVector(string1));
+  obj->SetProperty(*s1, Smi::FromInt(1), NONE);
+  Handle<String> s1_symbol = Factory::LookupAsciiSymbol(string1);
+  CHECK(obj->HasLocalProperty(*s1_symbol));
 
   // check symbol and string match
   static const char* string2 = "fugl";
-  String* s2 = String::cast(Heap::LookupAsciiSymbol(string2));
-  obj->SetProperty(s2, Smi::FromInt(1), NONE);
-  CHECK(obj->HasLocalProperty(
-            String::cast(Heap::AllocateStringFromAscii(CStrVector(string2)))));
+  Handle<String> s2_symbol = Factory::LookupAsciiSymbol(string2);
+  obj->SetProperty(*s2_symbol, Smi::FromInt(1), NONE);
+  Handle<String> s2 = Factory::NewStringFromAscii(CStrVector(string2));
+  CHECK(obj->HasLocalProperty(*s2));
 }
 
 
@@ -599,25 +618,22 @@ TEST(JSObjectMaps) {
   InitializeVM();
 
   v8::HandleScope sc;
-  String* name  = String::cast(Heap::LookupAsciiSymbol("theFunction"));
-  SharedFunctionInfo* function_share =
-    SharedFunctionInfo::cast(Heap::AllocateSharedFunctionInfo(name));
-  JSFunction* function =
-    JSFunction::cast(Heap::AllocateFunction(*Top::function_map(),
-                                            function_share,
-                                            Heap::undefined_value()));
-  Map* initial_map =
-      Map::cast(Heap::AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize));
-  function->set_initial_map(initial_map);
-  String* prop_name = String::cast(Heap::LookupAsciiSymbol("theSlot"));
-  JSObject* obj = JSObject::cast(Heap::AllocateJSObject(function));
+  Handle<String> name = Factory::LookupAsciiSymbol("theFunction");
+  Handle<JSFunction> function =
+      Factory::NewFunction(name, Factory::undefined_value());
+  Handle<Map> initial_map =
+      Factory::NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
+  function->set_initial_map(*initial_map);
+
+  Handle<String> prop_name = Factory::LookupAsciiSymbol("theSlot");
+  Handle<JSObject> obj = Factory::NewJSObject(function);
 
   // Set a propery
-  obj->SetProperty(prop_name, Smi::FromInt(23), NONE);
-  CHECK_EQ(Smi::FromInt(23), obj->GetProperty(prop_name));
+  obj->SetProperty(*prop_name, Smi::FromInt(23), NONE);
+  CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
 
   // Check the map has changed
-  CHECK(initial_map != obj->map());
+  CHECK(*initial_map != obj->map());
 }
 
 
@@ -625,12 +641,13 @@ TEST(JSArray) {
   InitializeVM();
 
   v8::HandleScope sc;
-  String* name = String::cast(Heap::LookupAsciiSymbol("Array"));
-  JSFunction* function =
-      JSFunction::cast(Top::context()->global()->GetProperty(name));
+  Handle<String> name = Factory::LookupAsciiSymbol("Array");
+  Handle<JSFunction> function = Handle<JSFunction>(
+      JSFunction::cast(Top::context()->global()->GetProperty(*name)));
 
   // Allocate the object.
-  JSArray* array = JSArray::cast(Heap::AllocateJSObject(function));
+  Handle<JSObject> object = Factory::NewJSObject(function);
+  Handle<JSArray> array = Handle<JSArray>::cast(object);
   array->Initialize(0);
 
   // Set array length to 0.
@@ -639,27 +656,27 @@ TEST(JSArray) {
   CHECK(array->HasFastElements());  // Must be in fast mode.
 
   // array[length] = name.
-  array->SetElement(0, name);
+  array->SetElement(0, *name);
   CHECK_EQ(Smi::FromInt(1), array->length());
-  CHECK_EQ(array->GetElement(0), name);
+  CHECK_EQ(array->GetElement(0), *name);
 
-// Set array length with larger than smi value.
-  Object* length =
-      Heap::NumberFromUint32(static_cast<uint32_t>(Smi::kMaxValue) + 1);
-  array->SetElementsLength(length);
+  // Set array length with larger than smi value.
+  Handle<Object> length =
+      Factory::NewNumberFromUint(static_cast<uint32_t>(Smi::kMaxValue) + 1);
+  array->SetElementsLength(*length);
 
   uint32_t int_length = 0;
-  CHECK(Array::IndexFromObject(length, &int_length));
-  CHECK_EQ(length, array->length());
+  CHECK(Array::IndexFromObject(*length, &int_length));
+  CHECK_EQ(*length, array->length());
   CHECK(array->HasDictionaryElements());  // Must be in slow mode.
 
   // array[length] = name.
-  array->SetElement(int_length, name);
+  array->SetElement(int_length, *name);
   uint32_t new_int_length = 0;
   CHECK(Array::IndexFromObject(array->length(), &new_int_length));
   CHECK_EQ(static_cast<double>(int_length), new_int_length - 1);
-  CHECK_EQ(array->GetElement(int_length), name);
-  CHECK_EQ(array->GetElement(0), name);
+  CHECK_EQ(array->GetElement(int_length), *name);
+  CHECK_EQ(array->GetElement(0), *name);
 }
 
 
@@ -667,41 +684,42 @@ TEST(JSObjectCopy) {
   InitializeVM();
 
   v8::HandleScope sc;
-  String* name = String::cast(Heap::Object_symbol());
-  JSFunction* constructor =
-      JSFunction::cast(Top::context()->global()->GetProperty(name));
-  JSObject* obj = JSObject::cast(Heap::AllocateJSObject(constructor));
-  String* first = String::cast(Heap::LookupAsciiSymbol("first"));
-  String* second = String::cast(Heap::LookupAsciiSymbol("second"));
+  String* object_symbol = String::cast(Heap::Object_symbol());
+  JSFunction* object_function =
+      JSFunction::cast(Top::context()->global()->GetProperty(object_symbol));
+  Handle<JSFunction> constructor(object_function);
+  Handle<JSObject> obj = Factory::NewJSObject(constructor);
+  Handle<String> first = Factory::LookupAsciiSymbol("first");
+  Handle<String> second = Factory::LookupAsciiSymbol("second");
 
-  obj->SetProperty(first, Smi::FromInt(1), NONE);
-  obj->SetProperty(second, Smi::FromInt(2), NONE);
+  obj->SetProperty(*first, Smi::FromInt(1), NONE);
+  obj->SetProperty(*second, Smi::FromInt(2), NONE);
 
-  obj->SetElement(0, first);
-  obj->SetElement(1, second);
+  obj->SetElement(0, *first);
+  obj->SetElement(1, *second);
 
   // Make the clone.
-  JSObject* clone = JSObject::cast(Heap::CopyJSObject(obj));
-  CHECK(clone != obj);
+  Handle<JSObject> clone = Copy(obj);
+  CHECK(!clone.is_identical_to(obj));
 
   CHECK_EQ(obj->GetElement(0), clone->GetElement(0));
   CHECK_EQ(obj->GetElement(1), clone->GetElement(1));
 
-  CHECK_EQ(obj->GetProperty(first), clone->GetProperty(first));
-  CHECK_EQ(obj->GetProperty(second), clone->GetProperty(second));
+  CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*first));
+  CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*second));
 
   // Flip the values.
-  clone->SetProperty(first, Smi::FromInt(2), NONE);
-  clone->SetProperty(second, Smi::FromInt(1), NONE);
+  clone->SetProperty(*first, Smi::FromInt(2), NONE);
+  clone->SetProperty(*second, Smi::FromInt(1), NONE);
 
-  clone->SetElement(0, second);
-  clone->SetElement(1, first);
+  clone->SetElement(0, *second);
+  clone->SetElement(1, *first);
 
   CHECK_EQ(obj->GetElement(1), clone->GetElement(0));
   CHECK_EQ(obj->GetElement(0), clone->GetElement(1));
 
-  CHECK_EQ(obj->GetProperty(second), clone->GetProperty(first));
-  CHECK_EQ(obj->GetProperty(first), clone->GetProperty(second));
+  CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*first));
+  CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*second));
 }
 
 
index 9853af3..4c5101c 100644 (file)
@@ -174,12 +174,11 @@ namespace {
 
 class ScopedLoggerInitializer {
  public:
-  explicit ScopedLoggerInitializer(bool log, bool prof_lazy)
-      : saved_log_(i::FLAG_log),
-        saved_prof_lazy_(i::FLAG_prof_lazy),
+  explicit ScopedLoggerInitializer(bool prof_lazy)
+      : saved_prof_lazy_(i::FLAG_prof_lazy),
         saved_prof_(i::FLAG_prof),
         saved_prof_auto_(i::FLAG_prof_auto),
-        trick_to_run_init_flags_(init_flags_(log, prof_lazy)),
+        trick_to_run_init_flags_(init_flags_(prof_lazy)),
         need_to_set_up_logger_(i::V8::IsRunning()),
         scope_(),
         env_(v8::Context::New()) {
@@ -193,14 +192,12 @@ class ScopedLoggerInitializer {
     i::FLAG_prof_lazy = saved_prof_lazy_;
     i::FLAG_prof = saved_prof_;
     i::FLAG_prof_auto = saved_prof_auto_;
-    i::FLAG_log = saved_log_;
   }
 
   v8::Handle<v8::Context>& env() { return env_; }
 
  private:
-  static bool init_flags_(bool log, bool prof_lazy) {
-    i::FLAG_log = log;
+  static bool init_flags_(bool prof_lazy) {
     i::FLAG_prof = true;
     i::FLAG_prof_lazy = prof_lazy;
     i::FLAG_prof_auto = false;
@@ -208,7 +205,6 @@ class ScopedLoggerInitializer {
     return prof_lazy;
   }
 
-  const bool saved_log_;
   const bool saved_prof_lazy_;
   const bool saved_prof_;
   const bool saved_prof_auto_;
@@ -320,7 +316,7 @@ static void CheckThatProfilerWorks(LogBufferMatcher* matcher) {
 
 
 TEST(ProfLazyMode) {
-  ScopedLoggerInitializer initialize_logger(false, true);
+  ScopedLoggerInitializer initialize_logger(true);
 
   // No sampling should happen prior to resuming profiler.
   CHECK(!LoggerTestHelper::IsSamplerActive());
@@ -394,19 +390,19 @@ class LoopingThread : public v8::internal::Thread {
 class LoopingJsThread : public LoopingThread {
  public:
   void RunLoop() {
-    {
-      v8::Locker locker;
-      CHECK(v8::internal::ThreadManager::HasId());
-      SetV8ThreadId();
-    }
+    v8::Locker locker;
+    CHECK(v8::internal::ThreadManager::HasId());
+    SetV8ThreadId();
     while (IsRunning()) {
-      v8::Locker locker;
       v8::HandleScope scope;
       v8::Persistent<v8::Context> context = v8::Context::New();
-      v8::Context::Scope context_scope(context);
-      SignalRunning();
-      CompileAndRunScript(
-          "var j; for (var i=0; i<10000; ++i) { j = Math.sin(i); }");
+      CHECK(!context.IsEmpty());
+      {
+        v8::Context::Scope context_scope(context);
+        SignalRunning();
+        CompileAndRunScript(
+            "var j; for (var i=0; i<10000; ++i) { j = Math.sin(i); }");
+      }
       context.Dispose();
       i::OS::Sleep(1);
     }
@@ -540,7 +536,7 @@ static v8::Handle<v8::Value> ObjMethod1(const v8::Arguments& args) {
 }
 
 TEST(LogCallbacks) {
-  ScopedLoggerInitializer initialize_logger(false, false);
+  ScopedLoggerInitializer initialize_logger(false);
   LogBufferMatcher matcher;
 
   v8::Persistent<v8::FunctionTemplate> obj =
@@ -590,7 +586,7 @@ static v8::Handle<v8::Value> Prop2Getter(v8::Local<v8::String> property,
 }
 
 TEST(LogAccessorCallbacks) {
-  ScopedLoggerInitializer initialize_logger(false, false);
+  ScopedLoggerInitializer initialize_logger(false);
   LogBufferMatcher matcher;
 
   v8::Persistent<v8::FunctionTemplate> obj =
@@ -625,7 +621,7 @@ TEST(LogAccessorCallbacks) {
 
 
 TEST(LogTags) {
-  ScopedLoggerInitializer initialize_logger(true, false);
+  ScopedLoggerInitializer initialize_logger(false);
   LogBufferMatcher matcher;
 
   const char* open_tag = "open-tag,";
@@ -710,6 +706,35 @@ TEST(LogTags) {
 }
 
 
+TEST(IsLoggingPreserved) {
+  ScopedLoggerInitializer initialize_logger(false);
+
+  CHECK(Logger::is_logging());
+  Logger::ResumeProfiler(v8::PROFILER_MODULE_CPU, 1);
+  CHECK(Logger::is_logging());
+  Logger::PauseProfiler(v8::PROFILER_MODULE_CPU, 1);
+  CHECK(Logger::is_logging());
+
+  CHECK(Logger::is_logging());
+  Logger::ResumeProfiler(
+      v8::PROFILER_MODULE_HEAP_STATS | v8::PROFILER_MODULE_JS_CONSTRUCTORS, 1);
+  CHECK(Logger::is_logging());
+  Logger::PauseProfiler(
+      v8::PROFILER_MODULE_HEAP_STATS | v8::PROFILER_MODULE_JS_CONSTRUCTORS, 1);
+  CHECK(Logger::is_logging());
+
+  CHECK(Logger::is_logging());
+  Logger::ResumeProfiler(
+      v8::PROFILER_MODULE_CPU |
+      v8::PROFILER_MODULE_HEAP_STATS | v8::PROFILER_MODULE_JS_CONSTRUCTORS, 1);
+  CHECK(Logger::is_logging());
+  Logger::PauseProfiler(
+      v8::PROFILER_MODULE_CPU |
+      v8::PROFILER_MODULE_HEAP_STATS | v8::PROFILER_MODULE_JS_CONSTRUCTORS, 1);
+  CHECK(Logger::is_logging());
+}
+
+
 static inline bool IsStringEqualTo(const char* r, const char* s) {
   return strncmp(r, s, strlen(r)) == 0;
 }
index c34840a..1283dfd 100644 (file)
@@ -131,7 +131,7 @@ TEST(ExternalReferenceEncoder) {
       ExternalReference::address_of_real_stack_limit();
   CHECK_EQ(make_code(UNCLASSIFIED, 5),
            encoder.Encode(real_stack_limit_address.address()));
-  CHECK_EQ(make_code(UNCLASSIFIED, 11),
+  CHECK_EQ(make_code(UNCLASSIFIED, 12),
            encoder.Encode(ExternalReference::debug_break().address()));
   CHECK_EQ(make_code(UNCLASSIFIED, 7),
            encoder.Encode(ExternalReference::new_space_start().address()));
@@ -165,7 +165,7 @@ TEST(ExternalReferenceDecoder) {
   CHECK_EQ(ExternalReference::address_of_real_stack_limit().address(),
            decoder.Decode(make_code(UNCLASSIFIED, 5)));
   CHECK_EQ(ExternalReference::debug_break().address(),
-           decoder.Decode(make_code(UNCLASSIFIED, 11)));
+           decoder.Decode(make_code(UNCLASSIFIED, 12)));
   CHECK_EQ(ExternalReference::new_space_start().address(),
            decoder.Decode(make_code(UNCLASSIFIED, 7)));
 }
@@ -302,6 +302,10 @@ DEPENDENT_TEST(Deserialize, Serialize) {
 
 
 DEPENDENT_TEST(DeserializeFromSecondSerialization, SerializeTwice) {
+  // BUG(632): Disable this test until the partial_snapshots branch is
+  // merged back.
+  return;
+
   v8::HandleScope scope;
 
   Deserialize();
@@ -330,6 +334,10 @@ DEPENDENT_TEST(DeserializeAndRunScript2, Serialize) {
 
 DEPENDENT_TEST(DeserializeFromSecondSerializationAndRunScript2,
                SerializeTwice) {
+  // BUG(632): Disable this test until the partial_snapshots branch is
+  // merged back.
+  return;
+
   v8::HandleScope scope;
 
   Deserialize();
@@ -481,8 +489,8 @@ TEST(LinearAllocation) {
          i += kSmallFixedArraySize) {
       Object* obj = Heap::AllocateFixedArray(kSmallFixedArrayLength);
       if (new_last != NULL) {
-        CHECK_EQ(reinterpret_cast<char*>(obj),
-                 reinterpret_cast<char*>(new_last) + kSmallFixedArraySize);
+        CHECK(reinterpret_cast<char*>(obj) ==
+              reinterpret_cast<char*>(new_last) + kSmallFixedArraySize);
       }
       new_last = obj;
     }
@@ -500,8 +508,8 @@ TEST(LinearAllocation) {
         pointer_last = NULL;
       }
       if (pointer_last != NULL) {
-        CHECK_EQ(reinterpret_cast<char*>(obj),
-                 reinterpret_cast<char*>(pointer_last) + kSmallFixedArraySize);
+        CHECK(reinterpret_cast<char*>(obj) ==
+              reinterpret_cast<char*>(pointer_last) + kSmallFixedArraySize);
       }
       pointer_last = obj;
     }
@@ -517,8 +525,8 @@ TEST(LinearAllocation) {
         data_last = NULL;
       }
       if (data_last != NULL) {
-        CHECK_EQ(reinterpret_cast<char*>(obj),
-                 reinterpret_cast<char*>(data_last) + kSmallStringSize);
+        CHECK(reinterpret_cast<char*>(obj) ==
+              reinterpret_cast<char*>(data_last) + kSmallStringSize);
       }
       data_last = obj;
     }
@@ -534,8 +542,8 @@ TEST(LinearAllocation) {
         map_last = NULL;
       }
       if (map_last != NULL) {
-        CHECK_EQ(reinterpret_cast<char*>(obj),
-                 reinterpret_cast<char*>(map_last) + kMapSize);
+        CHECK(reinterpret_cast<char*>(obj) ==
+              reinterpret_cast<char*>(map_last) + kMapSize);
       }
       map_last = obj;
     }
diff --git a/deps/v8/test/mjsunit/array-elements-from-array-prototype-chain.js b/deps/v8/test/mjsunit/array-elements-from-array-prototype-chain.js
new file mode 100644 (file)
index 0000000..edbeb2a
--- /dev/null
@@ -0,0 +1,191 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+////////////////////////////////////////////////////////////////////////
+// Tests below verify that elements set on Array.prototype's proto propagate
+// for various Array.prototype functions (like unshift, shift, etc.)
+// If add any new tests here, consider adding them to all other files:
+//   array-elements-from-array-prototype.js
+//   array-elements-from-array-prototype-chain.js
+//   array-elements-from-object-prototype.js
+// those ideally should be identical modulo host of elements and
+// the way elements introduced.
+//
+// Note: they are put into a separate file as we need maximally clean
+// VM setup---some optimizations might be already turned off in
+// 'dirty' VM.
+////////////////////////////////////////////////////////////////////////
+
+var at3 = '@3'
+var at7 = '@7'
+
+Array.prototype.__proto__ = {3: at3};
+Array.prototype.__proto__.__proto__ = {7: at7};
+
+var a = new Array(13)
+
+assertEquals(at3, a[3])
+assertFalse(a.hasOwnProperty(3))
+
+assertEquals(at7, a[7])
+assertFalse(a.hasOwnProperty(7))
+
+assertEquals(undefined, a.shift(), 'hole should be returned as undefined')
+// Side-effects: Array.prototype[3] percolates into a[2] and Array.prototype[7[
+// into a[6], still visible at the corresponding indices.
+
+assertEquals(at3, a[2])
+assertTrue(a.hasOwnProperty(2))
+assertEquals(at3, a[3])
+assertFalse(a.hasOwnProperty(3))
+
+assertEquals(at7, a[6])
+assertTrue(a.hasOwnProperty(6))
+assertEquals(at7, a[7])
+assertFalse(a.hasOwnProperty(7))
+
+a.unshift('foo', 'bar')
+// Side-effects: Array.prototype[3] now percolates into a[5] and Array.prototype[7]
+// into a[9].
+
+assertEquals(at3, a[3])
+assertFalse(a.hasOwnProperty(3))
+assertEquals(at3, a[4])
+assertTrue(a.hasOwnProperty(4))
+assertEquals(at3, a[5])
+assertTrue(a.hasOwnProperty(5))
+
+assertEquals(undefined, a[6])
+assertFalse(a.hasOwnProperty(6))
+
+assertEquals(at7, a[7])
+assertFalse(a.hasOwnProperty(7))
+assertEquals(at7, a[8])
+assertTrue(a.hasOwnProperty(8))
+assertEquals(at7, a[9])
+assertTrue(a.hasOwnProperty(9))
+
+var sliced = a.slice(3, 10)
+// Slice must keep intact a and reify holes at indices 0--2 and 4--6.
+
+assertEquals(at3, a[3])
+assertFalse(a.hasOwnProperty(3))
+assertEquals(at3, a[4])
+assertTrue(a.hasOwnProperty(4))
+assertEquals(at3, a[5])
+assertTrue(a.hasOwnProperty(5))
+
+assertEquals(undefined, a[6])
+assertFalse(a.hasOwnProperty(6))
+
+assertEquals(at7, a[7])
+assertFalse(a.hasOwnProperty(7))
+assertEquals(at7, a[8])
+assertTrue(a.hasOwnProperty(8))
+assertEquals(at7, a[9])
+assertTrue(a.hasOwnProperty(9))
+
+assertEquals(at3, sliced[0])
+assertTrue(sliced.hasOwnProperty(0))
+assertEquals(at3, sliced[1])
+assertTrue(sliced.hasOwnProperty(1))
+assertEquals(at3, sliced[2])
+assertTrue(sliced.hasOwnProperty(2))
+
+// Note: sliced[3] comes directly from Array.prototype[3]
+assertEquals(at3, sliced[3]);
+assertFalse(sliced.hasOwnProperty(3))
+
+assertEquals(at7, sliced[4])
+assertTrue(sliced.hasOwnProperty(4))
+assertEquals(at7, sliced[5])
+assertTrue(sliced.hasOwnProperty(5))
+assertEquals(at7, sliced[6])
+assertTrue(sliced.hasOwnProperty(6))
+
+
+// Splice is too complicated the operation, start afresh.
+
+// Shrking array.
+var a0 = [0, 1, , , 4, 5, , , , 9]
+var result = a0.splice(4, 1)
+// Side-effects: everything before 4 is kept intact:
+
+assertEquals(0, a0[0])
+assertTrue(a0.hasOwnProperty(0))
+assertEquals(1, a0[1])
+assertTrue(a0.hasOwnProperty(1))
+assertEquals(undefined, a0[2])
+assertFalse(a0.hasOwnProperty(2))
+assertEquals(at3, a0[3])
+assertFalse(a0.hasOwnProperty(3))
+
+// 4 and above shifted left by one reifying at7 into a0[6] and keeping
+// a hole at a0[7]
+
+assertEquals(5, a0[4])
+assertTrue(a0.hasOwnProperty(4))
+assertEquals(undefined, a0[5])
+assertFalse(a0.hasOwnProperty(5))
+assertEquals(at7, a0[6])
+assertTrue(a0.hasOwnProperty(6))
+assertEquals(at7, a0[7])
+assertFalse(a0.hasOwnProperty(7))
+assertEquals(9, a0[8])
+assertTrue(a0.hasOwnProperty(8))
+
+// Growing array.
+var a1 = [0, 1, , , 4, 5, , , , 9]
+var result = a1.splice(4, 0, undefined)
+// Side-effects: everything before 4 is kept intact:
+
+assertEquals(0, a1[0])
+assertTrue(a1.hasOwnProperty(0))
+assertEquals(1, a1[1])
+assertTrue(a1.hasOwnProperty(1))
+assertEquals(undefined, a1[2])
+assertFalse(a1.hasOwnProperty(2))
+assertEquals(at3, a1[3])
+assertFalse(a1.hasOwnProperty(3))
+
+// Now owned undefined resides at 4 and rest is shifted right by one
+// reifying at7 into a0[8] and keeping a hole at a0[7].
+
+assertEquals(undefined, a1[4])
+assertTrue(a1.hasOwnProperty(4))
+assertEquals(4, a1[5])
+assertTrue(a1.hasOwnProperty(5))
+assertEquals(5, a1[6])
+assertTrue(a1.hasOwnProperty(6))
+assertEquals(at7, a1[7])
+assertFalse(a1.hasOwnProperty(7))
+assertEquals(at7, a1[8])
+assertTrue(a1.hasOwnProperty(8))
+assertEquals(undefined, a1[9])
+assertFalse(a1.hasOwnProperty(9))
+assertEquals(9, a1[10])
+assertTrue(a1.hasOwnProperty(10))
diff --git a/deps/v8/test/mjsunit/array-elements-from-array-prototype.js b/deps/v8/test/mjsunit/array-elements-from-array-prototype.js
new file mode 100644 (file)
index 0000000..b89cdfa
--- /dev/null
@@ -0,0 +1,191 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+////////////////////////////////////////////////////////////////////////
+// Tests below verify that elements set on Array.prototype propagate
+// for various Array.prototype functions (like unshift, shift, etc.)
+// If add any new tests here, consider adding them to all other files:
+//   array-elements-from-array-prototype.js
+//   array-elements-from-array-prototype-chain.js
+//   array-elements-from-object-prototype.js
+// those ideally should be identical modulo host of elements and
+// the way elements introduced.
+//
+// Note: they are put into a separate file as we need maximally clean
+// VM setup---some optimizations might be already turned off in
+// 'dirty' VM.
+////////////////////////////////////////////////////////////////////////
+
+var at3 = '@3'
+var at7 = '@7'
+
+Array.prototype[3] = at3
+Array.prototype[7] = at7
+
+var a = new Array(13)
+
+assertEquals(at3, a[3])
+assertFalse(a.hasOwnProperty(3))
+
+assertEquals(at7, a[7])
+assertFalse(a.hasOwnProperty(7))
+
+assertEquals(undefined, a.shift(), 'hole should be returned as undefined')
+// Side-effects: Array.prototype[3] percolates into a[2] and Array.prototype[7[
+// into a[6], still visible at the corresponding indices.
+
+assertEquals(at3, a[2])
+assertTrue(a.hasOwnProperty(2))
+assertEquals(at3, a[3])
+assertFalse(a.hasOwnProperty(3))
+
+assertEquals(at7, a[6])
+assertTrue(a.hasOwnProperty(6))
+assertEquals(at7, a[7])
+assertFalse(a.hasOwnProperty(7))
+
+a.unshift('foo', 'bar')
+// Side-effects: Array.prototype[3] now percolates into a[5] and Array.prototype[7]
+// into a[9].
+
+assertEquals(at3, a[3])
+assertFalse(a.hasOwnProperty(3))
+assertEquals(at3, a[4])
+assertTrue(a.hasOwnProperty(4))
+assertEquals(at3, a[5])
+assertTrue(a.hasOwnProperty(5))
+
+assertEquals(undefined, a[6])
+assertFalse(a.hasOwnProperty(6))
+
+assertEquals(at7, a[7])
+assertFalse(a.hasOwnProperty(7))
+assertEquals(at7, a[8])
+assertTrue(a.hasOwnProperty(8))
+assertEquals(at7, a[9])
+assertTrue(a.hasOwnProperty(9))
+
+var sliced = a.slice(3, 10)
+// Slice must keep intact a and reify holes at indices 0--2 and 4--6.
+
+assertEquals(at3, a[3])
+assertFalse(a.hasOwnProperty(3))
+assertEquals(at3, a[4])
+assertTrue(a.hasOwnProperty(4))
+assertEquals(at3, a[5])
+assertTrue(a.hasOwnProperty(5))
+
+assertEquals(undefined, a[6])
+assertFalse(a.hasOwnProperty(6))
+
+assertEquals(at7, a[7])
+assertFalse(a.hasOwnProperty(7))
+assertEquals(at7, a[8])
+assertTrue(a.hasOwnProperty(8))
+assertEquals(at7, a[9])
+assertTrue(a.hasOwnProperty(9))
+
+assertEquals(at3, sliced[0])
+assertTrue(sliced.hasOwnProperty(0))
+assertEquals(at3, sliced[1])
+assertTrue(sliced.hasOwnProperty(1))
+assertEquals(at3, sliced[2])
+assertTrue(sliced.hasOwnProperty(2))
+
+// Note: sliced[3] comes directly from Array.prototype[3]
+assertEquals(at3, sliced[3]);
+assertFalse(sliced.hasOwnProperty(3))
+
+assertEquals(at7, sliced[4])
+assertTrue(sliced.hasOwnProperty(4))
+assertEquals(at7, sliced[5])
+assertTrue(sliced.hasOwnProperty(5))
+assertEquals(at7, sliced[6])
+assertTrue(sliced.hasOwnProperty(6))
+
+
+// Splice is too complicated the operation, start afresh.
+
+// Shrking array.
+var a0 = [0, 1, , , 4, 5, , , , 9]
+var result = a0.splice(4, 1)
+// Side-effects: everything before 4 is kept intact:
+
+assertEquals(0, a0[0])
+assertTrue(a0.hasOwnProperty(0))
+assertEquals(1, a0[1])
+assertTrue(a0.hasOwnProperty(1))
+assertEquals(undefined, a0[2])
+assertFalse(a0.hasOwnProperty(2))
+assertEquals(at3, a0[3])
+assertFalse(a0.hasOwnProperty(3))
+
+// 4 and above shifted left by one reifying at7 into a0[6] and keeping
+// a hole at a0[7]
+
+assertEquals(5, a0[4])
+assertTrue(a0.hasOwnProperty(4))
+assertEquals(undefined, a0[5])
+assertFalse(a0.hasOwnProperty(5))
+assertEquals(at7, a0[6])
+assertTrue(a0.hasOwnProperty(6))
+assertEquals(at7, a0[7])
+assertFalse(a0.hasOwnProperty(7))
+assertEquals(9, a0[8])
+assertTrue(a0.hasOwnProperty(8))
+
+// Growing array.
+var a1 = [0, 1, , , 4, 5, , , , 9]
+var result = a1.splice(4, 0, undefined)
+// Side-effects: everything before 4 is kept intact:
+
+assertEquals(0, a1[0])
+assertTrue(a1.hasOwnProperty(0))
+assertEquals(1, a1[1])
+assertTrue(a1.hasOwnProperty(1))
+assertEquals(undefined, a1[2])
+assertFalse(a1.hasOwnProperty(2))
+assertEquals(at3, a1[3])
+assertFalse(a1.hasOwnProperty(3))
+
+// Now owned undefined resides at 4 and rest is shifted right by one
+// reifying at7 into a0[8] and keeping a hole at a0[7].
+
+assertEquals(undefined, a1[4])
+assertTrue(a1.hasOwnProperty(4))
+assertEquals(4, a1[5])
+assertTrue(a1.hasOwnProperty(5))
+assertEquals(5, a1[6])
+assertTrue(a1.hasOwnProperty(6))
+assertEquals(at7, a1[7])
+assertFalse(a1.hasOwnProperty(7))
+assertEquals(at7, a1[8])
+assertTrue(a1.hasOwnProperty(8))
+assertEquals(undefined, a1[9])
+assertFalse(a1.hasOwnProperty(9))
+assertEquals(9, a1[10])
+assertTrue(a1.hasOwnProperty(10))
diff --git a/deps/v8/test/mjsunit/array-elements-from-object-prototype.js b/deps/v8/test/mjsunit/array-elements-from-object-prototype.js
new file mode 100644 (file)
index 0000000..a6ad0ee
--- /dev/null
@@ -0,0 +1,191 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+////////////////////////////////////////////////////////////////////////
+// Tests below verify that elements set on Object.prototype propagate
+// for various Array.prototype functions (like unshift, shift, etc.)
+// If add any new tests here, consider adding them to all other files:
+//   array-elements-from-array-prototype.js
+//   array-elements-from-array-prototype-chain.js
+//   array-elements-from-object-prototype.js
+// those ideally should be identical modulo host of elements and
+// the way elements introduced.
+//
+// Note: they are put into a separate file as we need maximally clean
+// VM setup---some optimizations might be already turned off in
+// 'dirty' VM.
+////////////////////////////////////////////////////////////////////////
+
+var at3 = '@3'
+var at7 = '@7'
+
+Object.prototype[3] = at3
+Object.prototype[7] = at7
+
+var a = new Array(13)
+
+assertEquals(at3, a[3])
+assertFalse(a.hasOwnProperty(3))
+
+assertEquals(at7, a[7])
+assertFalse(a.hasOwnProperty(7))
+
+assertEquals(undefined, a.shift(), 'hole should be returned as undefined')
+// Side-effects: Array.prototype[3] percolates into a[2] and Array.prototype[7[
+// into a[6], still visible at the corresponding indices.
+
+assertEquals(at3, a[2])
+assertTrue(a.hasOwnProperty(2))
+assertEquals(at3, a[3])
+assertFalse(a.hasOwnProperty(3))
+
+assertEquals(at7, a[6])
+assertTrue(a.hasOwnProperty(6))
+assertEquals(at7, a[7])
+assertFalse(a.hasOwnProperty(7))
+
+a.unshift('foo', 'bar')
+// Side-effects: Array.prototype[3] now percolates into a[5] and Array.prototype[7]
+// into a[9].
+
+assertEquals(at3, a[3])
+assertFalse(a.hasOwnProperty(3))
+assertEquals(at3, a[4])
+assertTrue(a.hasOwnProperty(4))
+assertEquals(at3, a[5])
+assertTrue(a.hasOwnProperty(5))
+
+assertEquals(undefined, a[6])
+assertFalse(a.hasOwnProperty(6))
+
+assertEquals(at7, a[7])
+assertFalse(a.hasOwnProperty(7))
+assertEquals(at7, a[8])
+assertTrue(a.hasOwnProperty(8))
+assertEquals(at7, a[9])
+assertTrue(a.hasOwnProperty(9))
+
+var sliced = a.slice(3, 10)
+// Slice must keep intact a and reify holes at indices 0--2 and 4--6.
+
+assertEquals(at3, a[3])
+assertFalse(a.hasOwnProperty(3))
+assertEquals(at3, a[4])
+assertTrue(a.hasOwnProperty(4))
+assertEquals(at3, a[5])
+assertTrue(a.hasOwnProperty(5))
+
+assertEquals(undefined, a[6])
+assertFalse(a.hasOwnProperty(6))
+
+assertEquals(at7, a[7])
+assertFalse(a.hasOwnProperty(7))
+assertEquals(at7, a[8])
+assertTrue(a.hasOwnProperty(8))
+assertEquals(at7, a[9])
+assertTrue(a.hasOwnProperty(9))
+
+assertEquals(at3, sliced[0])
+assertTrue(sliced.hasOwnProperty(0))
+assertEquals(at3, sliced[1])
+assertTrue(sliced.hasOwnProperty(1))
+assertEquals(at3, sliced[2])
+assertTrue(sliced.hasOwnProperty(2))
+
+// Note: sliced[3] comes directly from Array.prototype[3]
+assertEquals(at3, sliced[3]);
+assertFalse(sliced.hasOwnProperty(3))
+
+assertEquals(at7, sliced[4])
+assertTrue(sliced.hasOwnProperty(4))
+assertEquals(at7, sliced[5])
+assertTrue(sliced.hasOwnProperty(5))
+assertEquals(at7, sliced[6])
+assertTrue(sliced.hasOwnProperty(6))
+
+
+// Splice is too complicated the operation, start afresh.
+
+// Shrking array.
+var a0 = [0, 1, , , 4, 5, , , , 9]
+var result = a0.splice(4, 1)
+// Side-effects: everything before 4 is kept intact:
+
+assertEquals(0, a0[0])
+assertTrue(a0.hasOwnProperty(0))
+assertEquals(1, a0[1])
+assertTrue(a0.hasOwnProperty(1))
+assertEquals(undefined, a0[2])
+assertFalse(a0.hasOwnProperty(2))
+assertEquals(at3, a0[3])
+assertFalse(a0.hasOwnProperty(3))
+
+// 4 and above shifted left by one reifying at7 into a0[6] and keeping
+// a hole at a0[7]
+
+assertEquals(5, a0[4])
+assertTrue(a0.hasOwnProperty(4))
+assertEquals(undefined, a0[5])
+assertFalse(a0.hasOwnProperty(5))
+assertEquals(at7, a0[6])
+assertTrue(a0.hasOwnProperty(6))
+assertEquals(at7, a0[7])
+assertFalse(a0.hasOwnProperty(7))
+assertEquals(9, a0[8])
+assertTrue(a0.hasOwnProperty(8))
+
+// Growing array.
+var a1 = [0, 1, , , 4, 5, , , , 9]
+var result = a1.splice(4, 0, undefined)
+// Side-effects: everything before 4 is kept intact:
+
+assertEquals(0, a1[0])
+assertTrue(a1.hasOwnProperty(0))
+assertEquals(1, a1[1])
+assertTrue(a1.hasOwnProperty(1))
+assertEquals(undefined, a1[2])
+assertFalse(a1.hasOwnProperty(2))
+assertEquals(at3, a1[3])
+assertFalse(a1.hasOwnProperty(3))
+
+// Now owned undefined resides at 4 and rest is shifted right by one
+// reifying at7 into a0[8] and keeping a hole at a0[7].
+
+assertEquals(undefined, a1[4])
+assertTrue(a1.hasOwnProperty(4))
+assertEquals(4, a1[5])
+assertTrue(a1.hasOwnProperty(5))
+assertEquals(5, a1[6])
+assertTrue(a1.hasOwnProperty(6))
+assertEquals(at7, a1[7])
+assertFalse(a1.hasOwnProperty(7))
+assertEquals(at7, a1[8])
+assertTrue(a1.hasOwnProperty(8))
+assertEquals(undefined, a1[9])
+assertFalse(a1.hasOwnProperty(9))
+assertEquals(9, a1[10])
+assertTrue(a1.hasOwnProperty(10))
index 9731e7a..967d720 100644 (file)
@@ -26,7 +26,7 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 var a = [0,1,2,3];
-a.length = 0;
+assertEquals(0, a.length = 0);
 
 assertEquals('undefined', typeof a[0]);
 assertEquals('undefined', typeof a[1]);
@@ -35,7 +35,7 @@ assertEquals('undefined', typeof a[3]);
 
 
 var a = [0,1,2,3];
-a.length = 2;
+assertEquals(2, a.length = 2);
 
 assertEquals(0, a[0]);
 assertEquals(1, a[1]);
@@ -50,7 +50,7 @@ a[1000000] = 1000000;
 a[2000000] = 2000000;
 
 assertEquals(2000001, a.length);
-a.length = 0;
+assertEquals(0, a.length = 0);
 assertEquals(0, a.length);
 assertEquals('undefined', typeof a[0]);
 assertEquals('undefined', typeof a[1000]);
@@ -65,7 +65,7 @@ a[1000000] = 1000000;
 a[2000000] = 2000000;
 
 assertEquals(2000001, a.length);
-a.length = 2000;
+assertEquals(2000, a.length = 2000);
 assertEquals(2000, a.length);
 assertEquals(0, a[0]);
 assertEquals(1000, a[1000]);
@@ -91,7 +91,7 @@ assertEquals(Math.pow(2,31)-1, a[Math.pow(2,31)-1]);
 assertEquals(Math.pow(2,32)-2, a[Math.pow(2,32)-2]);
 
 assertEquals(Math.pow(2,32)-1, a.length);
-a.length = Math.pow(2,30)+1;  // not a smi!
+assertEquals(Math.pow(2,30) + 1, a.length = Math.pow(2,30)+1);  // not a smi!
 assertEquals(Math.pow(2,30)+1, a.length);
 
 assertEquals(0, a[0]);
@@ -102,10 +102,20 @@ assertEquals('undefined', typeof a[Math.pow(2,32)-2], "top");
 
 
 var a = new Array();
-a.length = new Number(12);
+assertEquals(12, a.length = new Number(12));
 assertEquals(12, a.length);
 
 
 var o = { length: -23 };
 Array.prototype.pop.apply(o);
 assertEquals(4294967272, o.length);
+
+// Check case of compiled stubs.
+var a = [];
+for (var i = 0; i < 7; i++) {
+  assertEquals(3, a.length = 3);
+
+  var t = 239;
+  t = a.length = 7;
+  assertEquals(7, t);
+}
index c993a07..30e9f3e 100644 (file)
 })();
 
 
+// Check various variants of empty array's slicing.
+(function() {
+  for (var i = 0; i < 7; i++) {
+    assertEquals([], [].slice(0, 0));
+    assertEquals([], [].slice(1, 0));
+    assertEquals([], [].slice(0, 1));
+    assertEquals([], [].slice(-1, 0));
+  }
+})();
+
+
 // Check various forms of arguments omission.
 (function() {
   var array = new Array(7);
index 18f81fe..887097d 100644 (file)
     var array = new Array(10);
     var spliced = array.splice(1, 1, 'one', 'two');
     assertEquals(1, spliced.length);
-    assertFalse(0 in spliced);
+    assertFalse(0 in spliced, "0 in spliced");
 
     assertEquals(11, array.length);
-    assertFalse(0 in array);
+    assertFalse(0 in array, "0 in array");
     assertTrue(1 in array);
     assertTrue(2 in array);
-    assertFalse(3 in array);
+    assertFalse(3 in array, "3 in array");
+  }
+})();
+
+
+// Check various variants of empty array's splicing.
+(function() {
+  for (var i = 0; i < 7; i++) {
+    assertEquals([], [].splice(0, 0));
+    assertEquals([], [].splice(1, 0));
+    assertEquals([], [].splice(0, 1));
+    assertEquals([], [].splice(-1, 0));
+  }
+})();
+
+
+// Check that even if result array is empty, receiver gets sliced.
+(function() {
+  for (var i = 0; i < 7; i++) {
+    var a = [1, 2, 3];
+    assertEquals([], a.splice(1, 0, 'a', 'b', 'c'));
+    assertEquals([1, 'a', 'b', 'c', 2, 3], a);
   }
 })();
 
     assertEquals(undefined, array[7]);
 
     // and now check hasOwnProperty
-    assertFalse(array.hasOwnProperty(0));
-    assertFalse(array.hasOwnProperty(1));
+    assertFalse(array.hasOwnProperty(0), "array.hasOwnProperty(0)");
+    assertFalse(array.hasOwnProperty(1), "array.hasOwnProperty(1)");
     assertTrue(array.hasOwnProperty(2));
     assertTrue(array.hasOwnProperty(3));
     assertTrue(array.hasOwnProperty(4));
-    assertFalse(array.hasOwnProperty(5));
-    assertFalse(array.hasOwnProperty(6));
-    assertFalse(array.hasOwnProperty(7));
+    assertFalse(array.hasOwnProperty(5), "array.hasOwnProperty(5)");
+    assertFalse(array.hasOwnProperty(6), "array.hasOwnProperty(6)");
+    assertFalse(array.hasOwnProperty(7), "array.hasOwnProperty(7)");
     assertTrue(array.hasOwnProperty(8));
-    assertFalse(array.hasOwnProperty(9));
+    assertFalse(array.hasOwnProperty(9), "array.hasOwnProperty(9)");
 
     // and now check couple of indices above length.
-    assertFalse(array.hasOwnProperty(10));
-    assertFalse(array.hasOwnProperty(15));
-    assertFalse(array.hasOwnProperty(31));
-    assertFalse(array.hasOwnProperty(63));
-    assertFalse(array.hasOwnProperty(2 << 32 - 1));
+    assertFalse(array.hasOwnProperty(10), "array.hasOwnProperty(10)");
+    assertFalse(array.hasOwnProperty(15), "array.hasOwnProperty(15)");
+    assertFalse(array.hasOwnProperty(31), "array.hasOwnProperty(31)");
+    assertFalse(array.hasOwnProperty(63), "array.hasOwnProperty(63)");
+    assertFalse(array.hasOwnProperty(2 << 32 - 1), "array.hasOwnProperty(2 << 31 - 1)");
   }
 })();
 
     assertEquals(bigNum + 7, array.length);
   }
 })();
+
+(function() {
+  for (var i = 0; i < 7; i++) {
+    var a = [7, 8, 9];
+    a.splice(0, 0, 1, 2, 3, 4, 5, 6);
+    assertEquals([1, 2, 3, 4, 5, 6, 7, 8, 9], a);
+    assertFalse(a.hasOwnProperty(10), "a.hasOwnProperty(10)");
+    assertEquals(undefined, a[10]);
+  }
+})();
index 06a78a7..dbe245b 100644 (file)
     assertEquals(bigNum + 7, new Array(bigNum).unshift(1, 2, 3, 4, 5, 6, 7));
   }
 })();
+
+(function() {
+  for (var i = 0; i < 7; i++) {
+    var a = [6, 7, 8, 9];
+    a.unshift(1, 2, 3, 4, 5);
+    assertEquals([1, 2, 3, 4, 5, 6, 7, 8, 9], a);
+  }
+})();
diff --git a/deps/v8/test/mjsunit/bugs/bug-618.js b/deps/v8/test/mjsunit/bugs/bug-618.js
new file mode 100644 (file)
index 0000000..8f47440
--- /dev/null
@@ -0,0 +1,45 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// When this bug is corrected move to object-define-property and add
+// additional tests for configurable in the same manner as existing tests
+// there.
+
+function C() {
+  this.x = 23;
+}
+
+// If a setter is added to the prototype chain of a simple constructor setting 
+// one of the properties assigned in the constructor then this setter is 
+// ignored when constructing new objects from the constructor.
+
+// This only happens if the setter is added _after_ an instance has been 
+// created.
+
+assertEquals(23, new C().x);
+C.prototype.__defineSetter__('x', function(value) { this.y = 23; });
+assertEquals(void 0, new C().x));
index 8c53910..a592e4c 100644 (file)
@@ -147,3 +147,17 @@ function testToLocaleTimeString() {
 }
 
 testToLocaleTimeString();
+
+
+// Modified test from WebKit
+// LayoutTests/fast/js/script-tests/date-utc-timeclip.js:
+
+assertEquals(Date.UTC(275760, 8, 12, 23, 59, 59, 999), 8639999999999999);
+assertEquals(Date.UTC(275760, 8, 13), 8640000000000000);
+assertTrue(isNaN(Date.UTC(275760, 8, 13, 0, 0, 0, 1)));
+assertTrue(isNaN(Date.UTC(275760, 8, 14)));
+
+assertEquals(Date.UTC(-271821, 3, 20, 0, 0, 0, 1), -8639999999999999);
+assertEquals(Date.UTC(-271821, 3, 20), -8640000000000000);
+assertTrue(isNaN(Date.UTC(-271821, 3, 19, 23, 59, 59, 999)));
+assertTrue(isNaN(Date.UTC(-271821, 3, 19)));
diff --git a/deps/v8/test/mjsunit/debug-liveedit-1.js b/deps/v8/test/mjsunit/debug-liveedit-1.js
new file mode 100644 (file)
index 0000000..9c966a2
--- /dev/null
@@ -0,0 +1,48 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+
+Debug = debug.Debug
+
+eval("var something1 = 25; "
+     + " function ChooseAnimal() { return          'Cat';          } "
+     + " ChooseAnimal.Helper = function() { return 'Help!'; }");
+
+assertEquals("Cat", ChooseAnimal());
+
+var script = Debug.findScript(ChooseAnimal);
+
+var orig_animal = "Cat";
+var patch_pos = script.source.indexOf(orig_animal);
+var new_animal_patch = "Cap' + 'y' + 'bara";
+
+var change_log = new Array();
+Debug.LiveEditChangeScript(script, patch_pos, orig_animal.length, new_animal_patch, change_log);
+
+assertEquals("Capybara", ChooseAnimal());
diff --git a/deps/v8/test/mjsunit/debug-liveedit-2.js b/deps/v8/test/mjsunit/debug-liveedit-2.js
new file mode 100644 (file)
index 0000000..8a40dfc
--- /dev/null
@@ -0,0 +1,70 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+
+
+Debug = debug.Debug
+
+
+eval(
+    "function ChooseAnimal(p) {\n " +
+    "  if (p == 7) {\n" + // Use p
+    "    return;\n" +
+    "  }\n" +
+    "  return function Chooser() {\n" +
+    "    return 'Cat';\n" +
+    "  };\n" +
+    "}\n"
+);
+
+var old_closure = ChooseAnimal(19);
+
+assertEquals("Cat", old_closure());
+
+var script = Debug.findScript(ChooseAnimal);
+
+var orig_animal = "'Cat'";
+var patch_pos = script.source.indexOf(orig_animal);
+var new_animal_patch = "'Capybara' + p";
+
+// We patch innermost function "Chooser".
+// However, this does not actually patch existing "Chooser" instances,
+// because old value of parameter "p" was not saved.
+// Instead it patches ChooseAnimal.
+var change_log = new Array();
+Debug.LiveEditChangeScript(script, patch_pos, orig_animal.length, new_animal_patch, change_log);
+print("Change log: " + JSON.stringify(change_log) + "\n");
+
+var new_closure = ChooseAnimal(19);
+// New instance of closure is patched.
+assertEquals("Capybara19", new_closure());
+
+// Old instance of closure is not patched.
+assertEquals("Cat", old_closure());
+
diff --git a/deps/v8/test/mjsunit/debug-liveedit-check-stack.js b/deps/v8/test/mjsunit/debug-liveedit-check-stack.js
new file mode 100644 (file)
index 0000000..1d788be
--- /dev/null
@@ -0,0 +1,84 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+
+Debug = debug.Debug
+
+eval(
+    "function ChooseAnimal(callback) {\n " +
+    "  callback();\n" +
+    "  return 'Cat';\n" +
+    "}\n"
+);
+
+function Noop() {}
+var res = ChooseAnimal(Noop);
+
+assertEquals("Cat", res);
+
+var script = Debug.findScript(ChooseAnimal);
+
+var orig_animal = "'Cat'";
+var patch_pos = script.source.indexOf(orig_animal);
+var new_animal_patch = "'Capybara'";
+
+var got_exception = false;
+var successfully_changed = false;
+
+function Changer() {
+  // Never try the same patch again.
+  assertEquals(false, successfully_changed);
+  var change_log = new Array();
+  try {
+    Debug.LiveEditChangeScript(script, patch_pos, orig_animal.length, new_animal_patch, change_log);
+    successfully_changed = true;
+  } catch (e) {
+    if (e instanceof Debug.LiveEditChangeScript.Failure) {
+      got_exception = true;
+      print(e);
+    } else {
+      throw e;
+    }
+  }
+  print("Change log: " + JSON.stringify(change_log) + "\n");
+}
+
+var new_res = ChooseAnimal(Changer);
+// Function must be not pached.
+assertEquals("Cat", new_res);
+
+assertEquals(true, got_exception);
+
+// This time it should succeed.
+Changer();
+
+new_res = ChooseAnimal(Noop);
+// Function must be not pached.
+assertEquals("Capybara", new_res);
+
index af29df9..37cefd1 100644 (file)
@@ -84,16 +84,16 @@ function CheckScopeChain(scopes, exec_state) {
     var scope = exec_state.frame().scope(i);
     assertTrue(scope.isScope());
     assertEquals(scopes[i], scope.scopeType());
-    
+
     // Check the global object when hitting the global scope.
     if (scopes[i] == debug.ScopeType.Global) {
       assertEquals(this, scope.scopeObject().value());
     }
   }
-  
+
   // Get the debug command processor.
   var dcp = exec_state.debugCommandProcessor("unspecified_running_state");
-  
+
   // Send a scopes request and check the result.
   var json;
   request_json = '{"seq":0,"type":"request","command":"scopes"}'
@@ -133,7 +133,7 @@ function CheckScopeContent(content, number, exec_state) {
     }
     count++;
   }
-  
+
   // 'arguments' and might be exposed in the local and closure scope. Just
   // ignore this.
   var scope_size = scope.scopeObject().properties().length;
@@ -156,7 +156,7 @@ function CheckScopeContent(content, number, exec_state) {
 
   // Get the debug command processor.
   var dcp = exec_state.debugCommandProcessor("unspecified_running_state");
-  
+
   // Send a scope request for information on a single scope and check the
   // result.
   request_json = '{"seq":0,"type":"request","command":"scope","arguments":{"number":'
@@ -622,7 +622,7 @@ function the_full_monty(a, b) {
     with ({j:13}){
       return function() {
         var x = 14;
-        with ({a:15}) {      
+        with ({a:15}) {
           with ({b:16}) {
             debugger;
             some_global = a;
@@ -707,7 +707,7 @@ EndTest();
 
 
 BeginTest("Catch block 3");
-function catch_block_1() {
+function catch_block_3() {
   // Do eval to dynamically declare a local variable so that the context's
   // extension slot is initialized with JSContextExtensionObject.
   eval("var y = 78;");
@@ -726,12 +726,12 @@ listener_delegate = function(exec_state) {
   CheckScopeContent({e:'Exception'}, 0, exec_state);
   CheckScopeContent({y:78}, 1, exec_state);
 }
-catch_block_1()
+catch_block_3()
 EndTest();
 
 
 BeginTest("Catch block 4");
-function catch_block_2() {
+function catch_block_4() {
   // Do eval to dynamically declare a local variable so that the context's
   // extension slot is initialized with JSContextExtensionObject.
   eval("var y = 98;");
@@ -753,7 +753,7 @@ listener_delegate = function(exec_state) {
   CheckScopeContent({e:'Exception'}, 1, exec_state);
   CheckScopeContent({y:98}, 2, exec_state);
 }
-catch_block_2()
+catch_block_4()
 EndTest();
 
 
index effa145..402f90c 100644 (file)
@@ -52,7 +52,7 @@ for (i = 0; i < scripts.length; i++) {
 }
 
 // This has to be updated if the number of native scripts change.
-assertEquals(12, named_native_count);
+assertEquals(13, named_native_count);
 // If no snapshot is used, only the 'gc' extension is loaded.
 // If snapshot is used, all extensions are cached in the snapshot.
 assertTrue(extension_count == 1 || extension_count == 5);
index e2f601e..3750388 100644 (file)
@@ -147,7 +147,19 @@ var knownProblems = {
   "DeclareGlobals": true,
 
   "PromoteScheduledException": true,
-  "DeleteHandleScopeExtensions": true
+  "DeleteHandleScopeExtensions": true,
+
+  // That can only be invoked on Array.prototype.
+  "FinishArrayPrototypeSetup": true,
+
+  // LiveEdit feature is under development currently and has fragile input.
+  "LiveEditFindSharedFunctionInfosForScript": true,
+  "LiveEditGatherCompileInfo": true,
+  "LiveEditReplaceScript": true,
+  "LiveEditReplaceFunctionCode": true,
+  "LiveEditRelinkFunctionToScript": true,
+  "LiveEditPatchFunctionPositions": true,
+  "LiveEditCheckStackActivations": true
 };
 
 var currentlyUncallable = {
diff --git a/deps/v8/test/mjsunit/math-sqrt.js b/deps/v8/test/mjsunit/math-sqrt.js
new file mode 100644 (file)
index 0000000..ae29b74
--- /dev/null
@@ -0,0 +1,44 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Tests the special cases specified by ES 15.8.2.17
+
+// Simple sanity check
+assertEquals(2, Math.sqrt(4));
+assertEquals(0.1, Math.sqrt(0.01));
+
+// Spec tests
+assertEquals(NaN, Math.sqrt(NaN));
+assertEquals(NaN, Math.sqrt(-1));
+assertEquals(+0, Math.sqrt(+0));
+assertEquals(-0, Math.sqrt(-0));
+assertEquals(Infinity, Math.sqrt(Infinity));
+// -Infinity is smaller than 0 so it should return NaN
+assertEquals(NaN, Math.sqrt(-Infinity));
+
+
+
diff --git a/deps/v8/test/mjsunit/regress/regress-634.js b/deps/v8/test/mjsunit/regress/regress-634.js
new file mode 100644 (file)
index 0000000..b68e843
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+for (var i = 0; i < 1000000; i++) {
+  a = new Array(0);
+  assertEquals(0, a.length);
+  assertEquals(0, a.length);
+}
similarity index 81%
rename from deps/v8/src/usage-analyzer.h
rename to deps/v8/test/mjsunit/regress/regress-636.js
index 1b0ea4a..8e0196d 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Copyright 2010 the V8 project authors. All rights reserved.
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
 // met:
 // (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_USAGE_ANALYZER_H_
-#define V8_USAGE_ANALYZER_H_
+function test() {
+  var i, result = "";
+  var value = parseFloat(5.5);
+  value = Math.abs(1025);
+  for(i = 12; --i; result = ( value % 2 ) + result, value >>= 1);
+  return result;
+};
 
-namespace v8 {
-namespace internal {
-
-// Compute usage counts for all variables.
-// Used for variable allocation.
-bool AnalyzeVariableUsage(FunctionLiteral* lit);
-
-} }  // namespace v8::internal
-
-#endif  // V8_USAGE_ANALYZER_H_
+assertEquals("10000000001", test());
index 8ec8f1e..d1989df 100644 (file)
@@ -51,3 +51,16 @@ assertEquals(116, s.charCodeAt(NaN));
 assertTrue(isNaN(s.charCodeAt(-1)));
 assertTrue(isNaN(s.charCodeAt(4)));
 
+// Make sure enough of the one-char string cache is filled.
+var alpha = ['@'];
+for (var i = 1; i < 128; i++) {
+  var c = String.fromCharCode(i);
+  alpha[i] = c.charAt(0);
+}
+var alphaStr = alpha.join("");
+
+// Now test chars.
+for (var i = 1; i < 128; i++) {
+  assertEquals(alpha[i], alphaStr.charAt(i));
+  assertEquals(String.fromCharCode(i), alphaStr.charAt(i));
+}
index 2256286..c6b26a8 100644 (file)
@@ -152,3 +152,17 @@ assertEquals('o', S2);
 var s2 = (s[-2] = 't');
 assertEquals('undefined', typeof(s[-2]));
 assertEquals('t', s2);
+
+// Make sure enough of the one-char string cache is filled.
+var alpha = ['@'];
+for (var i = 1; i < 128; i++) {
+  var c = String.fromCharCode(i);
+  alpha[i] = c[0];
+}
+var alphaStr = alpha.join("");
+
+// Now test chars.
+for (var i = 1; i < 128; i++) {
+  assertEquals(alpha[i], alphaStr[i]);
+  assertEquals(String.fromCharCode(i), alphaStr[i]);
+}
diff --git a/deps/v8/test/mjsunit/string-split-cache.js b/deps/v8/test/mjsunit/string-split-cache.js
new file mode 100644 (file)
index 0000000..37c550f
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+var str = "abcdef";
+
+// Get a prefix of the string into the one-char string cache.
+assertEquals("a", str[0]);
+assertEquals("b", str[1]);
+assertEquals("c", str[2]);
+
+// Splitting by "" calls runtime StringToArray function that uses the
+// cache. So this test hits a case where only a prefix is cached.
+var array = str.split("");
+var expected = ["a", "b", "c", "d", "e", "f"];
+assertArrayEquals(expected, array);
index 86a7426..04fd060 100644 (file)
@@ -39,6 +39,13 @@ array = [
   "every", "map", "indexOf", "lastIndexOf", "reduce", "reduceRight"];
 CheckJSCSemantics(Array.prototype, array, "Array prototype");
 
+var old_Array_prototype = Array.prototype;
+var new_Array_prototype = {};
+for (var i = 0; i < 7; i++) {
+  Array.prototype = new_Array_prototype;
+  assertEquals(old_Array_prototype, Array.prototype);
+}
+
 array = [
   "toString", "toDateString", "toTimeString", "toLocaleString",
   "toLocaleDateString", "toLocaleTimeString", "valueOf", "getTime",
@@ -79,6 +86,13 @@ array = [
   "__lookupGetter__", "__defineSetter__", "__lookupSetter__"];
 CheckEcmaSemantics(Object.prototype, array, "Object prototype");
 
+var old_Object_prototype = Object.prototype;
+var new_Object_prototype = {};
+for (var i = 0; i < 7; i++) {
+  Object.prototype = new_Object_prototype;
+  assertEquals(old_Object_prototype, Object.prototype);
+}
+
 array = [
   "toString", "valueOf", "toJSON"];
 CheckEcmaSemantics(Boolean.prototype, array, "Boolean prototype");
index efba10b..59ec566 100644 (file)
@@ -27,7 +27,6 @@
 
 {
   'variables': {
-    'chromium_code': 1,
     'msvs_use_common_release': 0,
     'gcc_version%': 'unknown',
     'target_arch%': 'ia32',
         '../../src/unicode-inl.h',
         '../../src/unicode.cc',
         '../../src/unicode.h',
-        '../../src/usage-analyzer.cc',
-        '../../src/usage-analyzer.h',
         '../../src/utils.cc',
         '../../src/utils.h',
         '../../src/v8-counters.cc',
         '../../src/variables.h',
         '../../src/version.cc',
         '../../src/version.h',
-        '../../src/virtual-frame-inl.h',       
-        '../../src/virtual-frame.h',
+        '../../src/virtual-frame-inl.h',
         '../../src/virtual-frame.cc',
+        '../../src/virtual-frame.h',
         '../../src/zone-inl.h',
         '../../src/zone.cc',
         '../../src/zone.h',
           '../../src/messages.js',
           '../../src/apinatives.js',
           '../../src/debug-delay.js',
+          '../../src/liveedit-delay.js',
           '../../src/mirror-delay.js',
           '../../src/date-delay.js',
           '../../src/json-delay.js',
index df5293b..54b1bfb 100644 (file)
@@ -3,4 +3,4 @@ set SOURCE_DIR=%1
 set TARGET_DIR=%2
 set PYTHON="..\..\..\third_party\python_24\python.exe"
 if not exist %PYTHON% set PYTHON=python.exe
-%PYTHON% ..\js2c.py %TARGET_DIR%\natives.cc %TARGET_DIR%\natives-empty.cc CORE %SOURCE_DIR%\macros.py %SOURCE_DIR%\runtime.js %SOURCE_DIR%\v8natives.js %SOURCE_DIR%\array.js %SOURCE_DIR%\string.js %SOURCE_DIR%\uri.js %SOURCE_DIR%\math.js %SOURCE_DIR%\messages.js %SOURCE_DIR%\apinatives.js %SOURCE_DIR%\debug-delay.js %SOURCE_DIR%\mirror-delay.js %SOURCE_DIR%\date-delay.js %SOURCE_DIR%\regexp-delay.js %SOURCE_DIR%\json-delay.js
+%PYTHON% ..\js2c.py %TARGET_DIR%\natives.cc %TARGET_DIR%\natives-empty.cc CORE %SOURCE_DIR%\macros.py %SOURCE_DIR%\runtime.js %SOURCE_DIR%\v8natives.js %SOURCE_DIR%\array.js %SOURCE_DIR%\string.js %SOURCE_DIR%\uri.js %SOURCE_DIR%\math.js %SOURCE_DIR%\messages.js %SOURCE_DIR%\apinatives.js %SOURCE_DIR%\debug-delay.js %SOURCE_DIR%\liveedit-delay.js %SOURCE_DIR%\mirror-delay.js %SOURCE_DIR%\date-delay.js %SOURCE_DIR%\regexp-delay.js %SOURCE_DIR%\json-delay.js
index 47ba8c1..3122c6d 100644 (file)
                                >
                        </File>
                        <File
+                               RelativePath="..\..\src\liveedit-delay.js"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\..\src\macros.py"
                                >
                        </File>
index d21affe..cb7519b 100644 (file)
                                >\r
                        </File>\r
                        <File\r
+                               RelativePath="..\..\src\liveedit-delay.js"\r
+                               >\r
+                       </File>\r
+                       <File\r
                                RelativePath="..\..\src\macros.py"\r
                                >\r
                        </File>\r
index 6238044..1a7e14c 100644 (file)
                                >
                        </File>
                        <File
-                               RelativePath="..\..\src\usage-analyzer.cc"
-                               >
-                       </File>
-                       <File
-                               RelativePath="..\..\src\usage-analyzer.h"
-                               >
-                       </File>
-                       <File
                                RelativePath="..\..\src\utils.cc"
                                >
                        </File>
index 7f97da6..346c5eb 100644 (file)
                                >
                        </File>
                        <File
-                               RelativePath="..\..\src\usage-analyzer.cc"
-                               >
-                       </File>
-                       <File
-                               RelativePath="..\..\src\usage-analyzer.h"
-                               >
-                       </File>
-                       <File
                                RelativePath="..\..\src\utils.cc"
                                >
                        </File>
index b7ad20d..120dd19 100644 (file)
                                >
                        </File>
                        <File
-                               RelativePath="..\..\src\usage-analyzer.cc"
-                               >
-                       </File>
-                       <File
-                               RelativePath="..\..\src\usage-analyzer.h"
-                               >
-                       </File>
-                       <File
                                RelativePath="..\..\src\utils.cc"
                                >
                        </File>
index cbf88c9..a476d7d 100644 (file)
                                >
                        </File>
                        <File
+                               RelativePath="..\..\src\liveedit-delay.js"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\..\src\macros.py"
                                >
                        </File>