OSDN Git Service

Update V8 to bleeding_edge@2524
authorAndrei Popescu <andreip@google.com>
Thu, 23 Jul 2009 18:18:55 +0000 (19:18 +0100)
committerAndrei Popescu <andreip@google.com>
Thu, 23 Jul 2009 18:23:41 +0000 (19:23 +0100)
91 files changed:
V8Binding/Android.v8common.mk
V8Binding/v8/SConstruct
V8Binding/v8/benchmarks/run.html [changed mode: 0755->0644]
V8Binding/v8/benchmarks/style.css [changed mode: 0755->0644]
V8Binding/v8/include/v8.h
V8Binding/v8/src/SConscript
V8Binding/v8/src/api.cc
V8Binding/v8/src/arm/codegen-arm.cc
V8Binding/v8/src/arm/ic-arm.cc
V8Binding/v8/src/arm/macro-assembler-arm.cc
V8Binding/v8/src/arm/register-allocator-arm-inl.h
V8Binding/v8/src/arm/stub-cache-arm.cc
V8Binding/v8/src/bootstrapper.cc
V8Binding/v8/src/compilation-cache.cc
V8Binding/v8/src/debug.cc
V8Binding/v8/src/execution.cc
V8Binding/v8/src/flag-definitions.h
V8Binding/v8/src/frame-element.cc [new file with mode: 0644]
V8Binding/v8/src/frame-element.h
V8Binding/v8/src/hashmap.cc
V8Binding/v8/src/heap-inl.h
V8Binding/v8/src/heap.cc
V8Binding/v8/src/heap.h
V8Binding/v8/src/ia32/codegen-ia32.cc
V8Binding/v8/src/ia32/ic-ia32.cc
V8Binding/v8/src/ia32/macro-assembler-ia32.cc
V8Binding/v8/src/ia32/regexp-macro-assembler-ia32.cc
V8Binding/v8/src/ia32/register-allocator-ia32-inl.h
V8Binding/v8/src/ia32/stub-cache-ia32.cc
V8Binding/v8/src/ic.cc
V8Binding/v8/src/ic.h
V8Binding/v8/src/interpreter-irregexp.cc
V8Binding/v8/src/log.cc
V8Binding/v8/src/log.h
V8Binding/v8/src/objects-inl.h
V8Binding/v8/src/objects.cc
V8Binding/v8/src/objects.h
V8Binding/v8/src/parser.cc
V8Binding/v8/src/platform-macos.cc
V8Binding/v8/src/register-allocator.cc
V8Binding/v8/src/register-allocator.h
V8Binding/v8/src/rewriter.cc
V8Binding/v8/src/serialize.cc
V8Binding/v8/src/spaces.cc
V8Binding/v8/src/string-stream.cc
V8Binding/v8/src/string-stream.h
V8Binding/v8/src/stub-cache.cc
V8Binding/v8/src/stub-cache.h
V8Binding/v8/src/x64/assembler-x64.cc
V8Binding/v8/src/x64/assembler-x64.h
V8Binding/v8/src/x64/codegen-x64.cc
V8Binding/v8/src/x64/debug-x64.cc
V8Binding/v8/src/x64/disasm-x64.cc
V8Binding/v8/src/x64/ic-x64.cc
V8Binding/v8/src/x64/macro-assembler-x64.cc
V8Binding/v8/src/x64/macro-assembler-x64.h
V8Binding/v8/src/x64/register-allocator-x64-inl.h
V8Binding/v8/src/x64/stub-cache-x64.cc
V8Binding/v8/src/zone.cc
V8Binding/v8/test/cctest/cctest.status
V8Binding/v8/test/cctest/test-api.cc
V8Binding/v8/test/cctest/test-heap.cc
V8Binding/v8/test/cctest/test-mark-compact.cc
V8Binding/v8/test/message/message.status
V8Binding/v8/test/mjsunit/debug-stepin-accessor.js [new file with mode: 0644]
V8Binding/v8/test/mjsunit/mjsunit.status
V8Binding/v8/test/mjsunit/regexp-call-as-function.js [new file with mode: 0644]
V8Binding/v8/test/mjsunit/regress/regress-155924.js [new file with mode: 0644]
V8Binding/v8/test/mjsunit/regress/regress-345.js [new file with mode: 0644]
V8Binding/v8/test/mjsunit/regress/regress-406.js [new file with mode: 0644]
V8Binding/v8/test/mjsunit/tools/codemap.js
V8Binding/v8/test/mjsunit/tools/profile.js
V8Binding/v8/test/mjsunit/tools/tickprocessor-test.default
V8Binding/v8/test/mjsunit/tools/tickprocessor-test.ignore-unknown
V8Binding/v8/test/mjsunit/tools/tickprocessor-test.separate-ic
V8Binding/v8/test/mjsunit/tools/tickprocessor.js
V8Binding/v8/test/mozilla/mozilla.status
V8Binding/v8/tools/codemap.js
V8Binding/v8/tools/gyp/v8.gyp
V8Binding/v8/tools/mac-nm [new file with mode: 0755]
V8Binding/v8/tools/mac-tick-processor [new file with mode: 0755]
V8Binding/v8/tools/process-heap-prof.py [new file with mode: 0755]
V8Binding/v8/tools/profile.js
V8Binding/v8/tools/test.py
V8Binding/v8/tools/tickprocessor-driver.js
V8Binding/v8/tools/tickprocessor.js
V8Binding/v8/tools/v8.xcodeproj/project.pbxproj
V8Binding/v8/tools/visual_studio/v8_base.vcproj
V8Binding/v8/tools/visual_studio/v8_base_arm.vcproj
WEBKIT_MERGE_REVISION
WebCore/platform/SharedBuffer.h

index bf2e796..4da3a30 100644 (file)
@@ -21,6 +21,7 @@ V8_LOCAL_SRC_FILES := \
        src/execution.cc \
        src/factory.cc \
        src/flags.cc \
+       src/frame-element.cc \
        src/frames.cc \
        src/func-name-inferrer.cc \
        src/global-handles.cc \
index 78b050d..dbcd616 100644 (file)
@@ -149,31 +149,22 @@ LIBRARY_FLAGS = {
                        '-Wstrict-aliasing=2'],
       'CPPPATH':      ANDROID_INCLUDES,
     },
-    'wordsize:32': {
-      'arch:x64': {
-        'CCFLAGS':      ['-m64'],
-        'LINKFLAGS':    ['-m64']
-      }
-    },
-    'wordsize:64': {
-      'arch:ia32': {
-        'CCFLAGS':      ['-m32'],
-        'LINKFLAGS':    ['-m32']
-      },
-      'arch:arm': {
-        'CCFLAGS':      ['-m32'],
-        'LINKFLAGS':    ['-m32']
-      }
-    },
     'arch:ia32': {
-      'CPPDEFINES':   ['V8_TARGET_ARCH_IA32']
+      'CPPDEFINES':   ['V8_TARGET_ARCH_IA32'],
+      'CCFLAGS':      ['-m32'],
+      'LINKFLAGS':    ['-m32']
     },
     'arch:arm': {
       'CPPDEFINES':   ['V8_TARGET_ARCH_ARM']
     },
+    'simulator:arm': {
+      'CCFLAGS':      ['-m32'],
+      'LINKFLAGS':    ['-m32']
+    },
     'arch:x64': {
-      'CCFLAGS':      ['-fno-strict-aliasing'],
-      'CPPDEFINES':   ['V8_TARGET_ARCH_X64']
+      'CPPDEFINES':   ['V8_TARGET_ARCH_X64'],
+      'CCFLAGS':      ['-fno-strict-aliasing', '-m64'],
+      'LINKFLAGS':    ['-m64'],
     },
     'prof:oprofile': {
       'CPPDEFINES':   ['ENABLE_OPROFILE_AGENT']
@@ -341,22 +332,6 @@ CCTEST_EXTRA_FLAGS = {
         'CPPDEFINES': ['SK_RELEASE', 'NDEBUG']
       }
     },
-    'wordsize:32': {
-      'arch:x64': {
-        'CCFLAGS':      ['-m64'],
-        'LINKFLAGS':    ['-m64']
-      }
-    },
-    'wordsize:64': {
-      'arch:ia32': {
-        'CCFLAGS':      ['-m32'],
-        'LINKFLAGS':    ['-m32']
-      },
-      'arch:arm': {
-        'CCFLAGS':      ['-m32'],
-        'LINKFLAGS':    ['-m32']
-      }
-    }
   },
   'msvc': {
     'all': {
@@ -408,21 +383,17 @@ SAMPLE_FLAGS = {
         'CPPDEFINES': ['SK_RELEASE', 'NDEBUG']
       }
     },
-    'wordsize:32': {
-      'arch:x64': {
-        'CCFLAGS':      ['-m64'],
-        'LINKFLAGS':    ['-m64']
-      }
+    'arch:ia32': {
+      'CCFLAGS':      ['-m32'],
+      'LINKFLAGS':    ['-m32']
     },
-    'wordsize:64': {
-      'arch:ia32': {
-        'CCFLAGS':      ['-m32'],
-        'LINKFLAGS':    ['-m32']
-      },
-      'arch:arm': {
-        'CCFLAGS':      ['-m32'],
-        'LINKFLAGS':    ['-m32']
-      }
+    'arch:x64': {
+      'CCFLAGS':      ['-m64'],
+      'LINKFLAGS':    ['-m64']
+    },
+    'simulator:arm': {
+      'CCFLAGS':      ['-m32'],
+      'LINKFLAGS':    ['-m32']
     },
     'mode:release': {
       'CCFLAGS':      ['-O2']
@@ -533,7 +504,6 @@ def GuessToolchain(os):
 OS_GUESS = utils.GuessOS()
 TOOLCHAIN_GUESS = GuessToolchain(OS_GUESS)
 ARCH_GUESS = utils.GuessArchitecture()
-WORDSIZE_GUESS = utils.GuessWordsize()
 
 
 SIMPLE_OPTIONS = {
@@ -587,11 +557,6 @@ SIMPLE_OPTIONS = {
     'default': 'on',
     'help': 'use Microsoft Visual C++ link-time code generation'
   },
-  'wordsize': {
-    'values': ['64', '32'],
-    'default': WORDSIZE_GUESS,
-    'help': 'the word size'
-  },
   'simulator': {
     'values': ['arm', 'none'],
     'default': 'none',
old mode 100755 (executable)
new mode 100644 (file)
index 050764e..ef2c186
@@ -55,9 +55,35 @@ function Run() {
                              NotifyScore: AddScore }); 
 }
 
+function ShowWarningIfObsolete() {
+  // If anything goes wrong we will just catch the exception and no 
+  // warning is shown, i.e., no harm is done.
+  try {
+    var xmlhttp;
+    var next_version = parseInt(BenchmarkSuite.version) + 1; 
+    var next_version_url = "../v" + next_version + "/run.html";  
+    if (window.XMLHttpRequest) {
+      xmlhttp = new window.XMLHttpRequest();
+    } else if (window.ActiveXObject) {
+      xmlhttp = new window.ActiveXObject("Microsoft.XMLHTTP");
+    }
+    xmlhttp.open('GET', next_version_url, true);
+    xmlhttp.onreadystatechange = function() {
+      if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
+        document.getElementById('obsolete').style.display="block";
+      }
+    };
+    xmlhttp.send(null);
+  } catch(e) {
+    // Ignore exception if check for next version fails. 
+    // Hence no warning is displayed.
+  }
+}
+
 function Load() {
   var version = BenchmarkSuite.version;
   document.getElementById("version").innerHTML = version;
+  ShowWarningIfObsolete();  
   setTimeout(Run, 200);
 }
 </script>
@@ -65,6 +91,12 @@ function Load() {
 <body onload="Load()">
 <div>
   <div class="title"><h1>V8 Benchmark Suite - version <span id="version">?</span></h1></div>
+  <div class="warning" id="obsolete"> 
+Warning! This is not the latest version of the V8 benchmark
+suite. Consider running the   
+<a href="http://v8.googlecode.com/svn/data/benchmarks/current/run.html">
+latest version</a>.  
+  </div>
   <table>
     <tr>
       <td class="contents">
old mode 100755 (executable)
new mode 100644 (file)
index 46320c1..d9f4dbf
@@ -55,6 +55,15 @@ div.run {
   border: 1px solid rgb(51, 102, 204);
 }
 
+div.warning { 
+  background: #ffffd9;
+  border: 1px solid #d2d26a;
+  display: none;
+  margin: 1em 0 2em;
+  padding: 8px;
+  text-align: center; 
+}
+
 #status {
   text-align: center;
   margin-top: 50px;
index 8f22c81..cf8a3bf 100644 (file)
@@ -180,7 +180,7 @@ template <class T> class V8EXPORT_INLINE Handle {
   /**
    * Creates an empty handle.
    */
-  Handle();
+  inline Handle();
 
   /**
    * Creates a new handle for the specified value.
@@ -264,7 +264,7 @@ template <class T> class V8EXPORT_INLINE Handle {
  */
 template <class T> class V8EXPORT_INLINE Local : public Handle<T> {
  public:
-  Local();
+  inline Local();
   template <class S> inline Local(Local<S> that)
       : Handle<T>(reinterpret_cast<T*>(*that)) {
     /**
@@ -284,7 +284,7 @@ template <class T> class V8EXPORT_INLINE Local : public Handle<T> {
    *  The referee is kept alive by the local handle even when
    *  the original handle is destroyed/disposed.
    */
-  static Local<T> New(Handle<T> that);
+  inline static Local<T> New(Handle<T> that);
 };
 
 
@@ -312,7 +312,7 @@ template <class T> class V8EXPORT_INLINE Persistent : public Handle<T> {
    * Creates an empty persistent handle that doesn't point to any
    * storage cell.
    */
-  Persistent();
+  inline Persistent();
 
   /**
    * Creates a persistent handle for the same storage cell as the
@@ -353,7 +353,7 @@ template <class T> class V8EXPORT_INLINE Persistent : public Handle<T> {
    * Creates a new persistent handle for an existing local or
    * persistent handle.
    */
-  static Persistent<T> New(Handle<T> that);
+  inline static Persistent<T> New(Handle<T> that);
 
   /**
    * Releases the storage cell referenced by this persistent handle.
@@ -361,7 +361,7 @@ template <class T> class V8EXPORT_INLINE Persistent : public Handle<T> {
    * This handle's reference, and any any other references to the storage
    * cell remain and IsEmpty will still return false.
    */
-  void Dispose();
+  inline void Dispose();
 
   /**
    * Make the reference to this object weak.  When only weak handles
@@ -369,20 +369,20 @@ template <class T> class V8EXPORT_INLINE Persistent : public Handle<T> {
    * callback to the given V8::WeakReferenceCallback function, passing
    * it the object reference and the given parameters.
    */
-  void MakeWeak(void* parameters, WeakReferenceCallback callback);
+  inline void MakeWeak(void* parameters, WeakReferenceCallback callback);
 
   /** Clears the weak reference to this object.*/
-  void ClearWeak();
+  inline void ClearWeak();
 
   /**
    *Checks if the handle holds the only reference to an object.
    */
-  bool IsNearDeath() const;
+  inline bool IsNearDeath() const;
 
   /**
    * Returns true if the handle's reference is weak.
    */
-  bool IsWeak() const;
+  inline bool IsWeak() const;
 
  private:
   friend class ImplementationUtilities;
@@ -1113,6 +1113,13 @@ class V8EXPORT Object : public Value {
   /** Sets the value in an internal field. */
   void SetInternalField(int index, Handle<Value> value);
 
+  // The two functions below do not perform index bounds checks and
+  // they do not check that the VM is still running. Use with caution.
+  /** Gets a native pointer from an internal field. */
+  void* GetPointerFromInternalField(int index);
+  /** Sets a native pointer in an internal field. */
+  void SetPointerInInternalField(int index, void* value);
+
   // Testers for local properties.
   bool HasRealNamedProperty(Handle<String> key);
   bool HasRealIndexedProperty(uint32_t index);
index f1ca875..f9f9634 100755 (executable)
@@ -40,7 +40,7 @@ SOURCES = {
     'codegen.cc', 'compilation-cache.cc', 'compiler.cc', 'contexts.cc',
     'conversions.cc', 'counters.cc', 'dateparser.cc', 'debug.cc',
     'debug-agent.cc', 'disassembler.cc', 'execution.cc', 'factory.cc',
-    'flags.cc', 'frames.cc', 'func-name-inferrer.cc',
+    'flags.cc', 'frame-element.cc', 'frames.cc', 'func-name-inferrer.cc',
     'global-handles.cc', 'handles.cc', 'hashmap.cc',
     'heap.cc', 'ic.cc', 'interpreter-irregexp.cc', 'jsregexp.cc',
     'jump-target.cc', 'log.cc', 'log-utils.cc', 'mark-compact.cc', 'messages.cc',
index 3eab87a..9e3ca9b 100644 (file)
@@ -2465,6 +2465,44 @@ void v8::Object::SetInternalField(int index, v8::Handle<Value> value) {
 }
 
 
+void* v8::Object::GetPointerFromInternalField(int index) {
+  i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
+  i::Object* pointer = obj->GetInternalField(index);
+  if (pointer->IsSmi()) {
+    // Fast case, aligned native pointer.
+    return pointer;
+  }
+
+  // Read from uninitialized field.
+  if (!pointer->IsProxy()) {
+    // Play safe even if it's something unexpected.
+    ASSERT(pointer->IsUndefined());
+    return NULL;
+  }
+
+  // Unaligned native pointer.
+  return reinterpret_cast<void*>(i::Proxy::cast(pointer)->proxy());
+}
+
+
+void v8::Object::SetPointerInInternalField(int index, void* value) {
+  i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
+  i::Object* as_object = reinterpret_cast<i::Object*>(value);
+  if (as_object->IsSmi()) {
+    // Aligned pointer, store as is.
+    obj->SetInternalField(index, as_object);
+  } else {
+    // Currently internal fields are used by DOM wrappers which only
+    // get garbage collected by the mark-sweep collector, so we
+    // pretenure the proxy.
+    HandleScope scope;
+    i::Handle<i::Proxy> proxy =
+        i::Factory::NewProxy(reinterpret_cast<i::Address>(value), i::TENURED);
+    if (!proxy.is_null()) obj->SetInternalField(index, *proxy);
+  }
+}
+
+
 // --- E n v i r o n m e n t ---
 
 bool v8::V8::Initialize() {
@@ -2516,13 +2554,8 @@ Persistent<Context> v8::Context::New(
   i::Handle<i::Context> env;
   {
     ENTER_V8;
-#if defined(ANDROID)
-    // Avoid exact work when creating new context. Android has its
-    // own onLowMemory notification.
-#else
     // Give the heap a chance to cleanup if we've disposed contexts.
     i::Heap::CollectAllGarbageIfContextDisposed();
-#endif
 
     v8::Handle<ObjectTemplate> proxy_template = global_template;
     i::Handle<i::FunctionTemplateInfo> proxy_constructor;
index 3f7ccf5..5f8149e 100644 (file)
@@ -2897,7 +2897,7 @@ void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) {
     __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset));
 
     // Write to the indexed properties array.
-    int offset = i * kPointerSize + Array::kHeaderSize;
+    int offset = i * kPointerSize + FixedArray::kHeaderSize;
     __ str(r0, FieldMemOperand(r1, offset));
 
     // Update the write barrier for the array address.
@@ -3737,7 +3737,8 @@ void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
     }
     frame_->EmitPush(r0);  // r0 has result
   }
-  ASSERT((has_cc() && frame_->height() == original_height) ||
+  ASSERT(!has_valid_frame() ||
+         (has_cc() && frame_->height() == original_height) ||
          (!has_cc() && frame_->height() == original_height + 1));
 }
 
@@ -3871,22 +3872,12 @@ void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
                           &is_true,
                           false_target(),
                           false);
-    if (has_cc()) {
-      Branch(false, false_target());
-
-      // Evaluate right side expression.
-      is_true.Bind();
-      LoadConditionAndSpill(node->right(),
-                            NOT_INSIDE_TYPEOF,
-                            true_target(),
-                            false_target(),
-                            false);
-
-    } else {
+    if (has_valid_frame() && !has_cc()) {
+      // The left-hand side result is on top of the virtual frame.
       JumpTarget pop_and_continue;
       JumpTarget exit;
 
-      __ ldr(r0, frame_->Top());  // dup the stack top
+      __ ldr(r0, frame_->Top());  // Duplicate the stack top.
       frame_->EmitPush(r0);
       // Avoid popping the result if it converts to 'false' using the
       // standard ToBoolean() conversion as described in ECMA-262,
@@ -3904,6 +3895,22 @@ void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
 
       // Exit (always with a materialized value).
       exit.Bind();
+    } else if (has_cc() || is_true.is_linked()) {
+      // The left-hand side is either (a) partially compiled to
+      // control flow with a final branch left to emit or (b) fully
+      // compiled to control flow and possibly true.
+      if (has_cc()) {
+        Branch(false, false_target());
+      }
+      is_true.Bind();
+      LoadConditionAndSpill(node->right(),
+                            NOT_INSIDE_TYPEOF,
+                            true_target(),
+                            false_target(),
+                            false);
+    } else {
+      // Nothing to do.
+      ASSERT(!has_valid_frame() && !has_cc() && !is_true.is_linked());
     }
 
   } else if (op == Token::OR) {
@@ -3913,18 +3920,8 @@ void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
                           true_target(),
                           &is_false,
                           false);
-    if (has_cc()) {
-      Branch(true, true_target());
-
-      // Evaluate right side expression.
-      is_false.Bind();
-      LoadConditionAndSpill(node->right(),
-                            NOT_INSIDE_TYPEOF,
-                            true_target(),
-                            false_target(),
-                            false);
-
-    } else {
+    if (has_valid_frame() && !has_cc()) {
+      // The left-hand side result is on top of the virtual frame.
       JumpTarget pop_and_continue;
       JumpTarget exit;
 
@@ -3946,6 +3943,22 @@ void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
 
       // Exit (always with a materialized value).
       exit.Bind();
+    } else if (has_cc() || is_false.is_linked()) {
+      // The left-hand side is either (a) partially compiled to
+      // control flow with a final branch left to emit or (b) fully
+      // compiled to control flow and possibly false.
+      if (has_cc()) {
+        Branch(true, true_target());
+      }
+      is_false.Bind();
+      LoadConditionAndSpill(node->right(),
+                            NOT_INSIDE_TYPEOF,
+                            true_target(),
+                            false_target(),
+                            false);
+    } else {
+      // Nothing to do.
+      ASSERT(!has_valid_frame() && !has_cc() && !is_false.is_linked());
     }
 
   } else {
@@ -3989,7 +4002,8 @@ void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
     }
     frame_->EmitPush(r0);
   }
-  ASSERT((has_cc() && frame_->height() == original_height) ||
+  ASSERT(!has_valid_frame() ||
+         (has_cc() && frame_->height() == original_height) ||
          (!has_cc() && frame_->height() == original_height + 1));
 }
 
index b436760..82a2bec 100644 (file)
@@ -91,14 +91,14 @@ static void GenerateDictionaryLoad(MacroAssembler* masm,
   __ b(ne, miss);
 
   // Compute the capacity mask.
-  const int kCapacityOffset =
-      Array::kHeaderSize + StringDictionary::kCapacityIndex * kPointerSize;
+  const int kCapacityOffset = StringDictionary::kHeaderSize +
+      StringDictionary::kCapacityIndex * kPointerSize;
   __ ldr(r3, FieldMemOperand(t0, kCapacityOffset));
   __ mov(r3, Operand(r3, ASR, kSmiTagSize));  // convert smi to int
   __ sub(r3, r3, Operand(1));
 
-  const int kElementsStartOffset =
-      Array::kHeaderSize + StringDictionary::kElementsStartIndex * kPointerSize;
+  const int kElementsStartOffset = StringDictionary::kHeaderSize +
+      StringDictionary::kElementsStartIndex * kPointerSize;
 
   // Generate an unrolled loop that performs a few probes before
   // giving up. Measurements done on Gmail indicate that 2 probes
@@ -599,7 +599,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
 
   // Fast case: Do the load.
   __ bind(&fast);
-  __ add(r3, r1, Operand(Array::kHeaderSize - kHeapObjectTag));
+  __ add(r3, r1, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
   __ ldr(r0, MemOperand(r3, r0, LSL, kPointerSizeLog2));
   __ cmp(r0, Operand(Factory::the_hole_value()));
   // In case the loaded value is the_hole we have to consult GetProperty
@@ -666,9 +666,9 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
   // Untag the key (for checking against untagged length in the fixed array).
   __ mov(r1, Operand(r1, ASR, kSmiTagSize));
   // Compute address to store into and check array bounds.
-  __ add(r2, r3, Operand(Array::kHeaderSize - kHeapObjectTag));
+  __ add(r2, r3, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
   __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2));
-  __ ldr(ip, FieldMemOperand(r3, Array::kLengthOffset));
+  __ ldr(ip, FieldMemOperand(r3, FixedArray::kLengthOffset));
   __ cmp(r1, Operand(ip));
   __ b(lo, &fast);
 
@@ -696,7 +696,7 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
   __ mov(r3, Operand(r2));
   // NOTE: Computing the address to store into must take the fact
   // that the key has been incremented into account.
-  int displacement = Array::kHeaderSize - kHeapObjectTag -
+  int displacement = FixedArray::kHeaderSize - kHeapObjectTag -
       ((1 << kSmiTagSize) * 2);
   __ add(r2, r2, Operand(displacement));
   __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize));
@@ -721,7 +721,7 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
   __ cmp(r1, Operand(ip));
   __ b(hs, &extra);
   __ mov(r3, Operand(r2));
-  __ add(r2, r2, Operand(Array::kHeaderSize - kHeapObjectTag));
+  __ add(r2, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
   __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize));
 
 
index 47e2749..875c91e 100644 (file)
@@ -226,7 +226,7 @@ void MacroAssembler::RecordWrite(Register object, Register offset,
   // Add the page header (including remembered set), array header, and array
   // body size to the page address.
   add(object, object, Operand(Page::kObjectStartOffset
-                              + Array::kHeaderSize));
+                              + FixedArray::kHeaderSize));
   add(object, object, Operand(scratch));
 
   bind(&fast);
index d98818f..4691f29 100644 (file)
@@ -60,7 +60,7 @@ bool RegisterAllocator::IsReserved(Register reg) {
 
 int RegisterAllocator::ToNumber(Register reg) {
   ASSERT(reg.is_valid() && !IsReserved(reg));
-  static int numbers[] = {
+  const int kNumbers[] = {
     0,   // r0
     1,   // r1
     2,   // r2
@@ -78,15 +78,15 @@ int RegisterAllocator::ToNumber(Register reg) {
     11,  // lr
     -1   // pc
   };
-  return numbers[reg.code()];
+  return kNumbers[reg.code()];
 }
 
 
 Register RegisterAllocator::ToRegister(int num) {
   ASSERT(num >= 0 && num < kNumRegisters);
-  static Register registers[] =
+  const Register kRegisters[] =
       { r0, r1, r2, r3, r4, r5, r6, r7, r9, r10, ip, lr };
-  return registers[num];
+  return kRegisters[num];
 }
 
 
index 6d9ace8..d6650c9 100644 (file)
@@ -164,7 +164,7 @@ void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
     __ ldr(dst, FieldMemOperand(src, offset));
   } else {
     // Calculate the offset into the properties array.
-    int offset = index * kPointerSize + Array::kHeaderSize;
+    int offset = index * kPointerSize + FixedArray::kHeaderSize;
     __ ldr(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
     __ ldr(dst, FieldMemOperand(dst, offset));
   }
@@ -330,7 +330,7 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
     __ RecordWrite(receiver_reg, name_reg, scratch);
   } else {
     // Write to the properties array.
-    int offset = index * kPointerSize + Array::kHeaderSize;
+    int offset = index * kPointerSize + FixedArray::kHeaderSize;
     // Get the properties array
     __ ldr(scratch, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
     __ str(r0, FieldMemOperand(scratch, offset));
@@ -1121,8 +1121,6 @@ Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
 }
 
 
-// TODO(1224671): IC stubs for keyed loads have not been implemented
-// for ARM.
 Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
                                                 JSObject* receiver,
                                                 JSObject* holder,
index ad5396e..a2c4562 100644 (file)
@@ -47,14 +47,10 @@ namespace internal {
 // generate an index for each native JS file.
 class SourceCodeCache BASE_EMBEDDED {
  public:
-  explicit SourceCodeCache(Script::Type type): type_(type) { }
+  explicit SourceCodeCache(Script::Type type): type_(type), cache_(NULL) { }
 
   void Initialize(bool create_heap_objects) {
-    if (create_heap_objects) {
-      cache_ = Heap::empty_fixed_array();
-    } else {
-      cache_ = NULL;
-    }
+    cache_ = create_heap_objects ? Heap::empty_fixed_array() : NULL;
   }
 
   void Iterate(ObjectVisitor* v) {
@@ -1107,12 +1103,6 @@ bool Genesis::InstallNatives() {
     global_context()->set_empty_script(*script);
   }
 
-#ifdef V8_HOST_ARCH_64_BIT
-  // TODO(X64): Remove this when inline caches work.
-  FLAG_use_ic = false;
-#endif  // V8_HOST_ARCH_64_BIT
-
-
   if (FLAG_natives_file == NULL) {
     // Without natives file, install default natives.
     for (int i = Natives::GetDelayCount();
index 64af075..ec5b39c 100644 (file)
@@ -63,6 +63,8 @@ class CompilationSubCache {
     tables_ = NewArray<Object*>(generations);
   }
 
+  ~CompilationSubCache() { DeleteArray(tables_); }
+
   // Get the compilation cache tables for a specific generation.
   Handle<CompilationCacheTable> GetTable(int generation);
 
index 52be930..64f98c7 100644 (file)
@@ -334,8 +334,11 @@ void BreakLocationIterator::PrepareStepIn() {
       rinfo()->set_target_address(stub->entry());
     }
   } else {
-    // Step in through constructs call requires no changes to the running code.
-    ASSERT(RelocInfo::IsConstructCall(rmode()));
+    // Step in through construct call requires no changes to the running code.
+    // Step in through getters/setters should already be prepared as well
+    // because caller of this function (Debug::PrepareStep) is expected to
+    // flood the top frame's function with one shot breakpoints.
+    ASSERT(RelocInfo::IsConstructCall(rmode()) || code->is_inline_cache_stub());
   }
 }
 
@@ -1087,10 +1090,18 @@ void Debug::PrepareStep(StepAction step_action, int step_count) {
 
   // Compute whether or not the target is a call target.
   bool is_call_target = false;
+  bool is_load_or_store = false;
+  bool is_inline_cache_stub = false;
   if (RelocInfo::IsCodeTarget(it.rinfo()->rmode())) {
     Address target = it.rinfo()->target_address();
     Code* code = Code::GetCodeFromTargetAddress(target);
-    if (code->is_call_stub()) is_call_target = true;
+    if (code->is_call_stub()) {
+      is_call_target = true;
+    }
+    if (code->is_inline_cache_stub()) {
+      is_inline_cache_stub = true;
+      is_load_or_store = !is_call_target;
+    }
   }
 
   // If this is the last break code target step out is the only possibility.
@@ -1103,8 +1114,8 @@ void Debug::PrepareStep(StepAction step_action, int step_count) {
       JSFunction* function = JSFunction::cast(frames_it.frame()->function());
       FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
     }
-  } else if (!(is_call_target || RelocInfo::IsConstructCall(it.rmode())) ||
-             step_action == StepNext || step_action == StepMin) {
+  } else if (!(is_inline_cache_stub || RelocInfo::IsConstructCall(it.rmode()))
+             || step_action == StepNext || step_action == StepMin) {
     // Step next or step min.
 
     // Fill the current function with one-shot break points.
@@ -1117,9 +1128,20 @@ void Debug::PrepareStep(StepAction step_action, int step_count) {
   } else {
     // Fill the current function with one-shot break points even for step in on
     // a call target as the function called might be a native function for
-    // which step in will not stop.
+    // which step in will not stop. It also prepares for stepping in
+    // getters/setters.
     FloodWithOneShot(shared);
 
+    if (is_load_or_store) {
+      // Remember source position and frame to handle step in getter/setter. If
+      // there is a custom getter/setter it will be handled in
+      // Object::Get/SetPropertyWithCallback, otherwise the step action will be
+      // propagated on the next Debug::Break.
+      thread_local_.last_statement_position_ =
+          debug_info->code()->SourceStatementPosition(frame->pc());
+      thread_local_.last_fp_ = frame->fp();
+    }
+
     // Step in or Step in min
     it.PrepareStepIn();
     ActivateStepIn(frame);
index adc1872..40a9b4f 100644 (file)
@@ -164,19 +164,16 @@ Handle<Object> Execution::GetFunctionDelegate(Handle<Object> object) {
   // If you return a function from here, it will be called when an
   // attempt is made to call the given object as a function.
 
-  // The regular expression code here is really meant more as an
-  // example than anything else. KJS does not support calling regular
-  // expressions as functions, but SpiderMonkey does.
-  if (FLAG_call_regexp) {
-    bool is_regexp =
-        object->IsHeapObject() &&
-        (HeapObject::cast(*object)->map()->constructor() ==
-         *Top::regexp_function());
-
-    if (is_regexp) {
-      Handle<String> exec = Factory::exec_symbol();
-      return Handle<Object>(object->GetProperty(*exec));
-    }
+  // Regular expressions can be called as functions in both Firefox
+  // and Safari so we allow it too.
+  bool is_regexp =
+      object->IsHeapObject() &&
+      (HeapObject::cast(*object)->map()->constructor() ==
+       *Top::regexp_function());
+
+  if (is_regexp) {
+    Handle<String> exec = Factory::exec_symbol();
+    return Handle<Object>(object->GetProperty(*exec));
   }
 
   // Objects created through the API can have an instance-call handler
index 4e7829b..b0770b0 100644 (file)
@@ -144,9 +144,6 @@ DEFINE_bool(debugger_auto_break, false,
             "automatically set the debug break flag when debugger commands are "
             "in the queue (experimental)")
 
-// execution.cc
-DEFINE_bool(call_regexp, false, "allow calls to RegExp objects")
-
 // frames.cc
 DEFINE_int(max_stack_trace_source_length, 300,
            "maximum length of function source code printed in a stack trace.")
diff --git a/V8Binding/v8/src/frame-element.cc b/V8Binding/v8/src/frame-element.cc
new file mode 100644 (file)
index 0000000..e6bc2ea
--- /dev/null
@@ -0,0 +1,45 @@
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "frame-element.h"
+
+namespace v8 {
+namespace internal {
+
+// -------------------------------------------------------------------------
+// FrameElement implementation.
+
+
+FrameElement::ZoneObjectList* FrameElement::ConstantList() {
+  static ZoneObjectList list(10);
+  return &list;
+}
+
+
+} }  // namespace v8::internal
index 666aabb..ccdecf1 100644 (file)
@@ -91,10 +91,7 @@ class FrameElement BASE_EMBEDDED {
   // this table of handles to the actual constants.
   typedef ZoneList<Handle<Object> > ZoneObjectList;
 
-  static ZoneObjectList* ConstantList() {
-    static ZoneObjectList list(10);
-    return &list;
-  }
+  static ZoneObjectList* ConstantList();
 
   // Clear the constants indirection table.
   static void ClearConstantList() {
index b717312..3c4e5cd 100644 (file)
@@ -194,7 +194,10 @@ HashMap::Entry* HashMap::Probe(void* key, uint32_t hash) {
 void HashMap::Initialize(uint32_t capacity) {
   ASSERT(IsPowerOf2(capacity));
   map_ = reinterpret_cast<Entry*>(allocator_->New(capacity * sizeof(Entry)));
-  if (map_ == NULL) V8::FatalProcessOutOfMemory("HashMap::Initialize");
+  if (map_ == NULL) {
+    V8::FatalProcessOutOfMemory("HashMap::Initialize");
+    return;
+  }
   capacity_ = capacity;
   Clear();
 }
index 36c6f4b..d27f14f 100644 (file)
@@ -228,6 +228,31 @@ void Heap::ScavengeObject(HeapObject** p, HeapObject* object) {
 }
 
 
+int Heap::AdjustAmountOfExternalAllocatedMemory(int change_in_bytes) {
+  ASSERT(HasBeenSetup());
+  int amount = amount_of_external_allocated_memory_ + change_in_bytes;
+  if (change_in_bytes >= 0) {
+    // Avoid overflow.
+    if (amount > amount_of_external_allocated_memory_) {
+      amount_of_external_allocated_memory_ = amount;
+    }
+    int amount_since_last_global_gc =
+        amount_of_external_allocated_memory_ -
+        amount_of_external_allocated_memory_at_last_global_gc_;
+    if (amount_since_last_global_gc > external_allocation_limit_) {
+      CollectAllGarbage();
+    }
+  } else {
+    // Avoid underflow.
+    if (amount >= 0) {
+      amount_of_external_allocated_memory_ = amount;
+    }
+  }
+  ASSERT(amount_of_external_allocated_memory_ >= 0);
+  return amount_of_external_allocated_memory_;
+}
+
+
 void Heap::SetLastScriptId(Object* last_script_id) {
   roots_[kLastScriptIdRootIndex] = last_script_id;
 }
index 64059b1..213eec5 100644 (file)
@@ -56,13 +56,8 @@ MapSpace* Heap::map_space_ = NULL;
 CellSpace* Heap::cell_space_ = NULL;
 LargeObjectSpace* Heap::lo_space_ = NULL;
 
-#if defined(ANDROID)
-static const int kMinimumPromotionLimit = 1*MB;
-static const int kMinimumAllocationLimit = 2*MB;
-#else
 static const int kMinimumPromotionLimit = 2*MB;
 static const int kMinimumAllocationLimit = 8*MB;
-#endif
 
 int Heap::old_gen_promotion_limit_ = kMinimumPromotionLimit;
 int Heap::old_gen_allocation_limit_ = kMinimumAllocationLimit;
@@ -90,8 +85,8 @@ GCCallback Heap::global_gc_epilogue_callback_ = NULL;
 // Variables set based on semispace_size_ and old_generation_size_ in
 // ConfigureHeap.
 int Heap::young_generation_size_ = 0;  // Will be 2 * semispace_size_.
-
 int Heap::survived_since_last_expansion_ = 0;
+int Heap::external_allocation_limit_ = 0;
 
 Heap::HeapState Heap::gc_state_ = NOT_IN_GC;
 
@@ -1192,7 +1187,7 @@ bool Heap::CreateInitialMaps() {
   set_undetectable_long_ascii_string_map(Map::cast(obj));
   Map::cast(obj)->set_is_undetectable();
 
-  obj = AllocateMap(BYTE_ARRAY_TYPE, Array::kAlignedSize);
+  obj = AllocateMap(BYTE_ARRAY_TYPE, ByteArray::kAlignedSize);
   if (obj->IsFailure()) return false;
   set_byte_array_map(Map::cast(obj));
 
@@ -2993,6 +2988,7 @@ bool Heap::ConfigureHeap(int semispace_size, int old_gen_size) {
   semispace_size_ = RoundUpToPowerOf2(semispace_size_);
   initial_semispace_size_ = Min(initial_semispace_size_, semispace_size_);
   young_generation_size_ = 2 * semispace_size_;
+  external_allocation_limit_ = 10 * semispace_size_;
 
   // The old generation is paged.
   old_generation_size_ = RoundUp(old_generation_size_, Page::kPageSize);
@@ -3411,6 +3407,8 @@ void HeapProfiler::CollectStats(HeapObject* obj, HistogramInfo* info) {
 #ifdef ENABLE_LOGGING_AND_PROFILING
 void HeapProfiler::WriteSample() {
   LOG(HeapSampleBeginEvent("Heap", "allocated"));
+  LOG(HeapSampleStats(
+      "Heap", "allocated", Heap::Capacity(), Heap::SizeOfObjects()));
 
   HistogramInfo info[LAST_TYPE+1];
 #define DEF_TYPE_NAME(name) info[name].set_name(#name);
index 55a66bc..4e2c64c 100644 (file)
@@ -746,7 +746,7 @@ class Heap : public AllStatic {
   static Object* CreateSymbol(String* str);
 
   // Write barrier support for address[offset] = o.
-  inline static void RecordWrite(Address address, int offset);
+  static inline void RecordWrite(Address address, int offset);
 
   // Given an address occupied by a live code object, return that object.
   static Object* FindCodeObject(Address a);
@@ -802,22 +802,7 @@ class Heap : public AllStatic {
 
   // Adjusts the amount of registered external memory.
   // Returns the adjusted value.
-  static int AdjustAmountOfExternalAllocatedMemory(int change_in_bytes) {
-    int amount = amount_of_external_allocated_memory_ + change_in_bytes;
-    if (change_in_bytes >= 0) {
-      // Avoid overflow.
-      if (amount > amount_of_external_allocated_memory_) {
-        amount_of_external_allocated_memory_ = amount;
-      }
-    } else {
-      // Avoid underflow.
-      if (amount >= 0) {
-        amount_of_external_allocated_memory_ = amount;
-      }
-    }
-    ASSERT(amount_of_external_allocated_memory_ >= 0);
-    return amount_of_external_allocated_memory_;
-  }
+  static inline int AdjustAmountOfExternalAllocatedMemory(int change_in_bytes);
 
   // Allocate unitialized fixed array (pretenure == NON_TENURE).
   static Object* AllocateRawFixedArray(int length);
@@ -901,6 +886,10 @@ class Heap : public AllStatic {
   // every allocation in large object space.
   static int old_gen_allocation_limit_;
 
+  // Limit on the amount of externally allocated memory allowed
+  // between global GCs. If reached a global GC is forced.
+  static int external_allocation_limit_;
+
   // The amount of external memory registered through the API kept alive
   // by global handles
   static int amount_of_external_allocated_memory_;
@@ -1230,7 +1219,7 @@ class KeyedLookupCache {
   // Clear the cache.
   static void Clear();
  private:
-  inline static int Hash(Map* map, String* name);
+  static inline int Hash(Map* map, String* name);
   static const int kLength = 64;
   struct Key {
     Map* map;
index 6d1dc2d..457b22f 100644 (file)
@@ -3857,7 +3857,7 @@ Result CodeGenerator::LoadFromGlobalSlotCheckExtensions(
     s = s->outer_scope();
   }
 
-  if (s->is_eval_scope()) {
+  if (s != NULL && s->is_eval_scope()) {
     // Loop up the context chain.  There is no frame effect so it is
     // safe to use raw labels here.
     Label next, fast;
@@ -4351,7 +4351,7 @@ void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) {
            FieldOperand(elements.reg(), JSObject::kElementsOffset));
 
     // Write to the indexed properties array.
-    int offset = i * kPointerSize + Array::kHeaderSize;
+    int offset = i * kPointerSize + FixedArray::kHeaderSize;
     __ mov(FieldOperand(elements.reg(), offset), prop_value.reg());
 
     // Update the write barrier for the array address.
@@ -5388,12 +5388,6 @@ void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
   } else {
     Load(node->expression());
     switch (op) {
-      case Token::NOT:
-      case Token::DELETE:
-      case Token::TYPEOF:
-        UNREACHABLE();  // handled above
-        break;
-
       case Token::SUB: {
         bool overwrite =
             (node->AsBinaryOperation() != NULL &&
@@ -5448,6 +5442,8 @@ void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
       }
 
       default:
+        // NOT, DELETE, TYPEOF, and VOID are handled outside the
+        // switch.
         UNREACHABLE();
     }
   }
@@ -6309,7 +6305,7 @@ void Reference::GetValue(TypeofState typeof_state) {
         __ mov(index.reg(), key.reg());
         __ sar(index.reg(), kSmiTagSize);
         __ cmp(index.reg(),
-               FieldOperand(elements.reg(), Array::kLengthOffset));
+               FieldOperand(elements.reg(), FixedArray::kLengthOffset));
         deferred->Branch(above_equal);
 
         // Load and check that the result is not the hole.  We could
@@ -6323,7 +6319,7 @@ void Reference::GetValue(TypeofState typeof_state) {
         __ mov(value.reg(), Operand(elements.reg(),
                                     index.reg(),
                                     times_4,
-                                    Array::kHeaderSize - kHeapObjectTag));
+                                    FixedArray::kHeaderSize - kHeapObjectTag));
         elements.Unuse();
         index.Unuse();
         __ cmp(Operand(value.reg()), Immediate(Factory::the_hole_value()));
@@ -6495,7 +6491,7 @@ void Reference::SetValue(InitState init_state) {
         __ mov(Operand(tmp.reg(),
                        key.reg(),
                        times_2,
-                       Array::kHeaderSize - kHeapObjectTag),
+                       FixedArray::kHeaderSize - kHeapObjectTag),
                value.reg());
         __ IncrementCounter(&Counters::keyed_store_inline, 1);
 
index 90e0fd1..d64dee1 100644 (file)
@@ -43,6 +43,10 @@ namespace internal {
 
 
 // Helper function used to load a property from a dictionary backing storage.
+// This function may return false negatives, so miss_label
+// must always call a backup property load that is complete.
+// This function is safe to call if the receiver has fast properties,
+// or if name is not a symbol, and will jump to the miss_label in that case.
 static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label,
                                    Register r0, Register r1, Register r2,
                                    Register name) {
@@ -56,7 +60,7 @@ static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label,
   //
   // r2   - used to hold the capacity of the property dictionary.
   //
-  // name - holds the name of the property and is unchanges.
+  // name - holds the name of the property and is unchanged.
 
   Label done;
 
@@ -89,7 +93,8 @@ static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label,
 
   // Compute the capacity mask.
   const int kCapacityOffset =
-      Array::kHeaderSize + StringDictionary::kCapacityIndex * kPointerSize;
+      StringDictionary::kHeaderSize +
+      StringDictionary::kCapacityIndex * kPointerSize;
   __ mov(r2, FieldOperand(r0, kCapacityOffset));
   __ shr(r2, kSmiTagSize);  // convert smi to int
   __ dec(r2);
@@ -99,7 +104,8 @@ static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label,
   // cover ~93% of loads from dictionaries.
   static const int kProbes = 4;
   const int kElementsStartOffset =
-      Array::kHeaderSize + StringDictionary::kElementsStartIndex * kPointerSize;
+      StringDictionary::kHeaderSize +
+      StringDictionary::kElementsStartIndex * kPointerSize;
   for (int i = 0; i < kProbes; i++) {
     // Compute the masked index: (hash + i + i * i) & mask.
     __ mov(r1, FieldOperand(name, String::kLengthOffset));
@@ -153,6 +159,9 @@ static void GenerateCheckNonObjectOrLoaded(MacroAssembler* masm, Label* miss,
 }
 
 
+// The offset from the inlined patch site to the start of the
+// inlined load instruction.  It is 7 bytes (test eax, imm) plus
+// 6 bytes (jne slow_label).
 const int LoadIC::kOffsetToLoadInstruction = 13;
 
 
@@ -263,21 +272,28 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
          Immediate(Factory::hash_table_map()));
   __ j(equal, &slow, not_taken);
   // Check that the key (index) is within bounds.
-  __ cmp(eax, FieldOperand(ecx, Array::kLengthOffset));
+  __ cmp(eax, FieldOperand(ecx, FixedArray::kLengthOffset));
   __ j(below, &fast, taken);
   // Slow case: Load name and receiver from stack and jump to runtime.
   __ bind(&slow);
   __ IncrementCounter(&Counters::keyed_load_generic_slow, 1);
   KeyedLoadIC::Generate(masm, ExternalReference(Runtime::kKeyedGetProperty));
-  // Check if the key is a symbol that is not an array index.
+
   __ bind(&check_string);
+  // The key is not a smi.
+  // Is it a string?
+  __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx);
+  __ j(above_equal, &slow);
+  // Is the string an array index, with cached numeric value?
   __ mov(ebx, FieldOperand(eax, String::kLengthOffset));
   __ test(ebx, Immediate(String::kIsArrayIndexMask));
   __ j(not_zero, &index_string, not_taken);
-  __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
-  __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
+
+  // If the string is a symbol, do a quick inline probe of the receiver's
+  // dictionary, if it exists.
+  __ movzx_b(ebx, FieldOperand(edx, Map::kInstanceTypeOffset));
   __ test(ebx, Immediate(kIsSymbolMask));
-  __ j(not_zero, &slow, not_taken);
+  __ j(zero, &slow, not_taken);
   // Probe the dictionary leaving result in ecx.
   GenerateDictionaryLoad(masm, &slow, ebx, ecx, edx, eax);
   GenerateCheckNonObjectOrLoaded(masm, &slow, ecx, edx);
@@ -301,7 +317,8 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
   __ jmp(&index_int);
   // Fast case: Do the load.
   __ bind(&fast);
-  __ mov(eax, Operand(ecx, eax, times_4, Array::kHeaderSize - kHeapObjectTag));
+  __ mov(eax,
+         Operand(ecx, eax, times_4, FixedArray::kHeaderSize - kHeapObjectTag));
   __ cmp(Operand(eax), Immediate(Factory::the_hole_value()));
   // In case the loaded value is the_hole we have to consult GetProperty
   // to ensure the prototype chain is searched.
@@ -419,7 +436,8 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
   // eax: value
   // ecx: FixedArray
   // ebx: index (as a smi)
-  __ mov(Operand(ecx, ebx, times_2, Array::kHeaderSize - kHeapObjectTag), eax);
+  __ mov(Operand(ecx, ebx, times_2, FixedArray::kHeaderSize - kHeapObjectTag),
+         eax);
   // Update write barrier for the elements array address.
   __ mov(edx, Operand(eax));
   __ RecordWrite(ecx, 0, edx, ebx);
index 479b8ca..fae1525 100644 (file)
@@ -79,7 +79,7 @@ static void RecordWriteHelper(MacroAssembler* masm,
   // Add the page header, array header, and array body size to the page
   // address.
   masm->add(Operand(object), Immediate(Page::kObjectStartOffset
-                                       + Array::kHeaderSize));
+                                       + FixedArray::kHeaderSize));
   masm->add(object, Operand(scratch));
 
 
@@ -199,9 +199,10 @@ void MacroAssembler::RecordWrite(Register object, int offset,
       lea(dst, Operand(object, offset));
     } else {
       // array access: calculate the destination address in the same manner as
-      // KeyedStoreIC::GenerateGeneric
-      lea(dst,
-          Operand(object, dst, times_2, Array::kHeaderSize - kHeapObjectTag));
+      // KeyedStoreIC::GenerateGeneric.  Multiply a smi by 2 to get an offset
+      // into an array of words.
+      lea(dst, Operand(object, dst, times_2,
+                       FixedArray::kHeaderSize - kHeapObjectTag));
     }
     // If we are already generating a shared stub, not inlining the
     // record write code isn't going to save us any memory.
index 04a5390..c5d7c05 100644 (file)
@@ -1073,10 +1073,12 @@ int RegExpMacroAssemblerIA32::CaseInsensitiveCompareUC16(Address byte_offset1,
     unibrow::uchar c1 = substring1[i];
     unibrow::uchar c2 = substring2[i];
     if (c1 != c2) {
-      canonicalize.get(c1, '\0', &c1);
-      if (c1 != c2) {
-        canonicalize.get(c2, '\0', &c2);
-        if (c1 != c2) {
+      unibrow::uchar s1[1] = { c1 };
+      canonicalize.get(c1, '\0', s1);
+      if (s1[0] != c2) {
+        unibrow::uchar s2[1] = { c2 };
+        canonicalize.get(c2, '\0', s2);
+        if (s1[0] != s2[0]) {
           return 0;
         }
       }
index ddee472..99ae6eb 100644 (file)
@@ -49,7 +49,7 @@ bool RegisterAllocator::IsReserved(Register reg) {
 
 int RegisterAllocator::ToNumber(Register reg) {
   ASSERT(reg.is_valid() && !IsReserved(reg));
-  static int numbers[] = {
+  const int kNumbers[] = {
     0,   // eax
     2,   // ecx
     3,   // edx
@@ -59,14 +59,14 @@ int RegisterAllocator::ToNumber(Register reg) {
     -1,  // esi
     4    // edi
   };
-  return numbers[reg.code()];
+  return kNumbers[reg.code()];
 }
 
 
 Register RegisterAllocator::ToRegister(int num) {
   ASSERT(num >= 0 && num < kNumRegisters);
-  static Register registers[] = { eax, ebx, ecx, edx, edi };
-  return registers[num];
+  const Register kRegisters[] = { eax, ebx, ecx, edx, edi };
+  return kRegisters[num];
 }
 
 
index 0a887d5..e47ad1c 100644 (file)
@@ -266,15 +266,13 @@ void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
     __ mov(dst, FieldOperand(src, offset));
   } else {
     // Calculate the offset into the properties array.
-    int offset = index * kPointerSize + Array::kHeaderSize;
+    int offset = index * kPointerSize + FixedArray::kHeaderSize;
     __ mov(dst, FieldOperand(src, JSObject::kPropertiesOffset));
     __ mov(dst, FieldOperand(dst, offset));
   }
 }
 
 
-
-
 void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
   ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
   Code* code = NULL;
@@ -349,7 +347,7 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
     __ RecordWrite(receiver_reg, offset, name_reg, scratch);
   } else {
     // Write to the properties array.
-    int offset = index * kPointerSize + Array::kHeaderSize;
+    int offset = index * kPointerSize + FixedArray::kHeaderSize;
     // Get the properties array (optimistically).
     __ mov(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
     __ mov(FieldOperand(scratch, offset), eax);
index 7e82295..090d7a3 100644 (file)
@@ -273,28 +273,39 @@ static bool HasInterceptorGetter(JSObject* object) {
 static void LookupForRead(Object* object,
                           String* name,
                           LookupResult* lookup) {
-  object->Lookup(name, lookup);
-  if (lookup->IsNotFound() || lookup->type() != INTERCEPTOR) {
-    return;
-  }
+  AssertNoAllocation no_gc;  // pointers must stay valid
+
+  // Skip all the objects with named interceptors, but
+  // without actual getter.
+  while (true) {
+    object->Lookup(name, lookup);
+    // Besides normal conditions (property not found or it's not
+    // an interceptor), bail out of lookup is not cacheable: we won't
+    // be able to IC it anyway and regular lookup should work fine.
+    if (lookup->IsNotFound() || lookup->type() != INTERCEPTOR ||
+        !lookup->IsCacheable()) {
+      return;
+    }
 
-  JSObject* holder = lookup->holder();
-  if (HasInterceptorGetter(holder)) {
-    return;
-  }
+    JSObject* holder = lookup->holder();
+    if (HasInterceptorGetter(holder)) {
+      return;
+    }
 
-  // There is no getter, just skip it and lookup down the proto chain
-  holder->LocalLookupRealNamedProperty(name, lookup);
-  if (lookup->IsValid()) {
-    return;
-  }
+    holder->LocalLookupRealNamedProperty(name, lookup);
+    if (lookup->IsValid()) {
+      ASSERT(lookup->type() != INTERCEPTOR);
+      return;
+    }
 
-  Object* proto = holder->GetPrototype();
-  if (proto == Heap::null_value()) {
-    return;
-  }
+    Object* proto = holder->GetPrototype();
+    if (proto->IsNull()) {
+      lookup->NotFound();
+      return;
+    }
 
-  LookupForRead(proto, name, lookup);
+    object = proto;
+  }
 }
 
 
@@ -726,7 +737,9 @@ Object* KeyedLoadIC::Load(State state,
       return TypeError("non_object_property_load", object, name);
     }
 
-    if (FLAG_use_ic) {
+    // TODO(X64): Enable specialized stubs for length and prototype lookup.
+#ifndef V8_TARGET_ARCH_X64
+    if (false && FLAG_use_ic) {
       // Use specialized code for getting the length of strings.
       if (object->IsString() && name->Equals(Heap::length_symbol())) {
         Handle<String> string = Handle<String>::cast(object);
@@ -736,7 +749,7 @@ Object* KeyedLoadIC::Load(State state,
         set_target(Code::cast(code));
 #ifdef DEBUG
         TraceIC("KeyedLoadIC", name, state, target());
-#endif
+#endif  // DEBUG
         return Smi::FromInt(string->length());
       }
 
@@ -748,7 +761,7 @@ Object* KeyedLoadIC::Load(State state,
         set_target(Code::cast(code));
 #ifdef DEBUG
         TraceIC("KeyedLoadIC", name, state, target());
-#endif
+#endif  // DEBUG
         return JSArray::cast(*object)->length();
       }
 
@@ -761,10 +774,11 @@ Object* KeyedLoadIC::Load(State state,
         set_target(Code::cast(code));
 #ifdef DEBUG
         TraceIC("KeyedLoadIC", name, state, target());
-#endif
+#endif  // DEBUG
         return Accessors::FunctionGetPrototype(*object, 0);
       }
     }
+#endif  // !V8_TARGET_ARCH_X64
 
     // Check if the name is trivially convertible to an index and get
     // the element or char if so.
@@ -787,10 +801,13 @@ Object* KeyedLoadIC::Load(State state,
       }
     }
 
+    // TODO(X64): Enable inline caching for load.
+#ifndef V8_TARGET_ARCH_X64
     // Update the inline cache.
     if (FLAG_use_ic && lookup.IsLoaded()) {
       UpdateCaches(&lookup, state, object, name);
     }
+#endif
 
     PropertyAttributes attr;
     if (lookup.IsValid() && lookup.type() == INTERCEPTOR) {
@@ -961,6 +978,10 @@ Object* StoreIC::Store(State state,
     return *value;
   }
 
+  // TODO(X64): Enable inline cache for StoreIC.
+#ifdef V8_TARGET_ARCH_X64
+  USE(&LookupForWrite);  // The compiler complains otherwise.
+#else
   // Lookup the property locally in the receiver.
   if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) {
     LookupResult lookup;
@@ -968,6 +989,7 @@ Object* StoreIC::Store(State state,
       UpdateCaches(&lookup, state, receiver, name, value);
     }
   }
+#endif
 
   // Set the property.
   return receiver->SetProperty(*name, *value, NONE);
@@ -1086,10 +1108,13 @@ Object* KeyedStoreIC::Store(State state,
     LookupResult lookup;
     receiver->LocalLookup(*name, &lookup);
 
+    // TODO(X64): Enable inline cache for KeyedStoreIC.
+#ifndef V8_TARGET_ARCH_X64
     // Update inline cache and stub cache.
     if (FLAG_use_ic && lookup.IsLoaded()) {
       UpdateCaches(&lookup, state, receiver, name, value);
     }
+#endif
 
     // Set the property.
     return receiver->SetProperty(*name, *value, NONE);
@@ -1221,11 +1246,6 @@ void CallIC::GenerateInitialize(MacroAssembler* masm, int argc) {
 }
 
 
-void CallIC::GeneratePreMonomorphic(MacroAssembler* masm, int argc) {
-  Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss)));
-}
-
-
 void CallIC::GenerateMiss(MacroAssembler* masm, int argc) {
   Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss)));
 }
index 7d03377..593519b 100644 (file)
@@ -49,7 +49,8 @@ namespace internal {
   ICU(StoreInterceptorProperty)
 
 //
-// IC is the base class for LoadIC, StoreIC and CallIC.
+// IC is the base class for LoadIC, StoreIC, CallIC, KeyedLoadIC,
+// and KeyedStoreIC.
 //
 class IC {
  public:
@@ -173,7 +174,6 @@ class CallIC: public IC {
 
   // Code generator routines.
   static void GenerateInitialize(MacroAssembler* masm, int argc);
-  static void GeneratePreMonomorphic(MacroAssembler* masm, int argc);
   static void GenerateMiss(MacroAssembler* masm, int argc);
   static void GenerateMegamorphic(MacroAssembler* masm, int argc);
   static void GenerateNormal(MacroAssembler* masm, int argc);
@@ -219,8 +219,8 @@ class LoadIC: public IC {
   static void GenerateFunctionPrototype(MacroAssembler* masm);
 
   // The offset from the inlined patch site to the start of the
-  // inlined load instruction.  It is 7 bytes (test eax, imm) plus
-  // 6 bytes (jne slow_label).
+  // inlined load instruction.  It is architecture-dependent, and not
+  // used on ARM.
   static const int kOffsetToLoadInstruction;
 
  private:
index 0a8ae8c..ae914d3 100644 (file)
@@ -51,9 +51,11 @@ static bool BackRefMatchesNoCase(int from,
     unibrow::uchar old_char = subject[from++];
     unibrow::uchar new_char = subject[current++];
     if (old_char == new_char) continue;
-    interp_canonicalize.get(old_char, '\0', &old_char);
-    interp_canonicalize.get(new_char, '\0', &new_char);
-    if (old_char != new_char) {
+    unibrow::uchar old_string[1] = { old_char };
+    unibrow::uchar new_string[1] = { new_char };
+    interp_canonicalize.get(old_char, '\0', old_string);
+    interp_canonicalize.get(new_char, '\0', new_string);
+    if (old_string[0] != new_string[0]) {
       return false;
     }
   }
index 2ca89dd..33cf8e2 100644 (file)
@@ -843,7 +843,22 @@ void Logger::HeapSampleBeginEvent(const char* space, const char* kind) {
 #ifdef ENABLE_LOGGING_AND_PROFILING
   if (!Log::IsEnabled() || !FLAG_log_gc) return;
   LogMessageBuilder msg;
-  msg.Append("heap-sample-begin,\"%s\",\"%s\"\n", space, kind);
+  // Using non-relative system time in order to be able to synchronize with
+  // external memory profiling events (e.g. DOM memory size).
+  msg.Append("heap-sample-begin,\"%s\",\"%s\",%.0f\n",
+             space, kind, OS::TimeCurrentMillis());
+  msg.WriteToLogFile();
+#endif
+}
+
+
+void Logger::HeapSampleStats(const char* space, const char* kind,
+                             int capacity, int used) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  if (!Log::IsEnabled() || !FLAG_log_gc) return;
+  LogMessageBuilder msg;
+  msg.Append("heap-sample-stats,\"%s\",\"%s\",%d,%d\n",
+             space, kind, capacity, used);
   msg.WriteToLogFile();
 #endif
 }
index f68234f..95c9cde 100644 (file)
@@ -219,6 +219,8 @@ class Logger {
   static void HeapSampleBeginEvent(const char* space, const char* kind);
   static void HeapSampleEndEvent(const char* space, const char* kind);
   static void HeapSampleItemEvent(const char* type, int number, int bytes);
+  static void HeapSampleStats(const char* space, const char* kind,
+                              int capacity, int used);
 
   static void SharedLibraryEvent(const char* library_path,
                                  uintptr_t start,
index 37c9b8b..7abc7c3 100644 (file)
@@ -1075,7 +1075,12 @@ void JSGlobalPropertyCell::set_value(Object* val, WriteBarrierMode ignored) {
 
 
 int JSObject::GetHeaderSize() {
-  switch (map()->instance_type()) {
+  InstanceType type = map()->instance_type();
+  // Check for the most common kind of JavaScript object before
+  // falling into the generic switch. This speeds up the internal
+  // field operations considerably on average.
+  if (type == JS_OBJECT_TYPE) return JSObject::kHeaderSize;
+  switch (type) {
     case JS_GLOBAL_PROXY_TYPE:
       return JSGlobalProxy::kSize;
     case JS_GLOBAL_OBJECT_TYPE:
@@ -1090,7 +1095,6 @@ int JSObject::GetHeaderSize() {
       return JSValue::kSize;
     case JS_REGEXP_TYPE:
       return JSValue::kSize;
-    case JS_OBJECT_TYPE:
     case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
       return JSObject::kHeaderSize;
     default:
index a9004c9..72412c1 100644 (file)
@@ -216,6 +216,12 @@ Object* Object::GetPropertyWithDefinedGetter(Object* receiver,
   HandleScope scope;
   Handle<JSFunction> fun(JSFunction::cast(getter));
   Handle<Object> self(receiver);
+#ifdef ENABLE_DEBUGGER_SUPPORT
+  // Handle stepping into a getter if step into is active.
+  if (Debug::StepInActive()) {
+    Debug::HandleStepIn(fun, Handle<Object>::null(), 0, false);
+  }
+#endif
   bool has_pending_exception;
   Handle<Object> result =
       Execution::Call(fun, self, 0, NULL, &has_pending_exception);
@@ -1624,6 +1630,12 @@ Object* JSObject::SetPropertyWithDefinedSetter(JSFunction* setter,
   Handle<Object> value_handle(value);
   Handle<JSFunction> fun(JSFunction::cast(setter));
   Handle<JSObject> self(this);
+#ifdef ENABLE_DEBUGGER_SUPPORT
+  // Handle stepping into a setter if step into is active.
+  if (Debug::StepInActive()) {
+    Debug::HandleStepIn(fun, Handle<Object>::null(), 0, false);
+  }
+#endif
   bool has_pending_exception;
   Object** argv[] = { value_handle.location() };
   Execution::Call(fun, self, 1, argv, &has_pending_exception);
index 5c76e4a..5e5eb6b 100644 (file)
@@ -1718,6 +1718,10 @@ class Array: public HeapObject {
 
   // Layout descriptor.
   static const int kLengthOffset = HeapObject::kHeaderSize;
+
+ protected:
+  // No code should use the Array class directly, only its subclasses.
+  // Use the kHeaderSize of the appropriate subclass, which may be aligned.
   static const int kHeaderSize = kLengthOffset + kIntSize;
   static const int kAlignedSize = POINTER_SIZE_ALIGN(kHeaderSize);
 
@@ -2427,6 +2431,10 @@ class ByteArray: public Array {
   void ByteArrayVerify();
 #endif
 
+  // ByteArray headers are not quadword aligned.
+  static const int kHeaderSize = Array::kHeaderSize;
+  static const int kAlignedSize = Array::kAlignedSize;
+
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(ByteArray);
 };
index 89d6d5b..da2b286 100644 (file)
@@ -834,12 +834,7 @@ class AstBuildingParserFactory : public ParserFactory {
     return new CallEval(expression, arguments, pos);
   }
 
-  virtual Statement* EmptyStatement() {
-    // Use a statically allocated empty statement singleton to avoid
-    // allocating lots and lots of empty statements.
-    static v8::internal::EmptyStatement empty;
-    return &empty;
-  }
+  virtual Statement* EmptyStatement();
 };
 
 
@@ -1032,6 +1027,14 @@ Scope* AstBuildingParserFactory::NewScope(Scope* parent, Scope::Type type,
 }
 
 
+Statement* AstBuildingParserFactory::EmptyStatement() {
+  // Use a statically allocated empty statement singleton to avoid
+  // allocating lots and lots of empty statements.
+  static v8::internal::EmptyStatement empty;
+  return &empty;
+}
+
+
 Scope* ParserFactory::NewScope(Scope* parent, Scope::Type type,
                                bool inside_with) {
   ASSERT(parent != NULL);
@@ -2367,7 +2370,7 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
       result = NEW(TryFinally(try_block, finally_block));
       // Add the jump targets of the try block and the catch block.
       for (int i = 0; i < collector.targets()->length(); i++) {
-        catch_collector.targets()->Add(collector.targets()->at(i));
+        catch_collector.AddTarget(collector.targets()->at(i));
       }
       result->set_escaping_targets(catch_collector.targets());
     }
@@ -3928,7 +3931,7 @@ RegExpTree* RegExpParser::ParseDisjunction() {
     case '*':
     case '+':
     case '?':
-      ReportError(CStrVector("Nothing to repeat") CHECK_FAILED);
+      return ReportError(CStrVector("Nothing to repeat"));
     case '^': {
       Advance();
       if (multiline_) {
@@ -4003,7 +4006,7 @@ RegExpTree* RegExpParser::ParseDisjunction() {
     case '\\':
       switch (Next()) {
       case kEndMarker:
-        ReportError(CStrVector("\\ at end of pattern") CHECK_FAILED);
+        return ReportError(CStrVector("\\ at end of pattern"));
       case 'b':
         Advance(2);
         builder->AddAssertion(
@@ -4490,7 +4493,7 @@ CharacterRange RegExpParser::ParseClassAtom(uc16* char_class) {
         return CharacterRange::Singleton(0);  // Return dummy value.
       }
       case kEndMarker:
-        ReportError(CStrVector("\\ at end of pattern") CHECK_FAILED);
+        return ReportError(CStrVector("\\ at end of pattern"));
       default:
         uc32 c = ParseClassCharacterEscape(CHECK_FAILED);
         return CharacterRange::Singleton(c);
index 880931e..b5a57e1 100644 (file)
 // Platform specific code for MacOS goes here. For the POSIX comaptible parts
 // the implementation is in platform-posix.cc.
 
-#include <ucontext.h>
 #include <unistd.h>
 #include <sys/mman.h>
 #include <mach/mach_init.h>
+#include <mach-o/dyld.h>
+#include <mach-o/getsect.h>
 
 #include <AvailabilityMacros.h>
 
@@ -205,7 +206,19 @@ PosixMemoryMappedFile::~PosixMemoryMappedFile() {
 
 
 void OS::LogSharedLibraryAddresses() {
-  // TODO(1233579): Implement.
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  unsigned int images_count = _dyld_image_count();
+  for (unsigned int i = 0; i < images_count; ++i) {
+    const mach_header* header = _dyld_get_image_header(i);
+    if (header == NULL) continue;
+    unsigned int size;
+    char* code_ptr = getsectdatafromheader(header, SEG_TEXT, SECT_TEXT, &size);
+    if (code_ptr == NULL) continue;
+    const uintptr_t slide = _dyld_get_image_vmaddr_slide(i);
+    const uintptr_t start = reinterpret_cast<uintptr_t>(code_ptr) + slide;
+    LOG(SharedLibraryEvent(_dyld_get_image_name(i), start, start + size));
+  }
+#endif  // ENABLE_LOGGING_AND_PROFILING
 }
 
 
index d1b08bb..d55f949 100644 (file)
@@ -44,6 +44,12 @@ Result::Result(Register reg) {
 }
 
 
+Result::ZoneObjectList* Result::ConstantList() {
+  static ZoneObjectList list(10);
+  return &list;
+}
+
+
 // -------------------------------------------------------------------------
 // RegisterAllocator implementation.
 
index f7167d9..1765633 100644 (file)
@@ -92,10 +92,7 @@ class Result BASE_EMBEDDED {
   // of handles to the actual constants.
   typedef ZoneList<Handle<Object> > ZoneObjectList;
 
-  static ZoneObjectList* ConstantList() {
-    static ZoneObjectList list(10);
-    return &list;
-  }
+  static ZoneObjectList* ConstantList();
 
   // Clear the constants indirection table.
   static void ClearConstantList() {
index 4d1fbd9..8a7267a 100644 (file)
@@ -38,8 +38,9 @@ namespace internal {
 
 class AstOptimizer: public AstVisitor {
  public:
-  explicit AstOptimizer() {}
-  explicit AstOptimizer(Handle<String> enclosing_name) {
+  explicit AstOptimizer() : has_function_literal_(false) {}
+  explicit AstOptimizer(Handle<String> enclosing_name)
+      : has_function_literal_(false) {
     func_name_inferrer_.PushEnclosingName(enclosing_name);
   }
 
index 592cf5a..963138e 100644 (file)
@@ -1454,9 +1454,9 @@ void Deserializer::GetLog() {
 static void InitPagedSpace(PagedSpace* space,
                            int capacity,
                            List<Page*>* page_list) {
-  space->EnsureCapacity(capacity);
-  // TODO(1240712): PagedSpace::EnsureCapacity can return false due to
-  // a failure to allocate from the OS to expand the space.
+  if (!space->EnsureCapacity(capacity)) {
+    V8::FatalProcessOutOfMemory("InitPagedSpace");
+  }
   PageIterator it(space, PageIterator::ALL_PAGES);
   while (it.has_next()) page_list->Add(it.next());
 }
index 4177856..4f8119f 100644 (file)
@@ -133,8 +133,6 @@ PageIterator::PageIterator(PagedSpace* space, Mode mode) : space_(space) {
 #endif
       stop_page_ = space->last_page_;
       break;
-    default:
-      UNREACHABLE();
   }
 }
 
@@ -725,10 +723,10 @@ void PagedSpace::Shrink() {
   Page* current_page = top_page->next_page();
   // Loop over the pages to the end of the space.
   while (current_page->is_valid()) {
-    // Advance last_page_to_keep every other step to end up at the midpoint.
 #if defined(ANDROID)
-    // Free all free chunks.
+    // Free all chunks if possible
 #else
+    // Advance last_page_to_keep every other step to end up at the midpoint.
     if ((free_pages & 0x1) == 1) {
       pages_to_keep++;
       last_page_to_keep = last_page_to_keep->next_page();
@@ -751,6 +749,7 @@ void PagedSpace::Shrink() {
     last_page_ = p;
     p = p->next_page();
   }
+
   // The difference between free_pages and pages_to_keep is the number of
   // pages actually freed.
   ASSERT(pages_to_keep <= free_pages);
index 9a137e3..ee343a5 100644 (file)
@@ -44,12 +44,6 @@ char* HeapStringAllocator::allocate(unsigned bytes) {
 }
 
 
-NoAllocationStringAllocator::NoAllocationStringAllocator(unsigned bytes) {
-  size_ = bytes;
-  space_ = NewArray<char>(bytes);
-}
-
-
 NoAllocationStringAllocator::NoAllocationStringAllocator(char* memory,
                                                          unsigned size) {
   size_ = size;
index 15a72e0..5732944 100644 (file)
@@ -57,11 +57,10 @@ class HeapStringAllocator: public StringAllocator {
 
 
 // Allocator for use when no new c++ heap allocation is allowed.
-// Allocates all space up front and does no allocation while building
-// message.
+// Given a preallocated buffer up front and does no allocation while
+// building message.
 class NoAllocationStringAllocator: public StringAllocator {
  public:
-  explicit NoAllocationStringAllocator(unsigned bytes);
   NoAllocationStringAllocator(char* memory, unsigned size);
   char* allocate(unsigned bytes) { return space_; }
   char* grow(unsigned* bytes);
index 7eb8cd3..7ca2677 100644 (file)
@@ -863,6 +863,8 @@ Object* StubCompiler::CompileCallInitialize(Code::Flags flags) {
 Object* StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) {
   HandleScope scope;
   int argc = Code::ExtractArgumentsCountFromFlags(flags);
+  // The code of the PreMonomorphic stub is the same as the code
+  // of the Initialized stub.  They just differ on the code object flags.
   CallIC::GenerateInitialize(masm(), argc);
   Object* result = GetCodeWithFlags(flags, "CompileCallPreMonomorphic");
   if (!result->IsFailure()) {
index 8bee370..c6b002b 100644 (file)
@@ -256,11 +256,14 @@ class StubCache : public AllStatic {
   }
 
   // Compute the entry for a given offset in exactly the same way as
-  // we done in generated code. This makes it a lot easier to avoid
-  // making mistakes in the hashed offset computations.
+  // we do in generated code.  We generate an hash code that already
+  // ends in String::kHashShift 0s.  Then we shift it so it is a multiple
+  // of sizeof(Entry).  This makes it easier to avoid making mistakes
+  // in the hashed offset computations.
   static Entry* entry(Entry* table, int offset) {
+    const int shift_amount = kPointerSizeLog2 + 1 - String::kHashShift;
     return reinterpret_cast<Entry*>(
-        reinterpret_cast<Address>(table) + (offset << 1));
+        reinterpret_cast<Address>(table) + (offset << shift_amount));
   }
 };
 
index c4ee454..e9a6f7f 100644 (file)
@@ -456,13 +456,13 @@ void Assembler::arithmetic_op_32(byte opcode, Register dst, Register src) {
 
 
 void Assembler::arithmetic_op_32(byte opcode,
-                                 const Operand& dst,
-                                 Register src) {
+                                 Register reg,
+                                 const Operand& rm_reg) {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
-  emit_optional_rex_32(src, dst);
+  emit_optional_rex_32(reg, rm_reg);
   emit(opcode);
-  emit_operand(src, dst);
+  emit_operand(reg, rm_reg);
 }
 
 
@@ -2183,48 +2183,3 @@ const int RelocInfo::kApplyMask = 1 << RelocInfo::INTERNAL_REFERENCE;
 
 
 } }  // namespace v8::internal
-
-
-// TODO(x64): Implement and move these to their correct cc-files:
-#include "ast.h"
-#include "bootstrapper.h"
-#include "codegen-inl.h"
-#include "cpu.h"
-#include "debug.h"
-#include "disasm.h"
-#include "disassembler.h"
-#include "frames-inl.h"
-#include "x64/macro-assembler-x64.h"
-#include "x64/regexp-macro-assembler-x64.h"
-#include "ic-inl.h"
-#include "log.h"
-#include "macro-assembler.h"
-#include "parser.h"
-#include "regexp-macro-assembler.h"
-#include "regexp-stack.h"
-#include "register-allocator-inl.h"
-#include "register-allocator.h"
-#include "runtime.h"
-#include "scopes.h"
-#include "serialize.h"
-#include "stub-cache.h"
-#include "unicode.h"
-
-namespace v8 {
-namespace internal {
-
-
-void BreakLocationIterator::ClearDebugBreakAtReturn() {
-  UNIMPLEMENTED();
-}
-
-bool BreakLocationIterator::IsDebugBreakAtReturn()  {
-  UNIMPLEMENTED();
-  return false;
-}
-
-void BreakLocationIterator::SetDebugBreakAtReturn()  {
-  UNIMPLEMENTED();
-}
-
-} }  // namespace v8::internal
index e895332..1b2a35c 100644 (file)
@@ -521,10 +521,6 @@ class Assembler : public Malloced {
   void xchg(Register dst, Register src);
 
   // Arithmetics
-  void addq(Register dst, Register src) {
-    arithmetic_op(0x03, dst, src);
-  }
-
   void addl(Register dst, Register src) {
     arithmetic_op_32(0x03, dst, src);
   }
@@ -533,14 +529,21 @@ class Assembler : public Malloced {
     immediate_arithmetic_op_32(0x0, dst, src);
   }
 
+  void addl(Register dst, const Operand& src) {
+    arithmetic_op_32(0x03, dst, src);
+  }
+
   void addl(const Operand& dst, Immediate src) {
     immediate_arithmetic_op_32(0x0, dst, src);
   }
 
-  void addq(Register dst, const Operand& src) {
+  void addq(Register dst, Register src) {
     arithmetic_op(0x03, dst, src);
   }
 
+  void addq(Register dst, const Operand& src) {
+    arithmetic_op(0x03, dst, src);
+  }
 
   void addq(const Operand& dst, Register src) {
     arithmetic_op(0x01, src, dst);
@@ -567,11 +570,11 @@ class Assembler : public Malloced {
   }
 
   void cmpl(Register dst, const Operand& src) {
-    arithmetic_op_32(0x3B, src, dst);
+    arithmetic_op_32(0x3B, dst, src);
   }
 
   void cmpl(const Operand& dst, Register src) {
-    arithmetic_op_32(0x39, dst, src);
+    arithmetic_op_32(0x39, src, dst);
   }
 
   void cmpl(Register dst, Immediate src) {
@@ -718,6 +721,10 @@ class Assembler : public Malloced {
     shift_32(dst, 0x4);
   }
 
+  void shll(Register dst, Immediate shift_amount) {
+    shift_32(dst, shift_amount, 0x4);
+  }
+
   void shr(Register dst, Immediate shift_amount) {
     shift(dst, shift_amount, 0x5);
   }
@@ -1114,8 +1121,8 @@ class Assembler : public Malloced {
   // ModR/M byte.
   void arithmetic_op(byte opcode, Register dst, Register src);
   void arithmetic_op_32(byte opcode, Register dst, Register src);
-  void arithmetic_op_32(byte opcode, const Operand& dst, Register src);
-  void arithmetic_op(byte opcode, Register reg, const Operand& op);
+  void arithmetic_op_32(byte opcode, Register reg, const Operand& rm_reg);
+  void arithmetic_op(byte opcode, Register reg, const Operand& rm_reg);
   void immediate_arithmetic_op(byte subcode, Register dst, Immediate src);
   void immediate_arithmetic_op(byte subcode, const Operand& dst, Immediate src);
   // Operate on a 32-bit word in memory or register.
index e3e32e6..9ed7e74 100644 (file)
@@ -5321,6 +5321,7 @@ void Reference::GetValue(TypeofState typeof_state) {
       // patch the map check if appropriate.
 
       // TODO(x64): Implement inlined loads for keyed properties.
+      // Make sure to load length field as a 32-bit quantity.
       //      Comment cmnt(masm, "[ Load from keyed Property");
 
       RelocInfo::Mode mode = is_global
index e94e781..177eb90 100644 (file)
@@ -80,6 +80,21 @@ void Debug::GenerateStubNoRegistersDebugBreak(MacroAssembler* masm) {
   masm->int3();  // UNIMPLEMENTED
 }
 
+void BreakLocationIterator::ClearDebugBreakAtReturn() {
+  // TODO(X64): Implement this when we start setting Debug breaks.
+  UNIMPLEMENTED();
+}
+
+bool BreakLocationIterator::IsDebugBreakAtReturn()  {
+  // TODO(X64): Implement this when we start setting Debug breaks.
+  UNIMPLEMENTED();
+  return false;
+}
+
+void BreakLocationIterator::SetDebugBreakAtReturn()  {
+  UNIMPLEMENTED();
+}
+
 #endif  // ENABLE_DEBUGGER_SUPPORT
 
 } }  // namespace v8::internal
index f962c01..83fa9cd 100644 (file)
 
 namespace disasm {
 
-enum OperandOrder {
-  UNSET_OP_ORDER = 0, REG_OPER_OP_ORDER, OPER_REG_OP_ORDER
+enum OperandType {
+  UNSET_OP_ORDER = 0,
+  // Operand size decides between 16, 32 and 64 bit operands.
+  REG_OPER_OP_ORDER = 1,  // Register destination, operand source.
+  OPER_REG_OP_ORDER = 2,  // Operand destination, register source.
+  // Fixed 8-bit operands.
+  BYTE_SIZE_OPERAND_FLAG = 4,
+  BYTE_REG_OPER_OP_ORDER = REG_OPER_OP_ORDER | BYTE_SIZE_OPERAND_FLAG,
+  BYTE_OPER_REG_OP_ORDER = OPER_REG_OP_ORDER | BYTE_SIZE_OPERAND_FLAG
 };
 
 //------------------------------------------------------------------
@@ -43,28 +50,53 @@ enum OperandOrder {
 //------------------------------------------------------------------
 struct ByteMnemonic {
   int b;  // -1 terminates, otherwise must be in range (0..255)
-  OperandOrder op_order_;
+  OperandType op_order_;
   const char* mnem;
 };
 
 
 static ByteMnemonic two_operands_instr[] = {
-  { 0x03, REG_OPER_OP_ORDER, "add" },
-  { 0x21, OPER_REG_OP_ORDER, "and" },
-  { 0x23, REG_OPER_OP_ORDER, "and" },
-  { 0x3B, REG_OPER_OP_ORDER, "cmp" },
-  { 0x8D, REG_OPER_OP_ORDER, "lea" },
-  { 0x09, OPER_REG_OP_ORDER, "or" },
-  { 0x0B, REG_OPER_OP_ORDER, "or" },
-  { 0x1B, REG_OPER_OP_ORDER, "sbb" },
-  { 0x29, OPER_REG_OP_ORDER, "sub" },
-  { 0x2B, REG_OPER_OP_ORDER, "sub" },
-  { 0x85, REG_OPER_OP_ORDER, "test" },
-  { 0x31, OPER_REG_OP_ORDER, "xor" },
-  { 0x33, REG_OPER_OP_ORDER, "xor" },
-  { 0x87, REG_OPER_OP_ORDER, "xchg" },
-  { 0x8A, REG_OPER_OP_ORDER, "movb" },
-  { 0x8B, REG_OPER_OP_ORDER, "mov" },
+  { 0x00, BYTE_OPER_REG_OP_ORDER, "add" },
+  { 0x01, OPER_REG_OP_ORDER,      "add" },
+  { 0x02, BYTE_REG_OPER_OP_ORDER, "add" },
+  { 0x03, REG_OPER_OP_ORDER,      "add" },
+  { 0x08, BYTE_OPER_REG_OP_ORDER, "or" },
+  { 0x09, OPER_REG_OP_ORDER,      "or" },
+  { 0x0A, BYTE_REG_OPER_OP_ORDER, "or" },
+  { 0x0B, REG_OPER_OP_ORDER,      "or" },
+  { 0x10, BYTE_OPER_REG_OP_ORDER, "adc" },
+  { 0x11, OPER_REG_OP_ORDER,      "adc" },
+  { 0x12, BYTE_REG_OPER_OP_ORDER, "adc" },
+  { 0x13, REG_OPER_OP_ORDER,      "adc" },
+  { 0x18, BYTE_OPER_REG_OP_ORDER, "sbb" },
+  { 0x19, OPER_REG_OP_ORDER,      "sbb" },
+  { 0x1A, BYTE_REG_OPER_OP_ORDER, "sbb" },
+  { 0x1B, REG_OPER_OP_ORDER,      "sbb" },
+  { 0x20, BYTE_OPER_REG_OP_ORDER, "and" },
+  { 0x21, OPER_REG_OP_ORDER,      "and" },
+  { 0x22, BYTE_REG_OPER_OP_ORDER, "and" },
+  { 0x23, REG_OPER_OP_ORDER,      "and" },
+  { 0x28, BYTE_OPER_REG_OP_ORDER, "sub" },
+  { 0x29, OPER_REG_OP_ORDER,      "sub" },
+  { 0x2A, BYTE_REG_OPER_OP_ORDER, "sub" },
+  { 0x2B, REG_OPER_OP_ORDER,      "sub" },
+  { 0x30, BYTE_OPER_REG_OP_ORDER, "xor" },
+  { 0x31, OPER_REG_OP_ORDER,      "xor" },
+  { 0x32, BYTE_REG_OPER_OP_ORDER, "xor" },
+  { 0x33, REG_OPER_OP_ORDER,      "xor" },
+  { 0x38, BYTE_OPER_REG_OP_ORDER, "cmp" },
+  { 0x39, OPER_REG_OP_ORDER,      "cmp" },
+  { 0x3A, BYTE_REG_OPER_OP_ORDER, "cmp" },
+  { 0x3B, REG_OPER_OP_ORDER,      "cmp" },
+  { 0x8D, REG_OPER_OP_ORDER,      "lea" },
+  { 0x84, BYTE_REG_OPER_OP_ORDER, "test" },
+  { 0x85, REG_OPER_OP_ORDER,      "test" },
+  { 0x86, BYTE_REG_OPER_OP_ORDER, "xchg" },
+  { 0x87, REG_OPER_OP_ORDER,      "xchg" },
+  { 0x88, BYTE_OPER_REG_OP_ORDER, "mov" },
+  { 0x89, OPER_REG_OP_ORDER,      "mov" },
+  { 0x8A, BYTE_REG_OPER_OP_ORDER, "mov" },
+  { 0x8B, REG_OPER_OP_ORDER,      "mov" },
   { -1, UNSET_OP_ORDER, "" }
 };
 
@@ -97,6 +129,7 @@ static ByteMnemonic short_immediate_instr[] = {
   { 0x05, UNSET_OP_ORDER, "add" },
   { 0x0D, UNSET_OP_ORDER, "or" },
   { 0x15, UNSET_OP_ORDER, "adc" },
+  { 0x1D, UNSET_OP_ORDER, "sbb" },
   { 0x25, UNSET_OP_ORDER, "and" },
   { 0x2D, UNSET_OP_ORDER, "sub" },
   { 0x35, UNSET_OP_ORDER, "xor" },
@@ -127,7 +160,8 @@ enum InstructionType {
 struct InstructionDesc {
   const char* mnem;
   InstructionType type;
-  OperandOrder op_order_;
+  OperandType op_order_;
+  bool byte_size_operation;  // Fixed 8-bit operation.
 };
 
 
@@ -143,7 +177,7 @@ class InstructionTable {
   void Clear();
   void Init();
   void CopyTable(ByteMnemonic bm[], InstructionType type);
-  void SetTableRange(InstructionType type, byte start, byte end,
+  void SetTableRange(InstructionType type, byte start, byte end, bool byte_size,
                      const char* mnem);
   void AddJumpConditionalShort();
 };
@@ -157,9 +191,10 @@ InstructionTable::InstructionTable() {
 
 void InstructionTable::Clear() {
   for (int i = 0; i < 256; i++) {
-    instructions_[i].mnem = "";
+    instructions_[i].mnem = "(bad)";
     instructions_[i].type = NO_INSTR;
     instructions_[i].op_order_ = UNSET_OP_ORDER;
+    instructions_[i].byte_size_operation = false;
   }
 }
 
@@ -170,9 +205,9 @@ void InstructionTable::Init() {
   CopyTable(call_jump_instr, CALL_JUMP_INSTR);
   CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
   AddJumpConditionalShort();
-  SetTableRange(PUSHPOP_INSTR, 0x50, 0x57, "push");
-  SetTableRange(PUSHPOP_INSTR, 0x58, 0x5F, "pop");
-  SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, "mov");
+  SetTableRange(PUSHPOP_INSTR, 0x50, 0x57, false, "push");
+  SetTableRange(PUSHPOP_INSTR, 0x58, 0x5F, false, "pop");
+  SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, false, "mov");
 }
 
 
@@ -180,20 +215,27 @@ void InstructionTable::CopyTable(ByteMnemonic bm[], InstructionType type) {
   for (int i = 0; bm[i].b >= 0; i++) {
     InstructionDesc* id = &instructions_[bm[i].b];
     id->mnem = bm[i].mnem;
-    id->op_order_ = bm[i].op_order_;
-    assert(id->type == NO_INSTR);  // Information already entered
+    OperandType op_order = bm[i].op_order_;
+    id->op_order_ =
+        static_cast<OperandType>(op_order & ~BYTE_SIZE_OPERAND_FLAG);
+    assert(id->type == NO_INSTR);  // Information not already entered
     id->type = type;
+    id->byte_size_operation = ((op_order & BYTE_SIZE_OPERAND_FLAG) != 0);
   }
 }
 
 
-void InstructionTable::SetTableRange(InstructionType type, byte start,
-                                     byte end, const char* mnem) {
+void InstructionTable::SetTableRange(InstructionType type,
+                                     byte start,
+                                     byte end,
+                                     bool byte_size,
+                                     const char* mnem) {
   for (byte b = start; b <= end; b++) {
     InstructionDesc* id = &instructions_[b];
     assert(id->type == NO_INSTR);  // Information already entered
     id->mnem = mnem;
     id->type = type;
+    id->byte_size_operation = byte_size;
   }
 }
 
@@ -211,13 +253,16 @@ void InstructionTable::AddJumpConditionalShort() {
 static InstructionTable instruction_table;
 
 
-// The X64 disassembler implementation.
+//------------------------------------------------------------------------------
+// DisassemblerX64 implementation.
+
 enum UnimplementedOpcodeAction {
   CONTINUE_ON_UNIMPLEMENTED_OPCODE,
   ABORT_ON_UNIMPLEMENTED_OPCODE
 };
 
-
+// A new DisassemblerX64 object is created to disassemble each instruction.
+// The object can only disassemble a single instruction.
 class DisassemblerX64 {
  public:
   DisassemblerX64(const NameConverter& converter,
@@ -228,7 +273,9 @@ class DisassemblerX64 {
         abort_on_unimplemented_(
             unimplemented_action == ABORT_ON_UNIMPLEMENTED_OPCODE),
         rex_(0),
-        operand_size_(0) {
+        operand_size_(0),
+        group_1_prefix_(0),
+        byte_size_operand_(false) {
     tmp_buffer_[0] = '\0';
   }
 
@@ -240,6 +287,12 @@ class DisassemblerX64 {
   int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);
 
  private:
+  enum OperandSize {
+    BYTE_SIZE = 0,
+    WORD_SIZE = 1,
+    DOUBLEWORD_SIZE = 2,
+    QUADWORD_SIZE = 3
+  };
 
   const NameConverter& converter_;
   v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
@@ -247,12 +300,10 @@ class DisassemblerX64 {
   bool abort_on_unimplemented_;
   // Prefixes parsed
   byte rex_;
-  byte operand_size_;
-
-  void setOperandSizePrefix(byte prefix) {
-    ASSERT_EQ(0x66, prefix);
-    operand_size_ = prefix;
-  }
+  byte operand_size_;  // 0x66 or (if no group 3 prefix is present) 0x0.
+  byte group_1_prefix_;  // 0xF2, 0xF3, or (if no group 1 prefix is present) 0.
+  // Byte size operand override.
+  bool byte_size_operand_;
 
   void setRex(byte rex) {
     ASSERT_EQ(0x40, rex & 0xF0);
@@ -272,12 +323,15 @@ class DisassemblerX64 {
 
   bool rex_w() { return (rex_ & 0x08) != 0; }
 
-  int operand_size() {
-    return rex_w() ? 64 : (operand_size_ != 0) ? 16 : 32;
+  OperandSize operand_size() {
+    if (byte_size_operand_) return BYTE_SIZE;
+    if (rex_w()) return QUADWORD_SIZE;
+    if (operand_size_ != 0) return WORD_SIZE;
+    return DOUBLEWORD_SIZE;
   }
 
   char operand_size_code() {
-    return rex_w() ? 'q' : (operand_size_ != 0) ? 'w' : 'l';
+    return "bwlq"[operand_size()];
   }
 
   const char* NameOfCPURegister(int reg) const {
@@ -312,7 +366,7 @@ class DisassemblerX64 {
                int* base) {
     *scale = (data >> 6) & 3;
     *index = ((data >> 3) & 7) | (rex_x() ? 8 : 0);
-    *base = data & 7 | (rex_b() ? 8 : 0);
+    *base = (data & 7) | (rex_b() ? 8 : 0);
   }
 
   typedef const char* (DisassemblerX64::*RegisterNameMapping)(int reg) const;
@@ -322,11 +376,14 @@ class DisassemblerX64 {
   int PrintRightOperand(byte* modrmp);
   int PrintRightByteOperand(byte* modrmp);
   int PrintOperands(const char* mnem,
-                    OperandOrder op_order,
+                    OperandType op_order,
                     byte* data);
+  int PrintImmediate(byte* data, OperandSize size);
   int PrintImmediateOp(byte* data);
+  const char* TwoByteMnemonic(byte opcode);
+  int TwoByteOpcodeInstruction(byte* data);
   int F7Instruction(byte* data);
-  int D1D3C1Instruction(byte* data);
+  int ShiftInstruction(byte* data);
   int JumpShort(byte* data);
   int JumpConditional(byte* data);
   int JumpConditionalShort(byte* data);
@@ -336,7 +393,7 @@ class DisassemblerX64 {
 
   void UnimplementedInstruction() {
     if (abort_on_unimplemented_) {
-      UNIMPLEMENTED();
+      CHECK(false);
     } else {
       AppendToBuffer("'Unimplemented Instruction'");
     }
@@ -451,6 +508,36 @@ int DisassemblerX64::PrintRightOperandHelper(
 }
 
 
+int DisassemblerX64::PrintImmediate(byte* data, OperandSize size) {
+  int64_t value;
+  int count;
+  switch (size) {
+    case BYTE_SIZE:
+      value = *data;
+      count = 1;
+      break;
+    case WORD_SIZE:
+      value = *reinterpret_cast<int16_t*>(data);
+      count = 2;
+      break;
+    case DOUBLEWORD_SIZE:
+      value = *reinterpret_cast<uint32_t*>(data);
+      count = 4;
+      break;
+    case QUADWORD_SIZE:
+      value = *reinterpret_cast<int32_t*>(data);
+      count = 4;
+      break;
+    default:
+      UNREACHABLE();
+      value = 0;  // Initialize variables on all paths to satisfy the compiler.
+      count = 0;
+  }
+  AppendToBuffer(V8_PTR_PREFIX"x", value);
+  return count;
+}
+
+
 int DisassemblerX64::PrintRightOperand(byte* modrmp) {
   return PrintRightOperandHelper(modrmp,
                                  &DisassemblerX64::NameOfCPURegister);
@@ -466,25 +553,30 @@ int DisassemblerX64::PrintRightByteOperand(byte* modrmp) {
 // Returns number of bytes used including the current *data.
 // Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
 int DisassemblerX64::PrintOperands(const char* mnem,
-                                   OperandOrder op_order,
+                                   OperandType op_order,
                                    byte* data) {
   byte modrm = *data;
   int mod, regop, rm;
   get_modrm(modrm, &mod, &regop, &rm);
   int advance = 0;
+  const char* register_name =
+      byte_size_operand_ ? NameOfByteCPURegister(regop)
+                         : NameOfCPURegister(regop);
   switch (op_order) {
     case REG_OPER_OP_ORDER: {
       AppendToBuffer("%s%c %s,",
                      mnem,
                      operand_size_code(),
-                     NameOfCPURegister(regop));
-      advance = PrintRightOperand(data);
+                     register_name);
+      advance = byte_size_operand_ ? PrintRightByteOperand(data)
+                                   : PrintRightOperand(data);
       break;
     }
     case OPER_REG_OP_ORDER: {
       AppendToBuffer("%s%c ", mnem, operand_size_code());
-      advance = PrintRightOperand(data);
-      AppendToBuffer(",%s", NameOfCPURegister(regop));
+      advance = byte_size_operand_ ? PrintRightByteOperand(data)
+                                   : PrintRightOperand(data);
+      AppendToBuffer(",%s", register_name);
       break;
     }
     default:
@@ -498,7 +590,7 @@ int DisassemblerX64::PrintOperands(const char* mnem,
 // Returns number of bytes used by machine instruction, including *data byte.
 // Writes immediate instructions to 'tmp_buffer_'.
 int DisassemblerX64::PrintImmediateOp(byte* data) {
-  bool sign_extension_bit = (*data & 0x02) != 0;
+  bool byte_size_immediate = (*data & 0x02) != 0;
   byte modrm = *(data + 1);
   int mod, regop, rm;
   get_modrm(modrm, &mod, &regop, &rm);
@@ -528,15 +620,12 @@ int DisassemblerX64::PrintImmediateOp(byte* data) {
     default:
       UnimplementedInstruction();
   }
-  AppendToBuffer("%s ", mnem);
+  AppendToBuffer("%s%c ", mnem, operand_size_code());
   int count = PrintRightOperand(data + 1);
-  if (sign_extension_bit) {
-    AppendToBuffer(",0x%x", *(data + 1 + count));
-    return 1 + count + 1 /*int8*/;
-  } else {
-    AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count));
-    return 1 + count + 4 /*int32_t*/;
-  }
+  AppendToBuffer(",0x");
+  OperandSize immediate_size = byte_size_immediate ? BYTE_SIZE : operand_size();
+  count += PrintImmediate(data + 1 + count, immediate_size);
+  return 1 + count;
 }
 
 
@@ -589,78 +678,65 @@ int DisassemblerX64::F7Instruction(byte* data) {
 }
 
 
-int DisassemblerX64::D1D3C1Instruction(byte* data) {
-  byte op = *data;
-  assert(op == 0xD1 || op == 0xD3 || op == 0xC1);
+int DisassemblerX64::ShiftInstruction(byte* data) {
+  byte op = *data & (~1);
+  if (op != 0xD0 && op != 0xD2 && op != 0xC0) {
+    UnimplementedInstruction();
+    return 1;
+  }
   byte modrm = *(data + 1);
   int mod, regop, rm;
   get_modrm(modrm, &mod, &regop, &rm);
   ASSERT(regop < 8);
   int imm8 = -1;
   int num_bytes = 2;
-  if (mod == 3) {
-    const char* mnem = NULL;
-    if (op == 0xD1) {
-      imm8 = 1;
-      switch (regop) {
-        case 2:
-          mnem = "rcl";
-          break;
-        case 7:
-          mnem = "sar";
-          break;
-        case 4:
-          mnem = "shl";
-          break;
-        default:
-          UnimplementedInstruction();
-      }
-    } else if (op == 0xC1) {
-      imm8 = *(data + 2);
-      num_bytes = 3;
-      switch (regop) {
-        case 2:
-          mnem = "rcl";
-          break;
-        case 4:
-          mnem = "shl";
-          break;
-        case 5:
-          mnem = "shr";
-          break;
-        case 7:
-          mnem = "sar";
-          break;
-        default:
-          UnimplementedInstruction();
-      }
-    } else if (op == 0xD3) {
-      switch (regop) {
-        case 4:
-          mnem = "shl";
-          break;
-        case 5:
-          mnem = "shr";
-          break;
-        case 7:
-          mnem = "sar";
-          break;
-        default:
-          UnimplementedInstruction();
-      }
-    }
-    assert(mnem != NULL);
-    AppendToBuffer("%s%c %s,",
-                   mnem,
-                   operand_size_code(),
-                   NameOfCPURegister(rm));
-    if (imm8 > 0) {
-      AppendToBuffer("%d", imm8);
-    } else {
-      AppendToBuffer("cl");
-    }
-  } else {
+  if (mod != 3) {
     UnimplementedInstruction();
+    return num_bytes;
+  }
+  const char* mnem = NULL;
+  switch (regop) {
+    case 0:
+      mnem = "rol";
+      break;
+    case 1:
+      mnem = "ror";
+      break;
+    case 2:
+      mnem = "rcl";
+      break;
+    case 3:
+      mnem = "rcr";
+      break;
+    case 4:
+      mnem = "shl";
+      break;
+    case 5:
+      mnem = "shr";
+      break;
+    case 7:
+      mnem = "sar";
+      break;
+    default:
+      UnimplementedInstruction();
+      return num_bytes;
+  }
+  assert(mnem != NULL);
+  if (op == 0xD0) {
+    imm8 = 1;
+  } else if (op == 0xC0) {
+    imm8 = *(data + 2);
+    num_bytes = 3;
+  }
+  AppendToBuffer("%s%c %s,",
+                 mnem,
+                 operand_size_code(),
+                 byte_size_operand_ ? NameOfByteCPURegister(rm)
+                                    : NameOfCPURegister(rm));
+  if (op == 0xD2) {
+    AppendToBuffer("cl");
+  } else {
+    AppendToBuffer("%d", imm8);
   }
   return num_bytes;
 }
@@ -716,20 +792,14 @@ int DisassemblerX64::FPUInstruction(byte* data) {
   if (b1 == 0xD9) {
     const char* mnem = NULL;
     switch (b2) {
-      case 0xE8:
-        mnem = "fld1";
-        break;
-      case 0xEE:
-        mnem = "fldz";
+      case 0xE0:
+        mnem = "fchs";
         break;
       case 0xE1:
         mnem = "fabs";
         break;
-      case 0xE0:
-        mnem = "fchs";
-        break;
-      case 0xF8:
-        mnem = "fprem";
+      case 0xE4:
+        mnem = "ftst";
         break;
       case 0xF5:
         mnem = "fprem1";
@@ -737,8 +807,14 @@ int DisassemblerX64::FPUInstruction(byte* data) {
       case 0xF7:
         mnem = "fincstp";
         break;
-      case 0xE4:
-        mnem = "ftst";
+      case 0xE8:
+        mnem = "fld1";
+        break;
+      case 0xEE:
+        mnem = "fldz";
+        break;
+      case 0xF8:
+        mnem = "fprem";
         break;
     }
     if (mnem != NULL) {
@@ -862,38 +938,146 @@ int DisassemblerX64::FPUInstruction(byte* data) {
   return 2;
 }
 
-// Mnemonics for instructions 0xF0 byte.
+
+// Handle all two-byte opcodes, which start with 0x0F.
+// These instructions may be affected by an 0x66, 0xF2, or 0xF3 prefix.
+// We do not use any three-byte opcodes, which start with 0x0F38 or 0x0F3A.
+int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
+  byte opcode = *(data + 1);
+  byte* current = data + 2;
+  // At return, "current" points to the start of the next instruction.
+  const char* mnemonic = TwoByteMnemonic(opcode);
+  if (opcode == 0x1F) {
+    // NOP
+    int mod, regop, rm;
+    get_modrm(*current, &mod, &regop, &rm);
+    current++;
+    if (regop == 4) {  // SIB byte present.
+      current++;
+    }
+    if (mod == 1) {  // Byte displacement.
+      current += 1;
+    } else if (mod == 2) {  // 32-bit displacement.
+      current += 4;
+    }  // else no immediate displacement.
+    AppendToBuffer("nop");
+
+  } else  if (opcode == 0xA2 || opcode == 0x31) {
+    // RDTSC or CPUID
+    AppendToBuffer("%s", mnemonic);
+
+  } else if ((opcode & 0xF0) == 0x80) {
+    // Jcc: Conditional jump (branch).
+    current = data + JumpConditional(data);
+
+  } else if (opcode == 0xBE || opcode == 0xBF || opcode == 0xB6 ||
+             opcode == 0xB7 || opcode == 0xAF) {
+    // Size-extending moves, IMUL.
+    current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current);
+
+  } else if ((opcode & 0xF0) == 0x90) {
+    // SETcc: Set byte on condition. Needs pointer to beginning of instruction.
+    current = data + SetCC(data);
+
+  } else if (opcode == 0xAB || opcode == 0xA5 || opcode == 0xAD) {
+    // SHLD, SHRD (double-precision shift), BTS (bit set).
+    AppendToBuffer("%s ", mnemonic);
+    int mod, regop, rm;
+    get_modrm(*current, &mod, &regop, &rm);
+    current += PrintRightOperand(current);
+    if (opcode == 0xAB) {
+      AppendToBuffer(",%s", NameOfCPURegister(regop));
+    } else {
+      AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
+    }
+  } else if (group_1_prefix_ == 0xF2) {
+    // Beginning of instructions with prefix 0xF2.
+
+    if (opcode == 0x11 || opcode == 0x10) {
+      // MOVSD: Move scalar double-precision fp to/from/between XMM registers.
+      AppendToBuffer("movsd ");
+      int mod, regop, rm;
+      get_modrm(*current, &mod, &regop, &rm);
+      if (opcode == 0x11) {
+        current += PrintRightOperand(current);
+        AppendToBuffer(",%s", NameOfXMMRegister(regop));
+      } else {
+        AppendToBuffer("%s,", NameOfXMMRegister(regop));
+        current += PrintRightOperand(current);
+      }
+    } else if (opcode == 0x2A) {
+      // CVTSI2SD: integer to XMM double conversion.
+      int mod, regop, rm;
+      get_modrm(*current, &mod, &regop, &rm);
+      AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
+      data += PrintRightOperand(data);
+    } else if ((opcode & 0xF8) == 0x58) {
+      // XMM arithmetic. Mnemonic was retrieved at the start of this function.
+      int mod, regop, rm;
+      get_modrm(*current, &mod, &regop, &rm);
+      AppendToBuffer("%s %s,%s", mnemonic, NameOfXMMRegister(regop),
+                     NameOfXMMRegister(rm));
+    } else {
+      UnimplementedInstruction();
+    }
+  } else if (opcode == 0x2C && group_1_prefix_ == 0xF3) {
+    // Instruction with prefix 0xF3.
+
+    // CVTTSS2SI: Convert scalar single-precision FP to dword integer.
+    // Assert that mod is not 3, so source is memory, not an XMM register.
+    ASSERT((*current & 0xC0) != 0xC0);
+    current += PrintOperands("cvttss2si", REG_OPER_OP_ORDER, current);
+  } else {
+    UnimplementedInstruction();
+  }
+  return current - data;
+}
+
+
+// Mnemonics for two-byte opcode instructions starting with 0x0F.
+// The argument is the second byte of the two-byte opcode.
 // Returns NULL if the instruction is not handled here.
-static const char* F0Mnem(byte f0byte) {
-  switch (f0byte) {
+const char* DisassemblerX64::TwoByteMnemonic(byte opcode) {
+  switch (opcode) {
     case 0x1F:
       return "nop";
+    case 0x2A:  // F2 prefix.
+      return "cvtsi2sd";
     case 0x31:
       return "rdtsc";
+    case 0x58:  // F2 prefix.
+      return "addsd";
+    case 0x59:  // F2 prefix.
+      return "mulsd";
+    case 0x5C:  // F2 prefix.
+      return "subsd";
+    case 0x5E:  // F2 prefix.
+      return "divsd";
     case 0xA2:
       return "cpuid";
-    case 0xBE:
-      return "movsxb";
-    case 0xBF:
-      return "movsxw";
-    case 0xB6:
-      return "movzxb";
-    case 0xB7:
-      return "movzxw";
-    case 0xAF:
-      return "imul";
     case 0xA5:
       return "shld";
-    case 0xAD:
-      return "shrd";
     case 0xAB:
       return "bts";
+    case 0xAD:
+      return "shrd";
+    case 0xAF:
+      return "imul";
+    case 0xB6:
+      return "movzxb";
+    case 0xB7:
+      return "movzxw";
+    case 0xBE:
+      return "movsxb";
+    case 0xBF:
+      return "movsxw";
     default:
       return NULL;
   }
 }
 
-// Disassembled instruction '*instr' and writes it into 'out_buffer'.
+
+// Disassembles the instruction at instr, and writes it into out_buffer.
 int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
                                        byte* instr) {
   tmp_buffer_pos_ = 0;  // starting to write as position 0
@@ -905,19 +1089,21 @@ int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
   // Scan for prefixes.
   while (true) {
     current = *data;
-    if (current == 0x66) {
-      setOperandSizePrefix(current);
-      data++;
-    } else if ((current & 0xF0) == 0x40) {
+    if (current == 0x66) {  // Group 3 prefix.
+      operand_size_ = current;
+    } else if ((current & 0xF0) == 0x40) {  // REX prefix.
       setRex(current);
       if (rex_w()) AppendToBuffer("REX.W ");
-      data++;
-    } else {
+    } else if ((current & 0xFE) == 0xF2) {  // Group 1 prefix.
+      group_1_prefix_ = current;
+    } else {  // Not a prefix - an opcode.
       break;
     }
+    data++;
   }
 
   const InstructionDesc& idesc = instruction_table.Get(current);
+  byte_size_operand_ = idesc.byte_size_operation;
   switch (idesc.type) {
     case ZERO_OPERANDS_INSTR:
       AppendToBuffer(idesc.mnem);
@@ -949,15 +1135,15 @@ int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
     case MOVE_REG_INSTR: {
       byte* addr = NULL;
       switch (operand_size()) {
-        case 16:
+        case WORD_SIZE:
           addr = reinterpret_cast<byte*>(*reinterpret_cast<int16_t*>(data + 1));
           data += 3;
           break;
-        case 32:
+        case DOUBLEWORD_SIZE:
           addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
           data += 5;
           break;
-        case 64:
+        case QUADWORD_SIZE:
           addr = reinterpret_cast<byte*>(*reinterpret_cast<int64_t*>(data + 1));
           data += 9;
           break;
@@ -1012,8 +1198,8 @@ int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
         AppendToBuffer("imul %s,%s,0x%x", NameOfCPURegister(regop),
                        NameOfCPURegister(rm), imm);
         data += 2 + (*data == 0x6B ? 1 : 4);
-      }
         break;
+      }
 
       case 0xF6: {
         int mod, regop, rm;
@@ -1024,63 +1210,16 @@ int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
           UnimplementedInstruction();
         }
         data += 3;
-      }
         break;
+      }
 
       case 0x81:  // fall through
       case 0x83:  // 0x81 with sign extension bit set
         data += PrintImmediateOp(data);
         break;
 
-      case 0x0F: {
-        byte f0byte = *(data + 1);
-        const char* f0mnem = F0Mnem(f0byte);
-        if (f0byte == 0x1F) {
-          data += 1;
-          byte modrm = *data;
-          data += 1;
-          if (((modrm >> 3) & 7) == 4) {
-            // SIB byte present.
-            data += 1;
-          }
-          int mod = modrm >> 6;
-          if (mod == 1) {
-            // Byte displacement.
-            data += 1;
-          } else if (mod == 2) {
-            // 32-bit displacement.
-            data += 4;
-          }
-          AppendToBuffer("nop");
-        } else  if (f0byte == 0xA2 || f0byte == 0x31) {
-          AppendToBuffer("%s", f0mnem);
-          data += 2;
-        } else if ((f0byte & 0xF0) == 0x80) {
-          data += JumpConditional(data);
-        } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 || f0byte
-            == 0xB7 || f0byte == 0xAF) {
-          data += 2;
-          data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data);
-        } else if ((f0byte & 0xF0) == 0x90) {
-          data += SetCC(data);
-        } else {
-          data += 2;
-          if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) {
-            // shrd, shld, bts
-            AppendToBuffer("%s ", f0mnem);
-            int mod, regop, rm;
-            get_modrm(*data, &mod, &regop, &rm);
-            data += PrintRightOperand(data);
-            if (f0byte == 0xAB) {
-              AppendToBuffer(",%s", NameOfCPURegister(regop));
-            } else {
-              AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
-            }
-          } else {
-            UnimplementedInstruction();
-          }
-        }
-      }
+      case 0x0F:
+        data += TwoByteOpcodeInstruction(data);
         break;
 
       case 0x8F: {
@@ -1170,13 +1309,13 @@ int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
       case 0x95:
       case 0x96:
       case 0x97: {
-        int reg = current & 0x7 | (rex_b() ? 8 : 0);
+        int reg = (current & 0x7) | (rex_b() ? 8 : 0);
         if (reg == 0) {
           AppendToBuffer("nop");  // Common name for xchg rax,rax.
         } else {
           AppendToBuffer("xchg%c rax, %s",
                          operand_size_code(),
-                         NameOfByteCPURegister(reg));
+                         NameOfCPURegister(reg));
         }
       }
 
@@ -1209,17 +1348,39 @@ int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
         data += 2;
         break;
 
-      case 0xA9:
-        AppendToBuffer("test%c rax,0x%x",  // CHECKME!
+      case 0xA9: {
+        int64_t value = 0;
+        switch (operand_size()) {
+          case WORD_SIZE:
+            value = *reinterpret_cast<uint16_t*>(data + 1);
+            data += 3;
+            break;
+          case DOUBLEWORD_SIZE:
+            value = *reinterpret_cast<uint32_t*>(data + 1);
+            data += 5;
+            break;
+          case QUADWORD_SIZE:
+            value = *reinterpret_cast<int32_t*>(data + 1);
+            data += 5;
+            break;
+          default:
+            UNREACHABLE();
+        }
+        AppendToBuffer("test%c rax,0x%"V8_PTR_PREFIX"ux",
                        operand_size_code(),
-                       *reinterpret_cast<int32_t*>(data + 1));
-        data += 5;
+                       value);
         break;
-
+      }
       case 0xD1:  // fall through
       case 0xD3:  // fall through
       case 0xC1:
-        data += D1D3C1Instruction(data);
+        data += ShiftInstruction(data);
+        break;
+      case 0xD0:  // fall through
+      case 0xD2:  // fall through
+      case 0xC0:
+        byte_size_operand_ = true;
+        data += ShiftInstruction(data);
         break;
 
       case 0xD9:  // fall through
@@ -1236,73 +1397,13 @@ int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
         data += JumpShort(data);
         break;
 
-      case 0xF2:
-        if (*(data + 1) == 0x0F) {
-          byte b2 = *(data + 2);
-          if (b2 == 0x11) {
-            AppendToBuffer("movsd ");
-            data += 3;
-            int mod, regop, rm;
-            get_modrm(*data, &mod, &regop, &rm);
-            data += PrintRightOperand(data);
-            AppendToBuffer(",%s", NameOfXMMRegister(regop));
-          } else if (b2 == 0x10) {
-            data += 3;
-            int mod, regop, rm;
-            get_modrm(*data, &mod, &regop, &rm);
-            AppendToBuffer("movsd %s,", NameOfXMMRegister(regop));
-            data += PrintRightOperand(data);
-          } else {
-            const char* mnem = "?";
-            switch (b2) {
-              case 0x2A:
-                mnem = "cvtsi2sd";
-                break;
-              case 0x58:
-                mnem = "addsd";
-                break;
-              case 0x59:
-                mnem = "mulsd";
-                break;
-              case 0x5C:
-                mnem = "subsd";
-                break;
-              case 0x5E:
-                mnem = "divsd";
-                break;
-            }
-            data += 3;
-            int mod, regop, rm;
-            get_modrm(*data, &mod, &regop, &rm);
-            if (b2 == 0x2A) {
-              AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
-              data += PrintRightOperand(data);
-            } else {
-              AppendToBuffer("%s %s,%s", mnem, NameOfXMMRegister(regop),
-                             NameOfXMMRegister(rm));
-              data++;
-            }
-          }
-        } else {
-          UnimplementedInstruction();
-        }
-        break;
-
-      case 0xF3:
-        if (*(data + 1) == 0x0F && *(data + 2) == 0x2C) {
-          data += 3;
-          data += PrintOperands("cvttss2si", REG_OPER_OP_ORDER, data);
-        } else {
-          UnimplementedInstruction();
-        }
-        break;
-
       case 0xF7:
         data += F7Instruction(data);
         break;
 
       default:
         UnimplementedInstruction();
+        data += 1;
     }
   }  // !processed
 
index 7b8699f..db74baf 100644 (file)
@@ -43,11 +43,11 @@ namespace internal {
 
 
 void KeyedLoadIC::ClearInlinedVersion(Address address) {
-  UNIMPLEMENTED();
+  // TODO(X64): Implement this when LoadIC is enabled.
 }
 
 void KeyedStoreIC::ClearInlinedVersion(Address address) {
-  UNIMPLEMENTED();
+  // TODO(X64): Implement this when LoadIC is enabled.
 }
 
 void KeyedStoreIC::RestoreInlinedVersion(Address address) {
@@ -78,22 +78,32 @@ void KeyedLoadIC::Generate(MacroAssembler* masm,
 
 
 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
-  masm->int3();  // UNIMPLEMENTED.
-  masm->movq(kScratchRegister, Immediate(0xC0AB));  // Debugging aid.
+  // ----------- S t a t e -------------
+  //  -- rsp[0] : return address
+  //  -- rsp[8] : name
+  //  -- rsp[16] : receiver
+  // -----------------------------------
+
+  Generate(masm, ExternalReference(Runtime::kKeyedGetProperty));
 }
 
 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
-  masm->int3();  // UNIMPLEMENTED.
-  masm->movq(kScratchRegister, Immediate(0xC1AB));  // Debugging aid.
+  // ----------- S t a t e -------------
+  //  -- rsp[0] : return address
+  //  -- rsp[8] : name
+  //  -- rsp[16] : receiver
+  // -----------------------------------
+
+  Generate(masm, ExternalReference(Runtime::kKeyedGetProperty));
 }
 
 bool KeyedLoadIC::PatchInlinedLoad(Address address, Object* map) {
-  UNIMPLEMENTED();
+  // Never patch the map in the map check, so the check always fails.
   return false;
 }
 
 bool KeyedStoreIC::PatchInlinedStore(Address address, Object* map) {
-  UNIMPLEMENTED();
+  // Never patch the map in the map check, so the check always fails.
   return false;
 }
 
@@ -163,13 +173,11 @@ void KeyedStoreIC::Generate(MacroAssembler* masm, ExternalReference const& f) {
 }
 
 void KeyedStoreIC::GenerateExtendStorage(MacroAssembler* masm) {
-  masm->int3();  // UNIMPLEMENTED.
-  masm->movq(kScratchRegister, Immediate(0xC2AB));  // Debugging aid.
+  Generate(masm, ExternalReference(IC_Utility(kKeyedStoreIC_Miss)));
 }
 
 void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
-  masm->int3();  // UNIMPLEMENTED.
-  masm->movq(kScratchRegister, Immediate(0xC3AB));  // Debugging aid.
+  Generate(masm, ExternalReference(IC_Utility(kKeyedStoreIC_Miss)));
 }
 
 Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
@@ -228,20 +236,24 @@ void CallIC::Generate(MacroAssembler* masm,
   __ InvokeFunction(rdi, actual, JUMP_FUNCTION);
 }
 
-void CallIC::GenerateMegamorphic(MacroAssembler* a, int b) {
-  UNIMPLEMENTED();
+void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
+  // Cache miss: Jump to runtime.
+  Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss)));
 }
 
-void CallIC::GenerateNormal(MacroAssembler* a, int b) {
-  UNIMPLEMENTED();
+void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
+  // Cache miss: Jump to runtime.
+  Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss)));
 }
 
 
+// The offset from the inlined patch site to the start of the
+// inlined load instruction.
 const int LoadIC::kOffsetToLoadInstruction = 20;
 
 
 void LoadIC::ClearInlinedVersion(Address address) {
-  UNIMPLEMENTED();
+  // TODO(X64): Implement this when LoadIC is enabled.
 }
 
 
@@ -266,37 +278,54 @@ void LoadIC::Generate(MacroAssembler* masm, ExternalReference const& f) {
 
 
 void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
-  masm->int3();  // UNIMPLEMENTED.
-  masm->movq(kScratchRegister, Immediate(0xC4AB));  // Debugging aid.
+  Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss)));
 }
 
 void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
-  masm->int3();  // UNIMPLEMENTED.
-  masm->movq(kScratchRegister, Immediate(0xC5AB));  // Debugging aid.
+  Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss)));
 }
 
+
 void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
-  masm->int3();  // UNIMPLEMENTED.
-  masm->movq(kScratchRegister, Immediate(0xC6AB));  // Debugging aid.
+  // ----------- S t a t e -------------
+  //  -- rcx    : name
+  //  -- rsp[0] : return address
+  //  -- rsp[8] : receiver
+  // -----------------------------------
+
+  __ movq(rax, Operand(rsp, kPointerSize));
+
+  // Probe the stub cache.
+  Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
+                                         NOT_IN_LOOP,
+                                         MONOMORPHIC);
+  StubCache::GenerateProbe(masm, flags, rax, rcx, rbx, rdx);
+
+  // Cache miss: Jump to runtime.
+  Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss)));
 }
 
+
 void LoadIC::GenerateMiss(MacroAssembler* masm) {
-  masm->int3();  // UNIMPLEMENTED.
-  masm->movq(kScratchRegister, Immediate(0xC7AB));  // Debugging aid.
+  // ----------- S t a t e -------------
+  //  -- rcx    : name
+  //  -- rsp[0] : return address
+  //  -- rsp[8] : receiver
+  // -----------------------------------
+
+  Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss)));
 }
 
 void LoadIC::GenerateNormal(MacroAssembler* masm) {
-  masm->int3();  // UNIMPLEMENTED.
-  masm->movq(kScratchRegister, Immediate(0xC8AB));  // Debugging aid.
+  Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss)));
 }
 
 void LoadIC::GenerateStringLength(MacroAssembler* masm) {
-  masm->int3();  // UNIMPLEMENTED.
-  masm->movq(kScratchRegister, Immediate(0xC9AB));  // Debugging aid.
+  Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss)));
 }
 
 bool LoadIC::PatchInlinedLoad(Address address, Object* map, int index) {
-  UNIMPLEMENTED();
+  // TODO(X64): Implement this function.  Until then, the code is not patched.
   return false;
 }
 
@@ -319,13 +348,11 @@ void StoreIC::Generate(MacroAssembler* masm, ExternalReference const& f) {
 }
 
 void StoreIC::GenerateExtendStorage(MacroAssembler* masm) {
-  masm->int3();  // UNIMPLEMENTED.
-  masm->movq(kScratchRegister, Immediate(0xCAAB));  // Debugging aid.
+  Generate(masm, ExternalReference(IC_Utility(kStoreIC_Miss)));
 }
 
 void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
-  masm->int3();  // UNIMPLEMENTED.
-  masm->movq(kScratchRegister, Immediate(0xCBAB));  // Debugging aid.
+  Generate(masm, ExternalReference(IC_Utility(kStoreIC_Miss)));
 }
 
 
index 099a461..457011b 100644 (file)
@@ -882,4 +882,154 @@ void MacroAssembler::LeaveExitFrame(StackFrame::Type type) {
 }
 
 
+Register MacroAssembler::CheckMaps(JSObject* object, Register object_reg,
+                                   JSObject* holder, Register holder_reg,
+                                   Register scratch,
+                                   Label* miss) {
+  // Make sure there's no overlap between scratch and the other
+  // registers.
+  ASSERT(!scratch.is(object_reg) && !scratch.is(holder_reg));
+
+  // Keep track of the current object in register reg.  On the first
+  // iteration, reg is an alias for object_reg, on later iterations,
+  // it is an alias for holder_reg.
+  Register reg = object_reg;
+  int depth = 1;
+
+  // Check the maps in the prototype chain.
+  // Traverse the prototype chain from the object and do map checks.
+  while (object != holder) {
+    depth++;
+
+    // Only global objects and objects that do not require access
+    // checks are allowed in stubs.
+    ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
+
+    JSObject* prototype = JSObject::cast(object->GetPrototype());
+    if (Heap::InNewSpace(prototype)) {
+      // Get the map of the current object.
+      movq(scratch, FieldOperand(reg, HeapObject::kMapOffset));
+      Cmp(scratch, Handle<Map>(object->map()));
+      // Branch on the result of the map check.
+      j(not_equal, miss);
+      // Check access rights to the global object.  This has to happen
+      // after the map check so that we know that the object is
+      // actually a global object.
+      if (object->IsJSGlobalProxy()) {
+        CheckAccessGlobalProxy(reg, scratch, miss);
+
+        // Restore scratch register to be the map of the object.
+        // We load the prototype from the map in the scratch register.
+        movq(scratch, FieldOperand(reg, HeapObject::kMapOffset));
+      }
+      // The prototype is in new space; we cannot store a reference
+      // to it in the code. Load it from the map.
+      reg = holder_reg;  // from now the object is in holder_reg
+      movq(reg, FieldOperand(scratch, Map::kPrototypeOffset));
+
+    } else {
+      // Check the map of the current object.
+      Cmp(FieldOperand(reg, HeapObject::kMapOffset),
+          Handle<Map>(object->map()));
+      // Branch on the result of the map check.
+      j(not_equal, miss);
+      // Check access rights to the global object.  This has to happen
+      // after the map check so that we know that the object is
+      // actually a global object.
+      if (object->IsJSGlobalProxy()) {
+        CheckAccessGlobalProxy(reg, scratch, miss);
+      }
+      // The prototype is in old space; load it directly.
+      reg = holder_reg;  // from now the object is in holder_reg
+      Move(reg, Handle<JSObject>(prototype));
+    }
+
+    // Go to the next object in the prototype chain.
+    object = prototype;
+  }
+
+  // Check the holder map.
+  Cmp(FieldOperand(reg, HeapObject::kMapOffset),
+      Handle<Map>(holder->map()));
+  j(not_equal, miss);
+
+  // Log the check depth.
+  LOG(IntEvent("check-maps-depth", depth));
+
+  // Perform security check for access to the global object and return
+  // the holder register.
+  ASSERT(object == holder);
+  ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
+  if (object->IsJSGlobalProxy()) {
+    CheckAccessGlobalProxy(reg, scratch, miss);
+  }
+  return reg;
+}
+
+
+
+
+void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
+                                            Register scratch,
+                                            Label* miss) {
+  Label same_contexts;
+
+  ASSERT(!holder_reg.is(scratch));
+  ASSERT(!scratch.is(kScratchRegister));
+  // Load current lexical context from the stack frame.
+  movq(scratch, Operand(rbp, StandardFrameConstants::kContextOffset));
+
+  // When generating debug code, make sure the lexical context is set.
+  if (FLAG_debug_code) {
+    cmpq(scratch, Immediate(0));
+    Check(not_equal, "we should not have an empty lexical context");
+  }
+  // Load the global context of the current context.
+  int offset = Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
+  movq(scratch, FieldOperand(scratch, offset));
+  movq(scratch, FieldOperand(scratch, GlobalObject::kGlobalContextOffset));
+
+  // Check the context is a global context.
+  if (FLAG_debug_code) {
+    Cmp(FieldOperand(scratch, HeapObject::kMapOffset),
+        Factory::global_context_map());
+    Check(equal, "JSGlobalObject::global_context should be a global context.");
+  }
+
+  // Check if both contexts are the same.
+  cmpq(scratch, FieldOperand(holder_reg, JSGlobalProxy::kContextOffset));
+  j(equal, &same_contexts);
+
+  // Compare security tokens.
+  // Check that the security token in the calling global object is
+  // compatible with the security token in the receiving global
+  // object.
+
+  // Check the context is a global context.
+  if (FLAG_debug_code) {
+    // Preserve original value of holder_reg.
+    push(holder_reg);
+    movq(holder_reg, FieldOperand(holder_reg, JSGlobalProxy::kContextOffset));
+    Cmp(holder_reg, Factory::null_value());
+    Check(not_equal, "JSGlobalProxy::context() should not be null.");
+
+    // Read the first word and compare to global_context_map(),
+    movq(holder_reg, FieldOperand(holder_reg, HeapObject::kMapOffset));
+    Cmp(holder_reg, Factory::global_context_map());
+    Check(equal, "JSGlobalObject::global_context should be a global context.");
+    pop(holder_reg);
+  }
+
+  movq(kScratchRegister,
+       FieldOperand(holder_reg, JSGlobalProxy::kContextOffset));
+  int token_offset = Context::kHeaderSize +
+                     Context::SECURITY_TOKEN_INDEX * kPointerSize;
+  movq(scratch, FieldOperand(scratch, token_offset));
+  cmpq(scratch, FieldOperand(kScratchRegister, token_offset));
+  j(not_equal, miss);
+
+  bind(&same_contexts);
+}
+
+
 } }  // namespace v8::internal
index f13a7ad..2ee6eea 100644 (file)
@@ -212,7 +212,8 @@ class MacroAssembler: public Assembler {
 
   // Generate code for checking access rights - used for security checks
   // on access to global objects across environments. The holder register
-  // is left untouched, but the scratch register is clobbered.
+  // is left untouched, but the scratch register and kScratchRegister,
+  // which must be different, are clobbered.
   void CheckAccessGlobalProxy(Register holder_reg,
                               Register scratch,
                               Label* miss);
index 926dd64..54729d6 100644 (file)
@@ -46,7 +46,7 @@ bool RegisterAllocator::IsReserved(Register reg) {
 // non-reserved assembler registers.
 int RegisterAllocator::ToNumber(Register reg) {
   ASSERT(reg.is_valid() && !IsReserved(reg));
-  static const int numbers[] = {
+  const int kNumbers[] = {
     0,   // rax
     2,   // rcx
     3,   // rdx
@@ -64,15 +64,15 @@ int RegisterAllocator::ToNumber(Register reg) {
     8,   // r14
     9   // r15
   };
-  return numbers[reg.code()];
+  return kNumbers[reg.code()];
 }
 
 
 Register RegisterAllocator::ToRegister(int num) {
   ASSERT(num >= 0 && num < kNumRegisters);
-  static Register registers[] =
+  const Register kRegisters[] =
       { rax, rbx, rcx, rdx, rdi, r8, r9, r11, r14, r15, r13, r12 };
-  return registers[num];
+  return kRegisters[num];
 }
 
 
index c577615..ce7886b 100644 (file)
 namespace v8 {
 namespace internal {
 
-#define __ ACCESS_MASM((&masm_))
-
-
-Object* CallStubCompiler::CompileCallConstant(Object* a,
-                                              JSObject* b,
-                                              JSFunction* c,
-                                              String* d,
-                                              StubCompiler::CheckType e) {
-  UNIMPLEMENTED();
-  return NULL;
+#define __ ACCESS_MASM((masm()))
+
+
+Object* CallStubCompiler::CompileCallConstant(Object* object,
+                                              JSObject* holder,
+                                              JSFunction* function,
+                                              String* name,
+                                              StubCompiler::CheckType check) {
+  // ----------- S t a t e -------------
+  // -----------------------------------
+  // rsp[0] return address
+  // rsp[8] argument argc
+  // rsp[16] argument argc - 1
+  // ...
+  // rsp[argc * 8] argument 1
+  // rsp[(argc + 1) * 8] argument 0 = reciever
+  // rsp[(argc + 2) * 8] function name
+
+  Label miss;
+
+  // Get the receiver from the stack.
+  const int argc = arguments().immediate();
+  __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
+
+  // Check that the receiver isn't a smi.
+  if (check != NUMBER_CHECK) {
+    __ testl(rdx, Immediate(kSmiTagMask));
+    __ j(zero, &miss);
+  }
+
+  // Make sure that it's okay not to patch the on stack receiver
+  // unless we're doing a receiver map check.
+  ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
+
+  switch (check) {
+    case RECEIVER_MAP_CHECK:
+      // Check that the maps haven't changed.
+      CheckPrototypes(JSObject::cast(object), rdx, holder,
+                      rbx, rcx, name, &miss);
+
+      // Patch the receiver on the stack with the global proxy if
+      // necessary.
+      if (object->IsGlobalObject()) {
+        __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
+        __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
+      }
+      break;
+
+    case STRING_CHECK:
+      // Check that the object is a two-byte string or a symbol.
+      __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, rcx);
+      __ j(above_equal, &miss);
+      // Check that the maps starting from the prototype haven't changed.
+      GenerateLoadGlobalFunctionPrototype(masm(),
+                                          Context::STRING_FUNCTION_INDEX,
+                                          rcx);
+      CheckPrototypes(JSObject::cast(object->GetPrototype()), rcx, holder,
+                      rbx, rdx, name, &miss);
+      break;
+
+    case NUMBER_CHECK: {
+      Label fast;
+      // Check that the object is a smi or a heap number.
+      __ testl(rdx, Immediate(kSmiTagMask));
+      __ j(zero, &fast);
+      __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rcx);
+      __ j(not_equal, &miss);
+      __ bind(&fast);
+      // Check that the maps starting from the prototype haven't changed.
+      GenerateLoadGlobalFunctionPrototype(masm(),
+                                          Context::NUMBER_FUNCTION_INDEX,
+                                          rcx);
+      CheckPrototypes(JSObject::cast(object->GetPrototype()), rcx, holder,
+                      rbx, rdx, name, &miss);
+      break;
+    }
+
+    case BOOLEAN_CHECK: {
+      Label fast;
+      // Check that the object is a boolean.
+      __ Cmp(rdx, Factory::true_value());
+      __ j(equal, &fast);
+      __ Cmp(rdx, Factory::false_value());
+      __ j(not_equal, &miss);
+      __ bind(&fast);
+      // Check that the maps starting from the prototype haven't changed.
+      GenerateLoadGlobalFunctionPrototype(masm(),
+                                          Context::BOOLEAN_FUNCTION_INDEX,
+                                          rcx);
+      CheckPrototypes(JSObject::cast(object->GetPrototype()), rcx, holder,
+                      rbx, rdx, name, &miss);
+      break;
+    }
+
+    case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
+      CheckPrototypes(JSObject::cast(object), rdx, holder,
+                      rbx, rcx, name, &miss);
+      // Make sure object->elements()->map() != Heap::dictionary_array_map()
+      // Get the elements array of the object.
+      __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
+      // Check that the object is in fast mode (not dictionary).
+      __ Cmp(FieldOperand(rbx, HeapObject::kMapOffset),
+             Factory::hash_table_map());
+      __ j(equal, &miss);
+      break;
+
+    default:
+      UNREACHABLE();
+  }
+
+  // Get the function and setup the context.
+  __ Move(rdi, Handle<JSFunction>(function));
+  __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
+
+  // Jump to the cached code (tail call).
+  ASSERT(function->is_compiled());
+  Handle<Code> code(function->code());
+  ParameterCount expected(function->shared()->formal_parameter_count());
+  __ InvokeCode(code, expected, arguments(),
+                RelocInfo::CODE_TARGET, JUMP_FUNCTION);
+
+  // Handle call cache miss.
+  __ bind(&miss);
+  Handle<Code> ic = ComputeCallMiss(arguments().immediate());
+  __ Jump(ic, RelocInfo::CODE_TARGET);
+
+  // Return the generated code.
+  String* function_name = NULL;
+  if (function->shared()->name()->IsString()) {
+    function_name = String::cast(function->shared()->name());
+  }
+  return GetCode(CONSTANT_FUNCTION, function_name);
 }
 
-Object* CallStubCompiler::CompileCallField(Object* a,
-                                           JSObject* b,
-                                           int c,
-                                           String* d) {
-  UNIMPLEMENTED();
-  return NULL;
+
+Object* CallStubCompiler::CompileCallField(Object* object,
+                                           JSObject* holder,
+                                           int index,
+                                           String* name) {
+  // ----------- S t a t e -------------
+  // -----------------------------------
+  // rsp[0] return address
+  // rsp[8] argument argc
+  // rsp[16] argument argc - 1
+  // ...
+  // rsp[argc * 8] argument 1
+  // rsp[(argc + 1) * 8] argument 0 = receiver
+  // rsp[(argc + 2) * 8] function name
+  Label miss;
+
+  // Get the receiver from the stack.
+  const int argc = arguments().immediate();
+  __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
+
+  // Check that the receiver isn't a smi.
+  __ testl(rdx, Immediate(kSmiTagMask));
+  __ j(zero, &miss);
+
+  // Do the right check and compute the holder register.
+  Register reg =
+      CheckPrototypes(JSObject::cast(object), rdx, holder,
+                      rbx, rcx, name, &miss);
+
+  GenerateFastPropertyLoad(masm(), rdi, reg, holder, index);
+
+  // Check that the function really is a function.
+  __ testl(rdi, Immediate(kSmiTagMask));
+  __ j(zero, &miss);
+  __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rbx);
+  __ j(not_equal, &miss);
+
+  // Patch the receiver on the stack with the global proxy if
+  // necessary.
+  if (object->IsGlobalObject()) {
+    __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
+    __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
+  }
+
+  // Invoke the function.
+  __ InvokeFunction(rdi, arguments(), JUMP_FUNCTION);
+
+  // Handle call cache miss.
+  __ bind(&miss);
+  Handle<Code> ic = ComputeCallMiss(arguments().immediate());
+  __ Jump(ic, RelocInfo::CODE_TARGET);
+
+  // Return the generated code.
+  return GetCode(FIELD, name);
 }
 
 
 Object* CallStubCompiler::CompileCallInterceptor(Object* a,
                                                  JSObject* b,
                                                  String* c) {
-  UNIMPLEMENTED();
-  return NULL;
+  // TODO(X64): Implement a real stub.
+  return Failure::InternalError();
 }
 
 
@@ -71,8 +241,69 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
                                             JSGlobalPropertyCell* cell,
                                             JSFunction* function,
                                             String* name) {
-  UNIMPLEMENTED();
-  return NULL;
+  // ----------- S t a t e -------------
+  // -----------------------------------
+  // rsp[0] return address
+  // rsp[8] argument argc
+  // rsp[16] argument argc - 1
+  // ...
+  // rsp[argc * 8] argument 1
+  // rsp[(argc + 1) * 8] argument 0 = receiver
+  // rsp[(argc + 2) * 8] function name
+  Label miss;
+
+  __ IncrementCounter(&Counters::call_global_inline, 1);
+
+  // Get the number of arguments.
+  const int argc = arguments().immediate();
+
+  // Get the receiver from the stack.
+  __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
+
+  // If the object is the holder then we know that it's a global
+  // object which can only happen for contextual calls. In this case,
+  // the receiver cannot be a smi.
+  if (object != holder) {
+    __ testl(rdx, Immediate(kSmiTagMask));
+    __ j(zero, &miss);
+  }
+
+  // Check that the maps haven't changed.
+  CheckPrototypes(object, rdx, holder, rbx, rcx, name, &miss);
+
+  // Get the value from the cell.
+  __ Move(rdi, Handle<JSGlobalPropertyCell>(cell));
+  __ movq(rdi, FieldOperand(rdi, JSGlobalPropertyCell::kValueOffset));
+
+  // Check that the cell contains the same function.
+  __ Cmp(rdi, Handle<JSFunction>(function));
+  __ j(not_equal, &miss);
+
+  // Patch the receiver on the stack with the global proxy.
+  if (object->IsGlobalObject()) {
+    __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
+    __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
+  }
+
+  // Setup the context (function already in edi).
+  __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
+
+  // Jump to the cached code (tail call).
+  ASSERT(function->is_compiled());
+  Handle<Code> code(function->code());
+  ParameterCount expected(function->shared()->formal_parameter_count());
+  __ InvokeCode(code, expected, arguments(),
+                RelocInfo::CODE_TARGET, JUMP_FUNCTION);
+
+  // Handle call cache miss.
+  __ bind(&miss);
+  __ DecrementCounter(&Counters::call_global_inline, 1);
+  __ IncrementCounter(&Counters::call_global_inline_miss, 1);
+  Handle<Code> ic = ComputeCallMiss(arguments().immediate());
+  __ Jump(ic, RelocInfo::CODE_TARGET);
+
+  // Return the generated code.
+  return GetCode(NORMAL, name);
 }
 
 
@@ -80,34 +311,58 @@ Object* LoadStubCompiler::CompileLoadCallback(JSObject* a,
                                               JSObject* b,
                                               AccessorInfo* c,
                                               String* d) {
-  UNIMPLEMENTED();
-  return NULL;
+  // TODO(X64): Implement a real stub.
+  return Failure::InternalError();
 }
 
 
-Object* LoadStubCompiler::CompileLoadConstant(JSObject* a,
-                                              JSObject* b,
-                                              Object* c,
-                                              String* d) {
-  UNIMPLEMENTED();
-  return NULL;
+Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
+                                              JSObject* holder,
+                                              Object* value,
+                                              String* name) {
+  // ----------- S t a t e -------------
+  //  -- rcx    : name
+  //  -- rsp[0] : return address
+  //  -- rsp[8] : receiver
+  // -----------------------------------
+  Label miss;
+
+  __ movq(rax, (Operand(rsp, kPointerSize)));
+  GenerateLoadConstant(object, holder, rax, rbx, rdx, value, name, &miss);
+  __ bind(&miss);
+  GenerateLoadMiss(masm(), Code::LOAD_IC);
+
+  // Return the generated code.
+  return GetCode(CONSTANT_FUNCTION, name);
 }
 
 
-Object* LoadStubCompiler::CompileLoadField(JSObject* a,
-                                           JSObject* b,
-                                           int c,
-                                           String* d) {
-  UNIMPLEMENTED();
-  return NULL;
+Object* LoadStubCompiler::CompileLoadField(JSObject* object,
+                                           JSObject* holder,
+                                           int index,
+                                           String* name) {
+  // ----------- S t a t e -------------
+  //  -- rcx    : name
+  //  -- rsp[0] : return address
+  //  -- rsp[8] : receiver
+  // -----------------------------------
+  Label miss;
+
+  __ movq(rax, (Operand(rsp, kPointerSize)));
+  GenerateLoadField(object, holder, rax, rbx, rdx, index, name, &miss);
+  __ bind(&miss);
+  GenerateLoadMiss(masm(), Code::LOAD_IC);
+
+  // Return the generated code.
+  return GetCode(FIELD, name);
 }
 
 
 Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* a,
                                                  JSObject* b,
                                                  String* c) {
-  UNIMPLEMENTED();
-  return NULL;
+  // TODO(X64): Implement a real stub.
+  return Failure::InternalError();
 }
 
 
@@ -116,8 +371,51 @@ Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
                                             JSGlobalPropertyCell* cell,
                                             String* name,
                                             bool is_dont_delete) {
-  UNIMPLEMENTED();
-  return NULL;
+  // ----------- S t a t e -------------
+  //  -- rcx    : name
+  //  -- rsp[0] : return address
+  //  -- rsp[8] : receiver
+  // -----------------------------------
+  Label miss;
+
+  __ IncrementCounter(&Counters::named_load_global_inline, 1);
+
+  // Get the receiver from the stack.
+  __ movq(rax, (Operand(rsp, kPointerSize)));
+
+  // If the object is the holder then we know that it's a global
+  // object which can only happen for contextual loads. In this case,
+  // the receiver cannot be a smi.
+  if (object != holder) {
+    __ testl(rax, Immediate(kSmiTagMask));
+    __ j(zero, &miss);
+  }
+
+  // Check that the maps haven't changed.
+  CheckPrototypes(object, rax, holder, rbx, rdx, name, &miss);
+
+  // Get the value from the cell.
+  __ Move(rax, Handle<JSGlobalPropertyCell>(cell));
+  __ movq(rax, FieldOperand(rax, JSGlobalPropertyCell::kValueOffset));
+
+  // Check for deleted property if property can actually be deleted.
+  if (!is_dont_delete) {
+    __ Cmp(rax, Factory::the_hole_value());
+    __ j(equal, &miss);
+  } else if (FLAG_debug_code) {
+    __ Cmp(rax, Factory::the_hole_value());
+    __ Check(not_equal, "DontDelete cells can't contain the hole");
+  }
+
+  __ ret(0);
+
+  __ bind(&miss);
+  __ DecrementCounter(&Counters::named_load_global_inline, 1);
+  __ IncrementCounter(&Counters::named_load_global_inline_miss, 1);
+  GenerateLoadMiss(masm(), Code::LOAD_IC);
+
+  // Return the generated code.
+  return GetCode(NORMAL, name);
 }
 
 
@@ -129,12 +427,38 @@ Object* StoreStubCompiler::CompileStoreCallback(JSObject* a,
 }
 
 
-Object* StoreStubCompiler::CompileStoreField(JSObject* a,
-                                             int b,
-                                             Map* c,
-                                             String* d) {
-  UNIMPLEMENTED();
-  return NULL;
+Object* StoreStubCompiler::CompileStoreField(JSObject* object,
+                                             int index,
+                                             Map* transition,
+                                             String* name) {
+  // ----------- S t a t e -------------
+  //  -- rax    : value
+  //  -- rcx    : name
+  //  -- rsp[0] : return address
+  //  -- rsp[8] : receiver
+  // -----------------------------------
+  Label miss;
+
+  // Get the object from the stack.
+  __ movq(rbx, Operand(rsp, 1 * kPointerSize));
+
+  // Generate store field code.  Trashes the name register.
+  GenerateStoreField(masm(),
+                     Builtins::StoreIC_ExtendStorage,
+                     object,
+                     index,
+                     transition,
+                     rbx, rcx, rdx,
+                     &miss);
+
+  // Handle store cache miss.
+  __ bind(&miss);
+  __ Move(rcx, Handle<String>(name));  // restore name
+  Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
+  __ Jump(ic, RelocInfo::CODE_TARGET);
+
+  // Return the generated code.
+  return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
 }
 
 
@@ -175,6 +499,308 @@ Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
   return GetCodeWithFlags(flags, "LazyCompileStub");
 }
 
+
+Register StubCompiler::CheckPrototypes(JSObject* object,
+                                       Register object_reg,
+                                       JSObject* holder,
+                                       Register holder_reg,
+                                       Register scratch,
+                                       String* name,
+                                       Label* miss) {
+  // Check that the maps haven't changed.
+  Register result =
+      __ CheckMaps(object, object_reg, holder, holder_reg, scratch, miss);
+
+  // If we've skipped any global objects, it's not enough to verify
+  // that their maps haven't changed.
+  while (object != holder) {
+    if (object->IsGlobalObject()) {
+      GlobalObject* global = GlobalObject::cast(object);
+      Object* probe = global->EnsurePropertyCell(name);
+      if (probe->IsFailure()) {
+        set_failure(Failure::cast(probe));
+        return result;
+      }
+      JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe);
+      ASSERT(cell->value()->IsTheHole());
+      __ Move(scratch, Handle<Object>(cell));
+      __ Cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset),
+             Factory::the_hole_value());
+      __ j(not_equal, miss);
+    }
+    object = JSObject::cast(object->GetPrototype());
+  }
+
+  // Return the register containing the holder.
+  return result;
+}
+
+
+void StubCompiler::GenerateLoadField(JSObject* object,
+                                     JSObject* holder,
+                                     Register receiver,
+                                     Register scratch1,
+                                     Register scratch2,
+                                     int index,
+                                     String* name,
+                                     Label* miss) {
+  // Check that the receiver isn't a smi.
+  __ testl(receiver, Immediate(kSmiTagMask));
+  __ j(zero, miss);
+
+  // Check the prototype chain.
+  Register reg =
+      CheckPrototypes(object, receiver, holder,
+                      scratch1, scratch2, name, miss);
+
+  // Get the value from the properties.
+  GenerateFastPropertyLoad(masm(), rax, reg, holder, index);
+  __ ret(0);
+}
+
+
+void StubCompiler::GenerateLoadConstant(JSObject* object,
+                                        JSObject* holder,
+                                        Register receiver,
+                                        Register scratch1,
+                                        Register scratch2,
+                                        Object* value,
+                                        String* name,
+                                        Label* miss) {
+  // Check that the receiver isn't a smi.
+  __ testl(receiver, Immediate(kSmiTagMask));
+  __ j(zero, miss);
+
+  // Check that the maps haven't changed.
+  Register reg =
+      CheckPrototypes(object, receiver, holder,
+                      scratch1, scratch2, name, miss);
+
+  // Return the constant value.
+  __ Move(rax, Handle<Object>(value));
+  __ ret(0);
+}
+
+
+#undef __
+
+//-----------------------------------------------------------------------------
+// StubCompiler static helper functions
+
+#define __ ACCESS_MASM(masm)
+
+
+static void ProbeTable(MacroAssembler* masm,
+                       Code::Flags flags,
+                       StubCache::Table table,
+                       Register name,
+                       Register offset) {
+  ExternalReference key_offset(SCTableReference::keyReference(table));
+  Label miss;
+
+  __ movq(kScratchRegister, key_offset);
+  // Check that the key in the entry matches the name.
+  __ cmpl(name, Operand(kScratchRegister, offset, times_4, 0));
+  __ j(not_equal, &miss);
+  // Get the code entry from the cache.
+  // Use key_offset + kPointerSize, rather than loading value_offset.
+  __ movq(kScratchRegister,
+          Operand(kScratchRegister, offset, times_4, kPointerSize));
+  // Check that the flags match what we're looking for.
+  __ movl(offset, FieldOperand(kScratchRegister, Code::kFlagsOffset));
+  __ and_(offset, Immediate(~Code::kFlagsNotUsedInLookup));
+  __ cmpl(offset, Immediate(flags));
+  __ j(not_equal, &miss);
+
+  // Jump to the first instruction in the code stub.
+  __ addq(kScratchRegister, Immediate(Code::kHeaderSize - kHeapObjectTag));
+  __ jmp(kScratchRegister);
+
+  __ bind(&miss);
+}
+
+
+void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
+  ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
+  Code* code = NULL;
+  if (kind == Code::LOAD_IC) {
+    code = Builtins::builtin(Builtins::LoadIC_Miss);
+  } else {
+    code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
+  }
+
+  Handle<Code> ic(code);
+  __ Jump(ic, RelocInfo::CODE_TARGET);
+}
+
+
+void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
+                                                       int index,
+                                                       Register prototype) {
+  // Load the global or builtins object from the current context.
+  __ movq(prototype,
+             Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
+  // Load the global context from the global or builtins object.
+  __ movq(prototype,
+             FieldOperand(prototype, GlobalObject::kGlobalContextOffset));
+  // Load the function from the global context.
+  __ movq(prototype, Operand(prototype, Context::SlotOffset(index)));
+  // Load the initial map.  The global functions all have initial maps.
+  __ movq(prototype,
+             FieldOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
+  // Load the prototype from the initial map.
+  __ movq(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
+}
+
+
+// Load a fast property out of a holder object (src). In-object properties
+// are loaded directly otherwise the property is loaded from the properties
+// fixed array.
+void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
+                                            Register dst, Register src,
+                                            JSObject* holder, int index) {
+  // Adjust for the number of properties stored in the holder.
+  index -= holder->map()->inobject_properties();
+  if (index < 0) {
+    // Get the property straight out of the holder.
+    int offset = holder->map()->instance_size() + (index * kPointerSize);
+    __ movq(dst, FieldOperand(src, offset));
+  } else {
+    // Calculate the offset into the properties array.
+    int offset = index * kPointerSize + FixedArray::kHeaderSize;
+    __ movq(dst, FieldOperand(src, JSObject::kPropertiesOffset));
+    __ movq(dst, FieldOperand(dst, offset));
+  }
+}
+
+
+void StubCache::GenerateProbe(MacroAssembler* masm,
+                              Code::Flags flags,
+                              Register receiver,
+                              Register name,
+                              Register scratch,
+                              Register extra) {
+  Label miss;
+  USE(extra);  // The register extra is not used on the X64 platform.
+  // Make sure that code is valid. The shifting code relies on the
+  // entry size being 16.
+  ASSERT(sizeof(Entry) == 16);
+
+  // Make sure the flags do not name a specific type.
+  ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
+
+  // Make sure that there are no register conflicts.
+  ASSERT(!scratch.is(receiver));
+  ASSERT(!scratch.is(name));
+
+  // Check that the receiver isn't a smi.
+  __ testl(receiver, Immediate(kSmiTagMask));
+  __ j(zero, &miss);
+
+  // Get the map of the receiver and compute the hash.
+  __ movl(scratch, FieldOperand(name, String::kLengthOffset));
+  // Use only the low 32 bits of the map pointer.
+  __ addl(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
+  __ xor_(scratch, Immediate(flags));
+  __ and_(scratch, Immediate((kPrimaryTableSize - 1) << kHeapObjectTagSize));
+
+  // Probe the primary table.
+  ProbeTable(masm, flags, kPrimary, name, scratch);
+
+  // Primary miss: Compute hash for secondary probe.
+  __ movl(scratch, FieldOperand(name, String::kLengthOffset));
+  __ addl(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
+  __ xor_(scratch, Immediate(flags));
+  __ and_(scratch, Immediate((kPrimaryTableSize - 1) << kHeapObjectTagSize));
+  __ subl(scratch, name);
+  __ addl(scratch, Immediate(flags));
+  __ and_(scratch, Immediate((kSecondaryTableSize - 1) << kHeapObjectTagSize));
+
+  // Probe the secondary table.
+  ProbeTable(masm, flags, kSecondary, name, scratch);
+
+  // Cache miss: Fall-through and let caller handle the miss by
+  // entering the runtime system.
+  __ bind(&miss);
+}
+
+
+void StubCompiler::GenerateStoreField(MacroAssembler* masm,
+                                      Builtins::Name storage_extend,
+                                      JSObject* object,
+                                      int index,
+                                      Map* transition,
+                                      Register receiver_reg,
+                                      Register name_reg,
+                                      Register scratch,
+                                      Label* miss_label) {
+  // Check that the object isn't a smi.
+  __ testl(receiver_reg, Immediate(kSmiTagMask));
+  __ j(zero, miss_label);
+
+  // Check that the map of the object hasn't changed.
+  __ Cmp(FieldOperand(receiver_reg, HeapObject::kMapOffset),
+         Handle<Map>(object->map()));
+  __ j(not_equal, miss_label);
+
+  // Perform global security token check if needed.
+  if (object->IsJSGlobalProxy()) {
+    __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
+  }
+
+  // Stub never generated for non-global objects that require access
+  // checks.
+  ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
+
+  // Perform map transition for the receiver if necessary.
+  if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
+    // The properties must be extended before we can store the value.
+    // We jump to a runtime call that extends the properties array.
+    __ Move(rcx, Handle<Map>(transition));
+    Handle<Code> ic(Builtins::builtin(storage_extend));
+    __ Jump(ic, RelocInfo::CODE_TARGET);
+    return;
+  }
+
+  if (transition != NULL) {
+    // Update the map of the object; no write barrier updating is
+    // needed because the map is never in new space.
+    __ Move(FieldOperand(receiver_reg, HeapObject::kMapOffset),
+            Handle<Map>(transition));
+  }
+
+  // Adjust for the number of properties stored in the object. Even in the
+  // face of a transition we can use the old map here because the size of the
+  // object and the number of in-object properties is not going to change.
+  index -= object->map()->inobject_properties();
+
+  if (index < 0) {
+    // Set the property straight into the object.
+    int offset = object->map()->instance_size() + (index * kPointerSize);
+    __ movq(FieldOperand(receiver_reg, offset), rax);
+
+    // Update the write barrier for the array address.
+    // Pass the value being stored in the now unused name_reg.
+    __ movq(name_reg, rax);
+    __ RecordWrite(receiver_reg, offset, name_reg, scratch);
+  } else {
+    // Write to the properties array.
+    int offset = index * kPointerSize + FixedArray::kHeaderSize;
+    // Get the properties array (optimistically).
+    __ movq(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
+    __ movq(FieldOperand(scratch, offset), rax);
+
+    // Update the write barrier for the array address.
+    // Pass the value being stored in the now unused name_reg.
+    __ movq(name_reg, rax);
+    __ RecordWrite(scratch, offset, name_reg, receiver_reg);
+  }
+
+  // Return the value (register rax).
+  __ ret(0);
+}
+
+
 #undef __
 
 
index d78c19b..33fe557 100644 (file)
@@ -176,7 +176,10 @@ Address Zone::NewExpand(int size) {
     new_size = Max(kSegmentOverhead + size, kMaximumSegmentSize);
   }
   Segment* segment = Segment::New(new_size);
-  if (segment == NULL) V8::FatalProcessOutOfMemory("Zone");
+  if (segment == NULL) {
+    V8::FatalProcessOutOfMemory("Zone");
+    return NULL;
+  }
 
   // Recompute 'top' and 'limit' based on the new segment.
   Address result = RoundUp(segment->start(), kAlignment);
index bb82fc8..b234ca3 100644 (file)
@@ -63,7 +63,7 @@ test-api/TryCatchInTryFinally: FAIL
 
 
 [ $arch == x64 ]
-test-regexp/Graph: CRASH || FAIL
+test-regexp/Graph: PASS || CRASH || FAIL
 test-decls/Present: CRASH || FAIL
 test-decls/Unknown: CRASH || FAIL
 test-decls/Appearing: CRASH || FAIL
@@ -108,11 +108,9 @@ test-debug/StepWithException: CRASH || FAIL
 test-debug/DebugBreak: CRASH || FAIL
 test-debug/DisableBreak: CRASH || FAIL
 test-debug/MessageQueues: CRASH || FAIL
-test-debug/CallFunctionInDebugger: CRASH || FAIL
+test-debug/CallFunctionInDebugger: SKIP
 test-debug/RecursiveBreakpoints: CRASH || FAIL
 test-debug/DebuggerUnload: CRASH || FAIL
-test-debug/DebuggerClearMessageHandler: CRASH || FAIL
-test-debug/DebuggerClearMessageHandlerWhileActive: CRASH || FAIL
 test-debug/DebuggerHostDispatch: CRASH || FAIL
 test-debug/DebugBreakInMessageHandler: CRASH || FAIL
 test-api/HugeConsStringOutOfMemory: CRASH || FAIL
@@ -120,5 +118,5 @@ test-api/OutOfMemory: CRASH || FAIL
 test-api/OutOfMemoryNested: CRASH || FAIL
 test-api/Threading: CRASH || FAIL
 test-api/TryCatchSourceInfo: CRASH || FAIL
-test-api/RegExpInterruption: CRASH || FAIL
-test-api/RegExpStringModification: CRASH || FAIL
+test-api/RegExpInterruption: PASS || TIMEOUT
+test-api/RegExpStringModification: PASS || TIMEOUT
index 5b04b2c..806e711 100644 (file)
@@ -1266,6 +1266,38 @@ THREADED_TEST(InternalFields) {
 }
 
 
+THREADED_TEST(InternalFieldsNativePointers) {
+  v8::HandleScope scope;
+  LocalContext env;
+
+  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
+  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
+  instance_templ->SetInternalFieldCount(1);
+  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
+  CHECK_EQ(1, obj->InternalFieldCount());
+  CHECK(obj->GetPointerFromInternalField(0) == NULL);
+
+  char* data = new char[100];
+
+  void* aligned = data;
+  CHECK_EQ(0, reinterpret_cast<uintptr_t>(aligned) & 0x1);
+  void* unaligned = data + 1;
+  CHECK_EQ(1, reinterpret_cast<uintptr_t>(unaligned) & 0x1);
+
+  // Check reading and writing aligned pointers.
+  obj->SetPointerInInternalField(0, aligned);
+  i::Heap::CollectAllGarbage();
+  CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
+
+  // Check reading and writing unaligned pointers.
+  obj->SetPointerInInternalField(0, unaligned);
+  i::Heap::CollectAllGarbage();
+  CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
+
+  delete[] data;
+}
+
+
 THREADED_TEST(IdentityHash) {
   v8::HandleScope scope;
   LocalContext env;
@@ -5024,6 +5056,236 @@ THREADED_TEST(InterceptorLoadICWithOverride) {
 }
 
 
+// Test the case when we stored field into
+// a stub, but interceptor produced value on its own.
+THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
+  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
+    "proto = new Object();"
+    "o.__proto__ = proto;"
+    "proto.x = 239;"
+    "for (var i = 0; i < 1000; i++) {"
+    "  o.x;"
+    // Now it should be ICed and keep a reference to x defined on proto
+    "}"
+    "var result = 0;"
+    "for (var i = 0; i < 1000; i++) {"
+    "  result += o.x;"
+    "}"
+    "result;",
+    42 * 1000);
+}
+
+
+// Test the case when we stored field into
+// a stub, but it got invalidated later on.
+THREADED_TEST(InterceptorLoadICInvalidatedField) {
+  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
+    "proto1 = new Object();"
+    "proto2 = new Object();"
+    "o.__proto__ = proto1;"
+    "proto1.__proto__ = proto2;"
+    "proto2.y = 239;"
+    "for (var i = 0; i < 1000; i++) {"
+    "  o.y;"
+    // Now it should be ICed and keep a reference to y defined on proto2
+    "}"
+    "proto1.y = 42;"
+    "var result = 0;"
+    "for (var i = 0; i < 1000; i++) {"
+    "  result += o.y;"
+    "}"
+    "result;",
+    42 * 1000);
+}
+
+
+// Test the case when we stored field into
+// a stub, but it got invalidated later on due to override on
+// global object which is between interceptor and fields' holders.
+THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
+  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
+    "o.__proto__ = this;"  // set a global to be a proto of o.
+    "this.__proto__.y = 239;"
+    "for (var i = 0; i < 10; i++) {"
+    "  if (o.y != 239) throw 'oops: ' + o.y;"
+    // Now it should be ICed and keep a reference to y defined on field_holder.
+    "}"
+    "this.y = 42;"  // Assign on a global.
+    "var result = 0;"
+    "for (var i = 0; i < 10; i++) {"
+    "  result += o.y;"
+    "}"
+    "result;",
+    42 * 10);
+}
+
+
+static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
+  ApiTestFuzzer::Fuzz();
+  return v8_num(239);
+}
+
+
+static void SetOnThis(Local<String> name,
+                      Local<Value> value,
+                      const AccessorInfo& info) {
+  info.This()->ForceSet(name, value);
+}
+
+
+THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
+  v8::HandleScope scope;
+  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
+  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
+  templ->SetAccessor(v8_str("y"), Return239);
+  LocalContext context;
+  context->Global()->Set(v8_str("o"), templ->NewInstance());
+  v8::Handle<Value> value = CompileRun(
+      "var result = 0;"
+      "for (var i = 0; i < 7; i++) {"
+      "  result = o.y;"
+      "}");
+  CHECK_EQ(239, value->Int32Value());
+}
+
+
+THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
+  v8::HandleScope scope;
+  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
+  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
+  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
+  templ_p->SetAccessor(v8_str("y"), Return239);
+
+  LocalContext context;
+  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
+  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
+
+  v8::Handle<Value> value = CompileRun(
+      "o.__proto__ = p;"
+      "var result = 0;"
+      "for (var i = 0; i < 7; i++) {"
+      "  result = o.x + o.y;"
+      "}");
+  CHECK_EQ(239 + 42, value->Int32Value());
+}
+
+
+THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
+  v8::HandleScope scope;
+  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
+  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
+  templ->SetAccessor(v8_str("y"), Return239);
+
+  LocalContext context;
+  context->Global()->Set(v8_str("o"), templ->NewInstance());
+
+  v8::Handle<Value> value = CompileRun(
+    "fst = new Object();  fst.__proto__ = o;"
+    "snd = new Object();  snd.__proto__ = fst;"
+    "var result1 = 0;"
+    "for (var i = 0; i < 7;  i++) {"
+    "  result1 = snd.x;"
+    "}"
+    "fst.x = 239;"
+    "var result = 0;"
+    "for (var i = 0; i < 7; i++) {"
+    "  result = snd.x;"
+    "}"
+    "result + result1");
+  CHECK_EQ(239 + 42, value->Int32Value());
+}
+
+
+// Test the case when we stored callback into
+// a stub, but interceptor produced value on its own.
+THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
+  v8::HandleScope scope;
+  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
+  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
+  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
+  templ_p->SetAccessor(v8_str("y"), Return239);
+
+  LocalContext context;
+  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
+  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
+
+  v8::Handle<Value> value = CompileRun(
+    "o.__proto__ = p;"
+    "for (var i = 0; i < 7; i++) {"
+    "  o.x;"
+    // Now it should be ICed and keep a reference to x defined on p
+    "}"
+    "var result = 0;"
+    "for (var i = 0; i < 7; i++) {"
+    "  result += o.x;"
+    "}"
+    "result");
+  CHECK_EQ(42 * 7, value->Int32Value());
+}
+
+
+// Test the case when we stored callback into
+// a stub, but it got invalidated later on.
+THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
+  v8::HandleScope scope;
+  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
+  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
+  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
+  templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
+
+  LocalContext context;
+  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
+  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
+
+  v8::Handle<Value> value = CompileRun(
+    "inbetween = new Object();"
+    "o.__proto__ = inbetween;"
+    "inbetween.__proto__ = p;"
+    "for (var i = 0; i < 10; i++) {"
+    "  o.y;"
+    // Now it should be ICed and keep a reference to y defined on p
+    "}"
+    "inbetween.y = 42;"
+    "var result = 0;"
+    "for (var i = 0; i < 10; i++) {"
+    "  result += o.y;"
+    "}"
+    "result");
+  CHECK_EQ(42 * 10, value->Int32Value());
+}
+
+
+// Test the case when we stored callback into
+// a stub, but it got invalidated later on due to override on
+// global object which is between interceptor and callbacks' holders.
+THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
+  v8::HandleScope scope;
+  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
+  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
+  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
+  templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
+
+  LocalContext context;
+  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
+  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
+
+  v8::Handle<Value> value = CompileRun(
+    "o.__proto__ = this;"
+    "this.__proto__ = p;"
+    "for (var i = 0; i < 10; i++) {"
+    "  if (o.y != 239) throw 'oops: ' + o.y;"
+    // Now it should be ICed and keep a reference to y defined on p
+    "}"
+    "this.y = 42;"
+    "var result = 0;"
+    "for (var i = 0; i < 10; i++) {"
+    "  result += o.y;"
+    "}"
+    "result");
+  CHECK_EQ(42 * 10, value->Int32Value());
+}
+
+
 static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
                                                   const AccessorInfo& info) {
   ApiTestFuzzer::Fuzz();
@@ -5108,6 +5370,192 @@ THREADED_TEST(InterceptorCallIC) {
   CHECK_EQ(42, value->Int32Value());
 }
 
+
+// This test checks that if interceptor doesn't provide
+// a value, we can fetch regular value.
+THREADED_TEST(InterceptorCallICSeesOthers) {
+  v8::HandleScope scope;
+  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
+  templ->SetNamedPropertyHandler(NoBlockGetterX);
+  LocalContext context;
+  context->Global()->Set(v8_str("o"), templ->NewInstance());
+  v8::Handle<Value> value = CompileRun(
+    "o.x = function f(x) { return x + 1; };"
+    "var result = 0;"
+    "for (var i = 0; i < 7; i++) {"
+    "  result = o.x(41);"
+    "}");
+  CHECK_EQ(42, value->Int32Value());
+}
+
+
+static v8::Handle<Value> call_ic_function4;
+static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
+                                                  const AccessorInfo& info) {
+  ApiTestFuzzer::Fuzz();
+  CHECK(v8_str("x")->Equals(name));
+  return call_ic_function4;
+}
+
+
+// This test checks that if interceptor provides a function,
+// even if we cached shadowed variant, interceptor's function
+// is invoked
+THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
+  v8::HandleScope scope;
+  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
+  templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
+  LocalContext context;
+  context->Global()->Set(v8_str("o"), templ->NewInstance());
+  call_ic_function4 =
+      v8_compile("function f(x) { return x - 1; }; f")->Run();
+  v8::Handle<Value> value = CompileRun(
+    "o.__proto__.x = function(x) { return x + 1; };"
+    "var result = 0;"
+    "for (var i = 0; i < 1000; i++) {"
+    "  result = o.x(42);"
+    "}");
+  CHECK_EQ(41, value->Int32Value());
+}
+
+
+// Test the case when we stored cacheable lookup into
+// a stub, but it got invalidated later on
+THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
+  v8::HandleScope scope;
+  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
+  templ->SetNamedPropertyHandler(NoBlockGetterX);
+  LocalContext context;
+  context->Global()->Set(v8_str("o"), templ->NewInstance());
+  v8::Handle<Value> value = CompileRun(
+    "proto1 = new Object();"
+    "proto2 = new Object();"
+    "o.__proto__ = proto1;"
+    "proto1.__proto__ = proto2;"
+    "proto2.y = function(x) { return x + 1; };"
+    // Invoke it many times to compile a stub
+    "for (var i = 0; i < 7; i++) {"
+    "  o.y(42);"
+    "}"
+    "proto1.y = function(x) { return x - 1; };"
+    "var result = 0;"
+    "for (var i = 0; i < 7; i++) {"
+    "  result += o.y(42);"
+    "}");
+  CHECK_EQ(41 * 7, value->Int32Value());
+}
+
+
+static v8::Handle<Value> call_ic_function5;
+static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
+                                                  const AccessorInfo& info) {
+  ApiTestFuzzer::Fuzz();
+  if (v8_str("x")->Equals(name))
+    return call_ic_function5;
+  else
+    return Local<Value>();
+}
+
+
+// This test checks that if interceptor doesn't provide a function,
+// cached constant function is used
+THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
+  v8::HandleScope scope;
+  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
+  templ->SetNamedPropertyHandler(NoBlockGetterX);
+  LocalContext context;
+  context->Global()->Set(v8_str("o"), templ->NewInstance());
+  v8::Handle<Value> value = CompileRun(
+    "function inc(x) { return x + 1; };"
+    "inc(1);"
+    "o.x = inc;"
+    "var result = 0;"
+    "for (var i = 0; i < 1000; i++) {"
+    "  result = o.x(42);"
+    "}");
+  CHECK_EQ(43, value->Int32Value());
+}
+
+
+// This test checks that if interceptor provides a function,
+// even if we cached constant function, interceptor's function
+// is invoked
+THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
+  v8::HandleScope scope;
+  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
+  templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
+  LocalContext context;
+  context->Global()->Set(v8_str("o"), templ->NewInstance());
+  call_ic_function5 =
+      v8_compile("function f(x) { return x - 1; }; f")->Run();
+  v8::Handle<Value> value = CompileRun(
+    "function inc(x) { return x + 1; };"
+    "inc(1);"
+    "o.x = inc;"
+    "var result = 0;"
+    "for (var i = 0; i < 1000; i++) {"
+    "  result = o.x(42);"
+    "}");
+  CHECK_EQ(41, value->Int32Value());
+}
+
+
+// Test the case when we stored constant function into
+// a stub, but it got invalidated later on
+THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
+  v8::HandleScope scope;
+  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
+  templ->SetNamedPropertyHandler(NoBlockGetterX);
+  LocalContext context;
+  context->Global()->Set(v8_str("o"), templ->NewInstance());
+  v8::Handle<Value> value = CompileRun(
+    "function inc(x) { return x + 1; };"
+    "inc(1);"
+    "proto1 = new Object();"
+    "proto2 = new Object();"
+    "o.__proto__ = proto1;"
+    "proto1.__proto__ = proto2;"
+    "proto2.y = inc;"
+    // Invoke it many times to compile a stub
+    "for (var i = 0; i < 7; i++) {"
+    "  o.y(42);"
+    "}"
+    "proto1.y = function(x) { return x - 1; };"
+    "var result = 0;"
+    "for (var i = 0; i < 7; i++) {"
+    "  result += o.y(42);"
+    "}");
+  CHECK_EQ(41 * 7, value->Int32Value());
+}
+
+
+// Test the case when we stored constant function into
+// a stub, but it got invalidated later on due to override on
+// global object which is between interceptor and constant function' holders.
+THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
+  v8::HandleScope scope;
+  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
+  templ->SetNamedPropertyHandler(NoBlockGetterX);
+  LocalContext context;
+  context->Global()->Set(v8_str("o"), templ->NewInstance());
+  v8::Handle<Value> value = CompileRun(
+    "function inc(x) { return x + 1; };"
+    "inc(1);"
+    "o.__proto__ = this;"
+    "this.__proto__.y = inc;"
+    // Invoke it many times to compile a stub
+    "for (var i = 0; i < 7; i++) {"
+    "  if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
+    "}"
+    "this.y = function(x) { return x - 1; };"
+    "var result = 0;"
+    "for (var i = 0; i < 7; i++) {"
+    "  result += o.y(42);"
+    "}");
+  CHECK_EQ(41 * 7, value->Int32Value());
+}
+
+
 static int interceptor_call_count = 0;
 
 static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
@@ -5768,6 +6216,7 @@ THREADED_TEST(NestedHandleScopeAndContexts) {
 
 THREADED_TEST(ExternalAllocatedMemory) {
   v8::HandleScope outer;
+  v8::Persistent<Context> env = Context::New();
   const int kSize = 1024*1024;
   CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
   CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
@@ -7081,3 +7530,21 @@ THREADED_TEST(ReplaceConstantFunction) {
   obj_clone->Set(foo_string, v8::String::New("Hello"));
   CHECK(!obj->Get(foo_string)->IsUndefined());
 }
+
+
+// Regression test for http://crbug.com/16276.
+THREADED_TEST(Regress16276) {
+  v8::HandleScope scope;
+  LocalContext context;
+  // Force the IC in f to be a dictionary load IC.
+  CompileRun("function f(obj) { return obj.x; }\n"
+             "var obj = { x: { foo: 42 }, y: 87 };\n"
+             "var x = obj.x;\n"
+             "delete obj.y;\n"
+             "for (var i = 0; i < 5; i++) f(obj);");
+  // Detach the global object to make 'this' refer directly to the
+  // global object (not the proxy), and make sure that the dictionary
+  // load IC doesn't mess up loading directly from the global object.
+  context->DetachGlobal();
+  CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
+}
index 396bcc5..5163ff9 100644 (file)
@@ -36,7 +36,7 @@ TEST(HeapMaps) {
   InitializeVM();
   CheckMap(Heap::meta_map(), MAP_TYPE, Map::kSize);
   CheckMap(Heap::heap_number_map(), HEAP_NUMBER_TYPE, HeapNumber::kSize);
-  CheckMap(Heap::fixed_array_map(), FIXED_ARRAY_TYPE, Array::kAlignedSize);
+  CheckMap(Heap::fixed_array_map(), FIXED_ARRAY_TYPE, FixedArray::kHeaderSize);
   CheckMap(Heap::long_string_map(), LONG_STRING_TYPE,
            SeqTwoByteString::kAlignedSize);
 }
index 8db7339..743375d 100644 (file)
@@ -86,7 +86,8 @@ TEST(Promotion) {
   v8::HandleScope sc;
 
   // Allocate a fixed array in the new space.
-  int array_size = (Heap::MaxObjectSizeInPagedSpace() - Array::kHeaderSize) /
+  int array_size =
+      (Heap::MaxObjectSizeInPagedSpace() - FixedArray::kHeaderSize) /
       (kPointerSize * 4);
   Object* obj = Heap::AllocateFixedArray(array_size);
   CHECK(!obj->IsFailure());
@@ -118,7 +119,7 @@ TEST(NoPromotion) {
   CHECK(Heap::CollectGarbage(0, OLD_POINTER_SPACE));
 
   // Allocate a big Fixed array in the new space.
-  int size = (Heap::MaxObjectSizeInPagedSpace() - Array::kHeaderSize) /
+  int size = (Heap::MaxObjectSizeInPagedSpace() - FixedArray::kHeaderSize) /
       kPointerSize;
   Object* obj = Heap::AllocateFixedArray(size);
 
index d40151e..9afaa0f 100644 (file)
@@ -32,13 +32,13 @@ bugs: FAIL
 
 [ $arch == x64 ]
 
-simple-throw.js: FAIL
-try-catch-finally-throw-in-catch-and-finally.js: FAIL
-try-catch-finally-throw-in-catch.js: FAIL
-try-catch-finally-throw-in-finally.js: FAIL
-try-finally-throw-in-finally.js: FAIL
-try-finally-throw-in-try-and-finally.js: FAIL
-try-finally-throw-in-try.js: FAIL
-overwritten-builtins.js: FAIL
-regress-73.js: FAIL
-regress-75.js: FAIL
+simple-throw: FAIL
+try-catch-finally-throw-in-catch-and-finally: FAIL
+try-catch-finally-throw-in-catch: FAIL
+try-catch-finally-throw-in-finally: FAIL
+try-finally-throw-in-finally: FAIL
+try-finally-throw-in-try-and-finally: FAIL
+try-finally-throw-in-try: FAIL
+overwritten-builtins: FAIL
+regress/regress-73: FAIL
+regress/regress-75: FAIL
diff --git a/V8Binding/v8/test/mjsunit/debug-stepin-accessor.js b/V8Binding/v8/test/mjsunit/debug-stepin-accessor.js
new file mode 100644 (file)
index 0000000..8b24c3c
--- /dev/null
@@ -0,0 +1,248 @@
+// Copyright 2008 the V8 project authors. All rights reserved.\r
+// Redistribution and use in source and binary forms, with or without\r
+// modification, are permitted provided that the following conditions are\r
+// met:\r
+//\r
+//     * Redistributions of source code must retain the above copyright\r
+//       notice, this list of conditions and the following disclaimer.\r
+//     * Redistributions in binary form must reproduce the above\r
+//       copyright notice, this list of conditions and the following\r
+//       disclaimer in the documentation and/or other materials provided\r
+//       with the distribution.\r
+//     * Neither the name of Google Inc. nor the names of its\r
+//       contributors may be used to endorse or promote products derived\r
+//       from this software without specific prior written permission.\r
+//\r
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\r
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\r
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\r
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\r
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+\r
+// Flags: --expose-debug-as debug\r
+\r
+// Get the Debug object exposed from the debug context global object.\r
+Debug = debug.Debug\r
+\r
+var exception = null;\r
+var state = 1;\r
+var expected_source_line_text = null;\r
+var expected_function_name = null;\r
+\r
+// Simple debug event handler which first time will cause 'step in' action\r
+// to get into g.call and than check that execution is pauesed inside\r
+// function 'g'.\r
+function listener(event, exec_state, event_data, data) {\r
+  try {\r
+    if (event == Debug.DebugEvent.Break) {\r
+      if (state == 1) {\r
+        exec_state.prepareStep(Debug.StepAction.StepIn, 2);\r
+        state = 2;\r
+      } else if (state == 2) {\r
+        assertEquals(expected_source_line_text,\r
+                     event_data.sourceLineText());\r
+        assertEquals(expected_function_name, event_data.func().name());\r
+        state = 3;\r
+      }\r
+    }\r
+  } catch(e) {\r
+    exception = e;\r
+  }\r
+};\r
+\r
+// Add the debug event listener.\r
+Debug.setListener(listener);\r
+\r
+\r
+var c = {\r
+  name: 'name ',\r
+  get getter1() {\r
+    return this.name;  // getter 1\r
+  },\r
+  get getter2() {\r
+    return {  // getter 2\r
+     'a': c.name\r
+    };\r
+  },\r
+  set setter1(n) {\r
+    this.name = n;  // setter 1\r
+  }\r
+};\r
+\r
+c.__defineGetter__('y', function getterY() {\r
+  return this.name;  // getter y\r
+});\r
+\r
+c.__defineGetter__(3, function getter3() {\r
+  return this.name;  // getter 3\r
+});\r
+\r
+c.__defineSetter__('y', function setterY(n) {\r
+  this.name = n;  // setter y\r
+});\r
+\r
+c.__defineSetter__(3, function setter3(n) {\r
+  this.name = n;  // setter 3\r
+});\r
+\r
+var d = {\r
+  'c': c,\r
+};\r
+\r
+function testGetter1_1() {\r
+  expected_function_name = 'getter1';\r
+  expected_source_line_text = '    return this.name;  // getter 1';\r
+  debugger;\r
+  var x = c.getter1;\r
+}\r
+\r
+function testGetter1_2() {\r
+  expected_function_name = 'getter1';\r
+  expected_source_line_text = '    return this.name;  // getter 1';\r
+  debugger;\r
+  var x = c['getter1'];\r
+}\r
+\r
+function testGetter1_3() {\r
+  expected_function_name = 'getter1';\r
+  expected_source_line_text = '    return this.name;  // getter 1';\r
+  debugger;\r
+  for (var i = 1; i < 2; i++) {\r
+    var x = c['getter' + i];\r
+  }\r
+}\r
+\r
+function testGetter1_4() {\r
+  expected_function_name = 'getter1';\r
+  expected_source_line_text = '    return this.name;  // getter 1';\r
+  debugger;\r
+  var x = d.c.getter1;\r
+}\r
+\r
+function testGetter1_5() {\r
+  expected_function_name = 'getter1';\r
+  expected_source_line_text = '    return this.name;  // getter 1';\r
+  for (var i = 2; i != 1; i--);\r
+  debugger;\r
+  var x = d.c['getter' + i];\r
+}\r
+\r
+function testGetter2_1() {\r
+  expected_function_name = 'getter2';\r
+  expected_source_line_text = '    return {  // getter 2';\r
+  for (var i = 2; i != 1; i--);\r
+  debugger;\r
+  var t = d.c.getter2.name;\r
+}\r
+\r
+\r
+function testGetterY_1() {\r
+  expected_function_name = 'getterY';\r
+  expected_source_line_text = '  return this.name;  // getter y';\r
+  debugger;\r
+  var t = d.c.y;\r
+}\r
+\r
+function testIndexedGetter3_1() {\r
+  expected_function_name = 'getter3';\r
+  expected_source_line_text = '  return this.name;  // getter 3';\r
+  debugger;\r
+  var r = d.c[3];\r
+}\r
+\r
+function testSetterY_1() {\r
+  expected_function_name = 'setterY';\r
+  expected_source_line_text = '  this.name = n;  // setter y';\r
+  debugger;\r
+  d.c.y = 'www';\r
+}\r
+\r
+function testIndexedSetter3_1() {\r
+  expected_function_name = 'setter3';\r
+  expected_source_line_text = '  this.name = n;  // setter 3';\r
+  var i = 3\r
+  debugger;\r
+  d.c[3] = 'www';\r
+}\r
+\r
+function testSetter1_1() {\r
+  expected_function_name = 'setter1';\r
+  expected_source_line_text = '    this.name = n;  // setter 1';\r
+  debugger;\r
+  d.c.setter1 = 'aa';\r
+}\r
+\r
+function testSetter1_2() {\r
+  expected_function_name = 'setter1';\r
+  expected_source_line_text = '    this.name = n;  // setter 1';\r
+  debugger;\r
+  d.c['setter1'] = 'bb';\r
+}\r
+\r
+function testSetter1_3() {\r
+  expected_function_name = 'setter1';\r
+  expected_source_line_text = '    this.name = n;  // setter 1';\r
+  for (var i = 2; i != 1; i--);\r
+  debugger;\r
+  d.c['setter' + i] = i;\r
+}\r
+\r
+var e = {\r
+  name: 'e'\r
+};\r
+e.__proto__ = c;\r
+\r
+function testProtoGetter1_1() {\r
+  expected_function_name = 'getter1';\r
+  expected_source_line_text = '    return this.name;  // getter 1';\r
+  debugger;\r
+  var x = e.getter1;\r
+}\r
+\r
+function testProtoSetter1_1() {\r
+  expected_function_name = 'setter1';\r
+  expected_source_line_text = '    this.name = n;  // setter 1';\r
+  debugger;\r
+  e.setter1 = 'aa';\r
+}\r
+\r
+function testProtoIndexedGetter3_1() {\r
+  expected_function_name = 'getter3';\r
+  expected_source_line_text = '  return this.name;  // getter 3';\r
+  debugger;\r
+  var x = e[3];\r
+}\r
+\r
+function testProtoIndexedSetter3_1() {\r
+  expected_function_name = 'setter3';\r
+  expected_source_line_text = '  this.name = n;  // setter 3';\r
+  debugger;\r
+  e[3] = 'new val';\r
+}\r
+\r
+function testProtoSetter1_2() {\r
+  expected_function_name = 'setter1';\r
+  expected_source_line_text = '    this.name = n;  // setter 1';\r
+  for (var i = 2; i != 1; i--);\r
+  debugger;\r
+  e['setter' + i] = 'aa';\r
+}\r
+\r
+for (var n in this) {\r
+  if (n.substr(0, 4) != 'test') {\r
+    continue;\r
+  }\r
+  state = 1;\r
+  this[n]();\r
+  assertNull(exception);\r
+  assertEquals(3, state);\r
+}\r
+\r
+// Get rid of the debug event listener.\r
+Debug.setListener(null);\r
index 962e4d3..d30e78c 100644 (file)
@@ -58,6 +58,7 @@ debug-ignore-breakpoints: CRASH || FAIL
 debug-multiple-breakpoints: CRASH || FAIL
 debug-setbreakpoint: CRASH || FAIL || PASS
 debug-step-stub-callfunction: SKIP
+debug-stepin-accessor: CRASH || FAIL
 debug-stepin-constructor: CRASH, FAIL
 debug-stepin-function-call: CRASH || FAIL
 debug-step: SKIP
@@ -69,40 +70,44 @@ regress/regress-269: SKIP
 # Fails on real ARM hardware but not on the simulator.
 string-compare-alignment: PASS || FAIL
 
+# Times out often in release mode on ARM.
+array-splice: PASS || TIMEOUT
 
 [ $arch == x64 ]
 
-debug-backtrace.js: CRASH || FAIL
-date-parse.js: CRASH || FAIL
-debug-backtrace-text.js: CRASH || FAIL
-debug-multiple-breakpoints.js: CRASH || FAIL
-debug-breakpoints.js: CRASH || FAIL
-debug-changebreakpoint.js: CRASH || FAIL
-debug-clearbreakpoint.js: CRASH || FAIL
-debug-conditional-breakpoints.js: CRASH || FAIL
-debug-constructor.js: CRASH || FAIL
-debug-continue.js: CRASH || FAIL
-debug-enable-disable-breakpoints.js: CRASH || FAIL
-debug-evaluate-recursive.js: CRASH || FAIL
-debug-event-listener.js: CRASH || FAIL
-debug-evaluate.js: CRASH || FAIL
-debug-ignore-breakpoints.js: CRASH || FAIL
-debug-setbreakpoint.js: CRASH || FAIL
-debug-step-stub-callfunction.js: CRASH || FAIL
-debug-step.js: CRASH || FAIL
-mirror-date.js: CRASH || FAIL
-invalid-lhs.js: CRASH || FAIL
-debug-stepin-constructor.js: CRASH || FAIL
-new.js: CRASH || FAIL
-fuzz-natives.js: CRASH || FAIL
-greedy.js: CRASH || FAIL
-debug-handle.js: CRASH || FAIL
-string-indexof.js: CRASH || FAIL
-debug-clearbreakpointgroup.js: CRASH || FAIL
-regress/regress-269.js: CRASH || FAIL
-div-mod.js: CRASH || FAIL
-unicode-test.js: CRASH || FAIL
-regress/regress-392.js: CRASH || FAIL
-regress/regress-1200351.js: CRASH || FAIL
-regress/regress-998565.js: CRASH || FAIL
-tools/tickprocessor.js: CRASH || FAIL
+debug-backtrace: CRASH || FAIL
+date-parse: CRASH || FAIL
+debug-backtrace-text: CRASH || FAIL
+debug-multiple-breakpoints: CRASH || FAIL
+debug-breakpoints: CRASH || FAIL
+debug-changebreakpoint: CRASH || FAIL
+debug-clearbreakpoint: CRASH || FAIL
+debug-conditional-breakpoints: CRASH || FAIL
+debug-constructor: CRASH || FAIL
+debug-continue: CRASH || FAIL
+debug-enable-disable-breakpoints: CRASH || FAIL
+debug-evaluate-recursive: CRASH || FAIL
+debug-event-listener: CRASH || FAIL
+debug-evaluate: CRASH || FAIL
+debug-ignore-breakpoints: CRASH || FAIL
+debug-setbreakpoint: CRASH || FAIL
+debug-step-stub-callfunction: CRASH || FAIL
+debug-step: CRASH || FAIL
+mirror-date: CRASH || FAIL
+invalid-lhs: PASS || CRASH || FAIL
+debug-stepin-constructor: CRASH || FAIL
+debug-stepin-function-call: CRASH || FAIL
+debug-stepin-accessor: CRASH || FAIL
+new: CRASH || FAIL
+fuzz-natives: PASS || TIMEOUT
+greedy: PASS || TIMEOUT
+debug-handle: CRASH || FAIL
+string-indexof: PASS || TIMEOUT
+debug-clearbreakpointgroup: CRASH || FAIL
+regress/regress-269: CRASH || FAIL
+div-mod: CRASH || FAIL
+unicode-test: PASS || TIMEOUT
+regress/regress-392: CRASH || FAIL
+regress/regress-1200351: CRASH || FAIL
+regress/regress-998565: CRASH || FAIL
+tools/tickprocessor: PASS || CRASH || FAIL
diff --git a/V8Binding/v8/test/mjsunit/regexp-call-as-function.js b/V8Binding/v8/test/mjsunit/regexp-call-as-function.js
new file mode 100644 (file)
index 0000000..4cbe7f9
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test that regular expressions can be called as functions.  Calling
+// a regular expression as a function corresponds to calling it's exec
+// method.
+
+var regexp = /a(b)(c)/;
+var subject = "xyzabcde";
+var expected = 'abc,b,c';
+assertEquals(expected, String(regexp.exec(subject)));
+assertEquals(expected, String(regexp(subject)));
diff --git a/V8Binding/v8/test/mjsunit/regress/regress-155924.js b/V8Binding/v8/test/mjsunit/regress/regress-155924.js
new file mode 100644 (file)
index 0000000..666e3ba
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// A HeapNumber with certain bits in the mantissa of the floating point
+// value should not be able to masquerade as a string in a keyed lookup
+// inline cache stub.  See http://codereview.chromium.org/155924.
+
+A = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
+
+function foo() {
+  x = 1 << 26;
+  x = x * x;
+  // The following floating-point heap number has a second word similar
+  // to that of the string "5":
+  // 2^52 + index << cached_index_shift + cached_index_tag
+  x = x + (5 << 2) + (1 << 1);
+  return A[x];
+}
+
+assertEquals(undefined, foo(), "First lookup A[bad_float]");
+assertEquals(undefined, foo(), "Second lookup A[bad_float]");
+assertEquals(undefined, foo(), "Third lookup A[bad_float]");
diff --git a/V8Binding/v8/test/mjsunit/regress/regress-345.js b/V8Binding/v8/test/mjsunit/regress/regress-345.js
new file mode 100644 (file)
index 0000000..f7f28a1
--- /dev/null
@@ -0,0 +1,51 @@
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Escaping to the same target from both the try and catch blocks of
+// try...catch...finally should not fail at compile-time.
+//
+// Reported by nth10sd.
+// See http://code.google.com/p/v8/issues/detail?id=345
+
+do {
+  try {
+    continue;
+  } catch (e) {
+    continue;
+  } finally {
+  }
+} while (false);
+
+
+L: {
+  try {
+    break L;
+  } catch (e) {
+    break L;
+  } finally {
+  }
+}
diff --git a/V8Binding/v8/test/mjsunit/regress/regress-406.js b/V8Binding/v8/test/mjsunit/regress/regress-406.js
new file mode 100644 (file)
index 0000000..f48a5de
--- /dev/null
@@ -0,0 +1,69 @@
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test of constant folding of boolean-valued expressions.
+
+// See http://code.google.com/p/v8/issues/detail?id=406
+
+assertFalse(typeof(0) == "zero");
+assertTrue(typeof(0) != "zero");
+
+// The and and or truth tables with both operands constant.
+assertFalse(typeof(0) == "zero" && typeof(0) == "zero");
+assertFalse(typeof(0) == "zero" && typeof(0) != "zero");
+assertFalse(typeof(0) != "zero" && typeof(0) == "zero");
+assertTrue(typeof(0) != "zero" && typeof(0) != "zero");
+
+assertFalse(typeof(0) == "zero" || typeof(0) == "zero");
+assertTrue(typeof(0) == "zero" || typeof(0) != "zero");
+assertTrue(typeof(0) != "zero" || typeof(0) == "zero");
+assertTrue(typeof(0) != "zero" || typeof(0) != "zero");
+
+// Same with just the left operand constant.
+// Helper function to prevent simple constant folding.
+function one() { return 1; }
+
+assertFalse(typeof(0) == "zero" && one() < 0);
+assertFalse(typeof(0) == "zero" && one() > 0);
+assertFalse(typeof(0) != "zero" && one() < 0);
+assertTrue(typeof(0) != "zero" && one() > 0);
+
+assertFalse(typeof(0) == "zero" || one() < 0);
+assertTrue(typeof(0) == "zero" || one() > 0);
+assertTrue(typeof(0) != "zero" || one() < 0);
+assertTrue(typeof(0) != "zero" || one() > 0);
+
+// Same with just the right operand constant.
+assertFalse(one() < 0 && typeof(0) == "zero");
+assertFalse(one() < 0 && typeof(0) != "zero");
+assertFalse(one() > 0 && typeof(0) == "zero");
+assertTrue(one() > 0 && typeof(0) != "zero");
+
+assertFalse(one() < 0 || typeof(0) == "zero");
+assertTrue(one() < 0 || typeof(0) != "zero");
+assertTrue(one() > 0 || typeof(0) == "zero");
+assertTrue(one() > 0 || typeof(0) != "zero");
index 55b8758..06a91e8 100644 (file)
@@ -46,11 +46,11 @@ function assertNoEntry(codeMap, addr) {
 };
 
 
-(function testStaticCode() {
+(function testLibrariesAndStaticCode() {
   var codeMap = new devtools.profiler.CodeMap();
-  codeMap.addStaticCode(0x1500, newCodeEntry(0x3000, 'lib1'));
-  codeMap.addStaticCode(0x15500, newCodeEntry(0x5000, 'lib2'));
-  codeMap.addStaticCode(0x155500, newCodeEntry(0x10000, 'lib3'));
+  codeMap.addLibrary(0x1500, newCodeEntry(0x3000, 'lib1'));
+  codeMap.addLibrary(0x15500, newCodeEntry(0x5000, 'lib2'));
+  codeMap.addLibrary(0x155500, newCodeEntry(0x10000, 'lib3'));
   assertNoEntry(codeMap, 0);
   assertNoEntry(codeMap, 0x1500 - 1);
   assertEntry(codeMap, 'lib1', 0x1500);
@@ -71,6 +71,28 @@ function assertNoEntry(codeMap, addr) {
   assertEntry(codeMap, 'lib3', 0x155500 + 0x10000 - 1);
   assertNoEntry(codeMap, 0x155500 + 0x10000);
   assertNoEntry(codeMap, 0xFFFFFFFF);
+
+  codeMap.addStaticCode(0x1510, newCodeEntry(0x30, 'lib1-f1'));
+  codeMap.addStaticCode(0x1600, newCodeEntry(0x50, 'lib1-f2'));
+  codeMap.addStaticCode(0x15520, newCodeEntry(0x100, 'lib2-f1'));
+  assertEntry(codeMap, 'lib1', 0x1500);
+  assertEntry(codeMap, 'lib1', 0x1510 - 1);
+  assertEntry(codeMap, 'lib1-f1', 0x1510);
+  assertEntry(codeMap, 'lib1-f1', 0x1510 + 0x15);
+  assertEntry(codeMap, 'lib1-f1', 0x1510 + 0x30 - 1);
+  assertEntry(codeMap, 'lib1', 0x1510 + 0x30);
+  assertEntry(codeMap, 'lib1', 0x1600 - 1);
+  assertEntry(codeMap, 'lib1-f2', 0x1600);
+  assertEntry(codeMap, 'lib1-f2', 0x1600 + 0x30);
+  assertEntry(codeMap, 'lib1-f2', 0x1600 + 0x50 - 1);
+  assertEntry(codeMap, 'lib1', 0x1600 + 0x50);
+  assertEntry(codeMap, 'lib2', 0x15500);
+  assertEntry(codeMap, 'lib2', 0x15520 - 1);
+  assertEntry(codeMap, 'lib2-f1', 0x15520);
+  assertEntry(codeMap, 'lib2-f1', 0x15520 + 0x80);
+  assertEntry(codeMap, 'lib2-f1', 0x15520 + 0x100 - 1);
+  assertEntry(codeMap, 'lib2', 0x15520 + 0x100);
+
 })();
 
 
index 49eef3b..9ed851b 100644 (file)
@@ -72,10 +72,10 @@ ProfileTestDriver.prototype.funcAddrs_ = {
 
 
 ProfileTestDriver.prototype.addFunctions_ = function() {
-  this.profile.addStaticCode('lib1', 0x11000, 0x12000);
+  this.profile.addLibrary('lib1', 0x11000, 0x12000);
   this.profile.addStaticCode('lib1-f1', 0x11100, 0x11900);
   this.profile.addStaticCode('lib1-f2', 0x11200, 0x11500);
-  this.profile.addStaticCode('lib2', 0x21000, 0x22000);
+  this.profile.addLibrary('lib2', 0x21000, 0x22000);
   this.profile.addStaticCode('lib2-f1', 0x21100, 0x21900);
   this.profile.addStaticCode('lib2-f2', 0x21200, 0x21500);
   this.profile.addCode('T', 'F1', 0x50100, 0x100);
index a689ea8..702f4bc 100644 (file)
@@ -6,20 +6,19 @@ Statistical profiling result from v8.log, (13 ticks, 2 unaccounted, 0 excluded).
 
  [Shared libraries]:
    ticks  total  nonlib   name
-      2   15.4%    0.0%  /lib32/libm-2.7.so
+      3   23.1%    0.0%  /lib32/libm-2.7.so
       1    7.7%    0.0%  ffffe000-fffff000
 
  [JavaScript]:
    ticks  total  nonlib   name
-      1    7.7%   10.0%  LazyCompile: exp native math.js:41
+      1    7.7%   11.1%  LazyCompile: exp native math.js:41
 
  [C++]:
    ticks  total  nonlib   name
-      2   15.4%   20.0%  v8::internal::Runtime_Math_exp(v8::internal::Arguments)
-      1    7.7%   10.0%  v8::internal::JSObject::LocalLookupRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*)
-      1    7.7%   10.0%  v8::internal::HashTable<v8::internal::StringDictionaryShape, v8::internal::String*>::FindEntry(v8::internal::String*)
-      1    7.7%   10.0%  fegetexcept
-      1    7.7%   10.0%  exp
+      2   15.4%   22.2%  v8::internal::Runtime_Math_exp(v8::internal::Arguments)
+      1    7.7%   11.1%  v8::internal::JSObject::LocalLookupRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*)
+      1    7.7%   11.1%  v8::internal::HashTable<v8::internal::StringDictionaryShape, v8::internal::String*>::FindEntry(v8::internal::String*)
+      1    7.7%   11.1%  exp
 
  [GC]:
    ticks  total  nonlib   name
@@ -31,11 +30,11 @@ Statistical profiling result from v8.log, (13 ticks, 2 unaccounted, 0 excluded).
   Callers occupying less than 2.0% are not shown.
 
    ticks parent  name
-      2   15.4%  v8::internal::Runtime_Math_exp(v8::internal::Arguments)
-      2  100.0%    LazyCompile: exp native math.js:41
-      2  100.0%      Script: exp.js
+      3   23.1%  /lib32/libm-2.7.so
+      3  100.0%    LazyCompile: exp native math.js:41
+      3  100.0%      Script: exp.js
 
-      2   15.4%  /lib32/libm-2.7.so
+      2   15.4%  v8::internal::Runtime_Math_exp(v8::internal::Arguments)
       2  100.0%    LazyCompile: exp native math.js:41
       2  100.0%      Script: exp.js
 
@@ -47,10 +46,6 @@ Statistical profiling result from v8.log, (13 ticks, 2 unaccounted, 0 excluded).
 
       1    7.7%  ffffe000-fffff000
 
-      1    7.7%  fegetexcept
-      1  100.0%    LazyCompile: exp native math.js:41
-      1  100.0%      Script: exp.js
-
       1    7.7%  exp
       1  100.0%    LazyCompile: exp native math.js:41
       1  100.0%      Script: exp.js
index 87beb08..306d646 100644 (file)
@@ -2,20 +2,19 @@ Statistical profiling result from v8.log, (13 ticks, 2 unaccounted, 0 excluded).
 
  [Shared libraries]:
    ticks  total  nonlib   name
-      2   18.2%    0.0%  /lib32/libm-2.7.so
+      3   27.3%    0.0%  /lib32/libm-2.7.so
       1    9.1%    0.0%  ffffe000-fffff000
 
  [JavaScript]:
    ticks  total  nonlib   name
-      1    9.1%   12.5%  LazyCompile: exp native math.js:41
+      1    9.1%   14.3%  LazyCompile: exp native math.js:41
 
  [C++]:
    ticks  total  nonlib   name
-      2   18.2%   25.0%  v8::internal::Runtime_Math_exp(v8::internal::Arguments)
-      1    9.1%   12.5%  v8::internal::JSObject::LocalLookupRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*)
-      1    9.1%   12.5%  v8::internal::HashTable<v8::internal::StringDictionaryShape, v8::internal::String*>::FindEntry(v8::internal::String*)
-      1    9.1%   12.5%  fegetexcept
-      1    9.1%   12.5%  exp
+      2   18.2%   28.6%  v8::internal::Runtime_Math_exp(v8::internal::Arguments)
+      1    9.1%   14.3%  v8::internal::JSObject::LocalLookupRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*)
+      1    9.1%   14.3%  v8::internal::HashTable<v8::internal::StringDictionaryShape, v8::internal::String*>::FindEntry(v8::internal::String*)
+      1    9.1%   14.3%  exp
 
  [GC]:
    ticks  total  nonlib   name
@@ -27,11 +26,11 @@ Statistical profiling result from v8.log, (13 ticks, 2 unaccounted, 0 excluded).
   Callers occupying less than 2.0% are not shown.
 
    ticks parent  name
-      2   18.2%  v8::internal::Runtime_Math_exp(v8::internal::Arguments)
-      2  100.0%    LazyCompile: exp native math.js:41
-      2  100.0%      Script: exp.js
+      3   27.3%  /lib32/libm-2.7.so
+      3  100.0%    LazyCompile: exp native math.js:41
+      3  100.0%      Script: exp.js
 
-      2   18.2%  /lib32/libm-2.7.so
+      2   18.2%  v8::internal::Runtime_Math_exp(v8::internal::Arguments)
       2  100.0%    LazyCompile: exp native math.js:41
       2  100.0%      Script: exp.js
 
@@ -43,10 +42,6 @@ Statistical profiling result from v8.log, (13 ticks, 2 unaccounted, 0 excluded).
 
       1    9.1%  ffffe000-fffff000
 
-      1    9.1%  fegetexcept
-      1  100.0%    LazyCompile: exp native math.js:41
-      1  100.0%      Script: exp.js
-
       1    9.1%  exp
       1  100.0%    LazyCompile: exp native math.js:41
       1  100.0%      Script: exp.js
index 7eb3d9a..3a2041b 100644 (file)
@@ -6,22 +6,21 @@ Statistical profiling result from v8.log, (13 ticks, 2 unaccounted, 0 excluded).
 
  [Shared libraries]:
    ticks  total  nonlib   name
-      2   15.4%    0.0%  /lib32/libm-2.7.so
+      3   23.1%    0.0%  /lib32/libm-2.7.so
       1    7.7%    0.0%  ffffe000-fffff000
 
  [JavaScript]:
    ticks  total  nonlib   name
-      1    7.7%   10.0%  LoadIC: j
-      1    7.7%   10.0%  LoadIC: i
-      1    7.7%   10.0%  LazyCompile: exp native math.js:41
+      1    7.7%   11.1%  LoadIC: j
+      1    7.7%   11.1%  LoadIC: i
+      1    7.7%   11.1%  LazyCompile: exp native math.js:41
 
  [C++]:
    ticks  total  nonlib   name
-      2   15.4%   20.0%  v8::internal::Runtime_Math_exp(v8::internal::Arguments)
-      1    7.7%   10.0%  v8::internal::JSObject::LocalLookupRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*)
-      1    7.7%   10.0%  v8::internal::HashTable<v8::internal::StringDictionaryShape, v8::internal::String*>::FindEntry(v8::internal::String*)
-      1    7.7%   10.0%  fegetexcept
-      1    7.7%   10.0%  exp
+      2   15.4%   22.2%  v8::internal::Runtime_Math_exp(v8::internal::Arguments)
+      1    7.7%   11.1%  v8::internal::JSObject::LocalLookupRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*)
+      1    7.7%   11.1%  v8::internal::HashTable<v8::internal::StringDictionaryShape, v8::internal::String*>::FindEntry(v8::internal::String*)
+      1    7.7%   11.1%  exp
 
  [GC]:
    ticks  total  nonlib   name
@@ -33,11 +32,11 @@ Statistical profiling result from v8.log, (13 ticks, 2 unaccounted, 0 excluded).
   Callers occupying less than 2.0% are not shown.
 
    ticks parent  name
-      2   15.4%  v8::internal::Runtime_Math_exp(v8::internal::Arguments)
-      2  100.0%    LazyCompile: exp native math.js:41
-      2  100.0%      Script: exp.js
+      3   23.1%  /lib32/libm-2.7.so
+      3  100.0%    LazyCompile: exp native math.js:41
+      3  100.0%      Script: exp.js
 
-      2   15.4%  /lib32/libm-2.7.so
+      2   15.4%  v8::internal::Runtime_Math_exp(v8::internal::Arguments)
       2  100.0%    LazyCompile: exp native math.js:41
       2  100.0%      Script: exp.js
 
@@ -49,10 +48,6 @@ Statistical profiling result from v8.log, (13 ticks, 2 unaccounted, 0 excluded).
 
       1    7.7%  ffffe000-fffff000
 
-      1    7.7%  fegetexcept
-      1  100.0%    LazyCompile: exp native math.js:41
-      1  100.0%      Script: exp.js
-
       1    7.7%  exp
       1  100.0%    LazyCompile: exp native math.js:41
       1  100.0%      Script: exp.js
index 587106a..00c3fb1 100644 (file)
@@ -31,6 +31,7 @@
 // Files: tools/logreader.js tools/tickprocessor.js
 // Env: TEST_FILE_NAME
 
+
 (function testArgumentsProcessor() {
   var p_default = new ArgumentsProcessor([]);
   assertTrue(p_default.parse());
       '         U operator delete[](void*)@@GLIBCXX_3.4',
       '08049790 T _init',
       '08049f50 T _start',
-      '08139150 t v8::internal::Runtime_StringReplaceRegExpWithString(v8::internal::Arguments)',
-      '08139ca0 T v8::internal::Runtime::GetElementOrCharAt(v8::internal::Handle<v8::internal::Object>, unsigned int)',
-      '0813a0b0 t v8::internal::Runtime_DebugGetPropertyDetails(v8::internal::Arguments)',
-      '08181d30 W v8::internal::RegExpMacroAssemblerIrregexp::stack_limit_slack()',
+      '08139150 00000b4b t v8::internal::Runtime_StringReplaceRegExpWithString(v8::internal::Arguments)',
+      '08139ca0 000003f1 T v8::internal::Runtime::GetElementOrCharAt(v8::internal::Handle<v8::internal::Object>, unsigned int)',
+      '0813a0b0 00000855 t v8::internal::Runtime_DebugGetPropertyDetails(v8::internal::Arguments)',
+      '0818b220 00000036 W v8::internal::RegExpMacroAssembler::CheckPosition(int, v8::internal::Label*)',
       '         w __gmon_start__',
-      '081f08a0 B stdout'
+      '081f08a0 00000004 B stdout\n'
     ].join('\n'), ''];
   };
 
   assertEquals(
       [['_init', 0x08049790, 0x08049f50],
        ['_start', 0x08049f50, 0x08139150],
-       ['v8::internal::Runtime_StringReplaceRegExpWithString(v8::internal::Arguments)', 0x08139150, 0x08139ca0],
-       ['v8::internal::Runtime::GetElementOrCharAt(v8::internal::Handle<v8::internal::Object>, unsigned int)', 0x08139ca0, 0x0813a0b0],
-       ['v8::internal::Runtime_DebugGetPropertyDetails(v8::internal::Arguments)', 0x0813a0b0, 0x08181d30],
-       ['v8::internal::RegExpMacroAssemblerIrregexp::stack_limit_slack()', 0x08181d30, 0x081ee000]],
+       ['v8::internal::Runtime_StringReplaceRegExpWithString(v8::internal::Arguments)', 0x08139150, 0x08139150 + 0xb4b],
+       ['v8::internal::Runtime::GetElementOrCharAt(v8::internal::Handle<v8::internal::Object>, unsigned int)', 0x08139ca0, 0x08139ca0 + 0x3f1],
+       ['v8::internal::Runtime_DebugGetPropertyDetails(v8::internal::Arguments)', 0x0813a0b0, 0x0813a0b0 + 0x855],
+       ['v8::internal::RegExpMacroAssembler::CheckPosition(int, v8::internal::Label*)', 0x0818b220, 0x0818b220 + 0x36]],
       shell_syms);
 
   // libc library
   UnixCppEntriesProvider.prototype.loadSymbols = function(libName) {
     this.symbols = [[
-        '000162a0 T __libc_init_first',
-        '0002a5f0 T __isnan',
-        '0002a5f0 W isnan',
-        '0002aaa0 W scalblnf',
-        '0002aaa0 W scalbnf',
-        '0011a340 T __libc_thread_freeres',
-        '00128860 R _itoa_lower_digits'].join('\n'), ''];
+        '000162a0 00000005 T __libc_init_first',
+        '0002a5f0 0000002d T __isnan',
+        '0002a5f0 0000002d W isnan',
+        '0002aaa0 0000000d W scalblnf',
+        '0002aaa0 0000000d W scalbnf',
+        '0011a340 00000048 T __libc_thread_freeres',
+        '00128860 00000024 R _itoa_lower_digits\n'].join('\n'), ''];
   };
   var libc_prov = new UnixCppEntriesProvider();
   var libc_syms = [];
       function (name, start, end) {
         libc_syms.push(Array.prototype.slice.apply(arguments, [0]));
       });
-  assertEquals(
-      [['__libc_init_first', 0xf7c5c000 + 0x000162a0, 0xf7c5c000 + 0x0002a5f0],
-       ['isnan', 0xf7c5c000 + 0x0002a5f0, 0xf7c5c000 + 0x0002aaa0],
-       ['scalbnf', 0xf7c5c000 + 0x0002aaa0, 0xf7c5c000 + 0x0011a340],
-       ['__libc_thread_freeres', 0xf7c5c000 + 0x0011a340, 0xf7da5000]],
-      libc_syms);
+  var libc_ref_syms = [['__libc_init_first', 0x000162a0, 0x000162a0 + 0x5],
+       ['__isnan', 0x0002a5f0, 0x0002a5f0 + 0x2d],
+       ['scalblnf', 0x0002aaa0, 0x0002aaa0 + 0xd],
+       ['__libc_thread_freeres', 0x0011a340, 0x0011a340 + 0x48]];
+  for (var i = 0; i < libc_ref_syms.length; ++i) {
+    libc_ref_syms[i][1] += 0xf7c5c000;
+    libc_ref_syms[i][2] += 0xf7c5c000;
+  }
+  assertEquals(libc_ref_syms, libc_syms);
 
   UnixCppEntriesProvider.prototype.loadSymbols = oldLoadSymbols;
 })();
 
 
+(function testMacCppEntriesProvider() {
+  var oldLoadSymbols = MacCppEntriesProvider.prototype.loadSymbols;
+
+  // shell executable
+  MacCppEntriesProvider.prototype.loadSymbols = function(libName) {
+    this.symbols = [[
+      '         U operator delete[]',
+      '00001000 A __mh_execute_header',
+      '00001b00 T start',
+      '00001b40 t dyld_stub_binding_helper',
+      '0011b710 T v8::internal::RegExpMacroAssembler::CheckPosition',
+      '00134250 t v8::internal::Runtime_StringReplaceRegExpWithString',
+      '00137220 T v8::internal::Runtime::GetElementOrCharAt',
+      '00137400 t v8::internal::Runtime_DebugGetPropertyDetails',
+      '001c1a80 b _private_mem\n'
+    ].join('\n'), ''];
+  };
+
+  var shell_prov = new MacCppEntriesProvider();
+  var shell_syms = [];
+  shell_prov.parseVmSymbols('shell', 0x00001b00, 0x00163156,
+      function (name, start, end) {
+        shell_syms.push(Array.prototype.slice.apply(arguments, [0]));
+      });
+  assertEquals(
+      [['start', 0x00001b00, 0x00001b40],
+       ['dyld_stub_binding_helper', 0x00001b40, 0x0011b710],
+       ['v8::internal::RegExpMacroAssembler::CheckPosition', 0x0011b710, 0x00134250],
+       ['v8::internal::Runtime_StringReplaceRegExpWithString', 0x00134250, 0x00137220],
+       ['v8::internal::Runtime::GetElementOrCharAt', 0x00137220, 0x00137400],
+       ['v8::internal::Runtime_DebugGetPropertyDetails', 0x00137400, 0x00163156]],
+      shell_syms);
+
+  // stdc++ library
+  MacCppEntriesProvider.prototype.loadSymbols = function(libName) {
+    this.symbols = [[
+        '0000107a T __gnu_cxx::balloc::__mini_vector<std::pair<__gnu_cxx::bitmap_allocator<char>::_Alloc_block*, __gnu_cxx::bitmap_allocator<char>::_Alloc_block*> >::__mini_vector',
+        '0002c410 T std::basic_streambuf<char, std::char_traits<char> >::pubseekoff',
+        '0002c488 T std::basic_streambuf<char, std::char_traits<char> >::pubseekpos',
+        '000466aa T ___cxa_pure_virtual\n'].join('\n'), ''];
+  };
+  var stdc_prov = new MacCppEntriesProvider();
+  var stdc_syms = [];
+  stdc_prov.parseVmSymbols('stdc++', 0x95728fb4, 0x95770005,
+      function (name, start, end) {
+        stdc_syms.push(Array.prototype.slice.apply(arguments, [0]));
+      });
+  var stdc_ref_syms = [['__gnu_cxx::balloc::__mini_vector<std::pair<__gnu_cxx::bitmap_allocator<char>::_Alloc_block*, __gnu_cxx::bitmap_allocator<char>::_Alloc_block*> >::__mini_vector', 0x0000107a, 0x0002c410],
+       ['std::basic_streambuf<char, std::char_traits<char> >::pubseekoff', 0x0002c410, 0x0002c488],
+       ['std::basic_streambuf<char, std::char_traits<char> >::pubseekpos', 0x0002c488, 0x000466aa],
+       ['___cxa_pure_virtual', 0x000466aa, 0x95770005 - 0x95728fb4]];
+  for (var i = 0; i < stdc_ref_syms.length; ++i) {
+    stdc_ref_syms[i][1] += 0x95728fb4;
+    stdc_ref_syms[i][2] += 0x95728fb4;
+  }
+  assertEquals(stdc_ref_syms, stdc_syms);
+
+  MacCppEntriesProvider.prototype.loadSymbols = oldLoadSymbols;
+})();
+
+
 (function testWindowsCppEntriesProvider() {
   var oldLoadSymbols = WindowsCppEntriesProvider.prototype.loadSymbols;
 
@@ -174,8 +239,8 @@ CppEntriesProviderMock.prototype.parseVmSymbols = function(
          ['v8::internal::HashTable<v8::internal::StringDictionaryShape, v8::internal::String*>::FindEntry(v8::internal::String*)', 0x080f8210, 0x080f8800],
          ['v8::internal::Runtime_Math_exp(v8::internal::Arguments)', 0x08123b20, 0x08123b80]],
     '/lib32/libm-2.7.so':
-        [['exp', startAddr + 0x00009e80, startAddr + 0x00009f30],
-         ['fegetexcept', startAddr + 0x000061e0, startAddr + 0x00008b10]],
+        [['exp', startAddr + 0x00009e80, startAddr + 0x00009e80 + 0xa3],
+         ['fegetexcept', startAddr + 0x000061e0, startAddr + 0x000061e0 + 0x15]],
     'ffffe000-fffff000': []};
   assertTrue(name in symbols);
   var syms = symbols[name];
@@ -191,6 +256,7 @@ function PrintMonitor(outputOrFileName) {
   var outputPos = 0;
   var diffs = this.diffs = [];
   var realOut = this.realOut = [];
+  var unexpectedOut = this.unexpectedOut = null;
 
   this.oldPrint = print;
   print = function(str) {
@@ -198,13 +264,15 @@ function PrintMonitor(outputOrFileName) {
     for (var i = 0; i < strSplit.length; ++i) {
       s = strSplit[i];
       realOut.push(s);
-      assertTrue(outputPos < expectedOut.length,
-          'unexpected output: "' + s + '"');
-      if (expectedOut[outputPos] != s) {
-        diffs.push('line ' + outputPos + ': expected <' +
-                   expectedOut[outputPos] + '> found <' + s + '>\n');
+      if (outputPos < expectedOut.length) {
+        if (expectedOut[outputPos] != s) {
+          diffs.push('line ' + outputPos + ': expected <' +
+                     expectedOut[outputPos] + '> found <' + s + '>\n');
+        }
+        outputPos++;
+      } else {
+        unexpectedOut = true;
       }
-      outputPos++;
     }
   };
 };
@@ -218,9 +286,10 @@ PrintMonitor.prototype.loadExpectedOutput = function(fileName) {
 
 PrintMonitor.prototype.finish = function() {
   print = this.oldPrint;
-  if (this.diffs.length > 0) {
+  if (this.diffs.length > 0 || this.unexpectedOut != null) {
     print(this.realOut.join('\n'));
     assertEquals([], this.diffs);
+    assertNull(this.unexpectedOut);
   }
 };
 
index 13ae29c..538b0a8 100644 (file)
@@ -321,10 +321,6 @@ js1_5/Regress/regress-179524: FAIL_OK
 js1_5/Regress/regress-172699: FAIL_OK
 
 
-# Calls regexp objects with function call syntax; non-ECMA behavior.
-js1_2/Objects/toString-001: FAIL_OK
-
-
 # Assumes that the prototype of a function is enumerable. Non-ECMA,
 # see section 15.3.3.1, page 86.
 ecma/GlobalObject/15.1.2.2-1: FAIL_OK
@@ -338,6 +334,7 @@ ecma/GlobalObject/15.1.2.7: FAIL_OK
 # Tests that rely on specific details of function decompilation or
 # print strings for errors. Non-ECMA behavior.
 js1_2/function/tostring-2: FAIL_OK
+js1_2/Objects/toString-001: FAIL_OK
 js1_5/Exceptions/regress-332472: FAIL_OK
 js1_5/Regress/regress-173067: FAIL_OK
 js1_5/Regress/regress-355556: FAIL_OK
@@ -561,23 +558,11 @@ js1_5/Array/regress-350256-02: FAIL
 ecma_3/Function/regress-137181: FAIL
 
 
-# Calls regexp objects with function call syntax; non-ECMA behavior.
-ecma_2/RegExp/regress-001: FAIL
-js1_2/regexp/regress-6359: FAIL
-js1_2/regexp/regress-9141: FAIL
-js1_5/Regress/regress-224956: FAIL
-js1_5/Regress/regress-325925: FAIL
-js1_2/regexp/simple_form: FAIL
-
-
 # Tests that rely on specific details of function decompilation or
 # print strings for errors. Non-ECMA behavior.
 js1_4/Regress/function-003: FAIL
 
 
-# Relies on JavaScript 1.2 / 1.3 deprecated features.
-js1_2/function/regexparg-1: FAIL
-
 # 'export' and 'import' are not keywords in V8.
 ecma_2/Exceptions/lexical-010: FAIL
 ecma_2/Exceptions/lexical-022: FAIL
index d6df7fa..404127f 100644 (file)
@@ -48,11 +48,16 @@ devtools.profiler.CodeMap = function() {
   this.dynamicsNameGen_ = new devtools.profiler.CodeMap.NameGenerator();
 
   /**
-   * Static code entries. Used for libraries code.
+   * Static code entries. Used for statically compiled code.
    */
   this.statics_ = new goog.structs.SplayTree();
 
   /**
+   * Libraries entries. Used for the whole static code libraries.
+   */
+  this.libraries_ = new goog.structs.SplayTree();
+
+  /**
    * Map of memory pages occupied with static code.
    */
   this.pages_ = [];
@@ -108,6 +113,19 @@ devtools.profiler.CodeMap.prototype.deleteCode = function(start) {
 
 
 /**
+ * Adds a library entry.
+ *
+ * @param {number} start The starting address.
+ * @param {devtools.profiler.CodeMap.CodeEntry} codeEntry Code entry object.
+ */
+devtools.profiler.CodeMap.prototype.addLibrary = function(
+    start, codeEntry) {
+  this.markPages_(start, start + codeEntry.size);
+  this.libraries_.insert(start, codeEntry);
+};
+
+
+/**
  * Adds a static code entry.
  *
  * @param {number} start The starting address.
@@ -115,7 +133,6 @@ devtools.profiler.CodeMap.prototype.deleteCode = function(start) {
  */
 devtools.profiler.CodeMap.prototype.addStaticCode = function(
     start, codeEntry) {
-  this.markPages_(start, start + codeEntry.size);
   this.statics_.insert(start, codeEntry);
 };
 
@@ -157,7 +174,10 @@ devtools.profiler.CodeMap.prototype.findInTree_ = function(tree, addr) {
 devtools.profiler.CodeMap.prototype.findEntry = function(addr) {
   var pageAddr = addr >>> devtools.profiler.CodeMap.PAGE_ALIGNMENT;
   if (pageAddr in this.pages_) {
-    return this.findInTree_(this.statics_, addr);
+    // Static code entries can contain "holes" of unnamed code.
+    // In this case, the whole library is assigned to this address.
+    return this.findInTree_(this.statics_, addr) ||
+        this.findInTree_(this.libraries_, addr);
   }
   var min = this.dynamics_.findMin();
   var max = this.dynamics_.findMax();
@@ -176,7 +196,7 @@ devtools.profiler.CodeMap.prototype.findEntry = function(addr) {
 
 
 /**
- * Returns an array of all dynamic code entries, including deleted ones.
+ * Returns an array of all dynamic code entries.
  */
 devtools.profiler.CodeMap.prototype.getAllDynamicEntries = function() {
   return this.dynamics_.exportValues();
@@ -192,6 +212,14 @@ devtools.profiler.CodeMap.prototype.getAllStaticEntries = function() {
 
 
 /**
+ * Returns an array of all libraries entries.
+ */
+devtools.profiler.CodeMap.prototype.getAllLibrariesEntries = function() {
+  return this.libraries_.exportValues();
+};
+
+
+/**
  * Creates a code entry object.
  *
  * @param {number} size Code entry size in bytes.
index b11a7ff..fc49620 100644 (file)
         '../../src/frames-inl.h',
         '../../src/frames.cc',
         '../../src/frames.h',
+        '../../src/frame-element.cc',
         '../../src/frame-element.h',
         '../../src/func-name-inferrer.cc',
         '../../src/func-name-inferrer.h',
diff --git a/V8Binding/v8/tools/mac-nm b/V8Binding/v8/tools/mac-nm
new file mode 100755 (executable)
index 0000000..9c18177
--- /dev/null
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+# This script is a wrapper for OS X nm(1) tool. nm(1) perform C++ function
+# names demangling, so we're piping its output to c++filt(1) tool which does it.
+# But c++filt(1) comes with XCode (as a part of GNU binutils), so it doesn't
+# guaranteed to exist on a system.
+#
+# An alternative approach is to perform demangling in tick processor, but
+# for GNU C++ ABI this is a complex process (see cp-demangle.c sources), and
+# can't be done partially, because term boundaries are plain text symbols, such
+# as 'N', 'E', so one can't just do a search through a function name, it really
+# needs to be parsed, which requires a lot of knowledge to be coded in.
+
+if [ "`which c++filt`" == "" ]; then
+  nm $@
+else
+  nm $@ | c++filt -p -i
+fi
diff --git a/V8Binding/v8/tools/mac-tick-processor b/V8Binding/v8/tools/mac-tick-processor
new file mode 100755 (executable)
index 0000000..5fba622
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+# A wrapper script to call 'linux-tick-processor' with Mac-specific settings.
+
+tools_path=`cd $(dirname "$0");pwd`
+$tools_path/linux-tick-processor --mac --nm=$tools_path/mac-nm $@
diff --git a/V8Binding/v8/tools/process-heap-prof.py b/V8Binding/v8/tools/process-heap-prof.py
new file mode 100755 (executable)
index 0000000..b8ab2d3
--- /dev/null
@@ -0,0 +1,73 @@
+#!/usr/bin/env python
+#
+# Copyright 2009 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# This is an utility for converting V8 heap logs into .hp files that can
+# be further processed using 'hp2ps' tool (bundled with GHC and Valgrind)
+# to produce heap usage histograms.
+
+# Sample usage:
+# $ ./shell --log-gc script.js
+# $ tools/process-heap-prof.py v8.log | hp2ps -c > script-heap-graph.ps
+# ('-c' enables color, see hp2ps manual page for more options)
+
+import csv, sys, time
+
+def process_logfile(filename):
+  first_call_time = None
+  sample_time = 0.0
+  sampling = False
+  try:
+    logfile = open(filename, 'rb')
+    try:
+      logreader = csv.reader(logfile)
+
+      print('JOB "v8"')
+      print('DATE "%s"' % time.asctime(time.localtime()))
+      print('SAMPLE_UNIT "seconds"')
+      print('VALUE_UNIT "bytes"')
+
+      for row in logreader:
+        if row[0] == 'heap-sample-begin' and row[1] == 'Heap':
+          sample_time = float(row[3])/1000.0
+          if first_call_time == None:
+            first_call_time = sample_time
+          sample_time -= first_call_time
+          print('BEGIN_SAMPLE %.2f' % sample_time)
+          sampling = True
+        elif row[0] == 'heap-sample-end' and row[1] == 'Heap':
+          print('END_SAMPLE %.2f' % sample_time)
+          sampling = False
+        elif row[0] == 'heap-sample-item' and sampling:
+          print('%s %d' % (row[1], int(row[3])))
+    finally:
+      logfile.close()
+  except:
+    sys.exit('can\'t open %s' % filename)
+
+process_logfile(sys.argv[1])
index 614c635..db4b542 100644 (file)
@@ -86,7 +86,23 @@ devtools.profiler.Profile.prototype.handleUnknownCode = function(
 
 
 /**
- * Registers static (library) code entry.
+ * Registers a library.
+ *
+ * @param {string} name Code entry name.
+ * @param {number} startAddr Starting address.
+ * @param {number} endAddr Ending address.
+ */
+devtools.profiler.Profile.prototype.addLibrary = function(
+    name, startAddr, endAddr) {
+  var entry = new devtools.profiler.CodeMap.CodeEntry(
+      endAddr - startAddr, name);
+  this.codeMap_.addLibrary(startAddr, entry);
+  return entry;
+};
+
+
+/**
+ * Registers statically compiled code entry.
  *
  * @param {string} name Code entry name.
  * @param {number} startAddr Starting address.
index 05eb9fd..c1b8b80 100755 (executable)
@@ -1136,6 +1136,7 @@ def ProcessOptions(options):
     # was found, set the arch to the guess.
     if options.arch == 'none':
       options.arch = ARCH_GUESS
+    options.scons_flags.append("arch=" + options.arch)
   return True
 
 
index f7cfd13..dc67796 100644 (file)
@@ -37,11 +37,15 @@ function processArguments(args) {
   }
 }
 
+var entriesProviders = {
+  'unix': UnixCppEntriesProvider,
+  'windows': WindowsCppEntriesProvider,
+  'mac': MacCppEntriesProvider
+};
 
 var params = processArguments(arguments);
 var tickProcessor = new TickProcessor(
-  params.platform == 'unix' ? new UnixCppEntriesProvider(params.nm) :
-    new WindowsCppEntriesProvider(),
+  new (entriesProviders[params.platform])(params.nm),
   params.separateIc,
   params.ignoreUnknown,
   params.stateFilter);
index c95a4e6..efd9750 100644 (file)
@@ -174,7 +174,7 @@ TickProcessor.prototype.processLogFile = function(fileName) {
 
 TickProcessor.prototype.processSharedLibrary = function(
     name, startAddr, endAddr) {
-  var entry = this.profile_.addStaticCode(name, startAddr, endAddr);
+  var entry = this.profile_.addLibrary(name, startAddr, endAddr);
   this.setCodeType(entry.getName(), 'SHARED_LIB');
 
   var self = this;
@@ -380,14 +380,21 @@ CppEntriesProvider.prototype.parseVmSymbols = function(
 
   var prevEntry;
 
-  function addPrevEntry(end) {
+  function addEntry(funcInfo) {
     // Several functions can be mapped onto the same address. To avoid
     // creating zero-sized entries, skip such duplicates.
     // Also double-check that function belongs to the library address space.
-    if (prevEntry && prevEntry.start < end &&
-        prevEntry.start >= libStart && end <= libEnd) {
-      processorFunc(prevEntry.name, prevEntry.start, end);
+    if (prevEntry && !prevEntry.end &&
+        prevEntry.start < funcInfo.start &&
+        prevEntry.start >= libStart && funcInfo.start <= libEnd) {
+      processorFunc(prevEntry.name, prevEntry.start, funcInfo.start);
     }
+    if (funcInfo.end &&
+        (!prevEntry || prevEntry.start != funcInfo.start) &&
+        funcInfo.start >= libStart && funcInfo.end <= libEnd) {
+      processorFunc(funcInfo.name, funcInfo.start, funcInfo.end);
+    }
+    prevEntry = funcInfo;
   }
 
   while (true) {
@@ -400,10 +407,12 @@ CppEntriesProvider.prototype.parseVmSymbols = function(
     if (funcInfo.start < libStart && funcInfo.start < libEnd - libStart) {
       funcInfo.start += libStart;
     }
-    addPrevEntry(funcInfo.start);
-    prevEntry = funcInfo;
+    if (funcInfo.size) {
+      funcInfo.end = funcInfo.start + funcInfo.size;
+    }
+    addEntry(funcInfo);
   }
-  addPrevEntry(libEnd);
+  addEntry({name: '', start: libEnd});
 };
 
 
@@ -420,19 +429,17 @@ function UnixCppEntriesProvider(nmExec) {
   this.symbols = [];
   this.parsePos = 0;
   this.nmExec = nmExec;
+  this.FUNC_RE = /^([0-9a-fA-F]{8}) ([0-9a-fA-F]{8} )?[tTwW] (.*)$/;
 };
 inherits(UnixCppEntriesProvider, CppEntriesProvider);
 
 
-UnixCppEntriesProvider.FUNC_RE = /^([0-9a-fA-F]{8}) [tTwW] (.*)$/;
-
-
 UnixCppEntriesProvider.prototype.loadSymbols = function(libName) {
   this.parsePos = 0;
   try {
     this.symbols = [
-      os.system(this.nmExec, ['-C', '-n', libName], -1, -1),
-      os.system(this.nmExec, ['-C', '-n', '-D', libName], -1, -1)
+      os.system(this.nmExec, ['-C', '-n', '-S', libName], -1, -1),
+      os.system(this.nmExec, ['-C', '-n', '-S', '-D', libName], -1, -1)
     ];
   } catch (e) {
     // If the library cannot be found on this system let's not panic.
@@ -454,8 +461,34 @@ UnixCppEntriesProvider.prototype.parseNextLine = function() {
 
   var line = this.symbols[0].substring(this.parsePos, lineEndPos);
   this.parsePos = lineEndPos + 1;
-  var fields = line.match(UnixCppEntriesProvider.FUNC_RE);
-  return fields ? { name: fields[2], start: parseInt(fields[1], 16) } : null;
+  var fields = line.match(this.FUNC_RE);
+  var funcInfo = null;
+  if (fields) {
+    funcInfo = { name: fields[3], start: parseInt(fields[1], 16) };
+    if (fields[2]) {
+      funcInfo.size = parseInt(fields[2], 16);
+    }
+  }
+  return funcInfo;
+};
+
+
+function MacCppEntriesProvider(nmExec) {
+  UnixCppEntriesProvider.call(this, nmExec);
+  // Note an empty group. It is required, as UnixCppEntriesProvider expects 3 groups.
+  this.FUNC_RE = /^([0-9a-fA-F]{8}) ()[iItT] (.*)$/;
+};
+inherits(MacCppEntriesProvider, UnixCppEntriesProvider);
+
+
+MacCppEntriesProvider.prototype.loadSymbols = function(libName) {
+  this.parsePos = 0;
+  try {
+    this.symbols = [os.system(this.nmExec, ['-n', '-f', libName], -1, -1), ''];
+  } catch (e) {
+    // If the library cannot be found on this system let's not panic.
+    this.symbols = '';
+  }
 };
 
 
@@ -538,6 +571,8 @@ function ArgumentsProcessor(args) {
         'Specify that we are running on *nix platform'],
     '--windows': ['platform', 'windows',
         'Specify that we are running on Windows platform'],
+    '--mac': ['platform', 'mac',
+        'Specify that we are running on Mac OS X platform'],
     '--nm': ['nm', 'nm',
         'Specify the \'nm\' executable to use (e.g. --nm=/my_dir/nm)']
   };
index 368ba3f..da155b8 100644 (file)
@@ -59,6 +59,8 @@
                896FD03A0E78D717003DFB6A /* libv8-arm.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 89F23C870E78D5B2006B2466 /* libv8-arm.a */; };
                897F767F0E71B690007ACF34 /* shell.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1B50E719C0900D62E90 /* shell.cc */; };
                897F76850E71B6B1007ACF34 /* libv8.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8970F2F00E719FB2006AE7B5 /* libv8.a */; };
+               8981F6001010501900D1520E /* frame-element.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8981F5FE1010500F00D1520E /* frame-element.cc */; };
+               8981F6011010502800D1520E /* frame-element.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8981F5FE1010500F00D1520E /* frame-element.cc */; };
                898BD20E0EF6CC930068B00A /* debug-ia32.cc in Sources */ = {isa = PBXBuildFile; fileRef = 898BD20D0EF6CC850068B00A /* debug-ia32.cc */; };
                898BD20F0EF6CC9A0068B00A /* debug-arm.cc in Sources */ = {isa = PBXBuildFile; fileRef = 898BD20C0EF6CC850068B00A /* debug-arm.cc */; };
                89A15C7B0EE466EB00B48DEB /* regexp-macro-assembler-ia32.cc in Sources */ = {isa = PBXBuildFile; fileRef = 89A15C720EE466D000B48DEB /* regexp-macro-assembler-ia32.cc */; };
                897FF1B70E719C2E00D62E90 /* macros.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; name = macros.py; path = ../src/macros.py; sourceTree = "<group>"; };
                897FF32F0FAA0ED200136CF6 /* version.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = version.cc; sourceTree = "<group>"; };
                897FF3300FAA0ED200136CF6 /* version.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = version.h; sourceTree = "<group>"; };
+               8981F5FE1010500F00D1520E /* frame-element.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "frame-element.cc"; sourceTree = "<group>"; };
+               8981F5FF1010500F00D1520E /* frame-element.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "frame-element.h"; sourceTree = "<group>"; };
                898BD20C0EF6CC850068B00A /* debug-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "debug-arm.cc"; path = "arm/debug-arm.cc"; sourceTree = "<group>"; };
                898BD20D0EF6CC850068B00A /* debug-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "debug-ia32.cc"; path = "ia32/debug-ia32.cc"; sourceTree = "<group>"; };
                89A15C630EE4661A00B48DEB /* bytecodes-irregexp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "bytecodes-irregexp.h"; sourceTree = "<group>"; };
                                89471C7F0EB23EE400B6874B /* flag-definitions.h */,
                                897FF1350E719B8F00D62E90 /* flags.cc */,
                                897FF1360E719B8F00D62E90 /* flags.h */,
+                               8981F5FE1010500F00D1520E /* frame-element.cc */,
+                               8981F5FF1010500F00D1520E /* frame-element.h */,
                                897FF1370E719B8F00D62E90 /* frames-arm.cc */,
                                897FF1380E719B8F00D62E90 /* frames-arm.h */,
                                897FF1390E719B8F00D62E90 /* frames-ia32.cc */,
                                58950D670F5551C400F3E8BA /* virtual-frame-ia32.cc in Sources */,
                                89A88E2E0E71A6D60043BA31 /* zone.cc in Sources */,
                                9F4B7B890FCC877A00DC4117 /* log-utils.cc in Sources */,
+                               8981F6001010501900D1520E /* frame-element.cc in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                58950D690F5551CE00F3E8BA /* virtual-frame-arm.cc in Sources */,
                                89F23C820E78D5B2006B2466 /* zone.cc in Sources */,
                                9F4B7B8A0FCC877A00DC4117 /* log-utils.cc in Sources */,
+                               8981F6011010502800D1520E /* frame-element.cc in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index bfdcec9..ece631a 100644 (file)
                                >
                        </File>
                        <File
-                               RelativePath="..\..\src\ia32\frames-ia32.cc"
+                               RelativePath="..\..\src\frame-element.cc"
                                >
                        </File>
                        <File
-                               RelativePath="..\..\src\ia32\frames-ia32.h"
+                               RelativePath="..\..\src\frame-element.h"
                                >
                        </File>
                        <File
-                               RelativePath="..\..\src\frames-inl.h"
+                               RelativePath="..\..\src\ia32\frames-ia32.cc"
                                >
                        </File>
                        <File
-                               RelativePath="..\..\src\frame-element.h"
+                               RelativePath="..\..\src\ia32\frames-ia32.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\frames-inl.h"
                                >
                        </File>
                        <File
index 8ebe386..d73747e 100644 (file)
                                >
                        </File>
                        <File
+                               RelativePath="..\..\src\frame-element.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\frame-element.h"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\..\src\arm\frames-arm.cc"
                                >
                        </File>
index e66dc02..4706c2d 100644 (file)
@@ -2,4 +2,4 @@ We sync with Chromium release revision, which has both webkit revision and V8 re
 
 http://src.chromium.org/svn/branches/187/src@18043
   http://svn.webkit.org/repository/webkit/trunk@44544
-  http://v8.googlecode.com/svn/branches/bleeding_edge@2450
+  http://v8.googlecode.com/svn/branches/bleeding_edge@2530
index 3404a0c..cd918d6 100644 (file)
@@ -61,7 +61,10 @@ public:
     // The buffer must be in non-purgeable state before adopted to a SharedBuffer. 
     // It will stay that way until released.
     static PassRefPtr<SharedBuffer> adoptPurgeableBuffer(PurgeableBuffer* buffer);
-    
+
+#if PLATFORM(ANDROID)
+    virtual
+#endif
     ~SharedBuffer();
     
 #if PLATFORM(MAC)
@@ -73,7 +76,13 @@ public:
     static PassRefPtr<SharedBuffer> wrapCFData(CFDataRef);
 #endif
 
+#if PLATFORM(ANDROID)
+    virtual
+#endif
     const char* data() const;
+#if PLATFORM(ANDROID)
+    virtual
+#endif
     unsigned size() const;
     const Vector<char> &buffer() { return m_buffer; }