Commit 0ef3978a authored by verwaest@chromium.org's avatar verwaest@chromium.org

Always use the StoreFieldStub to do the actual storing.

BUG=
R=yangguo@chromium.org

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22931 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 313939a9
......@@ -581,77 +581,28 @@ void NamedStoreHandlerCompiler::GenerateStoreTransition(
}
// Generate StoreField 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
// registers have their original values.
void NamedStoreHandlerCompiler::GenerateStoreField(
Handle<JSObject> object, LookupResult* lookup, Register receiver_reg,
Register name_reg, Register value_reg, Register scratch1, Register scratch2,
Label* miss_label) {
// r0 : value
Label exit;
// Stub never generated for objects that require access checks.
DCHECK(!object->IsAccessCheckNeeded());
DCHECK(!object->IsJSGlobalProxy());
FieldIndex index = lookup->GetFieldIndex();
void NamedStoreHandlerCompiler::GenerateStoreField(LookupResult* lookup,
Register value_reg,
Label* miss_label) {
DCHECK(lookup->representation().IsHeapObject());
__ JumpIfSmi(value_reg, miss_label);
HeapType* field_type = lookup->GetFieldType();
HeapType::Iterator<Map> it = field_type->Classes();
if (!it.Done()) {
__ ldr(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
Label do_store;
while (true) {
__ CompareMap(scratch1, it.Current(), &do_store);
it.Advance();
if (it.Done()) {
__ b(ne, miss_label);
break;
}
__ b(eq, &do_store);
HeapType::Iterator<Map> it = lookup->GetFieldType()->Classes();
__ ldr(scratch1(), FieldMemOperand(value_reg, HeapObject::kMapOffset));
Label do_store;
while (true) {
__ CompareMap(scratch1(), it.Current(), &do_store);
it.Advance();
if (it.Done()) {
__ b(ne, miss_label);
break;
}
__ bind(&do_store);
}
if (index.is_inobject()) {
// Set the property straight into the object.
__ str(value_reg, FieldMemOperand(receiver_reg, index.offset()));
// Skip updating write barrier if storing a smi.
__ JumpIfSmi(value_reg, &exit);
// Update the write barrier for the array address.
// Pass the now unused name_reg as a scratch register.
__ mov(name_reg, value_reg);
__ RecordWriteField(receiver_reg, index.offset(), name_reg, scratch1,
kLRHasNotBeenSaved, kDontSaveFPRegs,
EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
} else {
// Write to the properties array.
// Get the properties array
__ ldr(scratch1,
FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
__ str(value_reg, FieldMemOperand(scratch1, index.offset()));
// Skip updating write barrier if storing a smi.
__ JumpIfSmi(value_reg, &exit);
// Update the write barrier for the array address.
// Ok to clobber receiver_reg and name_reg, since we return.
__ mov(name_reg, value_reg);
__ RecordWriteField(scratch1, index.offset(), name_reg, receiver_reg,
kLRHasNotBeenSaved, kDontSaveFPRegs,
EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
__ b(eq, &do_store);
}
__ bind(&do_store);
// Return the value (register r0).
DCHECK(value_reg.is(r0));
__ bind(&exit);
__ Ret();
StoreFieldStub stub(isolate(), lookup->GetFieldIndex(),
lookup->representation());
GenerateTailCall(masm(), stub.GetCode());
}
......
......@@ -531,77 +531,28 @@ void NamedStoreHandlerCompiler::GenerateStoreTransition(
}
// Generate StoreField code, value is passed in x0 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 registers have
// their original values.
void NamedStoreHandlerCompiler::GenerateStoreField(
Handle<JSObject> object, LookupResult* lookup, Register receiver_reg,
Register name_reg, Register value_reg, Register scratch1, Register scratch2,
Label* miss_label) {
// x0 : value
Label exit;
// Stub never generated for objects that require access checks.
DCHECK(!object->IsAccessCheckNeeded());
DCHECK(!object->IsJSGlobalProxy());
FieldIndex index = lookup->GetFieldIndex();
void NamedStoreHandlerCompiler::GenerateStoreField(LookupResult* lookup,
Register value_reg,
Label* miss_label) {
DCHECK(lookup->representation().IsHeapObject());
__ JumpIfSmi(value_reg, miss_label);
HeapType* field_type = lookup->GetFieldType();
HeapType::Iterator<Map> it = field_type->Classes();
if (!it.Done()) {
__ Ldr(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
Label do_store;
while (true) {
__ CompareMap(scratch1, it.Current());
it.Advance();
if (it.Done()) {
__ B(ne, miss_label);
break;
}
__ B(eq, &do_store);
HeapType::Iterator<Map> it = lookup->GetFieldType()->Classes();
__ Ldr(scratch1(), FieldMemOperand(value_reg, HeapObject::kMapOffset));
Label do_store;
while (true) {
__ CompareMap(scratch1(), it.Current());
it.Advance();
if (it.Done()) {
__ B(ne, miss_label);
break;
}
__ Bind(&do_store);
__ B(eq, &do_store);
}
__ Bind(&do_store);
if (index.is_inobject()) {
// Set the property straight into the object.
__ Str(value_reg, FieldMemOperand(receiver_reg, index.offset()));
// Skip updating write barrier if storing a smi.
__ JumpIfSmi(value_reg, &exit);
// Update the write barrier for the array address.
// Pass the now unused name_reg as a scratch register.
__ Mov(name_reg, value_reg);
__ RecordWriteField(receiver_reg, index.offset(), name_reg, scratch1,
kLRHasNotBeenSaved, kDontSaveFPRegs,
EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
} else {
// Write to the properties array.
// Get the properties array
__ Ldr(scratch1,
FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
__ Str(value_reg, FieldMemOperand(scratch1, index.offset()));
// Skip updating write barrier if storing a smi.
__ JumpIfSmi(value_reg, &exit);
// Update the write barrier for the array address.
// Ok to clobber receiver_reg and name_reg, since we return.
__ Mov(name_reg, value_reg);
__ RecordWriteField(scratch1, index.offset(), name_reg, receiver_reg,
kLRHasNotBeenSaved, kDontSaveFPRegs,
EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
}
__ Bind(&exit);
// Return the value (register x0).
DCHECK(value_reg.is(x0));
__ Ret();
StoreFieldStub stub(isolate(), lookup->GetFieldIndex(),
lookup->representation());
GenerateTailCall(masm(), stub.GetCode());
}
......
......@@ -937,6 +937,14 @@ void KeyedLoadGenericStub::InstallDescriptors(Isolate* isolate) {
}
// static
void StoreFieldStub::InstallDescriptors(Isolate* isolate) {
StoreFieldStub stub(isolate, FieldIndex::ForInObjectOffset(0),
Representation::None());
InstallDescriptor(isolate, &stub);
}
ArrayConstructorStub::ArrayConstructorStub(Isolate* isolate)
: PlatformCodeStub(isolate), argument_count_(ANY) {
ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
......
......@@ -990,6 +990,7 @@ class StoreFieldStub : public HandlerStub {
FieldIndex index() const { return index_; }
Representation representation() { return representation_; }
static void InstallDescriptors(Isolate* isolate);
protected:
explicit StoreFieldStub(Isolate* isolate);
......
......@@ -568,60 +568,27 @@ void NamedStoreHandlerCompiler::GenerateStoreTransition(
}
// Both name_reg and receiver_reg are preserved on jumps to miss_label,
// but may be destroyed if store is successful.
void NamedStoreHandlerCompiler::GenerateStoreField(
Handle<JSObject> object, LookupResult* lookup, Register receiver_reg,
Register name_reg, Register value_reg, Register scratch1, Register scratch2,
Label* miss_label) {
// Stub never generated for objects that require access checks.
DCHECK(!object->IsAccessCheckNeeded());
DCHECK(!object->IsJSGlobalProxy());
FieldIndex index = lookup->GetFieldIndex();
void NamedStoreHandlerCompiler::GenerateStoreField(LookupResult* lookup,
Register value_reg,
Label* miss_label) {
DCHECK(lookup->representation().IsHeapObject());
__ JumpIfSmi(value_reg, miss_label);
HeapType* field_type = lookup->GetFieldType();
HeapType::Iterator<Map> it = field_type->Classes();
if (!it.Done()) {
Label do_store;
while (true) {
__ CompareMap(value_reg, it.Current());
it.Advance();
if (it.Done()) {
__ j(not_equal, miss_label);
break;
}
__ j(equal, &do_store, Label::kNear);
HeapType::Iterator<Map> it = lookup->GetFieldType()->Classes();
Label do_store;
while (true) {
__ CompareMap(value_reg, it.Current());
it.Advance();
if (it.Done()) {
__ j(not_equal, miss_label);
break;
}
__ bind(&do_store);
__ j(equal, &do_store, Label::kNear);
}
__ bind(&do_store);
if (index.is_inobject()) {
// Set the property straight into the object.
__ mov(FieldOperand(receiver_reg, index.offset()), value_reg);
// Update the write barrier for the array address.
// Pass the value being stored in the now unused name_reg.
__ mov(name_reg, value_reg);
__ RecordWriteField(receiver_reg, index.offset(), name_reg, scratch1,
kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
} else {
// Write to the properties array.
// Get the properties array (optimistically).
__ mov(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
__ mov(FieldOperand(scratch1, index.offset()), value_reg);
// Update the write barrier for the array address.
// Pass the value being stored in the now unused name_reg.
__ mov(name_reg, value_reg);
__ RecordWriteField(scratch1, index.offset(), name_reg, receiver_reg,
kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
}
// Return the value (register eax).
DCHECK(value_reg.is(eax));
__ ret(0);
StoreFieldStub stub(isolate(), lookup->GetFieldIndex(),
lookup->representation());
GenerateTailCall(masm(), stub.GetCode());
}
......
......@@ -1473,13 +1473,21 @@ Handle<Code> StoreIC::CompileStoreHandler(LookupResult* lookup,
}
} else {
switch (lookup->type()) {
case FIELD:
if (!lookup->representation().IsHeapObject()) {
case FIELD: {
bool use_stub = true;
if (lookup->representation().IsHeapObject()) {
// Only use a generic stub if no types need to be tracked.
HeapType* field_type = lookup->GetFieldType();
HeapType::Iterator<Map> it = field_type->Classes();
use_stub = it.Done();
}
if (use_stub) {
StoreFieldStub stub(isolate(), lookup->GetFieldIndex(),
lookup->representation());
return stub.GetCode();
}
return compiler.CompileStoreField(lookup, name);
}
case NORMAL:
if (receiver->IsJSGlobalProxy() || receiver->IsGlobalObject()) {
// The stub generated for the global object picks the value directly
......
......@@ -2003,6 +2003,7 @@ bool Isolate::Init(Deserializer* des) {
StringAddStub::InstallDescriptors(this);
RegExpConstructResultStub::InstallDescriptors(this);
KeyedLoadGenericStub::InstallDescriptors(this);
StoreFieldStub::InstallDescriptors(this);
}
CallDescriptors::InitializeForIsolate(this);
......
......@@ -995,14 +995,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreTransition(
Handle<Code> NamedStoreHandlerCompiler::CompileStoreField(LookupResult* lookup,
Handle<Name> name) {
Label miss;
FrontendHeader(receiver(), name, &miss);
// Generate store field code.
GenerateStoreField(holder(), lookup, receiver(), this->name(), value(),
scratch1(), scratch2(), &miss);
// Handle store cache miss.
GenerateStoreField(lookup, value(), &miss);
__ bind(&miss);
TailCallBuiltin(masm(), MissBuiltin(kind()));
return GetCode(kind(), Code::FAST, name);
......
......@@ -589,10 +589,8 @@ class NamedStoreHandlerCompiler : public PropertyHandlerCompiler {
Register scratch2, Register scratch3,
Label* miss_label, Label* slow);
void GenerateStoreField(Handle<JSObject> object, LookupResult* lookup,
Register receiver_reg, Register name_reg,
Register value_reg, Register scratch1,
Register scratch2, Label* miss_label);
void GenerateStoreField(LookupResult* lookup, Register value_reg,
Label* miss_label);
static Builtins::Name SlowBuiltin(Code::Kind kind) {
switch (kind) {
......
......@@ -516,61 +516,27 @@ void NamedStoreHandlerCompiler::GenerateStoreTransition(
}
// Both name_reg and receiver_reg are preserved on jumps to miss_label,
// but may be destroyed if store is successful.
void NamedStoreHandlerCompiler::GenerateStoreField(
Handle<JSObject> object, LookupResult* lookup, Register receiver_reg,
Register name_reg, Register value_reg, Register scratch1, Register scratch2,
Label* miss_label) {
// Stub never generated for objects that require access checks.
DCHECK(!object->IsAccessCheckNeeded());
DCHECK(!object->IsJSGlobalProxy());
FieldIndex index = lookup->GetFieldIndex();
void NamedStoreHandlerCompiler::GenerateStoreField(LookupResult* lookup,
Register value_reg,
Label* miss_label) {
DCHECK(lookup->representation().IsHeapObject());
__ JumpIfSmi(value_reg, miss_label);
HeapType* field_type = lookup->GetFieldType();
HeapType::Iterator<Map> it = field_type->Classes();
if (!it.Done()) {
Label do_store;
while (true) {
__ CompareMap(value_reg, it.Current());
it.Advance();
if (it.Done()) {
__ j(not_equal, miss_label);
break;
}
__ j(equal, &do_store, Label::kNear);
HeapType::Iterator<Map> it = lookup->GetFieldType()->Classes();
Label do_store;
while (true) {
__ CompareMap(value_reg, it.Current());
it.Advance();
if (it.Done()) {
__ j(not_equal, miss_label);
break;
}
__ bind(&do_store);
__ j(equal, &do_store, Label::kNear);
}
__ bind(&do_store);
if (index.is_inobject()) {
// Set the property straight into the object.
__ movp(FieldOperand(receiver_reg, index.offset()), value_reg);
// Update the write barrier for the array address.
// Pass the value being stored in the now unused name_reg.
__ movp(name_reg, value_reg);
__ RecordWriteField(receiver_reg, index.offset(), name_reg, scratch1,
kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
} else {
// Write to the properties array.
// Get the properties array (optimistically).
__ movp(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
__ movp(FieldOperand(scratch1, index.offset()), value_reg);
// Update the write barrier for the array address.
// Pass the value being stored in the now unused name_reg.
__ movp(name_reg, value_reg);
__ RecordWriteField(scratch1, index.offset(), name_reg, receiver_reg,
kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
}
// Return the value (register rax).
DCHECK(value_reg.is(rax));
__ ret(0);
StoreFieldStub stub(isolate(), lookup->GetFieldIndex(),
lookup->representation());
GenerateTailCall(masm(), stub.GetCode());
}
......
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