Commit 360ee4f9 authored by ishell's avatar ishell Committed by Commit bot

[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}
parent bf1a94f1
......@@ -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();
}
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;
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);
}
// 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)
......
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