let load and store api callbacks use global proxy as receiver
R=verwaest@chromium.org BUG= Review URL: https://codereview.chromium.org/151063003 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19033 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
9e70f6a4e7
commit
ef2ca4ac09
@ -782,11 +782,23 @@ static void CompileCallLoadPropertyWithInterceptor(
|
||||
}
|
||||
|
||||
|
||||
static void GenerateFastApiCallBody(MacroAssembler* masm,
|
||||
const CallOptimization& optimization,
|
||||
int argc,
|
||||
Register holder_in,
|
||||
bool restore_context) {
|
||||
// Generate call to api function.
|
||||
static void GenerateFastApiCall(MacroAssembler* masm,
|
||||
const CallOptimization& optimization,
|
||||
Handle<Map> receiver_map,
|
||||
Register receiver,
|
||||
Register scratch_in,
|
||||
int argc,
|
||||
Register* values) {
|
||||
ASSERT(!receiver.is(scratch_in));
|
||||
__ push(receiver);
|
||||
// Write the arguments to stack frame.
|
||||
for (int i = 0; i < argc; i++) {
|
||||
Register arg = values[argc-1-i];
|
||||
ASSERT(!receiver.is(arg));
|
||||
ASSERT(!scratch_in.is(arg));
|
||||
__ push(arg);
|
||||
}
|
||||
ASSERT(optimization.is_simple_api_call());
|
||||
|
||||
// Abi for CallApiFunctionStub.
|
||||
@ -796,7 +808,21 @@ static void GenerateFastApiCallBody(MacroAssembler* masm,
|
||||
Register api_function_address = r1;
|
||||
|
||||
// Put holder in place.
|
||||
__ Move(holder, holder_in);
|
||||
CallOptimization::HolderLookup holder_lookup;
|
||||
Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType(
|
||||
receiver_map,
|
||||
&holder_lookup);
|
||||
switch (holder_lookup) {
|
||||
case CallOptimization::kHolderIsReceiver:
|
||||
__ Move(holder, receiver);
|
||||
break;
|
||||
case CallOptimization::kHolderFound:
|
||||
__ Move(holder, api_holder);
|
||||
break;
|
||||
case CallOptimization::kHolderNotFound:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
|
||||
Isolate* isolate = masm->isolate();
|
||||
Handle<JSFunction> function = optimization.constant_function();
|
||||
@ -828,36 +854,11 @@ static void GenerateFastApiCallBody(MacroAssembler* masm,
|
||||
__ mov(api_function_address, Operand(ref));
|
||||
|
||||
// Jump to stub.
|
||||
CallApiFunctionStub stub(restore_context, call_data_undefined, argc);
|
||||
CallApiFunctionStub stub(true, call_data_undefined, argc);
|
||||
__ TailCallStub(&stub);
|
||||
}
|
||||
|
||||
|
||||
// Generate call to api function.
|
||||
static void GenerateFastApiCall(MacroAssembler* masm,
|
||||
const CallOptimization& optimization,
|
||||
Register receiver,
|
||||
Register scratch,
|
||||
int argc,
|
||||
Register* values) {
|
||||
ASSERT(!receiver.is(scratch));
|
||||
__ push(receiver);
|
||||
// Write the arguments to stack frame.
|
||||
for (int i = 0; i < argc; i++) {
|
||||
Register arg = values[argc-1-i];
|
||||
ASSERT(!receiver.is(arg));
|
||||
ASSERT(!scratch.is(arg));
|
||||
__ push(arg);
|
||||
}
|
||||
// Stack now matches JSFunction abi.
|
||||
GenerateFastApiCallBody(masm,
|
||||
optimization,
|
||||
argc,
|
||||
receiver,
|
||||
true);
|
||||
}
|
||||
|
||||
|
||||
void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) {
|
||||
__ Jump(code, RelocInfo::CODE_TARGET);
|
||||
}
|
||||
@ -1075,9 +1076,11 @@ void LoadStubCompiler::GenerateLoadConstant(Handle<Object> value) {
|
||||
|
||||
|
||||
void LoadStubCompiler::GenerateLoadCallback(
|
||||
const CallOptimization& call_optimization) {
|
||||
const CallOptimization& call_optimization,
|
||||
Handle<Map> receiver_map) {
|
||||
GenerateFastApiCall(
|
||||
masm(), call_optimization, receiver(), scratch3(), 0, NULL);
|
||||
masm(), call_optimization, receiver_map,
|
||||
receiver(), scratch3(), 0, NULL);
|
||||
}
|
||||
|
||||
|
||||
@ -1267,7 +1270,8 @@ Handle<Code> StoreStubCompiler::CompileStoreCallback(
|
||||
|
||||
Register values[] = { value() };
|
||||
GenerateFastApiCall(
|
||||
masm(), call_optimization, receiver(), scratch3(), 1, values);
|
||||
masm(), call_optimization, handle(object->map()),
|
||||
receiver(), scratch3(), 1, values);
|
||||
|
||||
// Return the generated code.
|
||||
return GetCode(kind(), Code::FAST, name);
|
||||
|
@ -418,11 +418,30 @@ static void CompileCallLoadPropertyWithInterceptor(
|
||||
}
|
||||
|
||||
|
||||
static void GenerateFastApiCallBody(MacroAssembler* masm,
|
||||
const CallOptimization& optimization,
|
||||
int argc,
|
||||
Register holder_in,
|
||||
bool restore_context) {
|
||||
// Generate call to api function.
|
||||
// This function uses push() to generate smaller, faster code than
|
||||
// the version above. It is an optimization that should will be removed
|
||||
// when api call ICs are generated in hydrogen.
|
||||
static void GenerateFastApiCall(MacroAssembler* masm,
|
||||
const CallOptimization& optimization,
|
||||
Handle<Map> receiver_map,
|
||||
Register receiver,
|
||||
Register scratch_in,
|
||||
int argc,
|
||||
Register* values) {
|
||||
// Copy return value.
|
||||
__ pop(scratch_in);
|
||||
// receiver
|
||||
__ push(receiver);
|
||||
// Write the arguments to stack frame.
|
||||
for (int i = 0; i < argc; i++) {
|
||||
Register arg = values[argc-1-i];
|
||||
ASSERT(!receiver.is(arg));
|
||||
ASSERT(!scratch_in.is(arg));
|
||||
__ push(arg);
|
||||
}
|
||||
__ push(scratch_in);
|
||||
// Stack now matches JSFunction abi.
|
||||
ASSERT(optimization.is_simple_api_call());
|
||||
|
||||
// Abi for CallApiFunctionStub.
|
||||
@ -430,11 +449,24 @@ static void GenerateFastApiCallBody(MacroAssembler* masm,
|
||||
Register call_data = ebx;
|
||||
Register holder = ecx;
|
||||
Register api_function_address = edx;
|
||||
Register scratch = edi; // scratch_in is no longer valid.
|
||||
|
||||
// Put holder in place.
|
||||
__ Move(holder, holder_in);
|
||||
|
||||
Register scratch = edi;
|
||||
CallOptimization::HolderLookup holder_lookup;
|
||||
Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType(
|
||||
receiver_map,
|
||||
&holder_lookup);
|
||||
switch (holder_lookup) {
|
||||
case CallOptimization::kHolderIsReceiver:
|
||||
__ Move(holder, receiver);
|
||||
break;
|
||||
case CallOptimization::kHolderFound:
|
||||
__ LoadHeapObject(holder, api_holder);
|
||||
break;
|
||||
case CallOptimization::kHolderNotFound:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
|
||||
Isolate* isolate = masm->isolate();
|
||||
Handle<JSFunction> function = optimization.constant_function();
|
||||
@ -461,42 +493,11 @@ static void GenerateFastApiCallBody(MacroAssembler* masm,
|
||||
__ mov(api_function_address, Immediate(function_address));
|
||||
|
||||
// Jump to stub.
|
||||
CallApiFunctionStub stub(restore_context, call_data_undefined, argc);
|
||||
CallApiFunctionStub stub(true, call_data_undefined, argc);
|
||||
__ TailCallStub(&stub);
|
||||
}
|
||||
|
||||
|
||||
// Generate call to api function.
|
||||
// This function uses push() to generate smaller, faster code than
|
||||
// the version above. It is an optimization that should will be removed
|
||||
// when api call ICs are generated in hydrogen.
|
||||
static void GenerateFastApiCall(MacroAssembler* masm,
|
||||
const CallOptimization& optimization,
|
||||
Register receiver,
|
||||
Register scratch1,
|
||||
int argc,
|
||||
Register* values) {
|
||||
// Copy return value.
|
||||
__ pop(scratch1);
|
||||
// receiver
|
||||
__ push(receiver);
|
||||
// Write the arguments to stack frame.
|
||||
for (int i = 0; i < argc; i++) {
|
||||
Register arg = values[argc-1-i];
|
||||
ASSERT(!receiver.is(arg));
|
||||
ASSERT(!scratch1.is(arg));
|
||||
__ push(arg);
|
||||
}
|
||||
__ push(scratch1);
|
||||
// Stack now matches JSFunction abi.
|
||||
GenerateFastApiCallBody(masm,
|
||||
optimization,
|
||||
argc,
|
||||
receiver,
|
||||
true);
|
||||
}
|
||||
|
||||
|
||||
void StoreStubCompiler::GenerateRestoreName(MacroAssembler* masm,
|
||||
Label* label,
|
||||
Handle<Name> name) {
|
||||
@ -1065,10 +1066,11 @@ void LoadStubCompiler::GenerateLoadField(Register reg,
|
||||
|
||||
|
||||
void LoadStubCompiler::GenerateLoadCallback(
|
||||
const CallOptimization& call_optimization) {
|
||||
const CallOptimization& call_optimization,
|
||||
Handle<Map> receiver_map) {
|
||||
GenerateFastApiCall(
|
||||
masm(), call_optimization, receiver(),
|
||||
scratch1(), 0, NULL);
|
||||
masm(), call_optimization, receiver_map,
|
||||
receiver(), scratch1(), 0, NULL);
|
||||
}
|
||||
|
||||
|
||||
@ -1271,8 +1273,8 @@ Handle<Code> StoreStubCompiler::CompileStoreCallback(
|
||||
|
||||
Register values[] = { value() };
|
||||
GenerateFastApiCall(
|
||||
masm(), call_optimization, receiver(),
|
||||
scratch1(), 1, values);
|
||||
masm(), call_optimization, handle(object->map()),
|
||||
receiver(), scratch1(), 1, values);
|
||||
|
||||
// Return the generated code.
|
||||
return GetCode(kind(), Code::FAST, name);
|
||||
|
@ -938,7 +938,7 @@ Handle<Code> LoadIC::CompileHandler(LookupResult* lookup,
|
||||
}
|
||||
CallOptimization call_optimization(function);
|
||||
if (call_optimization.is_simple_api_call() &&
|
||||
call_optimization.IsCompatibleReceiver(*object)) {
|
||||
call_optimization.IsCompatibleReceiver(object, holder)) {
|
||||
return compiler.CompileLoadCallback(
|
||||
type, holder, name, call_optimization);
|
||||
}
|
||||
@ -1364,7 +1364,7 @@ Handle<Code> StoreIC::CompileHandler(LookupResult* lookup,
|
||||
Handle<JSFunction> function = Handle<JSFunction>::cast(setter);
|
||||
CallOptimization call_optimization(function);
|
||||
if (call_optimization.is_simple_api_call() &&
|
||||
call_optimization.IsCompatibleReceiver(*receiver)) {
|
||||
call_optimization.IsCompatibleReceiver(receiver, holder)) {
|
||||
return compiler.CompileStoreCallback(
|
||||
receiver, holder, name, call_optimization);
|
||||
}
|
||||
|
@ -951,7 +951,7 @@ Handle<Code> LoadStubCompiler::CompileLoadCallback(
|
||||
ASSERT(call_optimization.is_simple_api_call());
|
||||
Handle<JSFunction> callback = call_optimization.constant_function();
|
||||
CallbackHandlerFrontend(type, receiver(), holder, name, callback);
|
||||
GenerateLoadCallback(call_optimization);
|
||||
GenerateLoadCallback(call_optimization, IC::TypeToMap(*type, isolate()));
|
||||
|
||||
// Return the generated code.
|
||||
return GetCode(kind(), Code::FAST, name);
|
||||
@ -1357,7 +1357,6 @@ Handle<JSObject> CallOptimization::LookupHolderOfExpectedType(
|
||||
Handle<Map> object_map,
|
||||
HolderLookup* holder_lookup) const {
|
||||
ASSERT(is_simple_api_call());
|
||||
ASSERT_EQ(kHolderNotFound, *holder_lookup);
|
||||
if (!object_map->IsJSObjectMap()) {
|
||||
*holder_lookup = kHolderNotFound;
|
||||
return Handle<JSObject>::null();
|
||||
@ -1382,6 +1381,38 @@ Handle<JSObject> CallOptimization::LookupHolderOfExpectedType(
|
||||
}
|
||||
|
||||
|
||||
bool CallOptimization::IsCompatibleReceiver(Handle<Object> receiver,
|
||||
Handle<JSObject> holder) const {
|
||||
ASSERT(is_simple_api_call());
|
||||
if (!receiver->IsJSObject()) return false;
|
||||
Handle<Map> map(JSObject::cast(*receiver)->map());
|
||||
HolderLookup holder_lookup;
|
||||
Handle<JSObject> api_holder =
|
||||
LookupHolderOfExpectedType(map, &holder_lookup);
|
||||
switch (holder_lookup) {
|
||||
case kHolderNotFound:
|
||||
return false;
|
||||
case kHolderIsReceiver:
|
||||
return true;
|
||||
case kHolderFound:
|
||||
if (api_holder.is_identical_to(holder)) return true;
|
||||
// Check if holder is in prototype chain of api_holder.
|
||||
{
|
||||
JSObject* object = *api_holder;
|
||||
while (true) {
|
||||
Object* prototype = object->map()->prototype();
|
||||
if (!prototype->IsJSObject()) return false;
|
||||
if (prototype == *holder) return true;
|
||||
object = JSObject::cast(prototype);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void CallOptimization::Initialize(Handle<JSFunction> function) {
|
||||
constant_function_ = Handle<JSFunction>::null();
|
||||
is_simple_api_call_ = false;
|
||||
|
@ -611,7 +611,8 @@ class LoadStubCompiler: public BaseLoadStoreStubCompiler {
|
||||
void GenerateLoadConstant(Handle<Object> value);
|
||||
void GenerateLoadCallback(Register reg,
|
||||
Handle<ExecutableAccessorInfo> callback);
|
||||
void GenerateLoadCallback(const CallOptimization& call_optimization);
|
||||
void GenerateLoadCallback(const CallOptimization& call_optimization,
|
||||
Handle<Map> receiver_map);
|
||||
void GenerateLoadInterceptor(Register holder_reg,
|
||||
Handle<Object> object,
|
||||
Handle<JSObject> holder,
|
||||
@ -827,11 +828,9 @@ class CallOptimization BASE_EMBEDDED {
|
||||
Handle<Map> receiver_map,
|
||||
HolderLookup* holder_lookup) const;
|
||||
|
||||
bool IsCompatibleReceiver(Object* receiver) {
|
||||
ASSERT(is_simple_api_call());
|
||||
if (expected_receiver_type_.is_null()) return true;
|
||||
return expected_receiver_type_->IsTemplateFor(receiver);
|
||||
}
|
||||
// Check if the api holder is between the receiver and the holder.
|
||||
bool IsCompatibleReceiver(Handle<Object> receiver,
|
||||
Handle<JSObject> holder) const;
|
||||
|
||||
private:
|
||||
void Initialize(Handle<JSFunction> function);
|
||||
|
@ -392,23 +392,52 @@ static void CompileCallLoadPropertyWithInterceptor(
|
||||
}
|
||||
|
||||
|
||||
static void GenerateFastApiCallBody(MacroAssembler* masm,
|
||||
const CallOptimization& optimization,
|
||||
int argc,
|
||||
Register holder_in,
|
||||
bool restore_context) {
|
||||
// Generate call to api function.
|
||||
static void GenerateFastApiCall(MacroAssembler* masm,
|
||||
const CallOptimization& optimization,
|
||||
Handle<Map> receiver_map,
|
||||
Register receiver,
|
||||
Register scratch_in,
|
||||
int argc,
|
||||
Register* values) {
|
||||
ASSERT(optimization.is_simple_api_call());
|
||||
|
||||
__ PopReturnAddressTo(scratch_in);
|
||||
// receiver
|
||||
__ push(receiver);
|
||||
// Write the arguments to stack frame.
|
||||
for (int i = 0; i < argc; i++) {
|
||||
Register arg = values[argc-1-i];
|
||||
ASSERT(!receiver.is(arg));
|
||||
ASSERT(!scratch_in.is(arg));
|
||||
__ push(arg);
|
||||
}
|
||||
__ PushReturnAddressFrom(scratch_in);
|
||||
// Stack now matches JSFunction abi.
|
||||
|
||||
// Abi for CallApiFunctionStub.
|
||||
Register callee = rax;
|
||||
Register call_data = rbx;
|
||||
Register holder = rcx;
|
||||
Register api_function_address = rdx;
|
||||
Register scratch = rdi; // scratch_in is no longer valid.
|
||||
|
||||
// Put holder in place.
|
||||
__ Move(holder, holder_in);
|
||||
|
||||
Register scratch = rdi;
|
||||
CallOptimization::HolderLookup holder_lookup;
|
||||
Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType(
|
||||
receiver_map,
|
||||
&holder_lookup);
|
||||
switch (holder_lookup) {
|
||||
case CallOptimization::kHolderIsReceiver:
|
||||
__ Move(holder, receiver);
|
||||
break;
|
||||
case CallOptimization::kHolderFound:
|
||||
__ Move(holder, api_holder);
|
||||
break;
|
||||
case CallOptimization::kHolderNotFound:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
|
||||
Isolate* isolate = masm->isolate();
|
||||
Handle<JSFunction> function = optimization.constant_function();
|
||||
@ -436,38 +465,11 @@ static void GenerateFastApiCallBody(MacroAssembler* masm,
|
||||
api_function_address, function_address, RelocInfo::EXTERNAL_REFERENCE);
|
||||
|
||||
// Jump to stub.
|
||||
CallApiFunctionStub stub(restore_context, call_data_undefined, argc);
|
||||
CallApiFunctionStub stub(true, call_data_undefined, argc);
|
||||
__ TailCallStub(&stub);
|
||||
}
|
||||
|
||||
|
||||
// Generate call to api function.
|
||||
static void GenerateFastApiCall(MacroAssembler* masm,
|
||||
const CallOptimization& optimization,
|
||||
Register receiver,
|
||||
Register scratch1,
|
||||
int argc,
|
||||
Register* values) {
|
||||
__ PopReturnAddressTo(scratch1);
|
||||
// receiver
|
||||
__ push(receiver);
|
||||
// Write the arguments to stack frame.
|
||||
for (int i = 0; i < argc; i++) {
|
||||
Register arg = values[argc-1-i];
|
||||
ASSERT(!receiver.is(arg));
|
||||
ASSERT(!scratch1.is(arg));
|
||||
__ push(arg);
|
||||
}
|
||||
__ PushReturnAddressFrom(scratch1);
|
||||
// Stack now matches JSFunction abi.
|
||||
GenerateFastApiCallBody(masm,
|
||||
optimization,
|
||||
argc,
|
||||
receiver,
|
||||
true);
|
||||
}
|
||||
|
||||
|
||||
void StoreStubCompiler::GenerateRestoreName(MacroAssembler* masm,
|
||||
Label* label,
|
||||
Handle<Name> name) {
|
||||
@ -968,10 +970,11 @@ void LoadStubCompiler::GenerateLoadField(Register reg,
|
||||
|
||||
|
||||
void LoadStubCompiler::GenerateLoadCallback(
|
||||
const CallOptimization& call_optimization) {
|
||||
const CallOptimization& call_optimization,
|
||||
Handle<Map> receiver_map) {
|
||||
GenerateFastApiCall(
|
||||
masm(), call_optimization, receiver(),
|
||||
scratch1(), 0, NULL);
|
||||
masm(), call_optimization, receiver_map,
|
||||
receiver(), scratch1(), 0, NULL);
|
||||
}
|
||||
|
||||
|
||||
@ -1165,8 +1168,8 @@ Handle<Code> StoreStubCompiler::CompileStoreCallback(
|
||||
|
||||
Register values[] = { value() };
|
||||
GenerateFastApiCall(
|
||||
masm(), call_optimization, receiver(),
|
||||
scratch1(), 1, values);
|
||||
masm(), call_optimization, handle(object->map()),
|
||||
receiver(), scratch1(), 1, values);
|
||||
|
||||
// Return the generated code.
|
||||
return GetCode(kind(), Code::FAST, name);
|
||||
|
Loading…
Reference in New Issue
Block a user