Author: [email protected]
Date: Thu Jul  9 04:17:57 2009
New Revision: 2413

Added:
    branches/bleeding_edge/test/mjsunit/global-ic.js
Modified:
    branches/bleeding_edge/src/arm/stub-cache-arm.cc
    branches/bleeding_edge/src/ia32/stub-cache-ia32.cc
    branches/bleeding_edge/src/ic.cc
    branches/bleeding_edge/src/stub-cache.cc
    branches/bleeding_edge/src/stub-cache.h
    branches/bleeding_edge/src/x64/stub-cache-x64.cc

Log:
Allow access through the global proxy to use ICs.
Review URL: http://codereview.chromium.org/155283

Modified: branches/bleeding_edge/src/arm/stub-cache-arm.cc
==============================================================================
--- branches/bleeding_edge/src/arm/stub-cache-arm.cc    (original)
+++ branches/bleeding_edge/src/arm/stub-cache-arm.cc    Thu Jul  9 04:17:57  
2009
@@ -685,7 +685,8 @@
  }


-Object* CallStubCompiler::CompileCallGlobal(GlobalObject* object,
+Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
+                                            GlobalObject* holder,
                                              JSGlobalPropertyCell* cell,
                                              JSFunction* function,
                                              String* name) {
@@ -699,11 +700,19 @@
    // Get the number of arguments.
    const int argc = arguments().immediate();

-  // Check that the map of the global has not changed.
-  __ ldr(r2, MemOperand(sp, argc * kPointerSize));
-  __ ldr(r3, FieldMemOperand(r2, HeapObject::kMapOffset));
-  __ cmp(r3, Operand(Handle<Map>(object->map())));
-  __ b(ne, &miss);
+  // Get the receiver from the stack.
+  __ ldr(r0, MemOperand(sp, argc * 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) {
+    __ tst(r0, Operand(kSmiTagMask));
+    __ b(eq, &miss);
+  }
+
+  // Check that the maps haven't changed.
+  masm()->CheckMaps(object, r0, holder, r3, r2, &miss);

    // Get the value from the cell.
    __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
@@ -715,8 +724,10 @@

    // Patch the receiver on the stack with the global proxy if
    // necessary.
-  __ ldr(r3, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
-  __ str(r3, MemOperand(sp, argc * kPointerSize));
+  if (object->IsGlobalObject()) {
+    __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
+    __ str(r3, MemOperand(sp, argc * kPointerSize));
+  }

    // Setup the context (function already in r1).
    __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
@@ -1013,7 +1024,8 @@
  }


-Object* LoadStubCompiler::CompileLoadGlobal(GlobalObject* object,
+Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
+                                            GlobalObject* holder,
                                              JSGlobalPropertyCell* cell,
                                              String* name,
                                              bool is_dont_delete) {
@@ -1026,11 +1038,19 @@

    __ IncrementCounter(&Counters::named_load_global_inline, 1, r1, r3);

-  // Check that the map of the global has not changed.
+  // Get the receiver from the stack.
    __ ldr(r1, MemOperand(sp, 0 * kPointerSize));
-  __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
-  __ cmp(r3, Operand(Handle<Map>(object->map())));
-  __ b(ne, &miss);
+
+  // 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) {
+    __ tst(r1, Operand(kSmiTagMask));
+    __ b(eq, &miss);
+  }
+
+  // Check that the map of the global has not changed.
+  masm()->CheckMaps(object, r1, holder, r3, r0, &miss);

    // Get the value from the cell.
    __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));

Modified: branches/bleeding_edge/src/ia32/stub-cache-ia32.cc
==============================================================================
--- branches/bleeding_edge/src/ia32/stub-cache-ia32.cc  (original)
+++ branches/bleeding_edge/src/ia32/stub-cache-ia32.cc  Thu Jul  9 04:17:57  
2009
@@ -745,7 +745,8 @@
  }


-Object* CallStubCompiler::CompileCallGlobal(GlobalObject* object,
+Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
+                                            GlobalObject* holder,
                                              JSGlobalPropertyCell* cell,
                                              JSFunction* function,
                                              String* name) {
@@ -758,11 +759,19 @@
    // Get the number of arguments.
    const int argc = arguments().immediate();

-  // Check that the map of the global has not changed.
+  // Get the receiver from the stack.
    __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
-  __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
-         Immediate(Handle<Map>(object->map())));
-  __ j(not_equal, &miss, not_taken);
+
+  // 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) {
+    __ test(edx, Immediate(kSmiTagMask));
+    __ j(zero, &miss, not_taken);
+  }
+
+  // Check that the maps haven't changed.
+  masm()->CheckMaps(object, edx, holder, ebx, ecx, &miss);

    // Get the value from the cell.
    __ mov(edi, Immediate(Handle<JSGlobalPropertyCell>(cell)));
@@ -773,8 +782,10 @@
    __ j(not_equal, &miss, not_taken);

    // Patch the receiver on the stack with the global proxy.
-  __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
-  __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
+  if (object->IsGlobalObject()) {
+    __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
+    __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
+  }

    // Setup the context (function already in edi).
    __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
@@ -1122,7 +1133,8 @@
  }


-Object* LoadStubCompiler::CompileLoadGlobal(GlobalObject* object,
+Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
+                                            GlobalObject* holder,
                                              JSGlobalPropertyCell* cell,
                                              String* name,
                                              bool is_dont_delete) {
@@ -1135,11 +1147,19 @@

    __ IncrementCounter(&Counters::named_load_global_inline, 1);

-  // Check that the map of the global has not changed.
+  // Get the receiver from the stack.
    __ mov(eax, (Operand(esp, kPointerSize)));
-  __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
-         Immediate(Handle<Map>(object->map())));
-  __ j(not_equal, &miss, not_taken);
+
+  // 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) {
+    __ test(eax, Immediate(kSmiTagMask));
+    __ j(zero, &miss, not_taken);
+  }
+
+  // Check that the maps haven't changed.
+  masm()->CheckMaps(object, eax, holder, ebx, edx, &miss);

    // Get the value from the cell.
    __ mov(eax, Immediate(Handle<JSGlobalPropertyCell>(cell)));

Modified: branches/bleeding_edge/src/ic.cc
==============================================================================
--- branches/bleeding_edge/src/ic.cc    (original)
+++ branches/bleeding_edge/src/ic.cc    Thu Jul  9 04:17:57 2009
@@ -452,24 +452,26 @@
        }
        case NORMAL: {
          if (!object->IsJSObject()) return;
-        if (object->IsGlobalObject()) {
-          // The stub generated for the global object picks the value  
directly
-          // from the property cell. So the property must be directly on  
the
-          // global object.
-          Handle<GlobalObject> global = Handle<GlobalObject>::cast(object);
-          if (lookup->holder() != *global) return;
+        Handle<JSObject> receiver = Handle<JSObject>::cast(object);
+
+        if (lookup->holder()->IsGlobalObject()) {
+          GlobalObject* global = GlobalObject::cast(lookup->holder());
            JSGlobalPropertyCell* cell =
                JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
            if (!cell->value()->IsJSFunction()) return;
            JSFunction* function = JSFunction::cast(cell->value());
-          code = StubCache::ComputeCallGlobal(argc, in_loop, *name,  
*global,
-                                              cell, function);
+          code = StubCache::ComputeCallGlobal(argc,
+                                              in_loop,
+                                              *name,
+                                              *receiver,
+                                              global,
+                                              cell,
+                                              function);
          } else {
            // There is only one shared stub for calling normalized
            // properties. It does not traverse the prototype chain, so the
            // property must be found in the receiver for the stub to be
            // applicable.
-          Handle<JSObject> receiver = Handle<JSObject>::cast(object);
            if (lookup->holder() != *receiver) return;
            code = StubCache::ComputeCallNormal(argc, in_loop, *name,  
*receiver);
          }
@@ -657,16 +659,15 @@
          break;
        }
        case NORMAL: {
-        if (object->IsGlobalObject()) {
-          // The stub generated for the global object picks the value  
directly
-          // from the property cell. So the property must be directly on  
the
-          // global object.
-          Handle<GlobalObject> global = Handle<GlobalObject>::cast(object);
-          if (lookup->holder() != *global) return;
+        if (lookup->holder()->IsGlobalObject()) {
+          GlobalObject* global = GlobalObject::cast(lookup->holder());
            JSGlobalPropertyCell* cell =
                JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
-          code = StubCache::ComputeLoadGlobal(*name, *global,
-                                              cell,  
lookup->IsDontDelete());
+          code = StubCache::ComputeLoadGlobal(*name,
+                                              *receiver,
+                                              global,
+                                              cell,
+                                              lookup->IsDontDelete());
          } else {
            // There is only one shared stub for loading normalized
            // properties. It does not traverse the prototype chain, so the

Modified: branches/bleeding_edge/src/stub-cache.cc
==============================================================================
--- branches/bleeding_edge/src/stub-cache.cc    (original)
+++ branches/bleeding_edge/src/stub-cache.cc    Thu Jul  9 04:17:57 2009
@@ -173,14 +173,19 @@


  Object* StubCache::ComputeLoadGlobal(String* name,
-                                     GlobalObject* receiver,
+                                     JSObject* receiver,
+                                     GlobalObject* holder,
                                       JSGlobalPropertyCell* cell,
                                       bool is_dont_delete) {
    Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, NORMAL);
    Object* code = receiver->map()->FindInCodeCache(name, flags);
    if (code->IsUndefined()) {
      LoadStubCompiler compiler;
-    code = compiler.CompileLoadGlobal(receiver, cell, name,  
is_dont_delete);
+    code = compiler.CompileLoadGlobal(receiver,
+                                      holder,
+                                      cell,
+                                      name,
+                                      is_dont_delete);
      if (code->IsFailure()) return code;
      LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
      Object* result = receiver->map()->UpdateCodeCache(name,  
Code::cast(code));
@@ -537,7 +542,8 @@
  Object* StubCache::ComputeCallGlobal(int argc,
                                       InLoopFlag in_loop,
                                       String* name,
-                                     GlobalObject* receiver,
+                                     JSObject* receiver,
+                                     GlobalObject* holder,
                                       JSGlobalPropertyCell* cell,
                                       JSFunction* function) {
    Code::Flags flags =
@@ -550,7 +556,7 @@
      // caches.
      if (!function->is_compiled()) return Failure::InternalError();
      CallStubCompiler compiler(argc, in_loop);
-    code = compiler.CompileCallGlobal(receiver, cell, function, name);
+    code = compiler.CompileCallGlobal(receiver, holder, cell, function,  
name);
      if (code->IsFailure()) return code;
      ASSERT_EQ(flags, Code::cast(code)->flags());
      LOG(CodeCreateEvent(Logger::CALL_IC_TAG, Code::cast(code), name));

Modified: branches/bleeding_edge/src/stub-cache.h
==============================================================================
--- branches/bleeding_edge/src/stub-cache.h     (original)
+++ branches/bleeding_edge/src/stub-cache.h     Thu Jul  9 04:17:57 2009
@@ -79,7 +79,8 @@


    static Object* ComputeLoadGlobal(String* name,
-                                   GlobalObject* receiver,
+                                   JSObject* receiver,
+                                   GlobalObject* holder,
                                     JSGlobalPropertyCell* cell,
                                     bool is_dont_delete);

@@ -164,7 +165,8 @@
    static Object* ComputeCallGlobal(int argc,
                                     InLoopFlag in_loop,
                                     String* name,
-                                   GlobalObject* receiver,
+                                   JSObject* receiver,
+                                   GlobalObject* holder,
                                     JSGlobalPropertyCell* cell,
                                     JSFunction* function);

@@ -435,7 +437,8 @@
                                   JSObject* holder,
                                   String* name);

-  Object* CompileLoadGlobal(GlobalObject* object,
+  Object* CompileLoadGlobal(JSObject* object,
+                            GlobalObject* holder,
                              JSGlobalPropertyCell* holder,
                              String* name,
                              bool is_dont_delete);
@@ -519,7 +522,8 @@
    Object* CompileCallInterceptor(Object* object,
                                   JSObject* holder,
                                   String* name);
-  Object* CompileCallGlobal(GlobalObject* object,
+  Object* CompileCallGlobal(JSObject* object,
+                            GlobalObject* holder,
                              JSGlobalPropertyCell* cell,
                              JSFunction* function,
                              String* name);

Modified: branches/bleeding_edge/src/x64/stub-cache-x64.cc
==============================================================================
--- branches/bleeding_edge/src/x64/stub-cache-x64.cc    (original)
+++ branches/bleeding_edge/src/x64/stub-cache-x64.cc    Thu Jul  9 04:17:57  
2009
@@ -65,7 +65,8 @@



-Object* CallStubCompiler::CompileCallGlobal(GlobalObject* object,
+Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
+                                            GlobalObject* holder,
                                              JSGlobalPropertyCell* cell,
                                              JSFunction* function,
                                              String* name) {
@@ -109,7 +110,8 @@
  }


-Object* LoadStubCompiler::CompileLoadGlobal(GlobalObject* object,
+Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
+                                            GlobalObject* holder,
                                              JSGlobalPropertyCell* cell,
                                              String* name,
                                              bool is_dont_delete) {

Added: branches/bleeding_edge/test/mjsunit/global-ic.js
==============================================================================
--- (empty file)
+++ branches/bleeding_edge/test/mjsunit/global-ic.js    Thu Jul  9 04:17:57  
2009
@@ -0,0 +1,48 @@
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function f() {
+  return 87;
+}
+
+function LoadFromGlobal(global) { return global.x; }
+function StoreToGlobal(global, value) { global.x = value; }
+function CallOnGlobal(global) { return global.f(); }
+
+// Initialize the ICs in the functions.
+for (var i = 0; i < 3; i++) {
+  StoreToGlobal(this, 42 + i);
+  assertEquals(42 + i, LoadFromGlobal(this));
+  assertEquals(87, CallOnGlobal(this));
+}
+
+// Try the ICs with a smi. This should not crash.
+for (var i = 0; i < 3; i++) {
+  StoreToGlobal(i, 42 + i);
+  assertTrue(typeof LoadFromGlobal(i) == "undefined");
+  assertThrows("CallOnGlobal(" + i + ")");
+}

--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---

Reply via email to