[stubs] Reduce number of StoreTransitionStub instances.
... by passing a field offset as a runtime parameter. This CL also introduces a StoreMapStub - a special case of a store transition that used to be handled by old StoreTransitionStub. BUG=chromium:648545 Review-Url: https://codereview.chromium.org/2397573004 Cr-Commit-Position: refs/heads/master@{#39997}
This commit is contained in:
parent
bf1a94f1b2
commit
360ee4f9b0
@ -1115,12 +1115,32 @@ Node* CodeStubAssembler::StoreObjectField(
|
||||
IntPtrConstant(offset - kHeapObjectTag), value);
|
||||
}
|
||||
|
||||
Node* CodeStubAssembler::StoreObjectField(Node* object, Node* offset,
|
||||
Node* value) {
|
||||
int const_offset;
|
||||
if (ToInt32Constant(offset, const_offset)) {
|
||||
return StoreObjectField(object, const_offset, value);
|
||||
}
|
||||
return Store(MachineRepresentation::kTagged, object,
|
||||
IntPtrSub(offset, IntPtrConstant(kHeapObjectTag)), value);
|
||||
}
|
||||
|
||||
Node* CodeStubAssembler::StoreObjectFieldNoWriteBarrier(
|
||||
Node* object, int offset, Node* value, MachineRepresentation rep) {
|
||||
return StoreNoWriteBarrier(rep, object,
|
||||
IntPtrConstant(offset - kHeapObjectTag), value);
|
||||
}
|
||||
|
||||
Node* CodeStubAssembler::StoreObjectFieldNoWriteBarrier(
|
||||
Node* object, Node* offset, Node* value, MachineRepresentation rep) {
|
||||
int const_offset;
|
||||
if (ToInt32Constant(offset, const_offset)) {
|
||||
return StoreObjectFieldNoWriteBarrier(object, const_offset, value, rep);
|
||||
}
|
||||
return StoreNoWriteBarrier(
|
||||
rep, object, IntPtrSub(offset, IntPtrConstant(kHeapObjectTag)), value);
|
||||
}
|
||||
|
||||
Node* CodeStubAssembler::StoreMapNoWriteBarrier(Node* object, Node* map) {
|
||||
return StoreNoWriteBarrier(
|
||||
MachineRepresentation::kTagged, object,
|
||||
@ -5121,15 +5141,22 @@ void CodeStubAssembler::StoreNamedField(Node* object, FieldIndex index,
|
||||
Node* value, bool transition_to_field) {
|
||||
DCHECK_EQ(index.is_double(), representation.IsDouble());
|
||||
|
||||
StoreNamedField(object, IntPtrConstant(index.offset()), index.is_inobject(),
|
||||
representation, value, transition_to_field);
|
||||
}
|
||||
|
||||
void CodeStubAssembler::StoreNamedField(Node* object, Node* offset,
|
||||
bool is_inobject,
|
||||
Representation representation,
|
||||
Node* value, bool transition_to_field) {
|
||||
bool store_value_as_double = representation.IsDouble();
|
||||
int offset = index.offset();
|
||||
Node* property_storage = object;
|
||||
if (!index.is_inobject()) {
|
||||
if (!is_inobject) {
|
||||
property_storage = LoadProperties(object);
|
||||
}
|
||||
|
||||
if (representation.IsDouble()) {
|
||||
if (!FLAG_unbox_double_fields || !index.is_inobject()) {
|
||||
if (!FLAG_unbox_double_fields || !is_inobject) {
|
||||
if (transition_to_field) {
|
||||
Node* heap_number = AllocateHeapNumberWithValue(value, MUTABLE);
|
||||
// Store the new mutable heap number into the object.
|
||||
@ -5139,7 +5166,7 @@ void CodeStubAssembler::StoreNamedField(Node* object, FieldIndex index,
|
||||
// Load the heap number.
|
||||
property_storage = LoadObjectField(property_storage, offset);
|
||||
// Store the double value into it.
|
||||
offset = HeapNumber::kValueOffset;
|
||||
offset = IntPtrConstant(HeapNumber::kValueOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -313,9 +313,15 @@ class CodeStubAssembler : public compiler::CodeAssembler {
|
||||
// Store a field to an object on the heap.
|
||||
compiler::Node* StoreObjectField(
|
||||
compiler::Node* object, int offset, compiler::Node* value);
|
||||
compiler::Node* StoreObjectField(compiler::Node* object,
|
||||
compiler::Node* offset,
|
||||
compiler::Node* value);
|
||||
compiler::Node* StoreObjectFieldNoWriteBarrier(
|
||||
compiler::Node* object, int offset, compiler::Node* value,
|
||||
MachineRepresentation rep = MachineRepresentation::kTagged);
|
||||
compiler::Node* StoreObjectFieldNoWriteBarrier(
|
||||
compiler::Node* object, compiler::Node* offset, compiler::Node* value,
|
||||
MachineRepresentation rep = MachineRepresentation::kTagged);
|
||||
// Store the Map of an HeapObject.
|
||||
compiler::Node* StoreMapNoWriteBarrier(compiler::Node* object,
|
||||
compiler::Node* map);
|
||||
@ -754,6 +760,10 @@ class CodeStubAssembler : public compiler::CodeAssembler {
|
||||
Representation representation, compiler::Node* value,
|
||||
bool transition_to_field);
|
||||
|
||||
void StoreNamedField(compiler::Node* object, compiler::Node* offset,
|
||||
bool is_inobject, Representation representation,
|
||||
compiler::Node* value, bool transition_to_field);
|
||||
|
||||
// Emits keyed sloppy arguments load. Returns either the loaded value.
|
||||
compiler::Node* LoadKeyedSloppyArguments(compiler::Node* receiver,
|
||||
compiler::Node* key,
|
||||
|
@ -529,57 +529,59 @@ void StoreICTFStub::GenerateAssembly(CodeStubAssembler* assembler) const {
|
||||
assembler->StoreIC(&p);
|
||||
}
|
||||
|
||||
void StoreMapStub::GenerateAssembly(CodeStubAssembler* assembler) const {
|
||||
typedef compiler::Node Node;
|
||||
|
||||
Node* receiver = assembler->Parameter(Descriptor::kReceiver);
|
||||
Node* map = assembler->Parameter(Descriptor::kMap);
|
||||
Node* value = assembler->Parameter(Descriptor::kValue);
|
||||
|
||||
assembler->StoreObjectField(receiver, JSObject::kMapOffset, map);
|
||||
assembler->Return(value);
|
||||
}
|
||||
|
||||
void StoreTransitionStub::GenerateAssembly(CodeStubAssembler* assembler) const {
|
||||
typedef CodeStubAssembler::Label Label;
|
||||
typedef compiler::Node Node;
|
||||
|
||||
Node* receiver = assembler->Parameter(Descriptor::kReceiver);
|
||||
Node* name = assembler->Parameter(Descriptor::kName);
|
||||
Node* offset =
|
||||
assembler->SmiUntag(assembler->Parameter(Descriptor::kFieldOffset));
|
||||
Node* value = assembler->Parameter(Descriptor::kValue);
|
||||
Node* map = assembler->Parameter(Descriptor::kMap);
|
||||
Node* slot = assembler->Parameter(Descriptor::kSlot);
|
||||
Node* vector = assembler->Parameter(Descriptor::kVector);
|
||||
Node* context = assembler->Parameter(Descriptor::kContext);
|
||||
|
||||
StoreMode store_mode = this->store_mode();
|
||||
Node* prepared_value = value;
|
||||
|
||||
Label miss(assembler);
|
||||
bool needs_miss_case = false;
|
||||
|
||||
if (store_mode != StoreTransitionStub::StoreMapOnly) {
|
||||
Representation representation = this->representation();
|
||||
FieldIndex index = this->index();
|
||||
assembler->Comment(
|
||||
"Prepare value for write: representation: %s, index.is_inobject: %d, "
|
||||
"index.offset: %d",
|
||||
representation.Mnemonic(), index.is_inobject(), index.offset());
|
||||
prepared_value =
|
||||
assembler->PrepareValueForWrite(prepared_value, representation, &miss);
|
||||
// Only store to tagged field never bails out.
|
||||
needs_miss_case |= !representation.IsTagged();
|
||||
Representation representation = this->representation();
|
||||
assembler->Comment("StoreTransitionStub: is_inobject: %d: representation: %s",
|
||||
is_inobject(), representation.Mnemonic());
|
||||
|
||||
Node* prepared_value =
|
||||
assembler->PrepareValueForWrite(value, representation, &miss);
|
||||
|
||||
if (store_mode() == StoreTransitionStub::ExtendStorageAndStoreMapAndValue) {
|
||||
assembler->Comment("Extend storage");
|
||||
assembler->ExtendPropertiesBackingStore(receiver);
|
||||
} else {
|
||||
DCHECK(store_mode() == StoreTransitionStub::StoreMapAndValue);
|
||||
}
|
||||
|
||||
switch (store_mode) {
|
||||
case StoreTransitionStub::ExtendStorageAndStoreMapAndValue:
|
||||
assembler->Comment("Extend storage");
|
||||
assembler->ExtendPropertiesBackingStore(receiver);
|
||||
// Fall through.
|
||||
case StoreTransitionStub::StoreMapAndValue:
|
||||
assembler->Comment("Store value");
|
||||
// Store the new value into the "extended" object.
|
||||
assembler->StoreNamedField(receiver, index(), representation(),
|
||||
prepared_value, true);
|
||||
// Fall through.
|
||||
case StoreTransitionStub::StoreMapOnly:
|
||||
assembler->Comment("Store map");
|
||||
// And finally update the map.
|
||||
assembler->StoreObjectField(receiver, JSObject::kMapOffset, map);
|
||||
break;
|
||||
}
|
||||
// Store the new value into the "extended" object.
|
||||
assembler->Comment("Store value");
|
||||
assembler->StoreNamedField(receiver, offset, is_inobject(), representation,
|
||||
prepared_value, true);
|
||||
|
||||
// And finally update the map.
|
||||
assembler->Comment("Store map");
|
||||
assembler->StoreObjectField(receiver, JSObject::kMapOffset, map);
|
||||
assembler->Return(value);
|
||||
|
||||
if (needs_miss_case) {
|
||||
// Only store to tagged field never bails out.
|
||||
if (!representation.IsTagged()) {
|
||||
assembler->Bind(&miss);
|
||||
{
|
||||
assembler->Comment("Miss");
|
||||
|
@ -159,6 +159,7 @@ class ObjectLiteral;
|
||||
V(StoreGlobal) \
|
||||
V(StoreICTF) \
|
||||
V(StoreInterceptor) \
|
||||
V(StoreMap) \
|
||||
V(StoreTransition) \
|
||||
V(LoadApiGetter) \
|
||||
V(LoadIndexedInterceptor) \
|
||||
@ -1610,24 +1611,29 @@ class StoreFieldStub : public TurboFanCodeStub {
|
||||
DEFINE_TURBOFAN_CODE_STUB(StoreField, TurboFanCodeStub);
|
||||
};
|
||||
|
||||
class StoreMapStub : public TurboFanCodeStub {
|
||||
public:
|
||||
explicit StoreMapStub(Isolate* isolate) : TurboFanCodeStub(isolate) {}
|
||||
|
||||
Code::Kind GetCodeKind() const override { return Code::HANDLER; }
|
||||
ExtraICState GetExtraICState() const override { return Code::STORE_IC; }
|
||||
|
||||
private:
|
||||
DEFINE_CALL_INTERFACE_DESCRIPTOR(StoreTransition);
|
||||
DEFINE_TURBOFAN_CODE_STUB(StoreMap, TurboFanCodeStub);
|
||||
};
|
||||
|
||||
class StoreTransitionStub : public TurboFanCodeStub {
|
||||
public:
|
||||
enum StoreMode {
|
||||
StoreMapOnly,
|
||||
StoreMapAndValue,
|
||||
ExtendStorageAndStoreMapAndValue
|
||||
};
|
||||
|
||||
explicit StoreTransitionStub(Isolate* isolate) : TurboFanCodeStub(isolate) {
|
||||
minor_key_ = StoreModeBits::encode(StoreMapOnly);
|
||||
}
|
||||
|
||||
StoreTransitionStub(Isolate* isolate, FieldIndex index,
|
||||
StoreTransitionStub(Isolate* isolate, bool is_inobject,
|
||||
Representation representation, StoreMode store_mode)
|
||||
: TurboFanCodeStub(isolate) {
|
||||
DCHECK(store_mode != StoreMapOnly);
|
||||
int property_index_key = index.GetFieldAccessStubKey();
|
||||
minor_key_ = StoreFieldByIndexBits::encode(property_index_key) |
|
||||
minor_key_ = IsInobjectBits::encode(is_inobject) |
|
||||
RepresentationBits::encode(representation.kind()) |
|
||||
StoreModeBits::encode(store_mode);
|
||||
}
|
||||
@ -1635,27 +1641,24 @@ class StoreTransitionStub : public TurboFanCodeStub {
|
||||
Code::Kind GetCodeKind() const override { return Code::HANDLER; }
|
||||
ExtraICState GetExtraICState() const override { return Code::STORE_IC; }
|
||||
|
||||
FieldIndex index() const {
|
||||
DCHECK(store_mode() != StoreMapOnly);
|
||||
int property_index_key = StoreFieldByIndexBits::decode(minor_key_);
|
||||
return FieldIndex::FromFieldAccessStubKey(property_index_key);
|
||||
}
|
||||
bool is_inobject() const { return IsInobjectBits::decode(minor_key_); }
|
||||
|
||||
Representation representation() const {
|
||||
DCHECK(store_mode() != StoreMapOnly);
|
||||
return Representation::FromKind(RepresentationBits::decode(minor_key_));
|
||||
}
|
||||
|
||||
StoreMode store_mode() const { return StoreModeBits::decode(minor_key_); }
|
||||
|
||||
private:
|
||||
class StoreFieldByIndexBits : public BitField<int, 0, 13> {};
|
||||
class RepresentationBits : public BitField<Representation::Kind, 13, 4> {};
|
||||
class IsInobjectBits : public BitField<bool, 0, 1> {};
|
||||
class RepresentationBits
|
||||
: public BitField<Representation::Kind, IsInobjectBits::kNext, 4> {};
|
||||
STATIC_ASSERT(Representation::kNumRepresentations - 1 <
|
||||
RepresentationBits::kMax);
|
||||
class StoreModeBits : public BitField<StoreMode, 17, 2> {};
|
||||
class StoreModeBits
|
||||
: public BitField<StoreMode, RepresentationBits::kNext, 1> {};
|
||||
|
||||
DEFINE_CALL_INTERFACE_DESCRIPTOR(StoreTransition);
|
||||
DEFINE_CALL_INTERFACE_DESCRIPTOR(StoreNamedTransition);
|
||||
DEFINE_TURBOFAN_CODE_STUB(StoreTransition, TurboFanCodeStub);
|
||||
};
|
||||
|
||||
|
@ -135,9 +135,13 @@ void PropertyHandlerCompiler::DiscardVectorAndSlot() {
|
||||
__ add(sp, sp, Operand(2 * kPointerSize));
|
||||
}
|
||||
|
||||
void PropertyHandlerCompiler::PushReturnAddress(Register tmp) { UNREACHABLE(); }
|
||||
void PropertyHandlerCompiler::PushReturnAddress(Register tmp) {
|
||||
// No-op. Return address is in lr register.
|
||||
}
|
||||
|
||||
void PropertyHandlerCompiler::PopReturnAddress(Register tmp) { UNREACHABLE(); }
|
||||
void PropertyHandlerCompiler::PopReturnAddress(Register tmp) {
|
||||
// No-op. Return address is in lr register.
|
||||
}
|
||||
|
||||
void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
|
||||
MacroAssembler* masm, Label* miss_label, Register receiver,
|
||||
|
@ -44,9 +44,13 @@ void PropertyHandlerCompiler::DiscardVectorAndSlot() {
|
||||
__ Drop(2);
|
||||
}
|
||||
|
||||
void PropertyHandlerCompiler::PushReturnAddress(Register tmp) { UNREACHABLE(); }
|
||||
void PropertyHandlerCompiler::PushReturnAddress(Register tmp) {
|
||||
// No-op. Return address is in lr register.
|
||||
}
|
||||
|
||||
void PropertyHandlerCompiler::PopReturnAddress(Register tmp) { UNREACHABLE(); }
|
||||
void PropertyHandlerCompiler::PopReturnAddress(Register tmp) {
|
||||
// No-op. Return address is in lr register.
|
||||
}
|
||||
|
||||
void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
|
||||
MacroAssembler* masm, Label* miss_label, Register receiver,
|
||||
|
@ -504,7 +504,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreTransition(
|
||||
PopVectorAndSlot();
|
||||
}
|
||||
GenerateRestoreName(name);
|
||||
StoreTransitionStub stub(isolate());
|
||||
StoreMapStub stub(isolate());
|
||||
GenerateTailCall(masm(), stub.GetCode());
|
||||
|
||||
} else {
|
||||
@ -520,10 +520,17 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreTransition(
|
||||
if (need_save_restore) {
|
||||
PopVectorAndSlot();
|
||||
}
|
||||
GenerateRestoreName(name);
|
||||
StoreTransitionStub stub(isolate(),
|
||||
FieldIndex::ForDescriptor(*transition, descriptor),
|
||||
representation, store_mode);
|
||||
// We need to pass name on the stack.
|
||||
PopReturnAddress(this->name());
|
||||
__ Push(name);
|
||||
PushReturnAddress(this->name());
|
||||
|
||||
FieldIndex index = FieldIndex::ForDescriptor(*transition, descriptor);
|
||||
__ Move(StoreNamedTransitionDescriptor::FieldOffsetRegister(),
|
||||
Smi::FromInt(index.index() << kPointerSizeLog2));
|
||||
|
||||
StoreTransitionStub stub(isolate(), index.is_inobject(), representation,
|
||||
store_mode);
|
||||
GenerateTailCall(masm(), stub.GetCode());
|
||||
}
|
||||
|
||||
|
@ -129,9 +129,13 @@ void PropertyHandlerCompiler::DiscardVectorAndSlot() {
|
||||
__ Addu(sp, sp, Operand(2 * kPointerSize));
|
||||
}
|
||||
|
||||
void PropertyHandlerCompiler::PushReturnAddress(Register tmp) { UNREACHABLE(); }
|
||||
void PropertyHandlerCompiler::PushReturnAddress(Register tmp) {
|
||||
// No-op. Return address is in ra register.
|
||||
}
|
||||
|
||||
void PropertyHandlerCompiler::PopReturnAddress(Register tmp) { UNREACHABLE(); }
|
||||
void PropertyHandlerCompiler::PopReturnAddress(Register tmp) {
|
||||
// No-op. Return address is in ra register.
|
||||
}
|
||||
|
||||
void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
|
||||
MacroAssembler* masm, Label* miss_label, Register receiver,
|
||||
|
@ -129,9 +129,13 @@ void PropertyHandlerCompiler::DiscardVectorAndSlot() {
|
||||
__ Daddu(sp, sp, Operand(2 * kPointerSize));
|
||||
}
|
||||
|
||||
void PropertyHandlerCompiler::PushReturnAddress(Register tmp) { UNREACHABLE(); }
|
||||
void PropertyHandlerCompiler::PushReturnAddress(Register tmp) {
|
||||
// No-op. Return address is in ra register.
|
||||
}
|
||||
|
||||
void PropertyHandlerCompiler::PopReturnAddress(Register tmp) { UNREACHABLE(); }
|
||||
void PropertyHandlerCompiler::PopReturnAddress(Register tmp) {
|
||||
// No-op. Return address is in ra register.
|
||||
}
|
||||
|
||||
void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
|
||||
MacroAssembler* masm, Label* miss_label, Register receiver,
|
||||
|
@ -130,9 +130,13 @@ void PropertyHandlerCompiler::DiscardVectorAndSlot() {
|
||||
__ addi(sp, sp, Operand(2 * kPointerSize));
|
||||
}
|
||||
|
||||
void PropertyHandlerCompiler::PushReturnAddress(Register tmp) { UNREACHABLE(); }
|
||||
void PropertyHandlerCompiler::PushReturnAddress(Register tmp) {
|
||||
// No-op. Return address is in lr register.
|
||||
}
|
||||
|
||||
void PropertyHandlerCompiler::PopReturnAddress(Register tmp) { UNREACHABLE(); }
|
||||
void PropertyHandlerCompiler::PopReturnAddress(Register tmp) {
|
||||
// No-op. Return address is in lr register.
|
||||
}
|
||||
|
||||
void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
|
||||
MacroAssembler* masm, Label* miss_label, Register receiver,
|
||||
|
@ -125,9 +125,13 @@ void PropertyHandlerCompiler::DiscardVectorAndSlot() {
|
||||
__ la(sp, MemOperand(sp, 2 * kPointerSize));
|
||||
}
|
||||
|
||||
void PropertyHandlerCompiler::PushReturnAddress(Register tmp) { UNREACHABLE(); }
|
||||
void PropertyHandlerCompiler::PushReturnAddress(Register tmp) {
|
||||
// No-op. Return address is in lr register.
|
||||
}
|
||||
|
||||
void PropertyHandlerCompiler::PopReturnAddress(Register tmp) { UNREACHABLE(); }
|
||||
void PropertyHandlerCompiler::PopReturnAddress(Register tmp) {
|
||||
// No-op. Return address is in lr register.
|
||||
}
|
||||
|
||||
void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
|
||||
MacroAssembler* masm, Label* miss_label, Register receiver,
|
||||
|
@ -44,9 +44,15 @@ void PropertyHandlerCompiler::DiscardVectorAndSlot() {
|
||||
__ addp(rsp, Immediate(2 * kPointerSize));
|
||||
}
|
||||
|
||||
void PropertyHandlerCompiler::PushReturnAddress(Register tmp) { UNREACHABLE(); }
|
||||
void PropertyHandlerCompiler::PushReturnAddress(Register tmp) {
|
||||
MacroAssembler* masm = this->masm();
|
||||
__ Push(tmp);
|
||||
}
|
||||
|
||||
void PropertyHandlerCompiler::PopReturnAddress(Register tmp) { UNREACHABLE(); }
|
||||
void PropertyHandlerCompiler::PopReturnAddress(Register tmp) {
|
||||
MacroAssembler* masm = this->masm();
|
||||
__ Pop(tmp);
|
||||
}
|
||||
|
||||
void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
|
||||
MacroAssembler* masm, Label* miss_label, Register receiver,
|
||||
|
@ -160,6 +160,29 @@ void StoreTransitionDescriptor::InitializePlatformIndependent(
|
||||
machine_types);
|
||||
}
|
||||
|
||||
void StoreNamedTransitionDescriptor::InitializePlatformIndependent(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// kReceiver, kFieldOffset, kMap, kValue, kSlot, kVector, kName
|
||||
MachineType machine_types[] = {
|
||||
MachineType::AnyTagged(), MachineType::TaggedSigned(),
|
||||
MachineType::AnyTagged(), MachineType::AnyTagged(),
|
||||
MachineType::TaggedSigned(), MachineType::AnyTagged(),
|
||||
MachineType::AnyTagged()};
|
||||
data->InitializePlatformIndependent(arraysize(machine_types), 0,
|
||||
machine_types);
|
||||
}
|
||||
|
||||
void StoreNamedTransitionDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
Register registers[] = {
|
||||
ReceiverRegister(), FieldOffsetRegister(), MapRegister(),
|
||||
ValueRegister(), SlotRegister(), VectorRegister(),
|
||||
NameRegister(),
|
||||
};
|
||||
int len = arraysize(registers) - kStackArgumentsCount;
|
||||
data->InitializePlatformSpecific(len, registers);
|
||||
}
|
||||
|
||||
void StoreGlobalViaContextDescriptor::InitializePlatformIndependent(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// kSlot, kValue
|
||||
|
@ -24,6 +24,7 @@ class PlatformInterfaceDescriptor;
|
||||
V(LoadGlobalWithVector) \
|
||||
V(Store) \
|
||||
V(StoreWithVector) \
|
||||
V(StoreNamedTransition) \
|
||||
V(StoreTransition) \
|
||||
V(VarArgFunction) \
|
||||
V(FastNewClosure) \
|
||||
@ -349,6 +350,24 @@ class StoreTransitionDescriptor : public StoreDescriptor {
|
||||
static const int kStackArgumentsCount = kPassLastArgsOnStack ? 3 : 0;
|
||||
};
|
||||
|
||||
class StoreNamedTransitionDescriptor : public StoreTransitionDescriptor {
|
||||
public:
|
||||
DEFINE_PARAMETERS(kReceiver, kFieldOffset, kMap, kValue, kSlot, kVector,
|
||||
kName)
|
||||
DECLARE_DESCRIPTOR_WITH_CUSTOM_FUNCTION_TYPE(StoreNamedTransitionDescriptor,
|
||||
StoreTransitionDescriptor)
|
||||
|
||||
// Always pass name on the stack.
|
||||
static const bool kPassLastArgsOnStack = true;
|
||||
static const int kStackArgumentsCount =
|
||||
StoreTransitionDescriptor::kStackArgumentsCount + 1;
|
||||
|
||||
static const Register NameRegister() { return no_reg; }
|
||||
static const Register FieldOffsetRegister() {
|
||||
return StoreTransitionDescriptor::NameRegister();
|
||||
}
|
||||
};
|
||||
|
||||
class StoreWithVectorDescriptor : public StoreDescriptor {
|
||||
public:
|
||||
DEFINE_PARAMETERS(kReceiver, kName, kValue, kSlot, kVector)
|
||||
|
Loading…
Reference in New Issue
Block a user