MIPS: Cleanup in stub-cache.cc; remove unused ArrayLength store ICs.

Port r22805 (d6b2885f)

BUG=
R=dusan.milosavljevic@imgtec.com

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22824 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
akos.palfi@imgtec.com 2014-08-04 14:30:01 +00:00
parent 7a48b84856
commit 9664aedd6f
2 changed files with 447 additions and 476 deletions

View File

@ -280,14 +280,137 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell(
}
static void PushInterceptorArguments(MacroAssembler* masm,
Register receiver,
Register holder,
Register name,
Handle<JSObject> holder_obj) {
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsInfoIndex == 1);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 2);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 3);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 4);
__ push(name);
Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
DCHECK(!masm->isolate()->heap()->InNewSpace(*interceptor));
Register scratch = name;
__ li(scratch, Operand(interceptor));
__ Push(scratch, receiver, holder);
}
static void CompileCallLoadPropertyWithInterceptor(
MacroAssembler* masm,
Register receiver,
Register holder,
Register name,
Handle<JSObject> holder_obj,
IC::UtilityId id) {
PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
__ CallExternalReference(ExternalReference(IC_Utility(id), masm->isolate()),
NamedLoadHandlerCompiler::kInterceptorArgsLength);
}
// Generate call to api function.
void PropertyHandlerCompiler::GenerateFastApiCall(
MacroAssembler* masm, const CallOptimization& optimization,
Handle<Map> receiver_map, Register receiver, Register scratch_in,
bool is_store, int argc, Register* values) {
DCHECK(!receiver.is(scratch_in));
// Preparing to push, adjust sp.
__ Subu(sp, sp, Operand((argc + 1) * kPointerSize));
__ sw(receiver, MemOperand(sp, argc * kPointerSize)); // Push receiver.
// Write the arguments to stack frame.
for (int i = 0; i < argc; i++) {
Register arg = values[argc-1-i];
DCHECK(!receiver.is(arg));
DCHECK(!scratch_in.is(arg));
__ sw(arg, MemOperand(sp, (argc-1-i) * kPointerSize)); // Push arg.
}
DCHECK(optimization.is_simple_api_call());
// Abi for CallApiFunctionStub.
Register callee = a0;
Register call_data = t0;
Register holder = a2;
Register api_function_address = a1;
// Put holder in place.
CallOptimization::HolderLookup holder_lookup;
Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType(
receiver_map,
&holder_lookup);
switch (holder_lookup) {
case CallOptimization::kHolderIsReceiver:
__ Move(holder, receiver);
break;
case CallOptimization::kHolderFound:
__ li(holder, api_holder);
break;
case CallOptimization::kHolderNotFound:
UNREACHABLE();
break;
}
Isolate* isolate = masm->isolate();
Handle<JSFunction> function = optimization.constant_function();
Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
Handle<Object> call_data_obj(api_call_info->data(), isolate);
// Put callee in place.
__ li(callee, function);
bool call_data_undefined = false;
// Put call_data in place.
if (isolate->heap()->InNewSpace(*call_data_obj)) {
__ li(call_data, api_call_info);
__ lw(call_data, FieldMemOperand(call_data, CallHandlerInfo::kDataOffset));
} else if (call_data_obj->IsUndefined()) {
call_data_undefined = true;
__ LoadRoot(call_data, Heap::kUndefinedValueRootIndex);
} else {
__ li(call_data, call_data_obj);
}
// Put api_function_address in place.
Address function_address = v8::ToCData<Address>(api_call_info->callback());
ApiFunction fun(function_address);
ExternalReference::Type type = ExternalReference::DIRECT_API_CALL;
ExternalReference ref = ExternalReference(&fun, type, masm->isolate());
__ li(api_function_address, Operand(ref));
// Jump to stub.
CallApiFunctionStub stub(isolate, is_store, call_data_undefined, argc);
__ TailCallStub(&stub);
}
void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm,
Handle<Code> code) {
__ Jump(code, RelocInfo::CODE_TARGET);
}
#undef __
#define __ ACCESS_MASM(masm())
void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
Handle<Name> name) {
if (!label->is_unused()) {
__ bind(label);
__ li(this->name(), Operand(name));
}
}
// Generate StoreTransition code, value is passed in a0 register.
// After executing generated code, the receiver_reg and name_reg
// may be clobbered.
void NamedStoreHandlerCompiler::GenerateStoreTransition(
MacroAssembler* masm, LookupResult* lookup, Handle<Map> transition,
Handle<Name> name, Register receiver_reg, Register storage_reg,
Register value_reg, Register scratch1, Register scratch2, Register scratch3,
Label* miss_label, Label* slow) {
Handle<Map> transition, Handle<Name> name, Register receiver_reg,
Register storage_reg, Register value_reg, Register scratch1,
Register scratch2, Register scratch3, Label* miss_label, Label* slow) {
// a0 : value.
Label exit;
@ -298,7 +421,7 @@ void NamedStoreHandlerCompiler::GenerateStoreTransition(
DCHECK(!representation.IsNone());
if (details.type() == CONSTANT) {
Handle<Object> constant(descriptors->GetValue(descriptor), masm->isolate());
Handle<Object> constant(descriptors->GetValue(descriptor), isolate());
__ li(scratch1, constant);
__ Branch(miss_label, ne, value_reg, Operand(scratch1));
} else if (representation.IsSmi()) {
@ -357,7 +480,7 @@ void NamedStoreHandlerCompiler::GenerateStoreTransition(
__ Push(a2, a0);
__ TailCallExternalReference(
ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
masm->isolate()),
isolate()),
3, 1);
return;
}
@ -458,15 +581,15 @@ void NamedStoreHandlerCompiler::GenerateStoreTransition(
// may be clobbered. Upon branch to miss_label, the receiver and name
// registers have their original values.
void NamedStoreHandlerCompiler::GenerateStoreField(
MacroAssembler* masm, Handle<JSObject> object, LookupResult* lookup,
Register receiver_reg, Register name_reg, Register value_reg,
Register scratch1, Register scratch2, Label* miss_label) {
Handle<JSObject> object, LookupResult* lookup, Register receiver_reg,
Register name_reg, Register value_reg, Register scratch1, Register scratch2,
Label* miss_label) {
// a0 : value
Label exit;
// Stub never generated for non-global objects that require access
// checks.
DCHECK(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
// Stub never generated for objects that require access checks.
DCHECK(!object->IsAccessCheckNeeded());
DCHECK(!object->IsJSGlobalProxy());
FieldIndex index = lookup->GetFieldIndex();
@ -582,134 +705,6 @@ void NamedStoreHandlerCompiler::GenerateStoreField(
}
void NamedStoreHandlerCompiler::GenerateRestoreName(MacroAssembler* masm,
Label* label,
Handle<Name> name) {
if (!label->is_unused()) {
__ bind(label);
__ li(this->name(), Operand(name));
}
}
static void PushInterceptorArguments(MacroAssembler* masm,
Register receiver,
Register holder,
Register name,
Handle<JSObject> holder_obj) {
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsInfoIndex == 1);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 2);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 3);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 4);
__ push(name);
Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
DCHECK(!masm->isolate()->heap()->InNewSpace(*interceptor));
Register scratch = name;
__ li(scratch, Operand(interceptor));
__ Push(scratch, receiver, holder);
}
static void CompileCallLoadPropertyWithInterceptor(
MacroAssembler* masm,
Register receiver,
Register holder,
Register name,
Handle<JSObject> holder_obj,
IC::UtilityId id) {
PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
__ CallExternalReference(ExternalReference(IC_Utility(id), masm->isolate()),
NamedLoadHandlerCompiler::kInterceptorArgsLength);
}
// Generate call to api function.
void PropertyHandlerCompiler::GenerateFastApiCall(
MacroAssembler* masm, const CallOptimization& optimization,
Handle<Map> receiver_map, Register receiver, Register scratch_in,
bool is_store, int argc, Register* values) {
DCHECK(!receiver.is(scratch_in));
// Preparing to push, adjust sp.
__ Subu(sp, sp, Operand((argc + 1) * kPointerSize));
__ sw(receiver, MemOperand(sp, argc * kPointerSize)); // Push receiver.
// Write the arguments to stack frame.
for (int i = 0; i < argc; i++) {
Register arg = values[argc-1-i];
DCHECK(!receiver.is(arg));
DCHECK(!scratch_in.is(arg));
__ sw(arg, MemOperand(sp, (argc-1-i) * kPointerSize)); // Push arg.
}
DCHECK(optimization.is_simple_api_call());
// Abi for CallApiFunctionStub.
Register callee = a0;
Register call_data = t0;
Register holder = a2;
Register api_function_address = a1;
// Put holder in place.
CallOptimization::HolderLookup holder_lookup;
Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType(
receiver_map,
&holder_lookup);
switch (holder_lookup) {
case CallOptimization::kHolderIsReceiver:
__ Move(holder, receiver);
break;
case CallOptimization::kHolderFound:
__ li(holder, api_holder);
break;
case CallOptimization::kHolderNotFound:
UNREACHABLE();
break;
}
Isolate* isolate = masm->isolate();
Handle<JSFunction> function = optimization.constant_function();
Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
Handle<Object> call_data_obj(api_call_info->data(), isolate);
// Put callee in place.
__ li(callee, function);
bool call_data_undefined = false;
// Put call_data in place.
if (isolate->heap()->InNewSpace(*call_data_obj)) {
__ li(call_data, api_call_info);
__ lw(call_data, FieldMemOperand(call_data, CallHandlerInfo::kDataOffset));
} else if (call_data_obj->IsUndefined()) {
call_data_undefined = true;
__ LoadRoot(call_data, Heap::kUndefinedValueRootIndex);
} else {
__ li(call_data, call_data_obj);
}
// Put api_function_address in place.
Address function_address = v8::ToCData<Address>(api_call_info->callback());
ApiFunction fun(function_address);
ExternalReference::Type type = ExternalReference::DIRECT_API_CALL;
ExternalReference ref =
ExternalReference(&fun,
type,
masm->isolate());
__ li(api_function_address, Operand(ref));
// Jump to stub.
CallApiFunctionStub stub(isolate, is_store, call_data_undefined, argc);
__ TailCallStub(&stub);
}
void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm,
Handle<Code> code) {
__ Jump(code, RelocInfo::CODE_TARGET);
}
#undef __
#define __ ACCESS_MASM(masm())
Register PropertyHandlerCompiler::CheckPrototypes(
Register object_reg, Register holder_reg, Register scratch1,
Register scratch2, Handle<Name> name, Label* miss,
@ -835,7 +830,7 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
if (!miss->is_unused()) {
Label success;
__ Branch(&success);
GenerateRestoreName(masm(), miss, name);
GenerateRestoreName(miss, name);
TailCallBuiltin(masm(), MissBuiltin(kind()));
__ bind(&success);
}
@ -1271,17 +1266,6 @@ Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types,
}
void NamedStoreHandlerCompiler::GenerateStoreArrayLength() {
// Prepare tail call to StoreIC_ArrayLength.
__ Push(receiver(), value());
ExternalReference ref =
ExternalReference(IC_Utility(IC::kStoreIC_ArrayLength),
masm()->isolate());
__ TailCallExternalReference(ref, 2, 1);
}
Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic(
MapHandleList* receiver_maps, CodeHandleList* handler_stubs,
MapHandleList* transitioned_maps) {

View File

@ -281,318 +281,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell(
}
// Generate StoreTransition code, value is passed in a0 register.
// After executing generated code, the receiver_reg and name_reg
// may be clobbered.
void NamedStoreHandlerCompiler::GenerateStoreTransition(
MacroAssembler* masm, LookupResult* lookup, Handle<Map> transition,
Handle<Name> name, Register receiver_reg, Register storage_reg,
Register value_reg, Register scratch1, Register scratch2, Register scratch3,
Label* miss_label, Label* slow) {
// a0 : value.
Label exit;
int descriptor = transition->LastAdded();
DescriptorArray* descriptors = transition->instance_descriptors();
PropertyDetails details = descriptors->GetDetails(descriptor);
Representation representation = details.representation();
DCHECK(!representation.IsNone());
if (details.type() == CONSTANT) {
Handle<Object> constant(descriptors->GetValue(descriptor), masm->isolate());
__ li(scratch1, constant);
__ Branch(miss_label, ne, value_reg, Operand(scratch1));
} else if (representation.IsSmi()) {
__ JumpIfNotSmi(value_reg, miss_label);
} else if (representation.IsHeapObject()) {
__ JumpIfSmi(value_reg, miss_label);
HeapType* field_type = descriptors->GetFieldType(descriptor);
HeapType::Iterator<Map> it = field_type->Classes();
Handle<Map> current;
if (!it.Done()) {
__ ld(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
Label do_store;
while (true) {
// Do the CompareMap() directly within the Branch() functions.
current = it.Current();
it.Advance();
if (it.Done()) {
__ Branch(miss_label, ne, scratch1, Operand(current));
break;
}
__ Branch(&do_store, eq, scratch1, Operand(current));
}
__ bind(&do_store);
}
} else if (representation.IsDouble()) {
Label do_store, heap_number;
__ LoadRoot(scratch3, Heap::kMutableHeapNumberMapRootIndex);
__ AllocateHeapNumber(storage_reg, scratch1, scratch2, scratch3, slow,
TAG_RESULT, MUTABLE);
__ JumpIfNotSmi(value_reg, &heap_number);
__ SmiUntag(scratch1, value_reg);
__ mtc1(scratch1, f6);
__ cvt_d_w(f4, f6);
__ jmp(&do_store);
__ bind(&heap_number);
__ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex,
miss_label, DONT_DO_SMI_CHECK);
__ ldc1(f4, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
__ bind(&do_store);
__ sdc1(f4, FieldMemOperand(storage_reg, HeapNumber::kValueOffset));
}
// Stub never generated for objects that require access checks.
DCHECK(!transition->is_access_check_needed());
// Perform map transition for the receiver if necessary.
if (details.type() == FIELD &&
Map::cast(transition->GetBackPointer())->unused_property_fields() == 0) {
// The properties must be extended before we can store the value.
// We jump to a runtime call that extends the properties array.
__ push(receiver_reg);
__ li(a2, Operand(transition));
__ Push(a2, a0);
__ TailCallExternalReference(
ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
masm->isolate()),
3, 1);
return;
}
// Update the map of the object.
__ li(scratch1, Operand(transition));
__ sd(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
// Update the write barrier for the map field.
__ RecordWriteField(receiver_reg,
HeapObject::kMapOffset,
scratch1,
scratch2,
kRAHasNotBeenSaved,
kDontSaveFPRegs,
OMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
if (details.type() == CONSTANT) {
DCHECK(value_reg.is(a0));
__ Ret(USE_DELAY_SLOT);
__ mov(v0, a0);
return;
}
int index = transition->instance_descriptors()->GetFieldIndex(
transition->LastAdded());
// Adjust for the number of properties stored in the object. Even in the
// face of a transition we can use the old map here because the size of the
// object and the number of in-object properties is not going to change.
index -= transition->inobject_properties();
// TODO(verwaest): Share this code as a code stub.
SmiCheck smi_check = representation.IsTagged()
? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
if (index < 0) {
// Set the property straight into the object.
int offset = transition->instance_size() + (index * kPointerSize);
if (representation.IsDouble()) {
__ sd(storage_reg, FieldMemOperand(receiver_reg, offset));
} else {
__ sd(value_reg, FieldMemOperand(receiver_reg, offset));
}
if (!representation.IsSmi()) {
// Update the write barrier for the array address.
if (!representation.IsDouble()) {
__ mov(storage_reg, value_reg);
}
__ RecordWriteField(receiver_reg,
offset,
storage_reg,
scratch1,
kRAHasNotBeenSaved,
kDontSaveFPRegs,
EMIT_REMEMBERED_SET,
smi_check);
}
} else {
// Write to the properties array.
int offset = index * kPointerSize + FixedArray::kHeaderSize;
// Get the properties array
__ ld(scratch1,
FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
if (representation.IsDouble()) {
__ sd(storage_reg, FieldMemOperand(scratch1, offset));
} else {
__ sd(value_reg, FieldMemOperand(scratch1, offset));
}
if (!representation.IsSmi()) {
// Update the write barrier for the array address.
if (!representation.IsDouble()) {
__ mov(storage_reg, value_reg);
}
__ RecordWriteField(scratch1,
offset,
storage_reg,
receiver_reg,
kRAHasNotBeenSaved,
kDontSaveFPRegs,
EMIT_REMEMBERED_SET,
smi_check);
}
}
// Return the value (register v0).
DCHECK(value_reg.is(a0));
__ bind(&exit);
__ Ret(USE_DELAY_SLOT);
__ mov(v0, a0);
}
// Generate StoreField code, value is passed in a0 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(
MacroAssembler* masm, Handle<JSObject> object, LookupResult* lookup,
Register receiver_reg, Register name_reg, Register value_reg,
Register scratch1, Register scratch2, Label* miss_label) {
// a0 : value
Label exit;
// Stub never generated for non-global objects that require access
// checks.
DCHECK(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
FieldIndex index = lookup->GetFieldIndex();
Representation representation = lookup->representation();
DCHECK(!representation.IsNone());
if (representation.IsSmi()) {
__ JumpIfNotSmi(value_reg, miss_label);
} else if (representation.IsHeapObject()) {
__ JumpIfSmi(value_reg, miss_label);
HeapType* field_type = lookup->GetFieldType();
HeapType::Iterator<Map> it = field_type->Classes();
if (!it.Done()) {
__ ld(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
Label do_store;
Handle<Map> current;
while (true) {
// Do the CompareMap() directly within the Branch() functions.
current = it.Current();
it.Advance();
if (it.Done()) {
__ Branch(miss_label, ne, scratch1, Operand(current));
break;
}
__ Branch(&do_store, eq, scratch1, Operand(current));
}
__ bind(&do_store);
}
} else if (representation.IsDouble()) {
// Load the double storage.
if (index.is_inobject()) {
__ ld(scratch1, FieldMemOperand(receiver_reg, index.offset()));
} else {
__ ld(scratch1,
FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
__ ld(scratch1, FieldMemOperand(scratch1, index.offset()));
}
// Store the value into the storage.
Label do_store, heap_number;
__ JumpIfNotSmi(value_reg, &heap_number);
__ SmiUntag(scratch2, value_reg);
__ mtc1(scratch2, f6);
__ cvt_d_w(f4, f6);
__ jmp(&do_store);
__ bind(&heap_number);
__ CheckMap(value_reg, scratch2, Heap::kHeapNumberMapRootIndex,
miss_label, DONT_DO_SMI_CHECK);
__ ldc1(f4, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
__ bind(&do_store);
__ sdc1(f4, FieldMemOperand(scratch1, HeapNumber::kValueOffset));
// Return the value (register v0).
DCHECK(value_reg.is(a0));
__ Ret(USE_DELAY_SLOT);
__ mov(v0, a0);
return;
}
// TODO(verwaest): Share this code as a code stub.
SmiCheck smi_check = representation.IsTagged()
? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
if (index.is_inobject()) {
// Set the property straight into the object.
__ sd(value_reg, FieldMemOperand(receiver_reg, index.offset()));
if (!representation.IsSmi()) {
// 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,
kRAHasNotBeenSaved,
kDontSaveFPRegs,
EMIT_REMEMBERED_SET,
smi_check);
}
} else {
// Write to the properties array.
// Get the properties array.
__ ld(scratch1,
FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
__ sd(value_reg, FieldMemOperand(scratch1, index.offset()));
if (!representation.IsSmi()) {
// 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,
kRAHasNotBeenSaved,
kDontSaveFPRegs,
EMIT_REMEMBERED_SET,
smi_check);
}
}
// Return the value (register v0).
DCHECK(value_reg.is(a0));
__ bind(&exit);
__ Ret(USE_DELAY_SLOT);
__ mov(v0, a0);
}
void NamedStoreHandlerCompiler::GenerateRestoreName(MacroAssembler* masm,
Label* label,
Handle<Name> name) {
if (!label->is_unused()) {
__ bind(label);
__ li(this->name(), Operand(name));
}
}
static void PushInterceptorArguments(MacroAssembler* masm,
Register receiver,
Register holder,
@ -711,6 +399,316 @@ void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm,
#define __ ACCESS_MASM(masm())
void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
Handle<Name> name) {
if (!label->is_unused()) {
__ bind(label);
__ li(this->name(), Operand(name));
}
}
// Generate StoreTransition code, value is passed in a0 register.
// After executing generated code, the receiver_reg and name_reg
// may be clobbered.
void NamedStoreHandlerCompiler::GenerateStoreTransition(
Handle<Map> transition, Handle<Name> name, Register receiver_reg,
Register storage_reg, Register value_reg, Register scratch1,
Register scratch2, Register scratch3, Label* miss_label, Label* slow) {
// a0 : value.
Label exit;
int descriptor = transition->LastAdded();
DescriptorArray* descriptors = transition->instance_descriptors();
PropertyDetails details = descriptors->GetDetails(descriptor);
Representation representation = details.representation();
DCHECK(!representation.IsNone());
if (details.type() == CONSTANT) {
Handle<Object> constant(descriptors->GetValue(descriptor), isolate());
__ li(scratch1, constant);
__ Branch(miss_label, ne, value_reg, Operand(scratch1));
} else if (representation.IsSmi()) {
__ JumpIfNotSmi(value_reg, miss_label);
} else if (representation.IsHeapObject()) {
__ JumpIfSmi(value_reg, miss_label);
HeapType* field_type = descriptors->GetFieldType(descriptor);
HeapType::Iterator<Map> it = field_type->Classes();
Handle<Map> current;
if (!it.Done()) {
__ ld(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
Label do_store;
while (true) {
// Do the CompareMap() directly within the Branch() functions.
current = it.Current();
it.Advance();
if (it.Done()) {
__ Branch(miss_label, ne, scratch1, Operand(current));
break;
}
__ Branch(&do_store, eq, scratch1, Operand(current));
}
__ bind(&do_store);
}
} else if (representation.IsDouble()) {
Label do_store, heap_number;
__ LoadRoot(scratch3, Heap::kMutableHeapNumberMapRootIndex);
__ AllocateHeapNumber(storage_reg, scratch1, scratch2, scratch3, slow,
TAG_RESULT, MUTABLE);
__ JumpIfNotSmi(value_reg, &heap_number);
__ SmiUntag(scratch1, value_reg);
__ mtc1(scratch1, f6);
__ cvt_d_w(f4, f6);
__ jmp(&do_store);
__ bind(&heap_number);
__ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex,
miss_label, DONT_DO_SMI_CHECK);
__ ldc1(f4, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
__ bind(&do_store);
__ sdc1(f4, FieldMemOperand(storage_reg, HeapNumber::kValueOffset));
}
// Stub never generated for objects that require access checks.
DCHECK(!transition->is_access_check_needed());
// Perform map transition for the receiver if necessary.
if (details.type() == FIELD &&
Map::cast(transition->GetBackPointer())->unused_property_fields() == 0) {
// The properties must be extended before we can store the value.
// We jump to a runtime call that extends the properties array.
__ push(receiver_reg);
__ li(a2, Operand(transition));
__ Push(a2, a0);
__ TailCallExternalReference(
ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
isolate()),
3, 1);
return;
}
// Update the map of the object.
__ li(scratch1, Operand(transition));
__ sd(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
// Update the write barrier for the map field.
__ RecordWriteField(receiver_reg,
HeapObject::kMapOffset,
scratch1,
scratch2,
kRAHasNotBeenSaved,
kDontSaveFPRegs,
OMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
if (details.type() == CONSTANT) {
DCHECK(value_reg.is(a0));
__ Ret(USE_DELAY_SLOT);
__ mov(v0, a0);
return;
}
int index = transition->instance_descriptors()->GetFieldIndex(
transition->LastAdded());
// Adjust for the number of properties stored in the object. Even in the
// face of a transition we can use the old map here because the size of the
// object and the number of in-object properties is not going to change.
index -= transition->inobject_properties();
// TODO(verwaest): Share this code as a code stub.
SmiCheck smi_check = representation.IsTagged()
? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
if (index < 0) {
// Set the property straight into the object.
int offset = transition->instance_size() + (index * kPointerSize);
if (representation.IsDouble()) {
__ sd(storage_reg, FieldMemOperand(receiver_reg, offset));
} else {
__ sd(value_reg, FieldMemOperand(receiver_reg, offset));
}
if (!representation.IsSmi()) {
// Update the write barrier for the array address.
if (!representation.IsDouble()) {
__ mov(storage_reg, value_reg);
}
__ RecordWriteField(receiver_reg,
offset,
storage_reg,
scratch1,
kRAHasNotBeenSaved,
kDontSaveFPRegs,
EMIT_REMEMBERED_SET,
smi_check);
}
} else {
// Write to the properties array.
int offset = index * kPointerSize + FixedArray::kHeaderSize;
// Get the properties array
__ ld(scratch1,
FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
if (representation.IsDouble()) {
__ sd(storage_reg, FieldMemOperand(scratch1, offset));
} else {
__ sd(value_reg, FieldMemOperand(scratch1, offset));
}
if (!representation.IsSmi()) {
// Update the write barrier for the array address.
if (!representation.IsDouble()) {
__ mov(storage_reg, value_reg);
}
__ RecordWriteField(scratch1,
offset,
storage_reg,
receiver_reg,
kRAHasNotBeenSaved,
kDontSaveFPRegs,
EMIT_REMEMBERED_SET,
smi_check);
}
}
// Return the value (register v0).
DCHECK(value_reg.is(a0));
__ bind(&exit);
__ Ret(USE_DELAY_SLOT);
__ mov(v0, a0);
}
// Generate StoreField code, value is passed in a0 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) {
// a0 : value
Label exit;
// Stub never generated for objects that require access checks.
DCHECK(!object->IsAccessCheckNeeded());
DCHECK(!object->IsJSGlobalProxy());
FieldIndex index = lookup->GetFieldIndex();
Representation representation = lookup->representation();
DCHECK(!representation.IsNone());
if (representation.IsSmi()) {
__ JumpIfNotSmi(value_reg, miss_label);
} else if (representation.IsHeapObject()) {
__ JumpIfSmi(value_reg, miss_label);
HeapType* field_type = lookup->GetFieldType();
HeapType::Iterator<Map> it = field_type->Classes();
if (!it.Done()) {
__ ld(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
Label do_store;
Handle<Map> current;
while (true) {
// Do the CompareMap() directly within the Branch() functions.
current = it.Current();
it.Advance();
if (it.Done()) {
__ Branch(miss_label, ne, scratch1, Operand(current));
break;
}
__ Branch(&do_store, eq, scratch1, Operand(current));
}
__ bind(&do_store);
}
} else if (representation.IsDouble()) {
// Load the double storage.
if (index.is_inobject()) {
__ ld(scratch1, FieldMemOperand(receiver_reg, index.offset()));
} else {
__ ld(scratch1,
FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
__ ld(scratch1, FieldMemOperand(scratch1, index.offset()));
}
// Store the value into the storage.
Label do_store, heap_number;
__ JumpIfNotSmi(value_reg, &heap_number);
__ SmiUntag(scratch2, value_reg);
__ mtc1(scratch2, f6);
__ cvt_d_w(f4, f6);
__ jmp(&do_store);
__ bind(&heap_number);
__ CheckMap(value_reg, scratch2, Heap::kHeapNumberMapRootIndex,
miss_label, DONT_DO_SMI_CHECK);
__ ldc1(f4, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
__ bind(&do_store);
__ sdc1(f4, FieldMemOperand(scratch1, HeapNumber::kValueOffset));
// Return the value (register v0).
DCHECK(value_reg.is(a0));
__ Ret(USE_DELAY_SLOT);
__ mov(v0, a0);
return;
}
// TODO(verwaest): Share this code as a code stub.
SmiCheck smi_check = representation.IsTagged()
? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
if (index.is_inobject()) {
// Set the property straight into the object.
__ sd(value_reg, FieldMemOperand(receiver_reg, index.offset()));
if (!representation.IsSmi()) {
// 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,
kRAHasNotBeenSaved,
kDontSaveFPRegs,
EMIT_REMEMBERED_SET,
smi_check);
}
} else {
// Write to the properties array.
// Get the properties array.
__ ld(scratch1,
FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
__ sd(value_reg, FieldMemOperand(scratch1, index.offset()));
if (!representation.IsSmi()) {
// 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,
kRAHasNotBeenSaved,
kDontSaveFPRegs,
EMIT_REMEMBERED_SET,
smi_check);
}
}
// Return the value (register v0).
DCHECK(value_reg.is(a0));
__ bind(&exit);
__ Ret(USE_DELAY_SLOT);
__ mov(v0, a0);
}
Register PropertyHandlerCompiler::CheckPrototypes(
Register object_reg, Register holder_reg, Register scratch1,
Register scratch2, Handle<Name> name, Label* miss,
@ -836,7 +834,7 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
if (!miss->is_unused()) {
Label success;
__ Branch(&success);
GenerateRestoreName(masm(), miss, name);
GenerateRestoreName(miss, name);
TailCallBuiltin(masm(), MissBuiltin(kind()));
__ bind(&success);
}
@ -1272,17 +1270,6 @@ Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types,
}
void NamedStoreHandlerCompiler::GenerateStoreArrayLength() {
// Prepare tail call to StoreIC_ArrayLength.
__ Push(receiver(), value());
ExternalReference ref =
ExternalReference(IC_Utility(IC::kStoreIC_ArrayLength),
masm()->isolate());
__ TailCallExternalReference(ref, 2, 1);
}
Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic(
MapHandleList* receiver_maps, CodeHandleList* handler_stubs,
MapHandleList* transitioned_maps) {