[stubs] Port StoreGlobalStub to TurboFan.
BUG=v8:5269 Review-Url: https://codereview.chromium.org/2322373002 Cr-Commit-Position: refs/heads/master@{#39354}
This commit is contained in:
parent
a26769629b
commit
2136adbd96
@ -4513,6 +4513,8 @@ void CodeStubAssembler::StoreNamedField(Node* object, FieldIndex index,
|
||||
if (store_value_as_double) {
|
||||
StoreObjectFieldNoWriteBarrier(property_storage, offset, value,
|
||||
MachineRepresentation::kFloat64);
|
||||
} else if (representation.IsSmi()) {
|
||||
StoreObjectFieldNoWriteBarrier(property_storage, offset, value);
|
||||
} else {
|
||||
StoreObjectField(property_storage, offset, value);
|
||||
}
|
||||
|
@ -1519,99 +1519,6 @@ HValue* CodeStubGraphBuilder<ToBooleanICStub>::BuildCodeInitializedStub() {
|
||||
|
||||
Handle<Code> ToBooleanICStub::GenerateCode() { return DoGenerateCode(this); }
|
||||
|
||||
template <>
|
||||
HValue* CodeStubGraphBuilder<StoreGlobalStub>::BuildCodeInitializedStub() {
|
||||
StoreGlobalStub* stub = casted_stub();
|
||||
HParameter* value = GetParameter(Descriptor::kValue);
|
||||
if (stub->check_global()) {
|
||||
// Check that the map of the global has not changed: use a placeholder map
|
||||
// that will be replaced later with the global object's map.
|
||||
HParameter* proxy = GetParameter(Descriptor::kReceiver);
|
||||
HValue* proxy_map =
|
||||
Add<HLoadNamedField>(proxy, nullptr, HObjectAccess::ForMap());
|
||||
HValue* global =
|
||||
Add<HLoadNamedField>(proxy_map, nullptr, HObjectAccess::ForPrototype());
|
||||
HValue* map_cell = Add<HConstant>(isolate()->factory()->NewWeakCell(
|
||||
StoreGlobalStub::global_map_placeholder(isolate())));
|
||||
HValue* expected_map = Add<HLoadNamedField>(
|
||||
map_cell, nullptr, HObjectAccess::ForWeakCellValue());
|
||||
HValue* map =
|
||||
Add<HLoadNamedField>(global, nullptr, HObjectAccess::ForMap());
|
||||
IfBuilder map_check(this);
|
||||
map_check.IfNot<HCompareObjectEqAndBranch>(expected_map, map);
|
||||
map_check.ThenDeopt(DeoptimizeReason::kUnknownMap);
|
||||
map_check.End();
|
||||
}
|
||||
|
||||
HValue* weak_cell = Add<HConstant>(isolate()->factory()->NewWeakCell(
|
||||
StoreGlobalStub::property_cell_placeholder(isolate())));
|
||||
HValue* cell = Add<HLoadNamedField>(weak_cell, nullptr,
|
||||
HObjectAccess::ForWeakCellValue());
|
||||
Add<HCheckHeapObject>(cell);
|
||||
HObjectAccess access = HObjectAccess::ForPropertyCellValue();
|
||||
// Load the payload of the global parameter cell. A hole indicates that the
|
||||
// cell has been invalidated and that the store must be handled by the
|
||||
// runtime.
|
||||
HValue* cell_contents = Add<HLoadNamedField>(cell, nullptr, access);
|
||||
|
||||
auto cell_type = stub->cell_type();
|
||||
if (cell_type == PropertyCellType::kConstant ||
|
||||
cell_type == PropertyCellType::kUndefined) {
|
||||
// This is always valid for all states a cell can be in.
|
||||
IfBuilder builder(this);
|
||||
builder.If<HCompareObjectEqAndBranch>(cell_contents, value);
|
||||
builder.Then();
|
||||
builder.ElseDeopt(
|
||||
DeoptimizeReason::kUnexpectedCellContentsInConstantGlobalStore);
|
||||
builder.End();
|
||||
} else {
|
||||
IfBuilder builder(this);
|
||||
HValue* hole_value = graph()->GetConstantHole();
|
||||
builder.If<HCompareObjectEqAndBranch>(cell_contents, hole_value);
|
||||
builder.Then();
|
||||
builder.Deopt(DeoptimizeReason::kUnexpectedCellContentsInGlobalStore);
|
||||
builder.Else();
|
||||
// When dealing with constant types, the type may be allowed to change, as
|
||||
// long as optimized code remains valid.
|
||||
if (cell_type == PropertyCellType::kConstantType) {
|
||||
switch (stub->constant_type()) {
|
||||
case PropertyCellConstantType::kSmi:
|
||||
access = access.WithRepresentation(Representation::Smi());
|
||||
break;
|
||||
case PropertyCellConstantType::kStableMap: {
|
||||
// It is sufficient here to check that the value and cell contents
|
||||
// have identical maps, no matter if they are stable or not or if they
|
||||
// are the maps that were originally in the cell or not. If optimized
|
||||
// code will deopt when a cell has a unstable map and if it has a
|
||||
// dependency on a stable map, it will deopt if the map destabilizes.
|
||||
Add<HCheckHeapObject>(value);
|
||||
Add<HCheckHeapObject>(cell_contents);
|
||||
HValue* expected_map = Add<HLoadNamedField>(cell_contents, nullptr,
|
||||
HObjectAccess::ForMap());
|
||||
HValue* map =
|
||||
Add<HLoadNamedField>(value, nullptr, HObjectAccess::ForMap());
|
||||
IfBuilder map_check(this);
|
||||
map_check.IfNot<HCompareObjectEqAndBranch>(expected_map, map);
|
||||
map_check.ThenDeopt(DeoptimizeReason::kUnknownMap);
|
||||
map_check.End();
|
||||
access = access.WithRepresentation(Representation::HeapObject());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Add<HStoreNamedField>(cell, access, value);
|
||||
builder.End();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
Handle<Code> StoreGlobalStub::GenerateCode() {
|
||||
return DoGenerateCode(this);
|
||||
}
|
||||
|
||||
|
||||
template <>
|
||||
HValue* CodeStubGraphBuilder<ElementsTransitionAndStoreStub>::BuildCodeStub() {
|
||||
HValue* object = GetParameter(StoreTransitionHelper::ReceiverIndex());
|
||||
|
@ -4471,6 +4471,101 @@ void StoreFieldStub::GenerateAssembly(CodeStubAssembler* assembler) const {
|
||||
}
|
||||
}
|
||||
|
||||
void StoreGlobalStub::GenerateAssembly(CodeStubAssembler* assembler) const {
|
||||
typedef CodeStubAssembler::Label Label;
|
||||
typedef compiler::Node Node;
|
||||
|
||||
assembler->Comment(
|
||||
"StoreGlobalStub: cell_type=%d, constant_type=%d, check_global=%d",
|
||||
cell_type(), PropertyCellType::kConstantType == cell_type()
|
||||
? static_cast<int>(constant_type())
|
||||
: -1,
|
||||
check_global());
|
||||
|
||||
Node* receiver = assembler->Parameter(Descriptor::kReceiver);
|
||||
Node* name = assembler->Parameter(Descriptor::kName);
|
||||
Node* value = assembler->Parameter(Descriptor::kValue);
|
||||
Node* slot = assembler->Parameter(Descriptor::kSlot);
|
||||
Node* vector = assembler->Parameter(Descriptor::kVector);
|
||||
Node* context = assembler->Parameter(Descriptor::kContext);
|
||||
|
||||
Label miss(assembler);
|
||||
|
||||
if (check_global()) {
|
||||
// Check that the map of the global has not changed: use a placeholder map
|
||||
// that will be replaced later with the global object's map.
|
||||
Node* proxy_map = assembler->LoadMap(receiver);
|
||||
Node* global = assembler->LoadObjectField(proxy_map, Map::kPrototypeOffset);
|
||||
Node* map_cell = assembler->HeapConstant(isolate()->factory()->NewWeakCell(
|
||||
StoreGlobalStub::global_map_placeholder(isolate())));
|
||||
Node* expected_map = assembler->LoadWeakCellValue(map_cell);
|
||||
Node* map = assembler->LoadMap(global);
|
||||
assembler->GotoIf(assembler->WordNotEqual(expected_map, map), &miss);
|
||||
}
|
||||
|
||||
Node* weak_cell = assembler->HeapConstant(isolate()->factory()->NewWeakCell(
|
||||
StoreGlobalStub::property_cell_placeholder(isolate())));
|
||||
Node* cell = assembler->LoadWeakCellValue(weak_cell);
|
||||
assembler->GotoIf(assembler->WordIsSmi(cell), &miss);
|
||||
|
||||
// Load the payload of the global parameter cell. A hole indicates that the
|
||||
// cell has been invalidated and that the store must be handled by the
|
||||
// runtime.
|
||||
Node* cell_contents =
|
||||
assembler->LoadObjectField(cell, PropertyCell::kValueOffset);
|
||||
|
||||
PropertyCellType cell_type = this->cell_type();
|
||||
if (cell_type == PropertyCellType::kConstant ||
|
||||
cell_type == PropertyCellType::kUndefined) {
|
||||
// This is always valid for all states a cell can be in.
|
||||
assembler->GotoIf(assembler->WordNotEqual(cell_contents, value), &miss);
|
||||
} else {
|
||||
assembler->GotoIf(
|
||||
assembler->WordEqual(cell_contents, assembler->TheHoleConstant()),
|
||||
&miss);
|
||||
|
||||
// When dealing with constant types, the type may be allowed to change, as
|
||||
// long as optimized code remains valid.
|
||||
bool value_is_smi = false;
|
||||
if (cell_type == PropertyCellType::kConstantType) {
|
||||
switch (constant_type()) {
|
||||
case PropertyCellConstantType::kSmi:
|
||||
assembler->GotoUnless(assembler->WordIsSmi(value), &miss);
|
||||
value_is_smi = true;
|
||||
break;
|
||||
case PropertyCellConstantType::kStableMap: {
|
||||
// It is sufficient here to check that the value and cell contents
|
||||
// have identical maps, no matter if they are stable or not or if they
|
||||
// are the maps that were originally in the cell or not. If optimized
|
||||
// code will deopt when a cell has a unstable map and if it has a
|
||||
// dependency on a stable map, it will deopt if the map destabilizes.
|
||||
assembler->GotoIf(assembler->WordIsSmi(value), &miss);
|
||||
assembler->GotoIf(assembler->WordIsSmi(cell_contents), &miss);
|
||||
Node* expected_map = assembler->LoadMap(cell_contents);
|
||||
Node* map = assembler->LoadMap(value);
|
||||
assembler->GotoIf(assembler->WordNotEqual(expected_map, map), &miss);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (value_is_smi) {
|
||||
assembler->StoreObjectFieldNoWriteBarrier(
|
||||
cell, PropertyCell::kValueOffset, value);
|
||||
} else {
|
||||
assembler->StoreObjectField(cell, PropertyCell::kValueOffset, value);
|
||||
}
|
||||
}
|
||||
|
||||
assembler->Return(value);
|
||||
|
||||
assembler->Bind(&miss);
|
||||
{
|
||||
assembler->Comment("Miss");
|
||||
assembler->TailCallRuntime(Runtime::kStoreIC_Miss, context, receiver, name,
|
||||
value, slot, vector);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
compiler::Node* LessThanStub::Generate(CodeStubAssembler* assembler,
|
||||
compiler::Node* lhs, compiler::Node* rhs,
|
||||
|
@ -90,7 +90,6 @@ class ObjectLiteral;
|
||||
V(LoadField) \
|
||||
V(LoadScriptContextField) \
|
||||
V(StoreFastElement) \
|
||||
V(StoreGlobal) \
|
||||
V(StoreScriptContextField) \
|
||||
V(StoreTransition) \
|
||||
/* These should never be ported to TF */ \
|
||||
@ -167,6 +166,7 @@ class ObjectLiteral;
|
||||
V(LoadICTF) \
|
||||
V(KeyedLoadICTF) \
|
||||
V(StoreField) \
|
||||
V(StoreGlobal) \
|
||||
V(StoreInterceptor) \
|
||||
V(LoadApiGetter) \
|
||||
V(LoadIndexedInterceptor) \
|
||||
@ -1773,20 +1773,22 @@ class StoreTransitionStub : public HandlerStub {
|
||||
DEFINE_HANDLER_CODE_STUB(StoreTransition, HandlerStub);
|
||||
};
|
||||
|
||||
|
||||
class StoreGlobalStub : public HandlerStub {
|
||||
class StoreGlobalStub : public TurboFanCodeStub {
|
||||
public:
|
||||
StoreGlobalStub(Isolate* isolate, PropertyCellType type,
|
||||
Maybe<PropertyCellConstantType> constant_type,
|
||||
bool check_global)
|
||||
: HandlerStub(isolate) {
|
||||
: TurboFanCodeStub(isolate) {
|
||||
PropertyCellConstantType encoded_constant_type =
|
||||
constant_type.FromMaybe(PropertyCellConstantType::kSmi);
|
||||
set_sub_minor_key(CellTypeBits::encode(type) |
|
||||
ConstantTypeBits::encode(encoded_constant_type) |
|
||||
CheckGlobalBits::encode(check_global));
|
||||
minor_key_ = CellTypeBits::encode(type) |
|
||||
ConstantTypeBits::encode(encoded_constant_type) |
|
||||
CheckGlobalBits::encode(check_global);
|
||||
}
|
||||
|
||||
Code::Kind GetCodeKind() const override { return Code::HANDLER; }
|
||||
ExtraICState GetExtraICState() const override { return Code::STORE_IC; }
|
||||
|
||||
static Handle<HeapObject> property_cell_placeholder(Isolate* isolate) {
|
||||
return isolate->factory()->uninitialized_value();
|
||||
}
|
||||
@ -1807,37 +1809,25 @@ class StoreGlobalStub : public HandlerStub {
|
||||
return CodeStub::GetCodeCopy(pattern);
|
||||
}
|
||||
|
||||
Code::Kind kind() const override { return Code::STORE_IC; }
|
||||
|
||||
PropertyCellType cell_type() const {
|
||||
return CellTypeBits::decode(sub_minor_key());
|
||||
return CellTypeBits::decode(minor_key_);
|
||||
}
|
||||
|
||||
PropertyCellConstantType constant_type() const {
|
||||
DCHECK(PropertyCellType::kConstantType == cell_type());
|
||||
return ConstantTypeBits::decode(sub_minor_key());
|
||||
return ConstantTypeBits::decode(minor_key_);
|
||||
}
|
||||
|
||||
bool check_global() const { return CheckGlobalBits::decode(sub_minor_key()); }
|
||||
|
||||
Representation representation() {
|
||||
return Representation::FromKind(
|
||||
RepresentationBits::decode(sub_minor_key()));
|
||||
}
|
||||
|
||||
void set_representation(Representation r) {
|
||||
set_sub_minor_key(RepresentationBits::update(sub_minor_key(), r.kind()));
|
||||
}
|
||||
bool check_global() const { return CheckGlobalBits::decode(minor_key_); }
|
||||
|
||||
private:
|
||||
class CellTypeBits : public BitField<PropertyCellType, 0, 2> {};
|
||||
class ConstantTypeBits : public BitField<PropertyCellConstantType, 2, 2> {};
|
||||
class RepresentationBits : public BitField<Representation::Kind, 4, 8> {};
|
||||
class CheckGlobalBits : public BitField<bool, 12, 1> {};
|
||||
class ConstantTypeBits
|
||||
: public BitField<PropertyCellConstantType, CellTypeBits::kNext, 2> {};
|
||||
class CheckGlobalBits : public BitField<bool, ConstantTypeBits::kNext, 1> {};
|
||||
|
||||
// TODO(ishell): The stub uses only kValue parameter.
|
||||
DEFINE_CALL_INTERFACE_DESCRIPTOR(StoreWithVector);
|
||||
DEFINE_HANDLER_CODE_STUB(StoreGlobal, HandlerStub);
|
||||
DEFINE_TURBOFAN_CODE_STUB(StoreGlobal, TurboFanCodeStub);
|
||||
};
|
||||
|
||||
// TODO(ishell): remove, once StoreGlobalIC is implemented.
|
||||
|
Loading…
Reference in New Issue
Block a user