Allow access through the global proxy to use ICs.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2413 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
kasperl@chromium.org 2009-07-09 11:17:57 +00:00
parent d0c35af612
commit 98f1a228c6
7 changed files with 153 additions and 52 deletions

View File

@ -685,7 +685,8 @@ Object* CallStubCompiler::CompileCallInterceptor(Object* object,
}
Object* CallStubCompiler::CompileCallGlobal(GlobalObject* object,
Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
GlobalObject* holder,
JSGlobalPropertyCell* cell,
JSFunction* function,
String* name) {
@ -699,11 +700,19 @@ Object* CallStubCompiler::CompileCallGlobal(GlobalObject* object,
// 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 @@ Object* CallStubCompiler::CompileCallGlobal(GlobalObject* object,
// 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::CompileLoadInterceptor(JSObject* object,
}
Object* LoadStubCompiler::CompileLoadGlobal(GlobalObject* object,
Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
GlobalObject* holder,
JSGlobalPropertyCell* cell,
String* name,
bool is_dont_delete) {
@ -1026,11 +1038,19 @@ Object* LoadStubCompiler::CompileLoadGlobal(GlobalObject* object,
__ 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)));

View File

@ -745,7 +745,8 @@ Object* CallStubCompiler::CompileCallInterceptor(Object* object,
}
Object* CallStubCompiler::CompileCallGlobal(GlobalObject* object,
Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
GlobalObject* holder,
JSGlobalPropertyCell* cell,
JSFunction* function,
String* name) {
@ -758,11 +759,19 @@ Object* CallStubCompiler::CompileCallGlobal(GlobalObject* object,
// 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 @@ Object* CallStubCompiler::CompileCallGlobal(GlobalObject* object,
__ 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::CompileLoadInterceptor(JSObject* receiver,
}
Object* LoadStubCompiler::CompileLoadGlobal(GlobalObject* object,
Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
GlobalObject* holder,
JSGlobalPropertyCell* cell,
String* name,
bool is_dont_delete) {
@ -1135,11 +1147,19 @@ Object* LoadStubCompiler::CompileLoadGlobal(GlobalObject* object,
__ 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)));

View File

@ -452,24 +452,26 @@ void CallIC::UpdateCaches(LookupResult* lookup,
}
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 @@ void LoadIC::UpdateCaches(LookupResult* lookup,
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

View File

@ -173,14 +173,19 @@ Object* StubCache::ComputeLoadNormal(String* name, JSObject* receiver) {
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::ComputeCallNormal(int argc,
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 @@ Object* StubCache::ComputeCallGlobal(int argc,
// 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));

View File

@ -79,7 +79,8 @@ class StubCache : public AllStatic {
static Object* ComputeLoadGlobal(String* name,
GlobalObject* receiver,
JSObject* receiver,
GlobalObject* holder,
JSGlobalPropertyCell* cell,
bool is_dont_delete);
@ -164,7 +165,8 @@ class StubCache : public AllStatic {
static Object* ComputeCallGlobal(int argc,
InLoopFlag in_loop,
String* name,
GlobalObject* receiver,
JSObject* receiver,
GlobalObject* holder,
JSGlobalPropertyCell* cell,
JSFunction* function);
@ -435,7 +437,8 @@ class LoadStubCompiler: public StubCompiler {
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 @@ class CallStubCompiler: public StubCompiler {
Object* CompileCallInterceptor(Object* object,
JSObject* holder,
String* name);
Object* CompileCallGlobal(GlobalObject* object,
Object* CompileCallGlobal(JSObject* object,
GlobalObject* holder,
JSGlobalPropertyCell* cell,
JSFunction* function,
String* name);

View File

@ -65,7 +65,8 @@ Object* CallStubCompiler::CompileCallInterceptor(Object* a,
Object* CallStubCompiler::CompileCallGlobal(GlobalObject* object,
Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
GlobalObject* holder,
JSGlobalPropertyCell* cell,
JSFunction* function,
String* name) {
@ -109,7 +110,8 @@ Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* a,
}
Object* LoadStubCompiler::CompileLoadGlobal(GlobalObject* object,
Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
GlobalObject* holder,
JSGlobalPropertyCell* cell,
String* name,
bool is_dont_delete) {

48
test/mjsunit/global-ic.js Normal file
View File

@ -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 + ")");
}