ExtendStorageStub added, it is aimed for extending objects backing store when it runs out of space.
R=yangguo@chromium.org Review URL: https://codereview.chromium.org/587203002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24286 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
24d1ef4868
commit
171e62e589
@ -29,6 +29,9 @@ const Register StoreDescriptor::NameRegister() { return r2; }
|
||||
const Register StoreDescriptor::ValueRegister() { return r0; }
|
||||
|
||||
|
||||
const Register ExtendStorageDescriptor::MapRegister() { return r3; }
|
||||
|
||||
|
||||
const Register ElementTransitionAndStoreDescriptor::MapRegister() { return r3; }
|
||||
|
||||
|
||||
|
@ -29,6 +29,9 @@ const Register StoreDescriptor::NameRegister() { return x2; }
|
||||
const Register StoreDescriptor::ValueRegister() { return x0; }
|
||||
|
||||
|
||||
const Register ExtendStorageDescriptor::MapRegister() { return x3; }
|
||||
|
||||
|
||||
const Register ElementTransitionAndStoreDescriptor::MapRegister() { return x3; }
|
||||
|
||||
|
||||
|
@ -64,7 +64,8 @@ class CodeStubGraphBuilderBase : public HGraphBuilder {
|
||||
HLoadNamedField* BuildLoadNamedField(HValue* object,
|
||||
FieldIndex index);
|
||||
void BuildStoreNamedField(HValue* object, HValue* value, FieldIndex index,
|
||||
Representation representation);
|
||||
Representation representation,
|
||||
bool transition_to_field);
|
||||
|
||||
enum ArgumentClass {
|
||||
NONE,
|
||||
@ -721,7 +722,7 @@ Handle<Code> KeyedLoadSloppyArgumentsStub::GenerateCode() {
|
||||
|
||||
void CodeStubGraphBuilderBase::BuildStoreNamedField(
|
||||
HValue* object, HValue* value, FieldIndex index,
|
||||
Representation representation) {
|
||||
Representation representation, bool transition_to_field) {
|
||||
DCHECK(!index.is_double() || representation.IsDouble());
|
||||
int offset = index.offset();
|
||||
HObjectAccess access =
|
||||
@ -730,12 +731,31 @@ void CodeStubGraphBuilderBase::BuildStoreNamedField(
|
||||
: HObjectAccess::ForBackingStoreOffset(offset, representation);
|
||||
|
||||
if (representation.IsDouble()) {
|
||||
// Load the heap number.
|
||||
object = Add<HLoadNamedField>(
|
||||
object, static_cast<HValue*>(NULL),
|
||||
access.WithRepresentation(Representation::Tagged()));
|
||||
// Store the double value into it.
|
||||
access = HObjectAccess::ForHeapNumberValue();
|
||||
HObjectAccess heap_number_access =
|
||||
access.WithRepresentation(Representation::Tagged());
|
||||
if (transition_to_field) {
|
||||
// The store requires a mutable HeapNumber to be allocated.
|
||||
NoObservableSideEffectsScope no_side_effects(this);
|
||||
HInstruction* heap_number_size = Add<HConstant>(HeapNumber::kSize);
|
||||
|
||||
// TODO(hpayer): Allocation site pretenuring support.
|
||||
HInstruction* heap_number =
|
||||
Add<HAllocate>(heap_number_size, HType::HeapObject(), NOT_TENURED,
|
||||
MUTABLE_HEAP_NUMBER_TYPE);
|
||||
AddStoreMapConstant(heap_number,
|
||||
isolate()->factory()->mutable_heap_number_map());
|
||||
Add<HStoreNamedField>(heap_number, HObjectAccess::ForHeapNumberValue(),
|
||||
value);
|
||||
// Store the new mutable heap number into the object.
|
||||
access = heap_number_access;
|
||||
value = heap_number;
|
||||
} else {
|
||||
// Load the heap number.
|
||||
object = Add<HLoadNamedField>(object, static_cast<HValue*>(NULL),
|
||||
heap_number_access);
|
||||
// Store the double value into it.
|
||||
access = HObjectAccess::ForHeapNumberValue();
|
||||
}
|
||||
} else if (representation.IsHeapObject()) {
|
||||
BuildCheckHeapObject(value);
|
||||
}
|
||||
@ -747,7 +767,7 @@ void CodeStubGraphBuilderBase::BuildStoreNamedField(
|
||||
template <>
|
||||
HValue* CodeStubGraphBuilder<StoreFieldStub>::BuildCodeStub() {
|
||||
BuildStoreNamedField(GetParameter(0), GetParameter(2), casted_stub()->index(),
|
||||
casted_stub()->representation());
|
||||
casted_stub()->representation(), false);
|
||||
return GetParameter(2);
|
||||
}
|
||||
|
||||
@ -755,6 +775,47 @@ HValue* CodeStubGraphBuilder<StoreFieldStub>::BuildCodeStub() {
|
||||
Handle<Code> StoreFieldStub::GenerateCode() { return DoGenerateCode(this); }
|
||||
|
||||
|
||||
template <>
|
||||
HValue* CodeStubGraphBuilder<ExtendStorageStub>::BuildCodeStub() {
|
||||
HValue* object = GetParameter(ExtendStorageDescriptor::kReceiverIndex);
|
||||
HValue* properties =
|
||||
Add<HLoadNamedField>(object, static_cast<HValue*>(NULL),
|
||||
HObjectAccess::ForPropertiesPointer());
|
||||
HValue* length = AddLoadFixedArrayLength(properties);
|
||||
HValue* delta = Add<HConstant>(static_cast<int32_t>(JSObject::kFieldsAdded));
|
||||
HValue* new_capacity = AddUncasted<HAdd>(length, delta);
|
||||
|
||||
// Grow properties array.
|
||||
ElementsKind kind = FAST_ELEMENTS;
|
||||
Add<HBoundsCheck>(new_capacity,
|
||||
Add<HConstant>((Page::kMaxRegularHeapObjectSize -
|
||||
FixedArray::kHeaderSize) >>
|
||||
ElementsKindToShiftSize(kind)));
|
||||
|
||||
// Reuse this code for properties backing store allocation.
|
||||
HValue* new_properties = BuildAllocateAndInitializeArray(kind, new_capacity);
|
||||
|
||||
BuildCopyProperties(properties, new_properties, length, new_capacity);
|
||||
|
||||
// Store the new value into the "extended" object.
|
||||
Add<HStoreNamedField>(object, HObjectAccess::ForPropertiesPointer(),
|
||||
new_properties);
|
||||
|
||||
BuildStoreNamedField(
|
||||
object, GetParameter(ExtendStorageDescriptor::kValueIndex),
|
||||
casted_stub()->index(), casted_stub()->representation(), true);
|
||||
|
||||
// And finally update the map after the new field is added.
|
||||
Add<HStoreNamedField>(object, HObjectAccess::ForMap(),
|
||||
GetParameter(ExtendStorageDescriptor::kMapIndex));
|
||||
|
||||
return GetParameter(ExtendStorageDescriptor::kValueIndex);
|
||||
}
|
||||
|
||||
|
||||
Handle<Code> ExtendStorageStub::GenerateCode() { return DoGenerateCode(this); }
|
||||
|
||||
|
||||
template <>
|
||||
HValue* CodeStubGraphBuilder<StringLengthStub>::BuildCodeStub() {
|
||||
HValue* string = BuildLoadNamedField(GetParameter(0),
|
||||
|
@ -614,6 +614,11 @@ void ElementsTransitionAndStoreStub::InitializeDescriptor(
|
||||
}
|
||||
|
||||
|
||||
CallInterfaceDescriptor ExtendStorageStub::GetCallInterfaceDescriptor() {
|
||||
return ExtendStorageDescriptor(isolate());
|
||||
}
|
||||
|
||||
|
||||
static void InitializeVectorLoadStub(Isolate* isolate,
|
||||
CodeStubDescriptor* descriptor,
|
||||
Address deoptimization_handler) {
|
||||
|
@ -80,6 +80,7 @@ namespace internal {
|
||||
V(VectorKeyedLoad) \
|
||||
V(VectorLoad) \
|
||||
/* IC Handler stubs */ \
|
||||
V(ExtendStorage) \
|
||||
V(LoadConstant) \
|
||||
V(LoadField) \
|
||||
V(KeyedLoadSloppyArguments) \
|
||||
@ -998,6 +999,44 @@ class StoreFieldStub : public HandlerStub {
|
||||
};
|
||||
|
||||
|
||||
// Extend storage is called in a store inline cache when
|
||||
// it is necessary to extend the properties array of a
|
||||
// JSObject.
|
||||
class ExtendStorageStub : public HandlerStub {
|
||||
public:
|
||||
ExtendStorageStub(Isolate* isolate, FieldIndex index,
|
||||
Representation representation)
|
||||
: HandlerStub(isolate) {
|
||||
int property_index_key = index.GetFieldAccessStubKey();
|
||||
uint8_t repr = PropertyDetails::EncodeRepresentation(representation);
|
||||
set_sub_minor_key(StoreFieldByIndexBits::encode(property_index_key) |
|
||||
RepresentationBits::encode(repr));
|
||||
}
|
||||
|
||||
FieldIndex index() const {
|
||||
int property_index_key = StoreFieldByIndexBits::decode(sub_minor_key());
|
||||
return FieldIndex::FromFieldAccessStubKey(property_index_key);
|
||||
}
|
||||
|
||||
Representation representation() {
|
||||
uint8_t repr = RepresentationBits::decode(sub_minor_key());
|
||||
return PropertyDetails::DecodeRepresentation(repr);
|
||||
}
|
||||
|
||||
virtual CallInterfaceDescriptor GetCallInterfaceDescriptor() OVERRIDE;
|
||||
|
||||
protected:
|
||||
virtual Code::Kind kind() const { return Code::STORE_IC; }
|
||||
virtual Code::StubType GetStubType() { return Code::FAST; }
|
||||
|
||||
private:
|
||||
class StoreFieldByIndexBits : public BitField<int, 0, 13> {};
|
||||
class RepresentationBits : public BitField<uint8_t, 13, 4> {};
|
||||
|
||||
DEFINE_HANDLER_CODE_STUB(ExtendStorage, HandlerStub);
|
||||
};
|
||||
|
||||
|
||||
class StoreGlobalStub : public HandlerStub {
|
||||
public:
|
||||
StoreGlobalStub(Isolate* isolate, bool is_constant, bool check_global)
|
||||
|
@ -2626,16 +2626,15 @@ void HGraphBuilder::BuildInitializeElementsHeader(HValue* elements,
|
||||
}
|
||||
|
||||
|
||||
HValue* HGraphBuilder::BuildAllocateElementsAndInitializeElementsHeader(
|
||||
ElementsKind kind,
|
||||
HValue* capacity) {
|
||||
HValue* HGraphBuilder::BuildAllocateAndInitializeArray(ElementsKind kind,
|
||||
HValue* capacity) {
|
||||
// The HForceRepresentation is to prevent possible deopt on int-smi
|
||||
// conversion after allocation but before the new object fields are set.
|
||||
capacity = AddUncasted<HForceRepresentation>(capacity, Representation::Smi());
|
||||
HValue* size_in_bytes = BuildCalculateElementsSize(kind, capacity);
|
||||
HValue* new_elements = BuildAllocateElements(kind, size_in_bytes);
|
||||
BuildInitializeElementsHeader(new_elements, kind, capacity);
|
||||
return new_elements;
|
||||
HValue* new_array = BuildAllocateElements(kind, size_in_bytes);
|
||||
BuildInitializeElementsHeader(new_array, kind, capacity);
|
||||
return new_array;
|
||||
}
|
||||
|
||||
|
||||
@ -2754,8 +2753,8 @@ HValue* HGraphBuilder::BuildGrowElementsCapacity(HValue* object,
|
||||
(Page::kMaxRegularHeapObjectSize - FixedArray::kHeaderSize) >>
|
||||
ElementsKindToShiftSize(new_kind)));
|
||||
|
||||
HValue* new_elements = BuildAllocateElementsAndInitializeElementsHeader(
|
||||
new_kind, new_capacity);
|
||||
HValue* new_elements =
|
||||
BuildAllocateAndInitializeArray(new_kind, new_capacity);
|
||||
|
||||
BuildCopyElements(elements, kind, new_elements,
|
||||
new_kind, length, new_capacity);
|
||||
@ -2789,12 +2788,6 @@ void HGraphBuilder::BuildFillElementsWithValue(HValue* elements,
|
||||
}
|
||||
}
|
||||
|
||||
// Since we're about to store a hole value, the store instruction below must
|
||||
// assume an elements kind that supports heap object values.
|
||||
if (IsFastSmiOrObjectElementsKind(elements_kind)) {
|
||||
elements_kind = FAST_HOLEY_ELEMENTS;
|
||||
}
|
||||
|
||||
if (initial_capacity >= 0) {
|
||||
for (int i = 0; i < initial_capacity; i++) {
|
||||
HInstruction* key = Add<HConstant>(i);
|
||||
@ -2832,10 +2825,40 @@ void HGraphBuilder::BuildFillElementsWithHole(HValue* elements,
|
||||
? Add<HConstant>(factory->the_hole_value())
|
||||
: Add<HConstant>(nan_double);
|
||||
|
||||
// Since we're about to store a hole value, the store instruction below must
|
||||
// assume an elements kind that supports heap object values.
|
||||
if (IsFastSmiOrObjectElementsKind(elements_kind)) {
|
||||
elements_kind = FAST_HOLEY_ELEMENTS;
|
||||
}
|
||||
|
||||
BuildFillElementsWithValue(elements, elements_kind, from, to, hole);
|
||||
}
|
||||
|
||||
|
||||
void HGraphBuilder::BuildCopyProperties(HValue* from_properties,
|
||||
HValue* to_properties, HValue* length,
|
||||
HValue* capacity) {
|
||||
ElementsKind kind = FAST_ELEMENTS;
|
||||
|
||||
BuildFillElementsWithValue(to_properties, kind, length, capacity,
|
||||
graph()->GetConstantUndefined());
|
||||
|
||||
LoopBuilder builder(this, context(), LoopBuilder::kPostDecrement);
|
||||
|
||||
HValue* key = builder.BeginBody(length, graph()->GetConstant0(), Token::GT);
|
||||
|
||||
key = AddUncasted<HSub>(key, graph()->GetConstant1());
|
||||
key->ClearFlag(HValue::kCanOverflow);
|
||||
|
||||
HValue* element =
|
||||
Add<HLoadKeyed>(from_properties, key, static_cast<HValue*>(NULL), kind);
|
||||
|
||||
Add<HStoreKeyed>(to_properties, key, element, kind);
|
||||
|
||||
builder.EndBody();
|
||||
}
|
||||
|
||||
|
||||
void HGraphBuilder::BuildCopyElements(HValue* from_elements,
|
||||
ElementsKind from_elements_kind,
|
||||
HValue* to_elements,
|
||||
|
@ -1805,8 +1805,9 @@ class HGraphBuilder {
|
||||
ElementsKind kind,
|
||||
HValue* capacity);
|
||||
|
||||
HValue* BuildAllocateElementsAndInitializeElementsHeader(ElementsKind kind,
|
||||
HValue* capacity);
|
||||
// Build allocation and header initialization code for respective successor
|
||||
// of FixedArrayBase.
|
||||
HValue* BuildAllocateAndInitializeArray(ElementsKind kind, HValue* capacity);
|
||||
|
||||
// |array| must have been allocated with enough room for
|
||||
// 1) the JSArray and 2) an AllocationMemento if mode requires it.
|
||||
@ -1838,6 +1839,9 @@ class HGraphBuilder {
|
||||
HValue* from,
|
||||
HValue* to);
|
||||
|
||||
void BuildCopyProperties(HValue* from_properties, HValue* to_properties,
|
||||
HValue* length, HValue* capacity);
|
||||
|
||||
void BuildCopyElements(HValue* from_elements,
|
||||
ElementsKind from_elements_kind,
|
||||
HValue* to_elements,
|
||||
|
@ -29,6 +29,9 @@ const Register StoreDescriptor::NameRegister() { return ecx; }
|
||||
const Register StoreDescriptor::ValueRegister() { return eax; }
|
||||
|
||||
|
||||
const Register ExtendStorageDescriptor::MapRegister() { return ebx; }
|
||||
|
||||
|
||||
const Register ElementTransitionAndStoreDescriptor::MapRegister() {
|
||||
return ebx;
|
||||
}
|
||||
|
@ -396,14 +396,13 @@ void NamedStoreHandlerCompiler::GenerateStoreTransition(
|
||||
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);
|
||||
__ mov(r2, Operand(transition));
|
||||
__ Push(r2, r0);
|
||||
__ TailCallExternalReference(
|
||||
ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
|
||||
isolate()),
|
||||
3, 1);
|
||||
__ mov(ExtendStorageDescriptor::NameRegister(), Operand(name));
|
||||
__ mov(ExtendStorageDescriptor::MapRegister(), Operand(transition));
|
||||
|
||||
ExtendStorageStub stub(isolate(),
|
||||
FieldIndex::ForDescriptor(*transition, descriptor),
|
||||
representation);
|
||||
GenerateTailCall(masm(), stub.GetCode());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -441,13 +441,13 @@ void NamedStoreHandlerCompiler::GenerateStoreTransition(
|
||||
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.
|
||||
__ Mov(scratch1, Operand(transition));
|
||||
__ Push(receiver_reg, scratch1, value_reg);
|
||||
__ TailCallExternalReference(
|
||||
ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
|
||||
isolate()),
|
||||
3, 1);
|
||||
__ Mov(ExtendStorageDescriptor::NameRegister(), Operand(name));
|
||||
__ Mov(ExtendStorageDescriptor::MapRegister(), Operand(transition));
|
||||
|
||||
ExtendStorageStub stub(isolate(),
|
||||
FieldIndex::ForDescriptor(*transition, descriptor),
|
||||
representation);
|
||||
GenerateTailCall(masm(), stub.GetCode());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -390,16 +390,13 @@ void NamedStoreHandlerCompiler::GenerateStoreTransition(
|
||||
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.
|
||||
__ pop(scratch1); // Return address.
|
||||
__ push(receiver_reg);
|
||||
__ push(Immediate(transition));
|
||||
__ push(value_reg);
|
||||
__ push(scratch1);
|
||||
__ TailCallExternalReference(
|
||||
ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
|
||||
isolate()),
|
||||
3, 1);
|
||||
__ mov(ExtendStorageDescriptor::NameRegister(), Immediate(name));
|
||||
__ mov(ExtendStorageDescriptor::MapRegister(), Immediate(transition));
|
||||
|
||||
ExtendStorageStub stub(isolate(),
|
||||
FieldIndex::ForDescriptor(*transition, descriptor),
|
||||
representation);
|
||||
GenerateTailCall(masm(), stub.GetCode());
|
||||
return;
|
||||
}
|
||||
|
||||
|
26
src/ic/ic.cc
26
src/ic/ic.cc
@ -2094,7 +2094,7 @@ RUNTIME_FUNCTION(StoreIC_Miss) {
|
||||
RUNTIME_FUNCTION(StoreIC_MissFromStubFailure) {
|
||||
TimerEventScope<TimerEventIcMiss> timer(isolate);
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 3);
|
||||
DCHECK(args.length() == 3 || args.length() == 4);
|
||||
StoreIC ic(IC::EXTRA_CALL_FRAME, isolate);
|
||||
Handle<Object> receiver = args.at<Object>(0);
|
||||
Handle<String> key = args.at<String>(1);
|
||||
@ -2106,30 +2106,6 @@ RUNTIME_FUNCTION(StoreIC_MissFromStubFailure) {
|
||||
}
|
||||
|
||||
|
||||
// Extend storage is called in a store inline cache when
|
||||
// it is necessary to extend the properties array of a
|
||||
// JSObject.
|
||||
RUNTIME_FUNCTION(SharedStoreIC_ExtendStorage) {
|
||||
TimerEventScope<TimerEventIcMiss> timer(isolate);
|
||||
HandleScope shs(isolate);
|
||||
DCHECK(args.length() == 3);
|
||||
|
||||
// Convert the parameters
|
||||
Handle<JSObject> object = args.at<JSObject>(0);
|
||||
Handle<Map> transition = args.at<Map>(1);
|
||||
Handle<Object> value = args.at<Object>(2);
|
||||
|
||||
// Check the object has run out out property space.
|
||||
DCHECK(object->HasFastProperties());
|
||||
DCHECK(object->map()->unused_property_fields() == 0);
|
||||
|
||||
JSObject::MigrateToNewProperty(object, transition, value);
|
||||
|
||||
// Return the stored value.
|
||||
return *value;
|
||||
}
|
||||
|
||||
|
||||
// Used from ic-<arch>.cc.
|
||||
RUNTIME_FUNCTION(KeyedStoreIC_Miss) {
|
||||
TimerEventScope<TimerEventIcMiss> timer(isolate);
|
||||
|
@ -21,7 +21,6 @@ namespace internal {
|
||||
ICU(CallIC_Customization_Miss) \
|
||||
ICU(StoreIC_Miss) \
|
||||
ICU(StoreIC_Slow) \
|
||||
ICU(SharedStoreIC_ExtendStorage) \
|
||||
ICU(KeyedStoreIC_Miss) \
|
||||
ICU(KeyedStoreIC_Slow) \
|
||||
/* Utilities for IC stubs. */ \
|
||||
|
@ -391,14 +391,14 @@ void NamedStoreHandlerCompiler::GenerateStoreTransition(
|
||||
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);
|
||||
__ mov(ExtendStorageDescriptor::NameRegister(), Operand(name));
|
||||
__ mov(ExtendStorageDescriptor::MapRegister(), Operand(transition));
|
||||
|
||||
|
||||
ExtendStorageStub stub(isolate(),
|
||||
FieldIndex::ForDescriptor(*transition, descriptor),
|
||||
representation);
|
||||
GenerateTailCall(masm(), stub.GetCode());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -391,14 +391,13 @@ void NamedStoreHandlerCompiler::GenerateStoreTransition(
|
||||
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);
|
||||
__ Mov(ExtendStorageDescriptor::NameRegister(), Operand(name));
|
||||
__ Mov(ExtendStorageDescriptor::MapRegister(), Operand(transition));
|
||||
|
||||
ExtendStorageStub stub(isolate(),
|
||||
FieldIndex::ForDescriptor(*transition, descriptor),
|
||||
representation);
|
||||
GenerateTailCall(masm(), stub.GetCode());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -384,16 +384,13 @@ void NamedStoreHandlerCompiler::GenerateStoreTransition(
|
||||
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.
|
||||
__ PopReturnAddressTo(scratch1);
|
||||
__ Push(receiver_reg);
|
||||
__ Push(transition);
|
||||
__ Push(value_reg);
|
||||
__ PushReturnAddressFrom(scratch1);
|
||||
__ TailCallExternalReference(
|
||||
ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
|
||||
isolate()),
|
||||
3, 1);
|
||||
__ Move(ExtendStorageDescriptor::NameRegister(), name);
|
||||
__ Move(ExtendStorageDescriptor::MapRegister(), transition);
|
||||
|
||||
ExtendStorageStub stub(isolate(),
|
||||
FieldIndex::ForDescriptor(*transition, descriptor),
|
||||
representation);
|
||||
GenerateTailCall(masm(), stub.GetCode());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -392,16 +392,13 @@ void NamedStoreHandlerCompiler::GenerateStoreTransition(
|
||||
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.
|
||||
__ pop(scratch1); // Return address.
|
||||
__ push(receiver_reg);
|
||||
__ push(Immediate(transition));
|
||||
__ push(value_reg);
|
||||
__ push(scratch1);
|
||||
__ TailCallExternalReference(
|
||||
ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
|
||||
isolate()),
|
||||
3, 1);
|
||||
__ mov(ExtendStorageDescriptor::NameRegister(), Immediate(name));
|
||||
__ mov(ExtendStorageDescriptor::MapRegister(), Immediate(transition));
|
||||
|
||||
ExtendStorageStub stub(isolate(),
|
||||
FieldIndex::ForDescriptor(*transition, descriptor),
|
||||
representation);
|
||||
GenerateTailCall(masm(), stub.GetCode());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -74,6 +74,13 @@ void StoreDescriptor::Initialize(CallInterfaceDescriptorData* data) {
|
||||
}
|
||||
|
||||
|
||||
void ExtendStorageDescriptor::Initialize(CallInterfaceDescriptorData* data) {
|
||||
Register registers[] = {ContextRegister(), ReceiverRegister(), NameRegister(),
|
||||
ValueRegister(), MapRegister()};
|
||||
data->Initialize(arraysize(registers), registers, NULL);
|
||||
}
|
||||
|
||||
|
||||
void ElementTransitionAndStoreDescriptor::Initialize(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
Register registers[] = {ContextRegister(), ValueRegister(), MapRegister(),
|
||||
|
@ -16,6 +16,7 @@ class PlatformInterfaceDescriptor;
|
||||
#define INTERFACE_DESCRIPTOR_LIST(V) \
|
||||
V(Load) \
|
||||
V(Store) \
|
||||
V(ExtendStorage) \
|
||||
V(ElementTransitionAndStore) \
|
||||
V(Instanceof) \
|
||||
V(VectorLoadICTrampoline) \
|
||||
@ -213,6 +214,22 @@ class StoreDescriptor : public CallInterfaceDescriptor {
|
||||
};
|
||||
|
||||
|
||||
class ExtendStorageDescriptor : public StoreDescriptor {
|
||||
public:
|
||||
DECLARE_DESCRIPTOR(ExtendStorageDescriptor, StoreDescriptor)
|
||||
|
||||
// Extends StoreDescriptor with Map parameter.
|
||||
enum ParameterIndices {
|
||||
kReceiverIndex,
|
||||
kNameIndex,
|
||||
kValueIndex,
|
||||
kMapIndex,
|
||||
kParameterCount
|
||||
};
|
||||
static const Register MapRegister();
|
||||
};
|
||||
|
||||
|
||||
class ElementTransitionAndStoreDescriptor : public StoreDescriptor {
|
||||
public:
|
||||
DECLARE_DESCRIPTOR(ElementTransitionAndStoreDescriptor, StoreDescriptor)
|
||||
|
@ -29,6 +29,9 @@ const Register StoreDescriptor::NameRegister() { return a2; }
|
||||
const Register StoreDescriptor::ValueRegister() { return a0; }
|
||||
|
||||
|
||||
const Register ExtendStorageDescriptor::MapRegister() { return a3; }
|
||||
|
||||
|
||||
const Register ElementTransitionAndStoreDescriptor::MapRegister() { return a3; }
|
||||
|
||||
|
||||
|
@ -29,6 +29,9 @@ const Register StoreDescriptor::NameRegister() { return a2; }
|
||||
const Register StoreDescriptor::ValueRegister() { return a0; }
|
||||
|
||||
|
||||
const Register ExtendStorageDescriptor::MapRegister() { return a3; }
|
||||
|
||||
|
||||
const Register ElementTransitionAndStoreDescriptor::MapRegister() { return a3; }
|
||||
|
||||
|
||||
|
@ -1962,7 +1962,7 @@ void JSObject::MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
|
||||
}
|
||||
|
||||
DCHECK(number_of_fields == old_number_of_fields + 1);
|
||||
// This migration is a transition from a map that has run out out property
|
||||
// This migration is a transition from a map that has run out of property
|
||||
// space. Therefore it could be done by extending the backing store.
|
||||
Handle<FixedArray> old_storage = handle(object->properties(), isolate);
|
||||
Handle<FixedArray> new_storage =
|
||||
@ -3753,15 +3753,6 @@ bool JSObject::TryMigrateInstance(Handle<JSObject> object) {
|
||||
}
|
||||
|
||||
|
||||
void JSObject::MigrateToNewProperty(Handle<JSObject> object,
|
||||
Handle<Map> map,
|
||||
Handle<Object> value) {
|
||||
JSObject::MigrateToMap(object, map);
|
||||
if (map->GetLastDescriptorDetails().type() != FIELD) return;
|
||||
object->WriteToField(map->LastAdded(), *value);
|
||||
}
|
||||
|
||||
|
||||
void JSObject::WriteToField(int descriptor, Object* value) {
|
||||
DisallowHeapAllocation no_gc;
|
||||
|
||||
|
@ -2209,10 +2209,6 @@ class JSObject: public JSReceiver {
|
||||
Handle<Name> name,
|
||||
Handle<Object> old_value);
|
||||
|
||||
static void MigrateToNewProperty(Handle<JSObject> object,
|
||||
Handle<Map> transition,
|
||||
Handle<Object> value);
|
||||
|
||||
private:
|
||||
friend class DictionaryElementsAccessor;
|
||||
friend class JSReceiver;
|
||||
|
@ -29,6 +29,9 @@ const Register StoreDescriptor::NameRegister() { return rcx; }
|
||||
const Register StoreDescriptor::ValueRegister() { return rax; }
|
||||
|
||||
|
||||
const Register ExtendStorageDescriptor::MapRegister() { return rbx; }
|
||||
|
||||
|
||||
const Register ElementTransitionAndStoreDescriptor::MapRegister() {
|
||||
return rbx;
|
||||
}
|
||||
|
@ -29,6 +29,9 @@ const Register StoreDescriptor::NameRegister() { return ecx; }
|
||||
const Register StoreDescriptor::ValueRegister() { return eax; }
|
||||
|
||||
|
||||
const Register ExtendStorageDescriptor::MapRegister() { return ebx; }
|
||||
|
||||
|
||||
const Register ElementTransitionAndStoreDescriptor::MapRegister() {
|
||||
return ebx;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user