Commit 98f1a228 authored by kasperl@chromium.org's avatar kasperl@chromium.org

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
parent d0c35af6
...@@ -685,7 +685,8 @@ Object* CallStubCompiler::CompileCallInterceptor(Object* object, ...@@ -685,7 +685,8 @@ Object* CallStubCompiler::CompileCallInterceptor(Object* object,
} }
Object* CallStubCompiler::CompileCallGlobal(GlobalObject* object, Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
GlobalObject* holder,
JSGlobalPropertyCell* cell, JSGlobalPropertyCell* cell,
JSFunction* function, JSFunction* function,
String* name) { String* name) {
...@@ -699,11 +700,19 @@ Object* CallStubCompiler::CompileCallGlobal(GlobalObject* object, ...@@ -699,11 +700,19 @@ Object* CallStubCompiler::CompileCallGlobal(GlobalObject* object,
// Get the number of arguments. // Get the number of arguments.
const int argc = arguments().immediate(); const int argc = arguments().immediate();
// Check that the map of the global has not changed. // Get the receiver from the stack.
__ ldr(r2, MemOperand(sp, argc * kPointerSize)); __ ldr(r0, MemOperand(sp, argc * kPointerSize));
__ ldr(r3, FieldMemOperand(r2, HeapObject::kMapOffset));
__ cmp(r3, Operand(Handle<Map>(object->map()))); // If the object is the holder then we know that it's a global
__ b(ne, &miss); // 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. // Get the value from the cell.
__ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell))); __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
...@@ -715,8 +724,10 @@ Object* CallStubCompiler::CompileCallGlobal(GlobalObject* object, ...@@ -715,8 +724,10 @@ Object* CallStubCompiler::CompileCallGlobal(GlobalObject* object,
// Patch the receiver on the stack with the global proxy if // Patch the receiver on the stack with the global proxy if
// necessary. // necessary.
__ ldr(r3, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset)); if (object->IsGlobalObject()) {
__ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
__ str(r3, MemOperand(sp, argc * kPointerSize)); __ str(r3, MemOperand(sp, argc * kPointerSize));
}
// Setup the context (function already in r1). // Setup the context (function already in r1).
__ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
...@@ -1013,7 +1024,8 @@ Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* object, ...@@ -1013,7 +1024,8 @@ Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
} }
Object* LoadStubCompiler::CompileLoadGlobal(GlobalObject* object, Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
GlobalObject* holder,
JSGlobalPropertyCell* cell, JSGlobalPropertyCell* cell,
String* name, String* name,
bool is_dont_delete) { bool is_dont_delete) {
...@@ -1026,11 +1038,19 @@ Object* LoadStubCompiler::CompileLoadGlobal(GlobalObject* object, ...@@ -1026,11 +1038,19 @@ Object* LoadStubCompiler::CompileLoadGlobal(GlobalObject* object,
__ IncrementCounter(&Counters::named_load_global_inline, 1, r1, r3); __ 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(r1, MemOperand(sp, 0 * kPointerSize));
__ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
__ cmp(r3, Operand(Handle<Map>(object->map()))); // If the object is the holder then we know that it's a global
__ b(ne, &miss); // 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. // Get the value from the cell.
__ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell))); __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
......
...@@ -745,7 +745,8 @@ Object* CallStubCompiler::CompileCallInterceptor(Object* object, ...@@ -745,7 +745,8 @@ Object* CallStubCompiler::CompileCallInterceptor(Object* object,
} }
Object* CallStubCompiler::CompileCallGlobal(GlobalObject* object, Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
GlobalObject* holder,
JSGlobalPropertyCell* cell, JSGlobalPropertyCell* cell,
JSFunction* function, JSFunction* function,
String* name) { String* name) {
...@@ -758,11 +759,19 @@ Object* CallStubCompiler::CompileCallGlobal(GlobalObject* object, ...@@ -758,11 +759,19 @@ Object* CallStubCompiler::CompileCallGlobal(GlobalObject* object,
// Get the number of arguments. // Get the number of arguments.
const int argc = arguments().immediate(); 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)); __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
__ cmp(FieldOperand(edx, HeapObject::kMapOffset),
Immediate(Handle<Map>(object->map()))); // If the object is the holder then we know that it's a global
__ j(not_equal, &miss, not_taken); // 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. // Get the value from the cell.
__ mov(edi, Immediate(Handle<JSGlobalPropertyCell>(cell))); __ mov(edi, Immediate(Handle<JSGlobalPropertyCell>(cell)));
...@@ -773,8 +782,10 @@ Object* CallStubCompiler::CompileCallGlobal(GlobalObject* object, ...@@ -773,8 +782,10 @@ Object* CallStubCompiler::CompileCallGlobal(GlobalObject* object,
__ j(not_equal, &miss, not_taken); __ j(not_equal, &miss, not_taken);
// Patch the receiver on the stack with the global proxy. // Patch the receiver on the stack with the global proxy.
if (object->IsGlobalObject()) {
__ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
__ mov(Operand(esp, (argc + 1) * kPointerSize), edx); __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
}
// Setup the context (function already in edi). // Setup the context (function already in edi).
__ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
...@@ -1122,7 +1133,8 @@ Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver, ...@@ -1122,7 +1133,8 @@ Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
} }
Object* LoadStubCompiler::CompileLoadGlobal(GlobalObject* object, Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
GlobalObject* holder,
JSGlobalPropertyCell* cell, JSGlobalPropertyCell* cell,
String* name, String* name,
bool is_dont_delete) { bool is_dont_delete) {
...@@ -1135,11 +1147,19 @@ Object* LoadStubCompiler::CompileLoadGlobal(GlobalObject* object, ...@@ -1135,11 +1147,19 @@ Object* LoadStubCompiler::CompileLoadGlobal(GlobalObject* object,
__ IncrementCounter(&Counters::named_load_global_inline, 1); __ 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))); __ mov(eax, (Operand(esp, kPointerSize)));
__ cmp(FieldOperand(eax, HeapObject::kMapOffset),
Immediate(Handle<Map>(object->map()))); // If the object is the holder then we know that it's a global
__ j(not_equal, &miss, not_taken); // 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. // Get the value from the cell.
__ mov(eax, Immediate(Handle<JSGlobalPropertyCell>(cell))); __ mov(eax, Immediate(Handle<JSGlobalPropertyCell>(cell)));
......
...@@ -452,24 +452,26 @@ void CallIC::UpdateCaches(LookupResult* lookup, ...@@ -452,24 +452,26 @@ void CallIC::UpdateCaches(LookupResult* lookup,
} }
case NORMAL: { case NORMAL: {
if (!object->IsJSObject()) return; if (!object->IsJSObject()) return;
if (object->IsGlobalObject()) { Handle<JSObject> receiver = Handle<JSObject>::cast(object);
// The stub generated for the global object picks the value directly
// from the property cell. So the property must be directly on the if (lookup->holder()->IsGlobalObject()) {
// global object. GlobalObject* global = GlobalObject::cast(lookup->holder());
Handle<GlobalObject> global = Handle<GlobalObject>::cast(object);
if (lookup->holder() != *global) return;
JSGlobalPropertyCell* cell = JSGlobalPropertyCell* cell =
JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup)); JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
if (!cell->value()->IsJSFunction()) return; if (!cell->value()->IsJSFunction()) return;
JSFunction* function = JSFunction::cast(cell->value()); JSFunction* function = JSFunction::cast(cell->value());
code = StubCache::ComputeCallGlobal(argc, in_loop, *name, *global, code = StubCache::ComputeCallGlobal(argc,
cell, function); in_loop,
*name,
*receiver,
global,
cell,
function);
} else { } else {
// There is only one shared stub for calling normalized // There is only one shared stub for calling normalized
// properties. It does not traverse the prototype chain, so the // properties. It does not traverse the prototype chain, so the
// property must be found in the receiver for the stub to be // property must be found in the receiver for the stub to be
// applicable. // applicable.
Handle<JSObject> receiver = Handle<JSObject>::cast(object);
if (lookup->holder() != *receiver) return; if (lookup->holder() != *receiver) return;
code = StubCache::ComputeCallNormal(argc, in_loop, *name, *receiver); code = StubCache::ComputeCallNormal(argc, in_loop, *name, *receiver);
} }
...@@ -657,16 +659,15 @@ void LoadIC::UpdateCaches(LookupResult* lookup, ...@@ -657,16 +659,15 @@ void LoadIC::UpdateCaches(LookupResult* lookup,
break; break;
} }
case NORMAL: { case NORMAL: {
if (object->IsGlobalObject()) { if (lookup->holder()->IsGlobalObject()) {
// The stub generated for the global object picks the value directly GlobalObject* global = GlobalObject::cast(lookup->holder());
// 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;
JSGlobalPropertyCell* cell = JSGlobalPropertyCell* cell =
JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup)); JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
code = StubCache::ComputeLoadGlobal(*name, *global, code = StubCache::ComputeLoadGlobal(*name,
cell, lookup->IsDontDelete()); *receiver,
global,
cell,
lookup->IsDontDelete());
} else { } else {
// There is only one shared stub for loading normalized // There is only one shared stub for loading normalized
// properties. It does not traverse the prototype chain, so the // properties. It does not traverse the prototype chain, so the
......
...@@ -173,14 +173,19 @@ Object* StubCache::ComputeLoadNormal(String* name, JSObject* receiver) { ...@@ -173,14 +173,19 @@ Object* StubCache::ComputeLoadNormal(String* name, JSObject* receiver) {
Object* StubCache::ComputeLoadGlobal(String* name, Object* StubCache::ComputeLoadGlobal(String* name,
GlobalObject* receiver, JSObject* receiver,
GlobalObject* holder,
JSGlobalPropertyCell* cell, JSGlobalPropertyCell* cell,
bool is_dont_delete) { bool is_dont_delete) {
Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, NORMAL); Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, NORMAL);
Object* code = receiver->map()->FindInCodeCache(name, flags); Object* code = receiver->map()->FindInCodeCache(name, flags);
if (code->IsUndefined()) { if (code->IsUndefined()) {
LoadStubCompiler compiler; 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; if (code->IsFailure()) return code;
LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name)); LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code)); Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
...@@ -537,7 +542,8 @@ Object* StubCache::ComputeCallNormal(int argc, ...@@ -537,7 +542,8 @@ Object* StubCache::ComputeCallNormal(int argc,
Object* StubCache::ComputeCallGlobal(int argc, Object* StubCache::ComputeCallGlobal(int argc,
InLoopFlag in_loop, InLoopFlag in_loop,
String* name, String* name,
GlobalObject* receiver, JSObject* receiver,
GlobalObject* holder,
JSGlobalPropertyCell* cell, JSGlobalPropertyCell* cell,
JSFunction* function) { JSFunction* function) {
Code::Flags flags = Code::Flags flags =
...@@ -550,7 +556,7 @@ Object* StubCache::ComputeCallGlobal(int argc, ...@@ -550,7 +556,7 @@ Object* StubCache::ComputeCallGlobal(int argc,
// caches. // caches.
if (!function->is_compiled()) return Failure::InternalError(); if (!function->is_compiled()) return Failure::InternalError();
CallStubCompiler compiler(argc, in_loop); 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; if (code->IsFailure()) return code;
ASSERT_EQ(flags, Code::cast(code)->flags()); ASSERT_EQ(flags, Code::cast(code)->flags());
LOG(CodeCreateEvent(Logger::CALL_IC_TAG, Code::cast(code), name)); LOG(CodeCreateEvent(Logger::CALL_IC_TAG, Code::cast(code), name));
......
...@@ -79,7 +79,8 @@ class StubCache : public AllStatic { ...@@ -79,7 +79,8 @@ class StubCache : public AllStatic {
static Object* ComputeLoadGlobal(String* name, static Object* ComputeLoadGlobal(String* name,
GlobalObject* receiver, JSObject* receiver,
GlobalObject* holder,
JSGlobalPropertyCell* cell, JSGlobalPropertyCell* cell,
bool is_dont_delete); bool is_dont_delete);
...@@ -164,7 +165,8 @@ class StubCache : public AllStatic { ...@@ -164,7 +165,8 @@ class StubCache : public AllStatic {
static Object* ComputeCallGlobal(int argc, static Object* ComputeCallGlobal(int argc,
InLoopFlag in_loop, InLoopFlag in_loop,
String* name, String* name,
GlobalObject* receiver, JSObject* receiver,
GlobalObject* holder,
JSGlobalPropertyCell* cell, JSGlobalPropertyCell* cell,
JSFunction* function); JSFunction* function);
...@@ -435,7 +437,8 @@ class LoadStubCompiler: public StubCompiler { ...@@ -435,7 +437,8 @@ class LoadStubCompiler: public StubCompiler {
JSObject* holder, JSObject* holder,
String* name); String* name);
Object* CompileLoadGlobal(GlobalObject* object, Object* CompileLoadGlobal(JSObject* object,
GlobalObject* holder,
JSGlobalPropertyCell* holder, JSGlobalPropertyCell* holder,
String* name, String* name,
bool is_dont_delete); bool is_dont_delete);
...@@ -519,7 +522,8 @@ class CallStubCompiler: public StubCompiler { ...@@ -519,7 +522,8 @@ class CallStubCompiler: public StubCompiler {
Object* CompileCallInterceptor(Object* object, Object* CompileCallInterceptor(Object* object,
JSObject* holder, JSObject* holder,
String* name); String* name);
Object* CompileCallGlobal(GlobalObject* object, Object* CompileCallGlobal(JSObject* object,
GlobalObject* holder,
JSGlobalPropertyCell* cell, JSGlobalPropertyCell* cell,
JSFunction* function, JSFunction* function,
String* name); String* name);
......
...@@ -65,7 +65,8 @@ Object* CallStubCompiler::CompileCallInterceptor(Object* a, ...@@ -65,7 +65,8 @@ Object* CallStubCompiler::CompileCallInterceptor(Object* a,
Object* CallStubCompiler::CompileCallGlobal(GlobalObject* object, Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
GlobalObject* holder,
JSGlobalPropertyCell* cell, JSGlobalPropertyCell* cell,
JSFunction* function, JSFunction* function,
String* name) { String* name) {
...@@ -109,7 +110,8 @@ Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* a, ...@@ -109,7 +110,8 @@ Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* a,
} }
Object* LoadStubCompiler::CompileLoadGlobal(GlobalObject* object, Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
GlobalObject* holder,
JSGlobalPropertyCell* cell, JSGlobalPropertyCell* cell,
String* name, String* name,
bool is_dont_delete) { bool is_dont_delete) {
......
// 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 + ")");
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment