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:
parent
3a476eb782
commit
838c0ab285
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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 {
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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()));
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user