[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:
ishell 2016-09-12 07:28:28 -07:00 committed by Commit bot
parent a26769629b
commit 2136adbd96
4 changed files with 113 additions and 119 deletions

View File

@ -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);
}

View File

@ -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());

View File

@ -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,

View File

@ -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.