Encapsulate type in the PropertyHandlerCompiler
BUG= R=ishell@chromium.org Review URL: https://codereview.chromium.org/426633002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22700 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
e7e89b32f1
commit
d07de6ed59
@ -733,10 +733,10 @@ void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm,
|
||||
|
||||
|
||||
Register PropertyHandlerCompiler::CheckPrototypes(
|
||||
Handle<HeapType> type, Register object_reg, Handle<JSObject> holder,
|
||||
Register holder_reg, Register scratch1, Register scratch2,
|
||||
Handle<Name> name, Label* miss, PrototypeCheckType check) {
|
||||
Handle<Map> receiver_map(IC::TypeToMap(*type, isolate()));
|
||||
Register object_reg, Handle<JSObject> holder, Register holder_reg,
|
||||
Register scratch1, Register scratch2, Handle<Name> name, Label* miss,
|
||||
PrototypeCheckType check) {
|
||||
Handle<Map> receiver_map(IC::TypeToMap(*type(), isolate()));
|
||||
|
||||
// Make sure there's no overlap between holder and object registers.
|
||||
ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
|
||||
@ -748,8 +748,8 @@ Register PropertyHandlerCompiler::CheckPrototypes(
|
||||
int depth = 0;
|
||||
|
||||
Handle<JSObject> current = Handle<JSObject>::null();
|
||||
if (type->IsConstant()) {
|
||||
current = Handle<JSObject>::cast(type->AsConstant()->Value());
|
||||
if (type()->IsConstant()) {
|
||||
current = Handle<JSObject>::cast(type()->AsConstant()->Value());
|
||||
}
|
||||
Handle<JSObject> prototype = Handle<JSObject>::null();
|
||||
Handle<Map> current_map = receiver_map;
|
||||
@ -864,14 +864,13 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
|
||||
}
|
||||
|
||||
|
||||
Register NamedLoadHandlerCompiler::CallbackFrontend(Handle<HeapType> type,
|
||||
Register object_reg,
|
||||
Register NamedLoadHandlerCompiler::CallbackFrontend(Register object_reg,
|
||||
Handle<JSObject> holder,
|
||||
Handle<Name> name,
|
||||
Handle<Object> callback) {
|
||||
Label miss;
|
||||
|
||||
Register reg = FrontendHeader(type, object_reg, holder, name, &miss);
|
||||
Register reg = FrontendHeader(object_reg, holder, name, &miss);
|
||||
|
||||
if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
|
||||
ASSERT(!reg.is(scratch2()));
|
||||
@ -972,9 +971,8 @@ void NamedLoadHandlerCompiler::GenerateLoadCallback(
|
||||
|
||||
|
||||
void NamedLoadHandlerCompiler::GenerateLoadInterceptor(
|
||||
Register holder_reg, Handle<Object> object,
|
||||
Handle<JSObject> interceptor_holder, LookupResult* lookup,
|
||||
Handle<Name> name) {
|
||||
Register holder_reg, Handle<JSObject> interceptor_holder,
|
||||
LookupResult* lookup, Handle<Name> name) {
|
||||
ASSERT(interceptor_holder->HasNamedInterceptor());
|
||||
ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
|
||||
|
||||
@ -987,10 +985,12 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(
|
||||
compile_followup_inline = true;
|
||||
} else if (lookup->type() == CALLBACKS &&
|
||||
lookup->GetCallbackObject()->IsExecutableAccessorInfo()) {
|
||||
ExecutableAccessorInfo* callback =
|
||||
ExecutableAccessorInfo::cast(lookup->GetCallbackObject());
|
||||
compile_followup_inline = callback->getter() != NULL &&
|
||||
callback->IsCompatibleReceiver(*object);
|
||||
Handle<ExecutableAccessorInfo> callback(
|
||||
ExecutableAccessorInfo::cast(lookup->GetCallbackObject()));
|
||||
compile_followup_inline =
|
||||
callback->getter() != NULL &&
|
||||
ExecutableAccessorInfo::IsCompatibleReceiverType(isolate(), callback,
|
||||
type());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1061,8 +1061,7 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(
|
||||
Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
|
||||
Handle<JSObject> object, Handle<JSObject> holder, Handle<Name> name,
|
||||
Handle<ExecutableAccessorInfo> callback) {
|
||||
Register holder_reg =
|
||||
Frontend(IC::CurrentTypeOf(object, isolate()), receiver(), holder, name);
|
||||
Register holder_reg = Frontend(receiver(), holder, name);
|
||||
|
||||
// Stub never generated for non-global objects that require access checks.
|
||||
ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
|
||||
@ -1147,8 +1146,8 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreInterceptor(
|
||||
|
||||
|
||||
Handle<Code> NamedLoadHandlerCompiler::CompileLoadNonexistent(
|
||||
Handle<HeapType> type, Handle<JSObject> last, Handle<Name> name) {
|
||||
NonexistentFrontend(type, last, name);
|
||||
Handle<JSObject> last, Handle<Name> name) {
|
||||
NonexistentFrontend(last, name);
|
||||
|
||||
// Return undefined if maps of the full prototype chain are still the
|
||||
// same and no global property with this name contains a value.
|
||||
@ -1236,25 +1235,25 @@ void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
|
||||
|
||||
|
||||
Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
|
||||
Handle<HeapType> type, Handle<GlobalObject> global,
|
||||
Handle<PropertyCell> cell, Handle<Name> name, bool is_dont_delete) {
|
||||
Handle<GlobalObject> global, Handle<PropertyCell> cell, Handle<Name> name,
|
||||
bool is_dont_delete) {
|
||||
Label miss;
|
||||
FrontendHeader(type, receiver(), global, name, &miss);
|
||||
FrontendHeader(receiver(), global, name, &miss);
|
||||
|
||||
// Get the value from the cell.
|
||||
__ mov(r3, Operand(cell));
|
||||
__ ldr(r4, FieldMemOperand(r3, Cell::kValueOffset));
|
||||
Register result = StoreIC::ValueRegister();
|
||||
__ mov(result, Operand(cell));
|
||||
__ ldr(result, FieldMemOperand(result, Cell::kValueOffset));
|
||||
|
||||
// Check for deleted property if property can actually be deleted.
|
||||
if (!is_dont_delete) {
|
||||
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
|
||||
__ cmp(r4, ip);
|
||||
__ cmp(result, ip);
|
||||
__ b(eq, &miss);
|
||||
}
|
||||
|
||||
Counters* counters = isolate()->counters();
|
||||
__ IncrementCounter(counters->named_load_global_stub(), 1, r1, r3);
|
||||
__ mov(r0, r4);
|
||||
__ Ret();
|
||||
|
||||
FrontendFooter(name, &miss);
|
||||
|
@ -682,10 +682,10 @@ void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm,
|
||||
|
||||
|
||||
Register PropertyHandlerCompiler::CheckPrototypes(
|
||||
Handle<HeapType> type, Register object_reg, Handle<JSObject> holder,
|
||||
Register holder_reg, Register scratch1, Register scratch2,
|
||||
Handle<Name> name, Label* miss, PrototypeCheckType check) {
|
||||
Handle<Map> receiver_map(IC::TypeToMap(*type, isolate()));
|
||||
Register object_reg, Handle<JSObject> holder, Register holder_reg,
|
||||
Register scratch1, Register scratch2, Handle<Name> name, Label* miss,
|
||||
PrototypeCheckType check) {
|
||||
Handle<Map> receiver_map(IC::TypeToMap(*type(), isolate()));
|
||||
|
||||
// object_reg and holder_reg registers can alias.
|
||||
ASSERT(!AreAliased(object_reg, scratch1, scratch2));
|
||||
@ -696,8 +696,8 @@ Register PropertyHandlerCompiler::CheckPrototypes(
|
||||
int depth = 0;
|
||||
|
||||
Handle<JSObject> current = Handle<JSObject>::null();
|
||||
if (type->IsConstant()) {
|
||||
current = Handle<JSObject>::cast(type->AsConstant()->Value());
|
||||
if (type()->IsConstant()) {
|
||||
current = Handle<JSObject>::cast(type()->AsConstant()->Value());
|
||||
}
|
||||
Handle<JSObject> prototype = Handle<JSObject>::null();
|
||||
Handle<Map> current_map = receiver_map;
|
||||
@ -817,14 +817,13 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
|
||||
}
|
||||
|
||||
|
||||
Register NamedLoadHandlerCompiler::CallbackFrontend(Handle<HeapType> type,
|
||||
Register object_reg,
|
||||
Register NamedLoadHandlerCompiler::CallbackFrontend(Register object_reg,
|
||||
Handle<JSObject> holder,
|
||||
Handle<Name> name,
|
||||
Handle<Object> callback) {
|
||||
Label miss;
|
||||
|
||||
Register reg = FrontendHeader(type, object_reg, holder, name, &miss);
|
||||
Register reg = FrontendHeader(object_reg, holder, name, &miss);
|
||||
// FrontendHeader can return its result into scratch1() so do not
|
||||
// use it.
|
||||
Register scratch2 = this->scratch2();
|
||||
@ -934,9 +933,8 @@ void NamedLoadHandlerCompiler::GenerateLoadCallback(
|
||||
|
||||
|
||||
void NamedLoadHandlerCompiler::GenerateLoadInterceptor(
|
||||
Register holder_reg, Handle<Object> object,
|
||||
Handle<JSObject> interceptor_holder, LookupResult* lookup,
|
||||
Handle<Name> name) {
|
||||
Register holder_reg, Handle<JSObject> interceptor_holder,
|
||||
LookupResult* lookup, Handle<Name> name) {
|
||||
ASSERT(!AreAliased(receiver(), this->name(),
|
||||
scratch1(), scratch2(), scratch3()));
|
||||
ASSERT(interceptor_holder->HasNamedInterceptor());
|
||||
@ -950,10 +948,12 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(
|
||||
compile_followup_inline = true;
|
||||
} else if (lookup->type() == CALLBACKS &&
|
||||
lookup->GetCallbackObject()->IsExecutableAccessorInfo()) {
|
||||
ExecutableAccessorInfo* callback =
|
||||
ExecutableAccessorInfo::cast(lookup->GetCallbackObject());
|
||||
compile_followup_inline = callback->getter() != NULL &&
|
||||
callback->IsCompatibleReceiver(*object);
|
||||
Handle<ExecutableAccessorInfo> callback(
|
||||
ExecutableAccessorInfo::cast(lookup->GetCallbackObject()));
|
||||
compile_followup_inline =
|
||||
callback->getter() != NULL &&
|
||||
ExecutableAccessorInfo::IsCompatibleReceiverType(isolate(), callback,
|
||||
type());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1024,8 +1024,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
|
||||
Handle<JSObject> object, Handle<JSObject> holder, Handle<Name> name,
|
||||
Handle<ExecutableAccessorInfo> callback) {
|
||||
ASM_LOCATION("NamedStoreHandlerCompiler::CompileStoreCallback");
|
||||
Register holder_reg =
|
||||
Frontend(IC::CurrentTypeOf(object, isolate()), receiver(), holder, name);
|
||||
Register holder_reg = Frontend(receiver(), holder, name);
|
||||
|
||||
// Stub never generated for non-global objects that require access checks.
|
||||
ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
|
||||
@ -1116,8 +1115,8 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreInterceptor(
|
||||
|
||||
|
||||
Handle<Code> NamedLoadHandlerCompiler::CompileLoadNonexistent(
|
||||
Handle<HeapType> type, Handle<JSObject> last, Handle<Name> name) {
|
||||
NonexistentFrontend(type, last, name);
|
||||
Handle<JSObject> last, Handle<Name> name) {
|
||||
NonexistentFrontend(last, name);
|
||||
|
||||
// Return undefined if maps of the full prototype chain are still the
|
||||
// same and no global property with this name contains a value.
|
||||
@ -1206,23 +1205,23 @@ void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
|
||||
|
||||
|
||||
Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
|
||||
Handle<HeapType> type, Handle<GlobalObject> global,
|
||||
Handle<PropertyCell> cell, Handle<Name> name, bool is_dont_delete) {
|
||||
Handle<GlobalObject> global, Handle<PropertyCell> cell, Handle<Name> name,
|
||||
bool is_dont_delete) {
|
||||
Label miss;
|
||||
FrontendHeader(type, receiver(), global, name, &miss);
|
||||
FrontendHeader(receiver(), global, name, &miss);
|
||||
|
||||
// Get the value from the cell.
|
||||
__ Mov(x3, Operand(cell));
|
||||
__ Ldr(x4, FieldMemOperand(x3, Cell::kValueOffset));
|
||||
Register result = StoreIC::ValueRegister();
|
||||
__ Mov(result, Operand(cell));
|
||||
__ Ldr(result, FieldMemOperand(result, Cell::kValueOffset));
|
||||
|
||||
// Check for deleted property if property can actually be deleted.
|
||||
if (!is_dont_delete) {
|
||||
__ JumpIfRoot(x4, Heap::kTheHoleValueRootIndex, &miss);
|
||||
__ JumpIfRoot(result, Heap::kTheHoleValueRootIndex, &miss);
|
||||
}
|
||||
|
||||
Counters* counters = isolate()->counters();
|
||||
__ IncrementCounter(counters->named_load_global_stub(), 1, x1, x3);
|
||||
__ Mov(x0, x4);
|
||||
__ Ret();
|
||||
|
||||
FrontendFooter(name, &miss);
|
||||
|
@ -693,10 +693,10 @@ void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm,
|
||||
|
||||
|
||||
Register PropertyHandlerCompiler::CheckPrototypes(
|
||||
Handle<HeapType> type, Register object_reg, Handle<JSObject> holder,
|
||||
Register holder_reg, Register scratch1, Register scratch2,
|
||||
Handle<Name> name, Label* miss, PrototypeCheckType check) {
|
||||
Handle<Map> receiver_map(IC::TypeToMap(*type, isolate()));
|
||||
Register object_reg, Handle<JSObject> holder, Register holder_reg,
|
||||
Register scratch1, Register scratch2, Handle<Name> name, Label* miss,
|
||||
PrototypeCheckType check) {
|
||||
Handle<Map> receiver_map(IC::TypeToMap(*type(), isolate()));
|
||||
|
||||
// Make sure there's no overlap between holder and object registers.
|
||||
ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
|
||||
@ -708,8 +708,8 @@ Register PropertyHandlerCompiler::CheckPrototypes(
|
||||
int depth = 0;
|
||||
|
||||
Handle<JSObject> current = Handle<JSObject>::null();
|
||||
if (type->IsConstant()) current =
|
||||
Handle<JSObject>::cast(type->AsConstant()->Value());
|
||||
if (type()->IsConstant())
|
||||
current = Handle<JSObject>::cast(type()->AsConstant()->Value());
|
||||
Handle<JSObject> prototype = Handle<JSObject>::null();
|
||||
Handle<Map> current_map = receiver_map;
|
||||
Handle<Map> holder_map(holder->map());
|
||||
@ -824,14 +824,13 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
|
||||
}
|
||||
|
||||
|
||||
Register NamedLoadHandlerCompiler::CallbackFrontend(Handle<HeapType> type,
|
||||
Register object_reg,
|
||||
Register NamedLoadHandlerCompiler::CallbackFrontend(Register object_reg,
|
||||
Handle<JSObject> holder,
|
||||
Handle<Name> name,
|
||||
Handle<Object> callback) {
|
||||
Label miss;
|
||||
|
||||
Register reg = FrontendHeader(type, object_reg, holder, name, &miss);
|
||||
Register reg = FrontendHeader(object_reg, holder, name, &miss);
|
||||
|
||||
if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
|
||||
ASSERT(!reg.is(scratch2()));
|
||||
@ -944,9 +943,8 @@ void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
|
||||
|
||||
|
||||
void NamedLoadHandlerCompiler::GenerateLoadInterceptor(
|
||||
Register holder_reg, Handle<Object> object,
|
||||
Handle<JSObject> interceptor_holder, LookupResult* lookup,
|
||||
Handle<Name> name) {
|
||||
Register holder_reg, Handle<JSObject> interceptor_holder,
|
||||
LookupResult* lookup, Handle<Name> name) {
|
||||
ASSERT(interceptor_holder->HasNamedInterceptor());
|
||||
ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
|
||||
|
||||
@ -959,10 +957,12 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(
|
||||
compile_followup_inline = true;
|
||||
} else if (lookup->type() == CALLBACKS &&
|
||||
lookup->GetCallbackObject()->IsExecutableAccessorInfo()) {
|
||||
ExecutableAccessorInfo* callback =
|
||||
ExecutableAccessorInfo::cast(lookup->GetCallbackObject());
|
||||
compile_followup_inline = callback->getter() != NULL &&
|
||||
callback->IsCompatibleReceiver(*object);
|
||||
Handle<ExecutableAccessorInfo> callback(
|
||||
ExecutableAccessorInfo::cast(lookup->GetCallbackObject()));
|
||||
compile_followup_inline =
|
||||
callback->getter() != NULL &&
|
||||
ExecutableAccessorInfo::IsCompatibleReceiverType(isolate(), callback,
|
||||
type());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1044,8 +1044,7 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(
|
||||
Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
|
||||
Handle<JSObject> object, Handle<JSObject> holder, Handle<Name> name,
|
||||
Handle<ExecutableAccessorInfo> callback) {
|
||||
Register holder_reg =
|
||||
Frontend(IC::CurrentTypeOf(object, isolate()), receiver(), holder, name);
|
||||
Register holder_reg = Frontend(receiver(), holder, name);
|
||||
|
||||
__ pop(scratch1()); // remove the return address
|
||||
__ push(receiver());
|
||||
@ -1173,8 +1172,8 @@ Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic(
|
||||
|
||||
|
||||
Handle<Code> NamedLoadHandlerCompiler::CompileLoadNonexistent(
|
||||
Handle<HeapType> type, Handle<JSObject> last, Handle<Name> name) {
|
||||
NonexistentFrontend(type, last, name);
|
||||
Handle<JSObject> last, Handle<Name> name) {
|
||||
NonexistentFrontend(last, name);
|
||||
|
||||
// Return undefined if maps of the full prototype chain are still the
|
||||
// same and no global property with this name contains a value.
|
||||
@ -1257,25 +1256,26 @@ void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
|
||||
|
||||
|
||||
Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
|
||||
Handle<HeapType> type, Handle<GlobalObject> global,
|
||||
Handle<PropertyCell> cell, Handle<Name> name, bool is_dont_delete) {
|
||||
Handle<GlobalObject> global, Handle<PropertyCell> cell, Handle<Name> name,
|
||||
bool is_dont_delete) {
|
||||
Label miss;
|
||||
|
||||
FrontendHeader(type, receiver(), global, name, &miss);
|
||||
FrontendHeader(receiver(), global, name, &miss);
|
||||
// Get the value from the cell.
|
||||
Register result = StoreIC::ValueRegister();
|
||||
if (masm()->serializer_enabled()) {
|
||||
__ mov(eax, Immediate(cell));
|
||||
__ mov(eax, FieldOperand(eax, PropertyCell::kValueOffset));
|
||||
__ mov(result, Immediate(cell));
|
||||
__ mov(result, FieldOperand(result, PropertyCell::kValueOffset));
|
||||
} else {
|
||||
__ mov(eax, Operand::ForCell(cell));
|
||||
__ mov(result, Operand::ForCell(cell));
|
||||
}
|
||||
|
||||
// Check for deleted property if property can actually be deleted.
|
||||
if (!is_dont_delete) {
|
||||
__ cmp(eax, factory()->the_hole_value());
|
||||
__ cmp(result, factory()->the_hole_value());
|
||||
__ j(equal, &miss);
|
||||
} else if (FLAG_debug_code) {
|
||||
__ cmp(eax, factory()->the_hole_value());
|
||||
__ cmp(result, factory()->the_hole_value());
|
||||
__ Check(not_equal, kDontDeleteCellsCannotContainTheHole);
|
||||
}
|
||||
|
||||
|
33
src/ic.cc
33
src/ic.cc
@ -942,7 +942,7 @@ Handle<Code> LoadIC::CompileHandler(LookupResult* lookup, Handle<Object> object,
|
||||
Handle<HeapType> type = receiver_type();
|
||||
Handle<JSObject> holder(lookup->holder());
|
||||
bool receiver_is_holder = object.is_identical_to(holder);
|
||||
NamedLoadHandlerCompiler compiler(isolate(), cache_holder);
|
||||
NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), cache_holder);
|
||||
|
||||
switch (lookup->type()) {
|
||||
case FIELD: {
|
||||
@ -950,12 +950,12 @@ Handle<Code> LoadIC::CompileHandler(LookupResult* lookup, Handle<Object> object,
|
||||
if (receiver_is_holder) {
|
||||
return SimpleFieldLoad(field);
|
||||
}
|
||||
return compiler.CompileLoadField(
|
||||
type, holder, name, field, lookup->representation());
|
||||
return compiler.CompileLoadField(holder, name, field,
|
||||
lookup->representation());
|
||||
}
|
||||
case CONSTANT: {
|
||||
Handle<Object> constant(lookup->GetConstant(), isolate());
|
||||
return compiler.CompileLoadConstant(type, holder, name, constant);
|
||||
return compiler.CompileLoadConstant(holder, name, constant);
|
||||
}
|
||||
case NORMAL:
|
||||
if (kind() != Code::LOAD_IC) break;
|
||||
@ -963,8 +963,8 @@ Handle<Code> LoadIC::CompileHandler(LookupResult* lookup, Handle<Object> object,
|
||||
Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder);
|
||||
Handle<PropertyCell> cell(
|
||||
global->GetPropertyCell(lookup), isolate());
|
||||
Handle<Code> code = compiler.CompileLoadGlobal(
|
||||
type, global, cell, name, lookup->IsDontDelete());
|
||||
Handle<Code> code = compiler.CompileLoadGlobal(global, cell, name,
|
||||
lookup->IsDontDelete());
|
||||
// TODO(verwaest): Move caching of these NORMAL stubs outside as well.
|
||||
CacheHolderFlag flag;
|
||||
Handle<Map> stub_holder_map =
|
||||
@ -997,8 +997,11 @@ Handle<Code> LoadIC::CompileHandler(LookupResult* lookup, Handle<Object> object,
|
||||
Handle<ExecutableAccessorInfo> info =
|
||||
Handle<ExecutableAccessorInfo>::cast(callback);
|
||||
if (v8::ToCData<Address>(info->getter()) == 0) break;
|
||||
if (!info->IsCompatibleReceiver(*object)) break;
|
||||
return compiler.CompileLoadCallback(type, holder, name, info);
|
||||
if (!ExecutableAccessorInfo::IsCompatibleReceiverType(isolate(), info,
|
||||
type)) {
|
||||
break;
|
||||
}
|
||||
return compiler.CompileLoadCallback(holder, name, info);
|
||||
} else if (callback->IsAccessorPair()) {
|
||||
Handle<Object> getter(Handle<AccessorPair>::cast(callback)->getter(),
|
||||
isolate());
|
||||
@ -1016,10 +1019,9 @@ Handle<Code> LoadIC::CompileHandler(LookupResult* lookup, Handle<Object> object,
|
||||
CallOptimization call_optimization(function);
|
||||
if (call_optimization.is_simple_api_call() &&
|
||||
call_optimization.IsCompatibleReceiver(object, holder)) {
|
||||
return compiler.CompileLoadCallback(
|
||||
type, holder, name, call_optimization);
|
||||
return compiler.CompileLoadCallback(holder, name, call_optimization);
|
||||
}
|
||||
return compiler.CompileLoadViaGetter(type, holder, name, function);
|
||||
return compiler.CompileLoadViaGetter(holder, name, function);
|
||||
}
|
||||
// TODO(dcarney): Handle correctly.
|
||||
ASSERT(callback->IsDeclaredAccessorInfo());
|
||||
@ -1027,7 +1029,7 @@ Handle<Code> LoadIC::CompileHandler(LookupResult* lookup, Handle<Object> object,
|
||||
}
|
||||
case INTERCEPTOR:
|
||||
ASSERT(HasInterceptorGetter(*holder));
|
||||
return compiler.CompileLoadInterceptor(type, holder, name);
|
||||
return compiler.CompileLoadInterceptor(holder, name);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -1392,7 +1394,7 @@ Handle<Code> StoreIC::CompileHandler(LookupResult* lookup,
|
||||
Handle<JSObject> receiver = Handle<JSObject>::cast(object);
|
||||
|
||||
Handle<JSObject> holder(lookup->holder());
|
||||
NamedStoreHandlerCompiler compiler(isolate());
|
||||
NamedStoreHandlerCompiler compiler(isolate(), receiver_type());
|
||||
|
||||
if (lookup->IsTransition()) {
|
||||
// Explicitly pass in the receiver map since LookupForWrite may have
|
||||
@ -1438,7 +1440,10 @@ Handle<Code> StoreIC::CompileHandler(LookupResult* lookup,
|
||||
Handle<ExecutableAccessorInfo>::cast(callback);
|
||||
if (v8::ToCData<Address>(info->setter()) == 0) break;
|
||||
if (!holder->HasFastProperties()) break;
|
||||
if (!info->IsCompatibleReceiver(*receiver)) break;
|
||||
if (!ExecutableAccessorInfo::IsCompatibleReceiverType(
|
||||
isolate(), info, receiver_type())) {
|
||||
break;
|
||||
}
|
||||
return compiler.CompileStoreCallback(receiver, holder, name, info);
|
||||
} else if (callback->IsAccessorPair()) {
|
||||
Handle<Object> setter(
|
||||
|
@ -6771,9 +6771,10 @@ void AccessorInfo::set_property_attributes(PropertyAttributes attributes) {
|
||||
|
||||
|
||||
bool AccessorInfo::IsCompatibleReceiver(Object* receiver) {
|
||||
Object* function_template = expected_receiver_type();
|
||||
if (!function_template->IsFunctionTemplateInfo()) return true;
|
||||
return FunctionTemplateInfo::cast(function_template)->IsTemplateFor(receiver);
|
||||
if (!HasExpectedReceiverType()) return true;
|
||||
if (!receiver->IsJSObject()) return false;
|
||||
return FunctionTemplateInfo::cast(expected_receiver_type())
|
||||
->IsTemplateFor(JSObject::cast(receiver)->map());
|
||||
}
|
||||
|
||||
|
||||
|
@ -409,8 +409,8 @@ MaybeHandle<Object> Object::GetPropertyWithAccessor(Handle<Object> receiver,
|
||||
ASSERT(!structure->IsForeign());
|
||||
// api style callbacks.
|
||||
if (structure->IsAccessorInfo()) {
|
||||
Handle<AccessorInfo> accessor_info = Handle<AccessorInfo>::cast(structure);
|
||||
if (!accessor_info->IsCompatibleReceiver(*receiver)) {
|
||||
Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure);
|
||||
if (!info->IsCompatibleReceiver(*receiver)) {
|
||||
Handle<Object> args[2] = { name, receiver };
|
||||
Handle<Object> error =
|
||||
isolate->factory()->NewTypeError("incompatible_method_receiver",
|
||||
@ -462,6 +462,17 @@ MaybeHandle<Object> Object::GetPropertyWithAccessor(Handle<Object> receiver,
|
||||
}
|
||||
|
||||
|
||||
bool AccessorInfo::IsCompatibleReceiverType(Isolate* isolate,
|
||||
Handle<AccessorInfo> info,
|
||||
Handle<HeapType> type) {
|
||||
if (!info->HasExpectedReceiverType()) return true;
|
||||
Handle<Map> map = IC::TypeToMap(*type, isolate);
|
||||
if (!map->IsJSObjectMap()) return false;
|
||||
return FunctionTemplateInfo::cast(info->expected_receiver_type())
|
||||
->IsTemplateFor(*map);
|
||||
}
|
||||
|
||||
|
||||
MaybeHandle<Object> Object::SetPropertyWithAccessor(
|
||||
Handle<Object> receiver, Handle<Name> name, Handle<Object> value,
|
||||
Handle<JSObject> holder, Handle<Object> structure, StrictMode strict_mode) {
|
||||
@ -474,8 +485,8 @@ MaybeHandle<Object> Object::SetPropertyWithAccessor(
|
||||
// Don't call executable accessor setters with non-JSObject receivers.
|
||||
if (!receiver->IsJSObject()) return value;
|
||||
// api style callbacks
|
||||
ExecutableAccessorInfo* data = ExecutableAccessorInfo::cast(*structure);
|
||||
if (!data->IsCompatibleReceiver(*receiver)) {
|
||||
ExecutableAccessorInfo* info = ExecutableAccessorInfo::cast(*structure);
|
||||
if (!info->IsCompatibleReceiver(*receiver)) {
|
||||
Handle<Object> args[2] = { name, receiver };
|
||||
Handle<Object> error =
|
||||
isolate->factory()->NewTypeError("incompatible_method_receiver",
|
||||
@ -485,13 +496,13 @@ MaybeHandle<Object> Object::SetPropertyWithAccessor(
|
||||
}
|
||||
// TODO(rossberg): Support symbols in the API.
|
||||
if (name->IsSymbol()) return value;
|
||||
Object* call_obj = data->setter();
|
||||
Object* call_obj = info->setter();
|
||||
v8::AccessorSetterCallback call_fun =
|
||||
v8::ToCData<v8::AccessorSetterCallback>(call_obj);
|
||||
if (call_fun == NULL) return value;
|
||||
Handle<String> key = Handle<String>::cast(name);
|
||||
LOG(isolate, ApiNamedPropertyAccess("store", *holder, *name));
|
||||
PropertyCallbackArguments args(isolate, data->data(), *receiver, *holder);
|
||||
PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder);
|
||||
args.Call(call_fun,
|
||||
v8::Utils::ToLocal(key),
|
||||
v8::Utils::ToLocal(value));
|
||||
|
@ -10528,6 +10528,9 @@ class AccessorInfo: public Struct {
|
||||
inline void set_property_attributes(PropertyAttributes attributes);
|
||||
|
||||
// Checks whether the given receiver is compatible with this accessor.
|
||||
static bool IsCompatibleReceiverType(Isolate* isolate,
|
||||
Handle<AccessorInfo> info,
|
||||
Handle<HeapType> type);
|
||||
inline bool IsCompatibleReceiver(Object* receiver);
|
||||
|
||||
DECLARE_CAST(AccessorInfo)
|
||||
@ -10547,6 +10550,9 @@ class AccessorInfo: public Struct {
|
||||
static const int kSize = kExpectedReceiverTypeOffset + kPointerSize;
|
||||
|
||||
private:
|
||||
inline bool HasExpectedReceiverType() {
|
||||
return expected_receiver_type()->IsFunctionTemplateInfo();
|
||||
}
|
||||
// Bit positions in flag.
|
||||
static const int kAllCanReadBit = 0;
|
||||
static const int kAllCanWriteBit = 1;
|
||||
|
@ -203,8 +203,8 @@ Handle<Code> NamedLoadHandlerCompiler::ComputeLoadNonexistent(
|
||||
cache_name, stub_holder_map, Code::LOAD_IC, flag, Code::FAST);
|
||||
if (!handler.is_null()) return handler;
|
||||
|
||||
NamedLoadHandlerCompiler compiler(isolate, flag);
|
||||
handler = compiler.CompileLoadNonexistent(type, last, cache_name);
|
||||
NamedLoadHandlerCompiler compiler(isolate, type, flag);
|
||||
handler = compiler.CompileLoadNonexistent(last, cache_name);
|
||||
Map::UpdateCodeCache(stub_holder_map, cache_name, handler);
|
||||
return handler;
|
||||
}
|
||||
@ -497,25 +497,27 @@ void StubCache::CollectMatchingMaps(SmallMapList* types,
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(StoreCallbackProperty) {
|
||||
JSObject* receiver = JSObject::cast(args[0]);
|
||||
JSObject* holder = JSObject::cast(args[1]);
|
||||
ExecutableAccessorInfo* callback = ExecutableAccessorInfo::cast(args[2]);
|
||||
Handle<JSObject> receiver = args.at<JSObject>(0);
|
||||
Handle<JSObject> holder = args.at<JSObject>(1);
|
||||
Handle<ExecutableAccessorInfo> callback = args.at<ExecutableAccessorInfo>(2);
|
||||
Handle<Name> name = args.at<Name>(3);
|
||||
Handle<Object> value = args.at<Object>(4);
|
||||
HandleScope scope(isolate);
|
||||
|
||||
ASSERT(callback->IsCompatibleReceiver(*receiver));
|
||||
|
||||
Address setter_address = v8::ToCData<Address>(callback->setter());
|
||||
v8::AccessorSetterCallback fun =
|
||||
FUNCTION_CAST<v8::AccessorSetterCallback>(setter_address);
|
||||
ASSERT(fun != NULL);
|
||||
ASSERT(callback->IsCompatibleReceiver(receiver));
|
||||
Handle<Name> name = args.at<Name>(3);
|
||||
Handle<Object> value = args.at<Object>(4);
|
||||
HandleScope scope(isolate);
|
||||
|
||||
// TODO(rossberg): Support symbols in the API.
|
||||
if (name->IsSymbol()) return *value;
|
||||
Handle<String> str = Handle<String>::cast(name);
|
||||
|
||||
LOG(isolate, ApiNamedPropertyAccess("store", receiver, *name));
|
||||
PropertyCallbackArguments
|
||||
custom_args(isolate, callback->data(), receiver, holder);
|
||||
LOG(isolate, ApiNamedPropertyAccess("store", *receiver, *name));
|
||||
PropertyCallbackArguments custom_args(isolate, callback->data(), *receiver,
|
||||
*holder);
|
||||
custom_args.Call(fun, v8::Utils::ToLocal(str), v8::Utils::ToLocal(value));
|
||||
RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
|
||||
return *value;
|
||||
@ -746,20 +748,19 @@ Handle<Code> PropertyAccessCompiler::GetCodeWithFlags(Code::Flags flags,
|
||||
#define __ ACCESS_MASM(masm())
|
||||
|
||||
|
||||
Register NamedLoadHandlerCompiler::FrontendHeader(Handle<HeapType> type,
|
||||
Register object_reg,
|
||||
Register NamedLoadHandlerCompiler::FrontendHeader(Register object_reg,
|
||||
Handle<JSObject> holder,
|
||||
Handle<Name> name,
|
||||
Label* miss) {
|
||||
PrototypeCheckType check_type = CHECK_ALL_MAPS;
|
||||
int function_index = -1;
|
||||
if (type->Is(HeapType::String())) {
|
||||
if (type()->Is(HeapType::String())) {
|
||||
function_index = Context::STRING_FUNCTION_INDEX;
|
||||
} else if (type->Is(HeapType::Symbol())) {
|
||||
} else if (type()->Is(HeapType::Symbol())) {
|
||||
function_index = Context::SYMBOL_FUNCTION_INDEX;
|
||||
} else if (type->Is(HeapType::Number())) {
|
||||
} else if (type()->Is(HeapType::Number())) {
|
||||
function_index = Context::NUMBER_FUNCTION_INDEX;
|
||||
} else if (type->Is(HeapType::Boolean())) {
|
||||
} else if (type()->Is(HeapType::Boolean())) {
|
||||
function_index = Context::BOOLEAN_FUNCTION_INDEX;
|
||||
} else {
|
||||
check_type = SKIP_RECEIVER;
|
||||
@ -770,26 +771,24 @@ Register NamedLoadHandlerCompiler::FrontendHeader(Handle<HeapType> type,
|
||||
masm(), function_index, scratch1(), miss);
|
||||
Object* function = isolate()->native_context()->get(function_index);
|
||||
Object* prototype = JSFunction::cast(function)->instance_prototype();
|
||||
type = IC::CurrentTypeOf(handle(prototype, isolate()), isolate());
|
||||
set_type_for_object(handle(prototype, isolate()));
|
||||
object_reg = scratch1();
|
||||
}
|
||||
|
||||
// Check that the maps starting from the prototype haven't changed.
|
||||
return CheckPrototypes(
|
||||
type, object_reg, holder, scratch1(), scratch2(), scratch3(),
|
||||
name, miss, check_type);
|
||||
return CheckPrototypes(object_reg, holder, scratch1(), scratch2(), scratch3(),
|
||||
name, miss, check_type);
|
||||
}
|
||||
|
||||
|
||||
// Frontend for store uses the name register. It has to be restored before a
|
||||
// miss.
|
||||
Register NamedStoreHandlerCompiler::FrontendHeader(Handle<HeapType> type,
|
||||
Register object_reg,
|
||||
Register NamedStoreHandlerCompiler::FrontendHeader(Register object_reg,
|
||||
Handle<JSObject> holder,
|
||||
Handle<Name> name,
|
||||
Label* miss) {
|
||||
return CheckPrototypes(type, object_reg, holder, this->name(),
|
||||
scratch1(), scratch2(), name, miss, SKIP_RECEIVER);
|
||||
return CheckPrototypes(object_reg, holder, this->name(), scratch1(),
|
||||
scratch2(), name, miss, SKIP_RECEIVER);
|
||||
}
|
||||
|
||||
|
||||
@ -801,19 +800,17 @@ bool PropertyICCompiler::IncludesNumberType(TypeHandleList* types) {
|
||||
}
|
||||
|
||||
|
||||
Register PropertyHandlerCompiler::Frontend(Handle<HeapType> type,
|
||||
Register object_reg,
|
||||
Register PropertyHandlerCompiler::Frontend(Register object_reg,
|
||||
Handle<JSObject> holder,
|
||||
Handle<Name> name) {
|
||||
Label miss;
|
||||
Register reg = FrontendHeader(type, object_reg, holder, name, &miss);
|
||||
Register reg = FrontendHeader(object_reg, holder, name, &miss);
|
||||
FrontendFooter(name, &miss);
|
||||
return reg;
|
||||
}
|
||||
|
||||
|
||||
void NamedLoadHandlerCompiler::NonexistentFrontend(Handle<HeapType> type,
|
||||
Handle<JSObject> last,
|
||||
void NamedLoadHandlerCompiler::NonexistentFrontend(Handle<JSObject> last,
|
||||
Handle<Name> name) {
|
||||
Label miss;
|
||||
|
||||
@ -821,11 +818,11 @@ void NamedLoadHandlerCompiler::NonexistentFrontend(Handle<HeapType> type,
|
||||
Handle<Map> last_map;
|
||||
if (last.is_null()) {
|
||||
holder = receiver();
|
||||
last_map = IC::TypeToMap(*type, isolate());
|
||||
last_map = IC::TypeToMap(*type(), isolate());
|
||||
// If |type| has null as its prototype, |last| is Handle<JSObject>::null().
|
||||
ASSERT(last_map->prototype() == isolate()->heap()->null_value());
|
||||
} else {
|
||||
holder = FrontendHeader(type, receiver(), last, name, &miss);
|
||||
holder = FrontendHeader(receiver(), last, name, &miss);
|
||||
last_map = handle(last->map());
|
||||
}
|
||||
|
||||
@ -846,9 +843,10 @@ void NamedLoadHandlerCompiler::NonexistentFrontend(Handle<HeapType> type,
|
||||
// If the last object in the prototype chain is a global object,
|
||||
// check that the global property cell is empty.
|
||||
if (last_map->IsJSGlobalObjectMap()) {
|
||||
Handle<JSGlobalObject> global = last.is_null()
|
||||
? Handle<JSGlobalObject>::cast(type->AsConstant()->Value())
|
||||
: Handle<JSGlobalObject>::cast(last);
|
||||
Handle<JSGlobalObject> global =
|
||||
last.is_null()
|
||||
? Handle<JSGlobalObject>::cast(type()->AsConstant()->Value())
|
||||
: Handle<JSGlobalObject>::cast(last);
|
||||
GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
|
||||
}
|
||||
|
||||
@ -857,39 +855,38 @@ void NamedLoadHandlerCompiler::NonexistentFrontend(Handle<HeapType> type,
|
||||
|
||||
|
||||
Handle<Code> NamedLoadHandlerCompiler::CompileLoadField(
|
||||
Handle<HeapType> type, Handle<JSObject> holder, Handle<Name> name,
|
||||
FieldIndex field, Representation representation) {
|
||||
Register reg = Frontend(type, receiver(), holder, name);
|
||||
Handle<JSObject> holder, Handle<Name> name, FieldIndex field,
|
||||
Representation representation) {
|
||||
Register reg = Frontend(receiver(), holder, name);
|
||||
GenerateLoadField(reg, holder, field, representation);
|
||||
return GetCode(kind(), Code::FAST, name);
|
||||
}
|
||||
|
||||
|
||||
Handle<Code> NamedLoadHandlerCompiler::CompileLoadConstant(
|
||||
Handle<HeapType> type, Handle<JSObject> holder, Handle<Name> name,
|
||||
Handle<Object> value) {
|
||||
Frontend(type, receiver(), holder, name);
|
||||
Handle<JSObject> holder, Handle<Name> name, Handle<Object> value) {
|
||||
Frontend(receiver(), holder, name);
|
||||
GenerateLoadConstant(value);
|
||||
return GetCode(kind(), Code::FAST, name);
|
||||
}
|
||||
|
||||
|
||||
Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
|
||||
Handle<HeapType> type, Handle<JSObject> holder, Handle<Name> name,
|
||||
Handle<JSObject> holder, Handle<Name> name,
|
||||
Handle<ExecutableAccessorInfo> callback) {
|
||||
Register reg = CallbackFrontend(type, receiver(), holder, name, callback);
|
||||
Register reg = CallbackFrontend(receiver(), holder, name, callback);
|
||||
GenerateLoadCallback(reg, callback);
|
||||
return GetCode(kind(), Code::FAST, name);
|
||||
}
|
||||
|
||||
|
||||
Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
|
||||
Handle<HeapType> type, Handle<JSObject> holder, Handle<Name> name,
|
||||
Handle<JSObject> holder, Handle<Name> name,
|
||||
const CallOptimization& call_optimization) {
|
||||
ASSERT(call_optimization.is_simple_api_call());
|
||||
Handle<JSFunction> callback = call_optimization.constant_function();
|
||||
CallbackFrontend(type, receiver(), holder, name, callback);
|
||||
Handle<Map>receiver_map = IC::TypeToMap(*type, isolate());
|
||||
CallbackFrontend(receiver(), holder, name, callback);
|
||||
Handle<Map> receiver_map = IC::TypeToMap(*type(), isolate());
|
||||
GenerateFastApiCall(
|
||||
masm(), call_optimization, receiver_map,
|
||||
receiver(), scratch1(), false, 0, NULL);
|
||||
@ -898,7 +895,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
|
||||
|
||||
|
||||
Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor(
|
||||
Handle<HeapType> type, Handle<JSObject> holder, Handle<Name> name) {
|
||||
Handle<JSObject> holder, Handle<Name> name) {
|
||||
// Perform a lookup after the interceptor.
|
||||
LookupResult lookup(isolate());
|
||||
holder->LookupOwnRealNamedProperty(name, &lookup);
|
||||
@ -909,10 +906,10 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor(
|
||||
}
|
||||
}
|
||||
|
||||
Register reg = Frontend(type, receiver(), holder, name);
|
||||
Register reg = Frontend(receiver(), holder, name);
|
||||
// TODO(368): Compile in the whole chain: all the interceptors in
|
||||
// prototypes and ultimate answer.
|
||||
GenerateLoadInterceptor(reg, type, holder, &lookup, name);
|
||||
GenerateLoadInterceptor(reg, holder, &lookup, name);
|
||||
return GetCode(kind(), Code::FAST, name);
|
||||
}
|
||||
|
||||
@ -929,8 +926,8 @@ void NamedLoadHandlerCompiler::GenerateLoadPostInterceptor(
|
||||
} else {
|
||||
// We found FIELD property in prototype chain of interceptor's holder.
|
||||
// Retrieve a field from field's holder.
|
||||
Register reg = Frontend(IC::CurrentTypeOf(interceptor_holder, isolate()),
|
||||
interceptor_reg, holder, name);
|
||||
set_type_for_object(interceptor_holder);
|
||||
Register reg = Frontend(interceptor_reg, holder, name);
|
||||
GenerateLoadField(
|
||||
reg, holder, field, lookup->representation());
|
||||
}
|
||||
@ -942,9 +939,8 @@ void NamedLoadHandlerCompiler::GenerateLoadPostInterceptor(
|
||||
ExecutableAccessorInfo::cast(lookup->GetCallbackObject()));
|
||||
ASSERT(callback->getter() != NULL);
|
||||
|
||||
Register reg =
|
||||
CallbackFrontend(IC::CurrentTypeOf(interceptor_holder, isolate()),
|
||||
interceptor_reg, holder, name, callback);
|
||||
set_type_for_object(interceptor_holder);
|
||||
Register reg = CallbackFrontend(interceptor_reg, holder, name, callback);
|
||||
GenerateLoadCallback(reg, callback);
|
||||
}
|
||||
}
|
||||
@ -964,10 +960,9 @@ Handle<Code> PropertyICCompiler::CompileMonomorphic(Handle<HeapType> type,
|
||||
|
||||
|
||||
Handle<Code> NamedLoadHandlerCompiler::CompileLoadViaGetter(
|
||||
Handle<HeapType> type, Handle<JSObject> holder, Handle<Name> name,
|
||||
Handle<JSFunction> getter) {
|
||||
Frontend(type, receiver(), holder, name);
|
||||
GenerateLoadViaGetter(masm(), type, receiver(), getter);
|
||||
Handle<JSObject> holder, Handle<Name> name, Handle<JSFunction> getter) {
|
||||
Frontend(receiver(), holder, name);
|
||||
GenerateLoadViaGetter(masm(), type(), receiver(), getter);
|
||||
return GetCode(kind(), Code::FAST, name);
|
||||
}
|
||||
|
||||
@ -995,8 +990,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreTransition(
|
||||
} while (!iter.IsAtEnd());
|
||||
}
|
||||
|
||||
Register holder_reg = FrontendHeader(IC::CurrentTypeOf(object, isolate()),
|
||||
receiver(), holder, name, &miss);
|
||||
Register holder_reg = FrontendHeader(receiver(), holder, name, &miss);
|
||||
|
||||
// If no property was found, and the holder (the last object in the
|
||||
// prototype chain) is in slow mode, we need to do a negative lookup on the
|
||||
@ -1030,8 +1024,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreField(
|
||||
Handle<JSObject> object, LookupResult* lookup, Handle<Name> name) {
|
||||
Label miss;
|
||||
|
||||
FrontendHeader(IC::CurrentTypeOf(object, isolate()), receiver(), object, name,
|
||||
&miss);
|
||||
FrontendHeader(receiver(), object, name, &miss);
|
||||
|
||||
// Generate store field code.
|
||||
GenerateStoreField(masm(),
|
||||
@ -1071,9 +1064,8 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreArrayLength(
|
||||
Handle<Code> NamedStoreHandlerCompiler::CompileStoreViaSetter(
|
||||
Handle<JSObject> object, Handle<JSObject> holder, Handle<Name> name,
|
||||
Handle<JSFunction> setter) {
|
||||
Handle<HeapType> type = IC::CurrentTypeOf(object, isolate());
|
||||
Frontend(type, receiver(), holder, name);
|
||||
GenerateStoreViaSetter(masm(), type, receiver(), setter);
|
||||
Frontend(receiver(), holder, name);
|
||||
GenerateStoreViaSetter(masm(), type(), receiver(), setter);
|
||||
|
||||
return GetCode(kind(), Code::FAST, name);
|
||||
}
|
||||
@ -1082,7 +1074,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreViaSetter(
|
||||
Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
|
||||
Handle<JSObject> object, Handle<JSObject> holder, Handle<Name> name,
|
||||
const CallOptimization& call_optimization) {
|
||||
Frontend(IC::CurrentTypeOf(object, isolate()), receiver(), holder, name);
|
||||
Frontend(receiver(), holder, name);
|
||||
Register values[] = { value() };
|
||||
GenerateFastApiCall(
|
||||
masm(), call_optimization, handle(object->map()),
|
||||
|
@ -374,22 +374,21 @@ class PropertyHandlerCompiler : public PropertyAccessCompiler {
|
||||
|
||||
protected:
|
||||
PropertyHandlerCompiler(Isolate* isolate, Code::Kind kind,
|
||||
CacheHolderFlag cache_holder)
|
||||
: PropertyAccessCompiler(isolate, kind, cache_holder) {}
|
||||
Handle<HeapType> type, CacheHolderFlag cache_holder)
|
||||
: PropertyAccessCompiler(isolate, kind, cache_holder), type_(type) {}
|
||||
|
||||
virtual ~PropertyHandlerCompiler() {}
|
||||
|
||||
virtual Register FrontendHeader(Handle<HeapType> type, Register object_reg,
|
||||
Handle<JSObject> holder, Handle<Name> name,
|
||||
Label* miss) {
|
||||
virtual Register FrontendHeader(Register object_reg, Handle<JSObject> holder,
|
||||
Handle<Name> name, Label* miss) {
|
||||
UNREACHABLE();
|
||||
return receiver();
|
||||
}
|
||||
|
||||
virtual void FrontendFooter(Handle<Name> name, Label* miss) { UNREACHABLE(); }
|
||||
|
||||
Register Frontend(Handle<HeapType> type, Register object_reg,
|
||||
Handle<JSObject> holder, Handle<Name> name);
|
||||
Register Frontend(Register object_reg, Handle<JSObject> holder,
|
||||
Handle<Name> name);
|
||||
|
||||
// TODO(verwaest): Make non-static.
|
||||
static void GenerateFastApiCall(MacroAssembler* masm,
|
||||
@ -431,67 +430,56 @@ class PropertyHandlerCompiler : public PropertyAccessCompiler {
|
||||
// register is only clobbered if it the same as the holder register. The
|
||||
// function returns a register containing the holder - either object_reg or
|
||||
// holder_reg.
|
||||
Register CheckPrototypes(Handle<HeapType> type,
|
||||
Register object_reg,
|
||||
Handle<JSObject> holder,
|
||||
Register holder_reg,
|
||||
Register scratch1,
|
||||
Register scratch2,
|
||||
Handle<Name> name,
|
||||
Label* miss,
|
||||
Register CheckPrototypes(Register object_reg, Handle<JSObject> holder,
|
||||
Register holder_reg, Register scratch1,
|
||||
Register scratch2, Handle<Name> name, Label* miss,
|
||||
PrototypeCheckType check = CHECK_ALL_MAPS);
|
||||
|
||||
Handle<Code> GetCode(Code::Kind kind, Code::StubType type, Handle<Name> name);
|
||||
void set_type_for_object(Handle<Object> object) {
|
||||
type_ = IC::CurrentTypeOf(object, isolate());
|
||||
}
|
||||
Handle<HeapType> type() const { return type_; }
|
||||
|
||||
private:
|
||||
Handle<HeapType> type_;
|
||||
};
|
||||
|
||||
|
||||
class NamedLoadHandlerCompiler : public PropertyHandlerCompiler {
|
||||
public:
|
||||
NamedLoadHandlerCompiler(Isolate* isolate,
|
||||
CacheHolderFlag cache_holder = kCacheOnReceiver)
|
||||
: PropertyHandlerCompiler(isolate, Code::LOAD_IC, cache_holder) {}
|
||||
NamedLoadHandlerCompiler(Isolate* isolate, Handle<HeapType> type,
|
||||
CacheHolderFlag cache_holder)
|
||||
: PropertyHandlerCompiler(isolate, Code::LOAD_IC, type, cache_holder) {}
|
||||
|
||||
virtual ~NamedLoadHandlerCompiler() {}
|
||||
|
||||
Handle<Code> CompileLoadField(Handle<HeapType> type,
|
||||
Handle<JSObject> holder,
|
||||
Handle<Name> name,
|
||||
Handle<Code> CompileLoadField(Handle<JSObject> holder, Handle<Name> name,
|
||||
FieldIndex index,
|
||||
Representation representation);
|
||||
|
||||
Handle<Code> CompileLoadCallback(Handle<HeapType> type,
|
||||
Handle<JSObject> holder,
|
||||
Handle<Name> name,
|
||||
Handle<Code> CompileLoadCallback(Handle<JSObject> holder, Handle<Name> name,
|
||||
Handle<ExecutableAccessorInfo> callback);
|
||||
|
||||
Handle<Code> CompileLoadCallback(Handle<HeapType> type,
|
||||
Handle<JSObject> holder,
|
||||
Handle<Name> name,
|
||||
Handle<Code> CompileLoadCallback(Handle<JSObject> holder, Handle<Name> name,
|
||||
const CallOptimization& call_optimization);
|
||||
|
||||
Handle<Code> CompileLoadConstant(Handle<HeapType> type,
|
||||
Handle<JSObject> holder,
|
||||
Handle<Name> name,
|
||||
Handle<Code> CompileLoadConstant(Handle<JSObject> holder, Handle<Name> name,
|
||||
Handle<Object> value);
|
||||
|
||||
Handle<Code> CompileLoadInterceptor(Handle<HeapType> type,
|
||||
Handle<JSObject> holder,
|
||||
Handle<Code> CompileLoadInterceptor(Handle<JSObject> holder,
|
||||
Handle<Name> name);
|
||||
|
||||
Handle<Code> CompileLoadViaGetter(Handle<HeapType> type,
|
||||
Handle<JSObject> holder,
|
||||
Handle<Name> name,
|
||||
Handle<Code> CompileLoadViaGetter(Handle<JSObject> holder, Handle<Name> name,
|
||||
Handle<JSFunction> getter);
|
||||
|
||||
Handle<Code> CompileLoadGlobal(Handle<GlobalObject> holder,
|
||||
Handle<PropertyCell> cell, Handle<Name> name,
|
||||
bool is_dont_delete);
|
||||
|
||||
static Handle<Code> ComputeLoadNonexistent(Handle<Name> name,
|
||||
Handle<HeapType> type);
|
||||
|
||||
Handle<Code> CompileLoadGlobal(Handle<HeapType> type,
|
||||
Handle<GlobalObject> holder,
|
||||
Handle<PropertyCell> cell,
|
||||
Handle<Name> name,
|
||||
bool is_dont_delete);
|
||||
|
||||
static void GenerateLoadViaGetter(MacroAssembler* masm, Handle<HeapType> type,
|
||||
Register receiver,
|
||||
Handle<JSFunction> getter);
|
||||
@ -518,20 +506,16 @@ class NamedLoadHandlerCompiler : public PropertyHandlerCompiler {
|
||||
static const int kInterceptorArgsLength = 4;
|
||||
|
||||
protected:
|
||||
virtual Register FrontendHeader(Handle<HeapType> type, Register object_reg,
|
||||
Handle<JSObject> holder, Handle<Name> name,
|
||||
Label* miss);
|
||||
virtual Register FrontendHeader(Register object_reg, Handle<JSObject> holder,
|
||||
Handle<Name> name, Label* miss);
|
||||
|
||||
virtual void FrontendFooter(Handle<Name> name, Label* miss);
|
||||
|
||||
private:
|
||||
Register CallbackFrontend(Handle<HeapType> type, Register object_reg,
|
||||
Handle<JSObject> holder, Handle<Name> name,
|
||||
Handle<Object> callback);
|
||||
Handle<Code> CompileLoadNonexistent(Handle<HeapType> type,
|
||||
Handle<JSObject> last, Handle<Name> name);
|
||||
void NonexistentFrontend(Handle<HeapType> type, Handle<JSObject> last,
|
||||
Handle<Name> name);
|
||||
Register CallbackFrontend(Register object_reg, Handle<JSObject> holder,
|
||||
Handle<Name> name, Handle<Object> callback);
|
||||
Handle<Code> CompileLoadNonexistent(Handle<JSObject> last, Handle<Name> name);
|
||||
void NonexistentFrontend(Handle<JSObject> last, Handle<Name> name);
|
||||
|
||||
void GenerateLoadField(Register reg,
|
||||
Handle<JSObject> holder,
|
||||
@ -543,7 +527,6 @@ class NamedLoadHandlerCompiler : public PropertyHandlerCompiler {
|
||||
void GenerateLoadCallback(const CallOptimization& call_optimization,
|
||||
Handle<Map> receiver_map);
|
||||
void GenerateLoadInterceptor(Register holder_reg,
|
||||
Handle<Object> object,
|
||||
Handle<JSObject> holder,
|
||||
LookupResult* lookup,
|
||||
Handle<Name> name);
|
||||
@ -570,8 +553,9 @@ class NamedLoadHandlerCompiler : public PropertyHandlerCompiler {
|
||||
|
||||
class NamedStoreHandlerCompiler : public PropertyHandlerCompiler {
|
||||
public:
|
||||
explicit NamedStoreHandlerCompiler(Isolate* isolate)
|
||||
: PropertyHandlerCompiler(isolate, Code::STORE_IC, kCacheOnReceiver) {}
|
||||
explicit NamedStoreHandlerCompiler(Isolate* isolate, Handle<HeapType> type)
|
||||
: PropertyHandlerCompiler(isolate, Code::STORE_IC, type,
|
||||
kCacheOnReceiver) {}
|
||||
|
||||
virtual ~NamedStoreHandlerCompiler() {}
|
||||
|
||||
@ -614,9 +598,8 @@ class NamedStoreHandlerCompiler : public PropertyHandlerCompiler {
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual Register FrontendHeader(Handle<HeapType> type, Register object_reg,
|
||||
Handle<JSObject> holder, Handle<Name> name,
|
||||
Label* miss);
|
||||
virtual Register FrontendHeader(Register object_reg, Handle<JSObject> holder,
|
||||
Handle<Name> name, Label* miss);
|
||||
|
||||
virtual void FrontendFooter(Handle<Name> name, Label* miss);
|
||||
void GenerateRestoreName(MacroAssembler* masm, Label* label,
|
||||
@ -672,7 +655,7 @@ class ElementHandlerCompiler : public PropertyHandlerCompiler {
|
||||
public:
|
||||
explicit ElementHandlerCompiler(Isolate* isolate)
|
||||
: PropertyHandlerCompiler(isolate, Code::KEYED_LOAD_IC,
|
||||
kCacheOnReceiver) {}
|
||||
Handle<HeapType>::null(), kCacheOnReceiver) {}
|
||||
|
||||
virtual ~ElementHandlerCompiler() {}
|
||||
|
||||
|
@ -633,10 +633,10 @@ void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm,
|
||||
|
||||
|
||||
Register PropertyHandlerCompiler::CheckPrototypes(
|
||||
Handle<HeapType> type, Register object_reg, Handle<JSObject> holder,
|
||||
Register holder_reg, Register scratch1, Register scratch2,
|
||||
Handle<Name> name, Label* miss, PrototypeCheckType check) {
|
||||
Handle<Map> receiver_map(IC::TypeToMap(*type, isolate()));
|
||||
Register object_reg, Handle<JSObject> holder, Register holder_reg,
|
||||
Register scratch1, Register scratch2, Handle<Name> name, Label* miss,
|
||||
PrototypeCheckType check) {
|
||||
Handle<Map> receiver_map(IC::TypeToMap(*type(), isolate()));
|
||||
|
||||
// Make sure there's no overlap between holder and object registers.
|
||||
ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
|
||||
@ -650,8 +650,8 @@ Register PropertyHandlerCompiler::CheckPrototypes(
|
||||
int depth = 0;
|
||||
|
||||
Handle<JSObject> current = Handle<JSObject>::null();
|
||||
if (type->IsConstant()) {
|
||||
current = Handle<JSObject>::cast(type->AsConstant()->Value());
|
||||
if (type()->IsConstant()) {
|
||||
current = Handle<JSObject>::cast(type()->AsConstant()->Value());
|
||||
}
|
||||
Handle<JSObject> prototype = Handle<JSObject>::null();
|
||||
Handle<Map> current_map = receiver_map;
|
||||
@ -765,14 +765,13 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
|
||||
}
|
||||
|
||||
|
||||
Register NamedLoadHandlerCompiler::CallbackFrontend(Handle<HeapType> type,
|
||||
Register object_reg,
|
||||
Register NamedLoadHandlerCompiler::CallbackFrontend(Register object_reg,
|
||||
Handle<JSObject> holder,
|
||||
Handle<Name> name,
|
||||
Handle<Object> callback) {
|
||||
Label miss;
|
||||
|
||||
Register reg = FrontendHeader(type, object_reg, holder, name, &miss);
|
||||
Register reg = FrontendHeader(object_reg, holder, name, &miss);
|
||||
|
||||
if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
|
||||
ASSERT(!reg.is(scratch2()));
|
||||
@ -875,9 +874,8 @@ void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
|
||||
|
||||
|
||||
void NamedLoadHandlerCompiler::GenerateLoadInterceptor(
|
||||
Register holder_reg, Handle<Object> object,
|
||||
Handle<JSObject> interceptor_holder, LookupResult* lookup,
|
||||
Handle<Name> name) {
|
||||
Register holder_reg, Handle<JSObject> interceptor_holder,
|
||||
LookupResult* lookup, Handle<Name> name) {
|
||||
ASSERT(interceptor_holder->HasNamedInterceptor());
|
||||
ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
|
||||
|
||||
@ -890,10 +888,12 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(
|
||||
compile_followup_inline = true;
|
||||
} else if (lookup->type() == CALLBACKS &&
|
||||
lookup->GetCallbackObject()->IsExecutableAccessorInfo()) {
|
||||
ExecutableAccessorInfo* callback =
|
||||
ExecutableAccessorInfo::cast(lookup->GetCallbackObject());
|
||||
compile_followup_inline = callback->getter() != NULL &&
|
||||
callback->IsCompatibleReceiver(*object);
|
||||
Handle<ExecutableAccessorInfo> callback(
|
||||
ExecutableAccessorInfo::cast(lookup->GetCallbackObject()));
|
||||
compile_followup_inline =
|
||||
callback->getter() != NULL &&
|
||||
ExecutableAccessorInfo::IsCompatibleReceiverType(isolate(), callback,
|
||||
type());
|
||||
}
|
||||
}
|
||||
|
||||
@ -967,8 +967,7 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(
|
||||
Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
|
||||
Handle<JSObject> object, Handle<JSObject> holder, Handle<Name> name,
|
||||
Handle<ExecutableAccessorInfo> callback) {
|
||||
Register holder_reg =
|
||||
Frontend(IC::CurrentTypeOf(object, isolate()), receiver(), holder, name);
|
||||
Register holder_reg = Frontend(receiver(), holder, name);
|
||||
|
||||
__ PopReturnAddressTo(scratch1());
|
||||
__ Push(receiver());
|
||||
@ -1103,8 +1102,8 @@ Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic(
|
||||
|
||||
|
||||
Handle<Code> NamedLoadHandlerCompiler::CompileLoadNonexistent(
|
||||
Handle<HeapType> type, Handle<JSObject> last, Handle<Name> name) {
|
||||
NonexistentFrontend(type, last, name);
|
||||
Handle<JSObject> last, Handle<Name> name) {
|
||||
NonexistentFrontend(last, name);
|
||||
|
||||
// Return undefined if maps of the full prototype chain are still the
|
||||
// same and no global property with this name contains a value.
|
||||
@ -1192,30 +1191,27 @@ void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
|
||||
|
||||
|
||||
Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
|
||||
Handle<HeapType> type, Handle<GlobalObject> global,
|
||||
Handle<PropertyCell> cell, Handle<Name> name, bool is_dont_delete) {
|
||||
Handle<GlobalObject> global, Handle<PropertyCell> cell, Handle<Name> name,
|
||||
bool is_dont_delete) {
|
||||
Label miss;
|
||||
// TODO(verwaest): Directly store to rax. Currently we cannot do this, since
|
||||
// rax is used as receiver(), which we would otherwise clobber before a
|
||||
// potential miss.
|
||||
FrontendHeader(type, receiver(), global, name, &miss);
|
||||
FrontendHeader(receiver(), global, name, &miss);
|
||||
|
||||
// Get the value from the cell.
|
||||
__ Move(rbx, cell);
|
||||
__ movp(rbx, FieldOperand(rbx, PropertyCell::kValueOffset));
|
||||
Register result = StoreIC::ValueRegister();
|
||||
__ Move(result, cell);
|
||||
__ movp(result, FieldOperand(result, PropertyCell::kValueOffset));
|
||||
|
||||
// Check for deleted property if property can actually be deleted.
|
||||
if (!is_dont_delete) {
|
||||
__ CompareRoot(rbx, Heap::kTheHoleValueRootIndex);
|
||||
__ CompareRoot(result, Heap::kTheHoleValueRootIndex);
|
||||
__ j(equal, &miss);
|
||||
} else if (FLAG_debug_code) {
|
||||
__ CompareRoot(rbx, Heap::kTheHoleValueRootIndex);
|
||||
__ CompareRoot(result, Heap::kTheHoleValueRootIndex);
|
||||
__ Check(not_equal, kDontDeleteCellsCannotContainTheHole);
|
||||
}
|
||||
|
||||
Counters* counters = isolate()->counters();
|
||||
__ IncrementCounter(counters->named_load_global_stub(), 1);
|
||||
__ movp(rax, rbx);
|
||||
__ ret(0);
|
||||
|
||||
FrontendFooter(name, &miss);
|
||||
|
Loading…
Reference in New Issue
Block a user