Commit 527c7972 authored by whesse@chromium.org's avatar whesse@chromium.org

Refactor GenerateLoadInterceptor, removing LoadInterceptorCompiler class and...

Refactor GenerateLoadInterceptor, removing LoadInterceptorCompiler class and CompileLoadInterceptor static function.
All platforms (x64, ia32, and ARM) changed.
Review URL: http://codereview.chromium.org/2251003

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4747 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent e8408703
......@@ -426,191 +426,6 @@ static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
}
class LoadInterceptorCompiler BASE_EMBEDDED {
public:
explicit LoadInterceptorCompiler(Register name) : name_(name) {}
void CompileCacheable(MacroAssembler* masm,
StubCompiler* stub_compiler,
Register receiver,
Register holder,
Register scratch1,
Register scratch2,
JSObject* interceptor_holder,
LookupResult* lookup,
String* name,
Label* miss_label) {
AccessorInfo* callback = NULL;
bool optimize = false;
// So far the most popular follow ups for interceptor loads are FIELD
// and CALLBACKS, so inline only them, other cases may be added
// later.
if (lookup->type() == FIELD) {
optimize = true;
} else if (lookup->type() == CALLBACKS) {
Object* callback_object = lookup->GetCallbackObject();
if (callback_object->IsAccessorInfo()) {
callback = AccessorInfo::cast(callback_object);
optimize = callback->getter() != NULL;
}
}
if (!optimize) {
CompileRegular(masm, receiver, holder, scratch2, interceptor_holder,
miss_label);
return;
}
// Save necessary data before invoking an interceptor.
// Requires a frame to make GC aware of pushed pointers.
__ EnterInternalFrame();
if (lookup->type() == CALLBACKS && !receiver.is(holder)) {
// CALLBACKS case needs a receiver to be passed into C++ callback.
__ Push(receiver, holder, name_);
} else {
__ Push(holder, name_);
}
// Invoke an interceptor. Note: map checks from receiver to
// interceptor's holder has been compiled before (see a caller
// of this method.)
CompileCallLoadPropertyWithInterceptor(masm,
receiver,
holder,
name_,
interceptor_holder);
// Check if interceptor provided a value for property. If it's
// the case, return immediately.
Label interceptor_failed;
__ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex);
__ cmp(r0, scratch1);
__ b(eq, &interceptor_failed);
__ LeaveInternalFrame();
__ Ret();
__ bind(&interceptor_failed);
__ pop(name_);
__ pop(holder);
if (lookup->type() == CALLBACKS && !receiver.is(holder)) {
__ pop(receiver);
}
__ LeaveInternalFrame();
// Check that the maps from interceptor's holder to lookup's holder
// haven't changed. And load lookup's holder into |holder| register.
if (interceptor_holder != lookup->holder()) {
holder = stub_compiler->CheckPrototypes(interceptor_holder, holder,
lookup->holder(), scratch1,
scratch2,
name,
miss_label);
}
if (lookup->type() == FIELD) {
// We found FIELD property in prototype chain of interceptor's holder.
// Retrieve a field from field's holder.
stub_compiler->GenerateFastPropertyLoad(masm,
r0,
holder,
lookup->holder(),
lookup->GetFieldIndex());
__ Ret();
} else {
// We found CALLBACKS property in prototype chain of interceptor's
// holder.
ASSERT(lookup->type() == CALLBACKS);
ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
ASSERT(callback != NULL);
ASSERT(callback->getter() != NULL);
// Tail call to runtime.
// Important invariant in CALLBACKS case: the code above must be
// structured to never clobber |receiver| register.
__ Move(scratch2, Handle<AccessorInfo>(callback));
// holder is either receiver or scratch1.
if (!receiver.is(holder)) {
ASSERT(scratch1.is(holder));
__ Push(receiver, holder, scratch2);
__ ldr(scratch1, FieldMemOperand(holder, AccessorInfo::kDataOffset));
__ Push(scratch1, name_);
} else {
__ push(receiver);
__ ldr(scratch1, FieldMemOperand(holder, AccessorInfo::kDataOffset));
__ Push(holder, scratch2, scratch1, name_);
}
ExternalReference ref =
ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
__ TailCallExternalReference(ref, 5, 1);
}
}
void CompileRegular(MacroAssembler* masm,
Register receiver,
Register holder,
Register scratch,
JSObject* interceptor_holder,
Label* miss_label) {
PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
ExternalReference ref = ExternalReference(
IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
__ TailCallExternalReference(ref, 5, 1);
}
private:
Register name_;
};
static void CompileLoadInterceptor(LoadInterceptorCompiler* compiler,
StubCompiler* stub_compiler,
MacroAssembler* masm,
JSObject* object,
JSObject* holder,
String* name,
LookupResult* lookup,
Register receiver,
Register scratch1,
Register scratch2,
Label* miss) {
ASSERT(holder->HasNamedInterceptor());
ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
// Check that the receiver isn't a smi.
__ BranchOnSmi(receiver, miss);
// Check that the maps haven't changed.
Register reg =
stub_compiler->CheckPrototypes(object, receiver, holder,
scratch1, scratch2, name, miss);
if (lookup->IsProperty() && lookup->IsCacheable()) {
compiler->CompileCacheable(masm,
stub_compiler,
receiver,
reg,
scratch1,
scratch2,
holder,
lookup,
name,
miss);
} else {
compiler->CompileRegular(masm,
receiver,
reg,
scratch2,
holder,
miss);
}
}
// Reserves space for the extra arguments to FastHandleApiCall in the
// caller's frame.
//
......@@ -1023,7 +838,7 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object,
void StubCompiler::GenerateLoadInterceptor(JSObject* object,
JSObject* holder,
JSObject* interceptor_holder,
LookupResult* lookup,
Register receiver,
Register name_reg,
......@@ -1031,18 +846,133 @@ void StubCompiler::GenerateLoadInterceptor(JSObject* object,
Register scratch2,
String* name,
Label* miss) {
LoadInterceptorCompiler compiler(name_reg);
CompileLoadInterceptor(&compiler,
this,
masm(),
object,
holder,
name,
lookup,
receiver,
scratch1,
scratch2,
miss);
ASSERT(interceptor_holder->HasNamedInterceptor());
ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
// Check that the receiver isn't a smi.
__ BranchOnSmi(receiver, miss);
// So far the most popular follow ups for interceptor loads are FIELD
// and CALLBACKS, so inline only them, other cases may be added
// later.
bool compile_followup_inline = false;
if (lookup->IsProperty() && lookup->IsCacheable()) {
if (lookup->type() == FIELD) {
compile_followup_inline = true;
} else if (lookup->type() == CALLBACKS &&
lookup->GetCallbackObject()->IsAccessorInfo() &&
AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL) {
compile_followup_inline = true;
}
}
if (compile_followup_inline) {
// Compile the interceptor call, followed by inline code to load the
// property from further up the prototype chain if the call fails.
// Check that the maps haven't changed.
Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
scratch1, scratch2, name, miss);
ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
// Save necessary data before invoking an interceptor.
// Requires a frame to make GC aware of pushed pointers.
__ EnterInternalFrame();
if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
// CALLBACKS case needs a receiver to be passed into C++ callback.
__ Push(receiver, holder_reg, name_reg);
} else {
__ Push(holder_reg, name_reg);
}
// Invoke an interceptor. Note: map checks from receiver to
// interceptor's holder has been compiled before (see a caller
// of this method.)
CompileCallLoadPropertyWithInterceptor(masm(),
receiver,
holder_reg,
name_reg,
interceptor_holder);
// Check if interceptor provided a value for property. If it's
// the case, return immediately.
Label interceptor_failed;
__ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex);
__ cmp(r0, scratch1);
__ b(eq, &interceptor_failed);
__ LeaveInternalFrame();
__ Ret();
__ bind(&interceptor_failed);
__ pop(name_reg);
__ pop(holder_reg);
if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
__ pop(receiver);
}
__ LeaveInternalFrame();
// Check that the maps from interceptor's holder to lookup's holder
// haven't changed. And load lookup's holder into |holder| register.
if (interceptor_holder != lookup->holder()) {
holder_reg = CheckPrototypes(interceptor_holder,
holder_reg,
lookup->holder(),
scratch1,
scratch2,
name,
miss);
}
if (lookup->type() == FIELD) {
// We found FIELD property in prototype chain of interceptor's holder.
// Retrieve a field from field's holder.
GenerateFastPropertyLoad(masm(), r0, holder_reg,
lookup->holder(), lookup->GetFieldIndex());
__ Ret();
} else {
// We found CALLBACKS property in prototype chain of interceptor's
// holder.
ASSERT(lookup->type() == CALLBACKS);
ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
ASSERT(callback != NULL);
ASSERT(callback->getter() != NULL);
// Tail call to runtime.
// Important invariant in CALLBACKS case: the code above must be
// structured to never clobber |receiver| register.
__ Move(scratch2, Handle<AccessorInfo>(callback));
// holder_reg is either receiver or scratch1.
if (!receiver.is(holder_reg)) {
ASSERT(scratch1.is(holder_reg));
__ Push(receiver, holder_reg, scratch2);
__ ldr(scratch1,
FieldMemOperand(holder_reg, AccessorInfo::kDataOffset));
__ Push(scratch1, name_reg);
} else {
__ push(receiver);
__ ldr(scratch1,
FieldMemOperand(holder_reg, AccessorInfo::kDataOffset));
__ Push(holder_reg, scratch2, scratch1, name_reg);
}
ExternalReference ref =
ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
__ TailCallExternalReference(ref, 5, 1);
}
} else { // !compile_followup_inline
// Call the runtime system to load the interceptor.
// Check that the maps haven't changed.
Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
scratch1, scratch2, name, miss);
PushInterceptorArguments(masm(), receiver, holder_reg,
name_reg, interceptor_holder);
ExternalReference ref = ExternalReference(
IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
__ TailCallExternalReference(ref, 5, 1);
}
}
......
......@@ -300,188 +300,6 @@ static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
}
template <class Compiler>
static void CompileLoadInterceptor(Compiler* compiler,
StubCompiler* stub_compiler,
MacroAssembler* masm,
JSObject* object,
JSObject* holder,
String* name,
LookupResult* lookup,
Register receiver,
Register scratch1,
Register scratch2,
Label* miss) {
ASSERT(holder->HasNamedInterceptor());
ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
// Check that the receiver isn't a smi.
__ test(receiver, Immediate(kSmiTagMask));
__ j(zero, miss, not_taken);
// Check that the maps haven't changed.
Register reg =
stub_compiler->CheckPrototypes(object, receiver, holder,
scratch1, scratch2, name, miss);
if (lookup->IsProperty() && lookup->IsCacheable()) {
compiler->CompileCacheable(masm,
stub_compiler,
receiver,
reg,
scratch1,
scratch2,
holder,
lookup,
name,
miss);
} else {
compiler->CompileRegular(masm,
receiver,
reg,
scratch2,
holder,
miss);
}
}
class LoadInterceptorCompiler BASE_EMBEDDED {
public:
explicit LoadInterceptorCompiler(Register name) : name_(name) {}
void CompileCacheable(MacroAssembler* masm,
StubCompiler* stub_compiler,
Register receiver,
Register holder,
Register scratch1,
Register scratch2,
JSObject* interceptor_holder,
LookupResult* lookup,
String* name,
Label* miss_label) {
AccessorInfo* callback = NULL;
bool optimize = false;
// So far the most popular follow ups for interceptor loads are FIELD
// and CALLBACKS, so inline only them, other cases may be added
// later.
if (lookup->type() == FIELD) {
optimize = true;
} else if (lookup->type() == CALLBACKS) {
Object* callback_object = lookup->GetCallbackObject();
if (callback_object->IsAccessorInfo()) {
callback = AccessorInfo::cast(callback_object);
optimize = callback->getter() != NULL;
}
}
if (!optimize) {
CompileRegular(masm, receiver, holder, scratch2, interceptor_holder,
miss_label);
return;
}
// Save necessary data before invoking an interceptor.
// Requires a frame to make GC aware of pushed pointers.
__ EnterInternalFrame();
if (lookup->type() == CALLBACKS && !receiver.is(holder)) {
// CALLBACKS case needs a receiver to be passed into C++ callback.
__ push(receiver);
}
__ push(holder);
__ push(name_);
// Invoke an interceptor. Note: map checks from receiver to
// interceptor's holder has been compiled before (see a caller
// of this method.)
CompileCallLoadPropertyWithInterceptor(masm,
receiver,
holder,
name_,
interceptor_holder);
// Check if interceptor provided a value for property. If it's
// the case, return immediately.
Label interceptor_failed;
__ cmp(eax, Factory::no_interceptor_result_sentinel());
__ j(equal, &interceptor_failed);
__ LeaveInternalFrame();
__ ret(0);
__ bind(&interceptor_failed);
__ pop(name_);
__ pop(holder);
if (lookup->type() == CALLBACKS && !receiver.is(holder)) {
__ pop(receiver);
}
__ LeaveInternalFrame();
// Check that the maps from interceptor's holder to lookup's holder
// haven't changed. And load lookup's holder into |holder| register.
if (interceptor_holder != lookup->holder()) {
holder = stub_compiler->CheckPrototypes(interceptor_holder, holder,
lookup->holder(), scratch1,
scratch2,
name,
miss_label);
}
if (lookup->type() == FIELD) {
// We found FIELD property in prototype chain of interceptor's holder.
// Retrieve a field from field's holder.
stub_compiler->GenerateFastPropertyLoad(masm, eax,
holder, lookup->holder(),
lookup->GetFieldIndex());
__ ret(0);
} else {
// We found CALLBACKS property in prototype chain of interceptor's
// holder.
ASSERT(lookup->type() == CALLBACKS);
ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
ASSERT(callback != NULL);
ASSERT(callback->getter() != NULL);
// Tail call to runtime.
// Important invariant in CALLBACKS case: the code above must be
// structured to never clobber |receiver| register.
__ pop(scratch2); // return address
__ push(receiver);
__ push(holder);
__ mov(holder, Immediate(Handle<AccessorInfo>(callback)));
__ push(holder);
__ push(FieldOperand(holder, AccessorInfo::kDataOffset));
__ push(name_);
__ push(scratch2); // restore return address
ExternalReference ref =
ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
__ TailCallExternalReference(ref, 5, 1);
}
}
void CompileRegular(MacroAssembler* masm,
Register receiver,
Register holder,
Register scratch,
JSObject* interceptor_holder,
Label* miss_label) {
__ pop(scratch); // save old return address
PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
__ push(scratch); // restore old return address
ExternalReference ref = ExternalReference(
IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
__ TailCallExternalReference(ref, 5, 1);
}
private:
Register name_;
};
// Reserves space for the extra arguments to FastHandleApiCall in the
// caller's frame.
//
......@@ -1052,7 +870,7 @@ void StubCompiler::GenerateLoadConstant(JSObject* object,
void StubCompiler::GenerateLoadInterceptor(JSObject* object,
JSObject* holder,
JSObject* interceptor_holder,
LookupResult* lookup,
Register receiver,
Register name_reg,
......@@ -1060,18 +878,130 @@ void StubCompiler::GenerateLoadInterceptor(JSObject* object,
Register scratch2,
String* name,
Label* miss) {
LoadInterceptorCompiler compiler(name_reg);
CompileLoadInterceptor(&compiler,
this,
masm(),
object,
holder,
name,
lookup,
receiver,
scratch1,
scratch2,
miss);
ASSERT(interceptor_holder->HasNamedInterceptor());
ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
// Check that the receiver isn't a smi.
__ test(receiver, Immediate(kSmiTagMask));
__ j(zero, miss, not_taken);
// So far the most popular follow ups for interceptor loads are FIELD
// and CALLBACKS, so inline only them, other cases may be added
// later.
bool compile_followup_inline = false;
if (lookup->IsProperty() && lookup->IsCacheable()) {
if (lookup->type() == FIELD) {
compile_followup_inline = true;
} else if (lookup->type() == CALLBACKS &&
lookup->GetCallbackObject()->IsAccessorInfo() &&
AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL) {
compile_followup_inline = true;
}
}
if (compile_followup_inline) {
// Compile the interceptor call, followed by inline code to load the
// property from further up the prototype chain if the call fails.
// Check that the maps haven't changed.
Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
scratch1, scratch2, name, miss);
ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
// Save necessary data before invoking an interceptor.
// Requires a frame to make GC aware of pushed pointers.
__ EnterInternalFrame();
if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
// CALLBACKS case needs a receiver to be passed into C++ callback.
__ push(receiver);
}
__ push(holder_reg);
__ push(name_reg);
// Invoke an interceptor. Note: map checks from receiver to
// interceptor's holder has been compiled before (see a caller
// of this method.)
CompileCallLoadPropertyWithInterceptor(masm(),
receiver,
holder_reg,
name_reg,
interceptor_holder);
// Check if interceptor provided a value for property. If it's
// the case, return immediately.
Label interceptor_failed;
__ cmp(eax, Factory::no_interceptor_result_sentinel());
__ j(equal, &interceptor_failed);
__ LeaveInternalFrame();
__ ret(0);
__ bind(&interceptor_failed);
__ pop(name_reg);
__ pop(holder_reg);
if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
__ pop(receiver);
}
__ LeaveInternalFrame();
// Check that the maps from interceptor's holder to lookup's holder
// haven't changed. And load lookup's holder into holder_reg.
if (interceptor_holder != lookup->holder()) {
holder_reg = CheckPrototypes(interceptor_holder,
holder_reg,
lookup->holder(),
scratch1,
scratch2,
name,
miss);
}
if (lookup->type() == FIELD) {
// We found FIELD property in prototype chain of interceptor's holder.
// Retrieve a field from field's holder.
GenerateFastPropertyLoad(masm(), eax, holder_reg,
lookup->holder(), lookup->GetFieldIndex());
__ ret(0);
} else {
// We found CALLBACKS property in prototype chain of interceptor's
// holder.
ASSERT(lookup->type() == CALLBACKS);
ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
ASSERT(callback != NULL);
ASSERT(callback->getter() != NULL);
// Tail call to runtime.
// Important invariant in CALLBACKS case: the code above must be
// structured to never clobber |receiver| register.
__ pop(scratch2); // return address
__ push(receiver);
__ push(holder_reg);
__ mov(holder_reg, Immediate(Handle<AccessorInfo>(callback)));
__ push(holder_reg);
__ push(FieldOperand(holder_reg, AccessorInfo::kDataOffset));
__ push(name_reg);
__ push(scratch2); // restore return address
ExternalReference ref =
ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
__ TailCallExternalReference(ref, 5, 1);
}
} else { // !compile_followup_inline
// Call the runtime system to load the interceptor.
// Check that the maps haven't changed.
Register holder_reg =
CheckPrototypes(object, receiver, interceptor_holder,
scratch1, scratch2, name, miss);
__ pop(scratch2); // save old return address
PushInterceptorArguments(masm(), receiver, holder_reg,
name_reg, interceptor_holder);
__ push(scratch2); // restore old return address
ExternalReference ref = ExternalReference(
IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
__ TailCallExternalReference(ref, 5, 1);
}
}
......
......@@ -375,189 +375,6 @@ void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
}
template <class Compiler>
static void CompileLoadInterceptor(Compiler* compiler,
StubCompiler* stub_compiler,
MacroAssembler* masm,
JSObject* object,
JSObject* holder,
String* name,
LookupResult* lookup,
Register receiver,
Register scratch1,
Register scratch2,
Label* miss) {
ASSERT(holder->HasNamedInterceptor());
ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
// Check that the receiver isn't a smi.
__ JumpIfSmi(receiver, miss);
// Check that the maps haven't changed.
Register reg =
stub_compiler->CheckPrototypes(object, receiver, holder,
scratch1, scratch2, name, miss);
if (lookup->IsProperty() && lookup->IsCacheable()) {
compiler->CompileCacheable(masm,
stub_compiler,
receiver,
reg,
scratch1,
scratch2,
holder,
lookup,
name,
miss);
} else {
compiler->CompileRegular(masm,
receiver,
reg,
scratch2,
holder,
miss);
}
}
class LoadInterceptorCompiler BASE_EMBEDDED {
public:
explicit LoadInterceptorCompiler(Register name) : name_(name) {}
void CompileCacheable(MacroAssembler* masm,
StubCompiler* stub_compiler,
Register receiver,
Register holder,
Register scratch1,
Register scratch2,
JSObject* interceptor_holder,
LookupResult* lookup,
String* name,
Label* miss_label) {
AccessorInfo* callback = NULL;
bool optimize = false;
// So far the most popular follow ups for interceptor loads are FIELD
// and CALLBACKS, so inline only them, other cases may be added
// later.
if (lookup->type() == FIELD) {
optimize = true;
} else if (lookup->type() == CALLBACKS) {
Object* callback_object = lookup->GetCallbackObject();
if (callback_object->IsAccessorInfo()) {
callback = AccessorInfo::cast(callback_object);
optimize = callback->getter() != NULL;
}
}
if (!optimize) {
CompileRegular(masm, receiver, holder, scratch2, interceptor_holder,
miss_label);
return;
}
// Save necessary data before invoking an interceptor.
// Requires a frame to make GC aware of pushed pointers.
__ EnterInternalFrame();
if (lookup->type() == CALLBACKS && !receiver.is(holder)) {
// CALLBACKS case needs a receiver to be passed into C++ callback.
__ push(receiver);
}
__ push(holder);
__ push(name_);
// Invoke an interceptor. Note: map checks from receiver to
// interceptor's holder has been compiled before (see a caller
// of this method.)
CompileCallLoadPropertyWithInterceptor(masm,
receiver,
holder,
name_,
interceptor_holder);
// Check if interceptor provided a value for property. If it's
// the case, return immediately.
Label interceptor_failed;
__ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex);
__ j(equal, &interceptor_failed);
__ LeaveInternalFrame();
__ ret(0);
__ bind(&interceptor_failed);
__ pop(name_);
__ pop(holder);
if (lookup->type() == CALLBACKS && !receiver.is(holder)) {
__ pop(receiver);
}
__ LeaveInternalFrame();
// Check that the maps from interceptor's holder to lookup's holder
// haven't changed. And load lookup's holder into |holder| register.
if (interceptor_holder != lookup->holder()) {
holder = stub_compiler->CheckPrototypes(interceptor_holder, holder,
lookup->holder(), scratch1,
scratch2,
name,
miss_label);
}
if (lookup->type() == FIELD) {
// We found FIELD property in prototype chain of interceptor's holder.
// Retrieve a field from field's holder.
stub_compiler->GenerateFastPropertyLoad(masm,
rax,
holder,
lookup->holder(),
lookup->GetFieldIndex());
__ ret(0);
} else {
// We found CALLBACKS property in prototype chain of interceptor's
// holder.
ASSERT(lookup->type() == CALLBACKS);
ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
ASSERT(callback != NULL);
ASSERT(callback->getter() != NULL);
// Tail call to runtime.
// Important invariant in CALLBACKS case: the code above must be
// structured to never clobber |receiver| register.
__ pop(scratch2); // return address
__ push(receiver);
__ push(holder);
__ Move(holder, Handle<AccessorInfo>(callback));
__ push(holder);
__ push(FieldOperand(holder, AccessorInfo::kDataOffset));
__ push(name_);
__ push(scratch2); // restore return address
ExternalReference ref =
ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
__ TailCallExternalReference(ref, 5, 1);
}
}
void CompileRegular(MacroAssembler* masm,
Register receiver,
Register holder,
Register scratch,
JSObject* interceptor_holder,
Label* miss_label) {
__ pop(scratch); // save old return address
PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
__ push(scratch); // restore old return address
ExternalReference ref = ExternalReference(
IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
__ TailCallExternalReference(ref, 5, 1);
}
private:
Register name_;
};
// Reserves space for the extra arguments to FastHandleApiCall in the
// caller's frame.
//
......@@ -2125,9 +1942,8 @@ Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
}
void StubCompiler::GenerateLoadInterceptor(JSObject* object,
JSObject* holder,
JSObject* interceptor_holder,
LookupResult* lookup,
Register receiver,
Register name_reg,
......@@ -2135,18 +1951,128 @@ void StubCompiler::GenerateLoadInterceptor(JSObject* object,
Register scratch2,
String* name,
Label* miss) {
LoadInterceptorCompiler compiler(name_reg);
CompileLoadInterceptor(&compiler,
this,
masm(),
object,
holder,
name,
lookup,
receiver,
scratch1,
scratch2,
miss);
ASSERT(interceptor_holder->HasNamedInterceptor());
ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
// Check that the receiver isn't a smi.
__ JumpIfSmi(receiver, miss);
// So far the most popular follow ups for interceptor loads are FIELD
// and CALLBACKS, so inline only them, other cases may be added
// later.
bool compile_followup_inline = false;
if (lookup->IsProperty() && lookup->IsCacheable()) {
if (lookup->type() == FIELD) {
compile_followup_inline = true;
} else if (lookup->type() == CALLBACKS &&
lookup->GetCallbackObject()->IsAccessorInfo() &&
AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL) {
compile_followup_inline = true;
}
}
if (compile_followup_inline) {
// Compile the interceptor call, followed by inline code to load the
// property from further up the prototype chain if the call fails.
// Check that the maps haven't changed.
Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
scratch1, scratch2, name, miss);
ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
// Save necessary data before invoking an interceptor.
// Requires a frame to make GC aware of pushed pointers.
__ EnterInternalFrame();
if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
// CALLBACKS case needs a receiver to be passed into C++ callback.
__ push(receiver);
}
__ push(holder_reg);
__ push(name_reg);
// Invoke an interceptor. Note: map checks from receiver to
// interceptor's holder has been compiled before (see a caller
// of this method.)
CompileCallLoadPropertyWithInterceptor(masm(),
receiver,
holder_reg,
name_reg,
interceptor_holder);
// Check if interceptor provided a value for property. If it's
// the case, return immediately.
Label interceptor_failed;
__ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex);
__ j(equal, &interceptor_failed);
__ LeaveInternalFrame();
__ ret(0);
__ bind(&interceptor_failed);
__ pop(name_reg);
__ pop(holder_reg);
if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
__ pop(receiver);
}
__ LeaveInternalFrame();
// Check that the maps from interceptor's holder to lookup's holder
// haven't changed. And load lookup's holder into |holder| register.
if (interceptor_holder != lookup->holder()) {
holder_reg = CheckPrototypes(interceptor_holder,
holder_reg,
lookup->holder(),
scratch1,
scratch2,
name,
miss);
}
if (lookup->type() == FIELD) {
// We found FIELD property in prototype chain of interceptor's holder.
// Retrieve a field from field's holder.
GenerateFastPropertyLoad(masm(), rax, holder_reg,
lookup->holder(), lookup->GetFieldIndex());
__ ret(0);
} else {
// We found CALLBACKS property in prototype chain of interceptor's
// holder.
ASSERT(lookup->type() == CALLBACKS);
ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
ASSERT(callback != NULL);
ASSERT(callback->getter() != NULL);
// Tail call to runtime.
// Important invariant in CALLBACKS case: the code above must be
// structured to never clobber |receiver| register.
__ pop(scratch2); // return address
__ push(receiver);
__ push(holder_reg);
__ Move(holder_reg, Handle<AccessorInfo>(callback));
__ push(holder_reg);
__ push(FieldOperand(holder_reg, AccessorInfo::kDataOffset));
__ push(name_reg);
__ push(scratch2); // restore return address
ExternalReference ref =
ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
__ TailCallExternalReference(ref, 5, 1);
}
} else { // !compile_followup_inline
// Call the runtime system to load the interceptor.
// Check that the maps haven't changed.
Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
scratch1, scratch2, name, miss);
__ pop(scratch2); // save old return address
PushInterceptorArguments(masm(), receiver, holder_reg,
name_reg, interceptor_holder);
__ push(scratch2); // restore old return address
ExternalReference ref = ExternalReference(
IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
__ TailCallExternalReference(ref, 5, 1);
}
}
......
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