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
-~----------~----~----~----~------~----~------~--~---