Reuse the nonexistent handler frontend for transition handlers

BUG=
R=ishell@chromium.org

Review URL: https://codereview.chromium.org/437953003

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22808 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
verwaest@chromium.org 2014-08-04 10:47:10 +00:00
parent 3a476eb782
commit 838c0ab285
10 changed files with 40 additions and 224 deletions

View File

@ -411,18 +411,6 @@ void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
}
void NamedStoreHandlerCompiler::GenerateNegativeHolderLookup(
Register holder_reg, Handle<Name> name, Label* miss) {
if (holder()->IsJSGlobalObject()) {
GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(holder()),
name, scratch1(), miss);
} else if (!holder()->HasFastProperties()) {
GenerateDictionaryNegativeLookup(masm(), miss, holder_reg, name, scratch1(),
scratch2());
}
}
// Generate StoreTransition code, value is passed in r0 register.
// When leaving generated code after success, the receiver_reg and name_reg
// may be clobbered. Upon branch to miss_label, the receiver and name
@ -1127,20 +1115,6 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreInterceptor(
}
Handle<Code> NamedLoadHandlerCompiler::CompileLoadNonexistent(
Handle<Name> name) {
NonexistentFrontend(name);
// Return undefined if maps of the full prototype chain are still the
// same and no global property with this name contains a value.
__ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
__ Ret();
// Return the generated code.
return GetCode(kind(), Code::FAST, name);
}
Register* PropertyAccessCompiler::load_calling_convention() {
// receiver, name, scratch1, scratch2, scratch3, scratch4.
Register receiver = LoadIC::ReceiverRegister();

View File

@ -368,18 +368,6 @@ void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
}
void NamedStoreHandlerCompiler::GenerateNegativeHolderLookup(
Register holder_reg, Handle<Name> name, Label* miss) {
if (holder()->IsJSGlobalObject()) {
GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(holder()),
name, scratch1(), miss);
} else if (!holder()->HasFastProperties()) {
GenerateDictionaryNegativeLookup(masm(), miss, holder_reg, name, scratch1(),
scratch2());
}
}
// Generate StoreTransition code, value is passed in x0 register.
// When leaving generated code after success, the receiver_reg and storage_reg
// may be clobbered. Upon branch to miss_label, the receiver and name registers
@ -1102,20 +1090,6 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreInterceptor(
}
Handle<Code> NamedLoadHandlerCompiler::CompileLoadNonexistent(
Handle<Name> name) {
NonexistentFrontend(name);
// Return undefined if maps of the full prototype chain are still the
// same and no global property with this name contains a value.
__ LoadRoot(x0, Heap::kUndefinedValueRootIndex);
__ Ret();
// Return the generated code.
return GetCode(kind(), Code::FAST, name);
}
// TODO(all): The so-called scratch registers are significant in some cases. For
// example, PropertyAccessCompiler::keyed_store_calling_convention()[3] (x3) is
// actually

View File

@ -410,18 +410,6 @@ void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
}
void NamedStoreHandlerCompiler::GenerateNegativeHolderLookup(
Register holder_reg, Handle<Name> name, Label* miss) {
if (holder()->IsJSGlobalObject()) {
GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(holder()),
name, scratch1(), miss);
} else if (!holder()->HasFastProperties()) {
GenerateDictionaryNegativeLookup(masm(), miss, holder_reg, name, scratch1(),
scratch2());
}
}
// Receiver_reg is preserved on jumps to miss_label, but may be destroyed if
// store is successful.
void NamedStoreHandlerCompiler::GenerateStoreTransition(
@ -1151,20 +1139,6 @@ Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic(
}
Handle<Code> NamedLoadHandlerCompiler::CompileLoadNonexistent(
Handle<Name> name) {
NonexistentFrontend(name);
// Return undefined if maps of the full prototype chain are still the
// same and no global property with this name contains a value.
__ mov(eax, isolate()->factory()->undefined_value());
__ ret(0);
// Return the generated code.
return GetCode(kind(), Code::FAST, name);
}
Register* PropertyAccessCompiler::load_calling_convention() {
// receiver, name, scratch1, scratch2, scratch3, scratch4.
Register receiver = LoadIC::ReceiverRegister();

View File

@ -1434,7 +1434,8 @@ Handle<Code> StoreIC::CompileStoreHandler(LookupResult* lookup,
Handle<Map> transition(lookup->GetTransitionTarget());
PropertyDetails details = lookup->GetPropertyDetails();
if (details.type() != CALLBACKS && details.attributes() == NONE) {
if (details.type() != CALLBACKS && details.attributes() == NONE &&
holder->HasFastProperties()) {
return compiler.CompileStoreTransition(transition, name);
}
} else {

View File

@ -280,19 +280,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell(
}
void NamedStoreHandlerCompiler::GenerateNegativeHolderLookup(
MacroAssembler* masm, Handle<JSObject> holder, Register holder_reg,
Handle<Name> name, Label* miss) {
if (holder->IsJSGlobalObject()) {
GenerateCheckPropertyCell(
masm, Handle<JSGlobalObject>::cast(holder), name, scratch1(), miss);
} else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) {
GenerateDictionaryNegativeLookup(
masm, miss, holder_reg, name, scratch1(), scratch2());
}
}
// Generate StoreTransition code, value is passed in a0 register.
// After executing generated code, the receiver_reg and name_reg
// may be clobbered.
@ -1130,19 +1117,6 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreInterceptor(
}
Handle<Code> NamedLoadHandlerCompiler::CompileLoadNonexistent(
Handle<Name> name) {
NonexistentFrontend(name);
// Return undefined if maps of the full prototype chain is still the same.
__ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
__ Ret();
// Return the generated code.
return GetCode(kind(), Code::FAST, name);
}
Register* PropertyAccessCompiler::load_calling_convention() {
// receiver, name, scratch1, scratch2, scratch3, scratch4.
Register receiver = LoadIC::ReceiverRegister();

View File

@ -281,19 +281,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell(
}
void NamedStoreHandlerCompiler::GenerateNegativeHolderLookup(
MacroAssembler* masm, Handle<JSObject> holder, Register holder_reg,
Handle<Name> name, Label* miss) {
if (holder->IsJSGlobalObject()) {
GenerateCheckPropertyCell(
masm, Handle<JSGlobalObject>::cast(holder), name, scratch1(), miss);
} else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) {
GenerateDictionaryNegativeLookup(
masm, miss, holder_reg, name, scratch1(), scratch2());
}
}
// Generate StoreTransition code, value is passed in a0 register.
// After executing generated code, the receiver_reg and name_reg
// may be clobbered.
@ -1131,19 +1118,6 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreInterceptor(
}
Handle<Code> NamedLoadHandlerCompiler::CompileLoadNonexistent(
Handle<Name> name) {
NonexistentFrontend(name);
// Return undefined if maps of the full prototype chain is still the same.
__ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
__ Ret();
// Return the generated code.
return GetCode(kind(), Code::FAST, name);
}
Register* PropertyAccessCompiler::load_calling_convention() {
// receiver, name, scratch1, scratch2, scratch3, scratch4.
Register receiver = LoadIC::ReceiverRegister();

View File

@ -803,9 +803,10 @@ Register PropertyHandlerCompiler::Frontend(Register object_reg,
}
void NamedLoadHandlerCompiler::NonexistentFrontend(Handle<Name> name) {
Label miss;
void PropertyHandlerCompiler::NonexistentFrontendHeader(Handle<Name> name,
Label* miss,
Register scratch1,
Register scratch2) {
Register holder_reg;
Handle<Map> last_map;
if (holder().is_null()) {
@ -815,33 +816,29 @@ void NamedLoadHandlerCompiler::NonexistentFrontend(Handle<Name> name) {
// Handle<JSObject>::null().
ASSERT(last_map->prototype() == isolate()->heap()->null_value());
} else {
holder_reg = FrontendHeader(receiver(), name, &miss);
holder_reg = FrontendHeader(receiver(), name, miss);
last_map = handle(holder()->map());
}
if (last_map->is_dictionary_map() && !last_map->IsJSGlobalObjectMap()) {
if (!name->IsUniqueName()) {
ASSERT(name->IsString());
name = factory()->InternalizeString(Handle<String>::cast(name));
if (last_map->is_dictionary_map()) {
if (last_map->IsJSGlobalObjectMap()) {
Handle<JSGlobalObject> global =
holder().is_null()
? Handle<JSGlobalObject>::cast(type()->AsConstant()->Value())
: Handle<JSGlobalObject>::cast(holder());
GenerateCheckPropertyCell(masm(), global, name, scratch1, miss);
} else {
if (!name->IsUniqueName()) {
ASSERT(name->IsString());
name = factory()->InternalizeString(Handle<String>::cast(name));
}
ASSERT(holder().is_null() ||
holder()->property_dictionary()->FindEntry(name) ==
NameDictionary::kNotFound);
GenerateDictionaryNegativeLookup(masm(), miss, holder_reg, name, scratch1,
scratch2);
}
ASSERT(holder().is_null() ||
holder()->property_dictionary()->FindEntry(name) ==
NameDictionary::kNotFound);
GenerateDictionaryNegativeLookup(masm(), &miss, holder_reg, name,
scratch2(), scratch3());
}
// 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 =
holder().is_null()
? Handle<JSGlobalObject>::cast(type()->AsConstant()->Value())
: Handle<JSGlobalObject>::cast(holder());
GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
}
FrontendFooter(name, &miss);
}
@ -861,6 +858,16 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadConstant(
}
Handle<Code> NamedLoadHandlerCompiler::CompileLoadNonexistent(
Handle<Name> name) {
Label miss;
NonexistentFrontendHeader(name, &miss, scratch2(), scratch3());
GenerateLoadConstant(isolate()->factory()->undefined_value());
FrontendFooter(name, &miss);
return GetCode(kind(), Code::FAST, name);
}
Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
Handle<Name> name, Handle<ExecutableAccessorInfo> callback) {
Register reg = CallbackFrontend(receiver(), name, callback);
@ -970,21 +977,15 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreTransition(
iter.Advance();
}
if (!last.is_null()) set_holder(last);
}
Register holder_reg = FrontendHeader(receiver(), 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
// holder.
if (is_nonexistent) {
GenerateNegativeHolderLookup(holder_reg, name, &miss);
NonexistentFrontendHeader(name, &miss, scratch1(), scratch2());
} else {
FrontendHeader(receiver(), name, &miss);
ASSERT(holder()->HasFastProperties());
}
GenerateStoreTransition(transition, name, receiver(), this->name(), value(),
scratch1(), scratch2(), scratch3(), &miss, &slow);
// Handle store cache miss.
GenerateRestoreName(&miss, name);
TailCallBuiltin(masm(), MissBuiltin(kind()));

View File

@ -391,6 +391,8 @@ class PropertyHandlerCompiler : public PropertyAccessCompiler {
virtual void FrontendFooter(Handle<Name> name, Label* miss) { UNREACHABLE(); }
Register Frontend(Register object_reg, Handle<Name> name);
void NonexistentFrontendHeader(Handle<Name> name, Label* miss,
Register scratch1, Register scratch2);
// TODO(verwaest): Make non-static.
static void GenerateFastApiCall(MacroAssembler* masm,
@ -519,8 +521,6 @@ class NamedLoadHandlerCompiler : public PropertyHandlerCompiler {
Register CallbackFrontend(Register object_reg, Handle<Name> name,
Handle<Object> callback);
Handle<Code> CompileLoadNonexistent(Handle<Name> name);
void NonexistentFrontend(Handle<Name> name);
void GenerateLoadField(Register reg,
FieldIndex field,
Representation representation);
@ -589,9 +589,6 @@ class NamedStoreHandlerCompiler : public PropertyHandlerCompiler {
void GenerateRestoreName(Label* label, Handle<Name> name);
private:
void GenerateNegativeHolderLookup(Register holder_reg, Handle<Name> name,
Label* miss);
void GenerateStoreTransition(Handle<Map> transition, Handle<Name> name,
Register receiver_reg, Register name_reg,
Register value_reg, Register scratch1,

View File

@ -367,18 +367,6 @@ void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
}
void NamedStoreHandlerCompiler::GenerateNegativeHolderLookup(
Register holder_reg, Handle<Name> name, Label* miss) {
if (holder()->IsJSGlobalObject()) {
GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(holder()),
name, scratch1(), miss);
} else if (!holder()->HasFastProperties()) {
GenerateDictionaryNegativeLookup(masm(), miss, holder_reg, name, scratch1(),
scratch2());
}
}
// Receiver_reg is preserved on jumps to miss_label, but may be destroyed if
// store is successful.
void NamedStoreHandlerCompiler::GenerateStoreTransition(
@ -1081,20 +1069,6 @@ Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic(
}
Handle<Code> NamedLoadHandlerCompiler::CompileLoadNonexistent(
Handle<Name> name) {
NonexistentFrontend(name);
// Return undefined if maps of the full prototype chain are still the
// same and no global property with this name contains a value.
__ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
__ ret(0);
// Return the generated code.
return GetCode(kind(), Code::FAST, name);
}
Register* PropertyAccessCompiler::load_calling_convention() {
// receiver, name, scratch1, scratch2, scratch3, scratch4.
Register receiver = LoadIC::ReceiverRegister();

View File

@ -401,19 +401,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell(
}
void NamedStoreHandlerCompiler::GenerateNegativeHolderLookup(
MacroAssembler* masm, Handle<JSObject> holder, Register holder_reg,
Handle<Name> name, Label* miss) {
if (holder->IsJSGlobalObject()) {
GenerateCheckPropertyCell(
masm, Handle<JSGlobalObject>::cast(holder), name, scratch1(), miss);
} else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) {
GenerateDictionaryNegativeLookup(
masm, miss, holder_reg, name, scratch1(), scratch2());
}
}
// Receiver_reg is preserved on jumps to miss_label, but may be destroyed if
// store is successful.
void NamedStoreHandlerCompiler::GenerateStoreTransition(
@ -1168,20 +1155,6 @@ Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic(
}
Handle<Code> NamedLoadHandlerCompiler::CompileLoadNonexistent(
Handle<Name> name) {
NonexistentFrontend(name);
// Return undefined if maps of the full prototype chain are still the
// same and no global property with this name contains a value.
__ mov(eax, isolate()->factory()->undefined_value());
__ ret(0);
// Return the generated code.
return GetCode(kind(), Code::FAST, name);
}
Register* PropertyAccessCompiler::load_calling_convention() {
// receiver, name, scratch1, scratch2, scratch3, scratch4.
Register receiver = LoadIC::ReceiverRegister();