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:
parent
d0c35af612
commit
98f1a228c6
@ -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)));
|
||||
|
@ -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)));
|
||||
|
35
src/ic.cc
35
src/ic.cc
@ -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
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
@ -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
48
test/mjsunit/global-ic.js
Normal 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 + ")");
|
||||
}
|
Loading…
Reference in New Issue
Block a user