Commit b851d753 authored by Clemens Hammacher's avatar Clemens Hammacher Committed by Commit Bot

Revert "Make LoadElimination aware of const fields (Part 2; stores)"

This reverts commit e588ff10.

Reason for revert: consistently crashes layout tests: https://ci.chromium.org/p/v8/builders/luci.v8.ci/V8-Blink%20Linux%2064/32225

Original change's description:
> Make LoadElimination aware of const fields (Part 2; stores)
> 
> Adds const information to store field accesses and uses it in load elimination
> 
> Change-Id: I00765c854c95c955dabd78557463267b95f75eef
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1611543
> Reviewed-by: Georg Neis <neis@chromium.org>
> Reviewed-by: Tobias Tebbi <tebbi@chromium.org>
> Commit-Queue: Georg Schmid <gsps@google.com>
> Cr-Commit-Position: refs/heads/master@{#61796}

TBR=jarin@chromium.org,neis@chromium.org,tebbi@chromium.org,bmeurer@chromium.org,gsps@google.com

Change-Id: Ia299c36b197c2aad7cfd953b06de06f4536ddb74
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1627975Reviewed-by: 's avatarClemens Hammacher <clemensh@chromium.org>
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#61813}
parent 2b0ac2fb
...@@ -92,11 +92,11 @@ PropertyAccessInfo PropertyAccessInfo::DataConstant( ...@@ -92,11 +92,11 @@ PropertyAccessInfo PropertyAccessInfo::DataConstant(
Zone* zone, Handle<Map> receiver_map, Zone* zone, Handle<Map> receiver_map,
ZoneVector<CompilationDependencies::Dependency const*>&& dependencies, ZoneVector<CompilationDependencies::Dependency const*>&& dependencies,
FieldIndex field_index, Representation field_representation, FieldIndex field_index, Representation field_representation,
Type field_type, MaybeHandle<Map> field_map, MaybeHandle<JSObject> holder, Type field_type, MaybeHandle<Map> field_map, MaybeHandle<JSObject> holder) {
MaybeHandle<Map> transition_map) { return PropertyAccessInfo(kDataConstant, holder, MaybeHandle<Map>(),
return PropertyAccessInfo(kDataConstant, holder, transition_map, field_index, field_index, field_representation, field_type,
field_representation, field_type, field_map, field_map, {{receiver_map}, zone},
{{receiver_map}, zone}, std::move(dependencies)); std::move(dependencies));
} }
// static // static
...@@ -796,22 +796,10 @@ PropertyAccessInfo AccessInfoFactory::LookupTransition( ...@@ -796,22 +796,10 @@ PropertyAccessInfo AccessInfoFactory::LookupTransition(
unrecorded_dependencies.push_back( unrecorded_dependencies.push_back(
dependencies()->TransitionDependencyOffTheRecord( dependencies()->TransitionDependencyOffTheRecord(
MapRef(broker(), transition_map))); MapRef(broker(), transition_map)));
// Transitioning stores *may* store to const fields. The resulting // Transitioning stores are never stores to constant fields.
// DataConstant access infos can be distinguished from later, i.e. redundant, return PropertyAccessInfo::DataField(
// stores to the same constant field by the presence of a transition map. zone(), map, std::move(unrecorded_dependencies), field_index,
switch (details.constness()) { details_representation, field_type, field_map, holder, transition_map);
case PropertyConstness::kMutable:
return PropertyAccessInfo::DataField(
zone(), map, std::move(unrecorded_dependencies), field_index,
details_representation, field_type, field_map, holder,
transition_map);
case PropertyConstness::kConst:
return PropertyAccessInfo::DataConstant(
zone(), map, std::move(unrecorded_dependencies), field_index,
details_representation, field_type, field_map, holder,
transition_map);
}
UNREACHABLE();
} }
} // namespace compiler } // namespace compiler
......
...@@ -85,8 +85,8 @@ class PropertyAccessInfo final { ...@@ -85,8 +85,8 @@ class PropertyAccessInfo final {
ZoneVector<CompilationDependencies::Dependency const*>&& ZoneVector<CompilationDependencies::Dependency const*>&&
unrecorded_dependencies, unrecorded_dependencies,
FieldIndex field_index, Representation field_representation, FieldIndex field_index, Representation field_representation,
Type field_type, MaybeHandle<Map> field_map, MaybeHandle<JSObject> holder, Type field_type, MaybeHandle<Map> field_map,
MaybeHandle<Map> transition_map = MaybeHandle<Map>()); MaybeHandle<JSObject> holder);
static PropertyAccessInfo AccessorConstant(Zone* zone, static PropertyAccessInfo AccessorConstant(Zone* zone,
Handle<Map> receiver_map, Handle<Map> receiver_map,
Handle<Object> constant, Handle<Object> constant,
......
...@@ -1616,39 +1616,17 @@ Node* JSCreateLowering::AllocateFastLiteral(Node* effect, Node* control, ...@@ -1616,39 +1616,17 @@ Node* JSCreateLowering::AllocateFastLiteral(Node* effect, Node* control,
DCHECK_EQ(kData, property_details.kind()); DCHECK_EQ(kData, property_details.kind());
NameRef property_name = boilerplate_map.GetPropertyKey(i); NameRef property_name = boilerplate_map.GetPropertyKey(i);
FieldIndex index = boilerplate_map.GetFieldIndexFor(i); FieldIndex index = boilerplate_map.GetFieldIndexFor(i);
FieldAccess access = {kTaggedBase, FieldAccess access = {
index.offset(), kTaggedBase, index.offset(), property_name.object(),
property_name.object(), MaybeHandle<Map>(), Type::Any(), MachineType::TypeCompressedTagged(),
MaybeHandle<Map>(), kFullWriteBarrier};
Type::Any(),
MachineType::TypeCompressedTagged(),
kFullWriteBarrier,
LoadSensitivity::kUnsafe,
property_details.constness()};
Node* value; Node* value;
if (boilerplate_map.IsUnboxedDoubleField(i)) { if (boilerplate_map.IsUnboxedDoubleField(i)) {
access.machine_type = MachineType::Float64(); access.machine_type = MachineType::Float64();
access.type = Type::Number(); access.type = Type::Number();
uint64_t value_bits = boilerplate.RawFastDoublePropertyAsBitsAt(index); value = jsgraph()->Constant(boilerplate.RawFastDoublePropertyAt(index));
if (value_bits == kHoleNanInt64) {
// This special case is analogous to is_uninitialized being true in the
// non-unboxed-double case below. The store of the hole NaN value here
// will always be followed by another store that actually initializes
// the field. The hole NaN should therefore be unobservable.
// Load elimination expects there to be at most one const store to any
// given field, so we always mark the unobservable ones as mutable.
access.constness = PropertyConstness::kMutable;
}
value = jsgraph()->Constant(bit_cast<double>(value_bits));
} else { } else {
ObjectRef boilerplate_value = boilerplate.RawFastPropertyAt(index); ObjectRef boilerplate_value = boilerplate.RawFastPropertyAt(index);
bool is_uninitialized =
boilerplate_value.IsHeapObject() &&
boilerplate_value.AsHeapObject().map().oddball_type() ==
OddballType::kUninitialized;
if (is_uninitialized) {
access.constness = PropertyConstness::kMutable;
}
if (boilerplate_value.IsJSObject()) { if (boilerplate_value.IsJSObject()) {
JSObjectRef boilerplate_object = boilerplate_value.AsJSObject(); JSObjectRef boilerplate_object = boilerplate_value.AsJSObject();
value = effect = AllocateFastLiteral(effect, control, value = effect = AllocateFastLiteral(effect, control,
...@@ -1665,6 +1643,10 @@ Node* JSCreateLowering::AllocateFastLiteral(Node* effect, Node* control, ...@@ -1665,6 +1643,10 @@ Node* JSCreateLowering::AllocateFastLiteral(Node* effect, Node* control,
value = effect = builder.Finish(); value = effect = builder.Finish();
} else if (property_details.representation().IsSmi()) { } else if (property_details.representation().IsSmi()) {
// Ensure that value is stored as smi. // Ensure that value is stored as smi.
bool is_uninitialized =
boilerplate_value.IsHeapObject() &&
boilerplate_value.AsHeapObject().map().oddball_type() ==
OddballType::kUninitialized;
value = is_uninitialized value = is_uninitialized
? jsgraph()->ZeroConstant() ? jsgraph()->ZeroConstant()
: jsgraph()->Constant(boilerplate_value.AsSmi()); : jsgraph()->Constant(boilerplate_value.AsSmi());
......
...@@ -208,13 +208,9 @@ void CallHandlerInfoData::Serialize(JSHeapBroker* broker) { ...@@ -208,13 +208,9 @@ void CallHandlerInfoData::Serialize(JSHeapBroker* broker) {
class JSObjectField { class JSObjectField {
public: public:
bool IsDouble() const { return object_ == nullptr; } bool IsDouble() const { return object_ == nullptr; }
uint64_t AsBitsOfDouble() const {
CHECK(IsDouble());
return number_bits_;
}
double AsDouble() const { double AsDouble() const {
CHECK(IsDouble()); CHECK(IsDouble());
return bit_cast<double>(number_bits_); return number_;
} }
bool IsObject() const { return object_ != nullptr; } bool IsObject() const { return object_ != nullptr; }
...@@ -223,12 +219,12 @@ class JSObjectField { ...@@ -223,12 +219,12 @@ class JSObjectField {
return object_; return object_;
} }
explicit JSObjectField(uint64_t value_bits) : number_bits_(value_bits) {} explicit JSObjectField(double value) : number_(value) {}
explicit JSObjectField(ObjectData* value) : object_(value) {} explicit JSObjectField(ObjectData* value) : object_(value) {}
private: private:
ObjectData* object_ = nullptr; ObjectData* object_ = nullptr;
uint64_t number_bits_ = 0; double number_ = 0;
}; };
class JSObjectData : public HeapObjectData { class JSObjectData : public HeapObjectData {
...@@ -1797,9 +1793,8 @@ void JSObjectData::SerializeRecursive(JSHeapBroker* broker, int depth) { ...@@ -1797,9 +1793,8 @@ void JSObjectData::SerializeRecursive(JSHeapBroker* broker, int depth) {
DCHECK_EQ(field_index.property_index(), DCHECK_EQ(field_index.property_index(),
static_cast<int>(inobject_fields_.size())); static_cast<int>(inobject_fields_.size()));
if (boilerplate->IsUnboxedDoubleField(field_index)) { if (boilerplate->IsUnboxedDoubleField(field_index)) {
uint64_t value_bits = double value = boilerplate->RawFastDoublePropertyAt(field_index);
boilerplate->RawFastDoublePropertyAsBitsAt(field_index); inobject_fields_.push_back(JSObjectField{value});
inobject_fields_.push_back(JSObjectField{value_bits});
} else { } else {
Handle<Object> value(boilerplate->RawFastPropertyAt(field_index), Handle<Object> value(boilerplate->RawFastPropertyAt(field_index),
isolate); isolate);
...@@ -2366,16 +2361,6 @@ double JSObjectRef::RawFastDoublePropertyAt(FieldIndex index) const { ...@@ -2366,16 +2361,6 @@ double JSObjectRef::RawFastDoublePropertyAt(FieldIndex index) const {
return object_data->GetInobjectField(index.property_index()).AsDouble(); return object_data->GetInobjectField(index.property_index()).AsDouble();
} }
uint64_t JSObjectRef::RawFastDoublePropertyAsBitsAt(FieldIndex index) const {
if (broker()->mode() == JSHeapBroker::kDisabled) {
AllowHandleDereference handle_dereference;
return object()->RawFastDoublePropertyAsBitsAt(index);
}
JSObjectData* object_data = data()->AsJSObject();
CHECK(index.is_inobject());
return object_data->GetInobjectField(index.property_index()).AsBitsOfDouble();
}
ObjectRef JSObjectRef::RawFastPropertyAt(FieldIndex index) const { ObjectRef JSObjectRef::RawFastPropertyAt(FieldIndex index) const {
if (broker()->mode() == JSHeapBroker::kDisabled) { if (broker()->mode() == JSHeapBroker::kDisabled) {
AllowHandleAllocation handle_allocation; AllowHandleAllocation handle_allocation;
......
...@@ -222,7 +222,6 @@ class JSObjectRef : public HeapObjectRef { ...@@ -222,7 +222,6 @@ class JSObjectRef : public HeapObjectRef {
using HeapObjectRef::HeapObjectRef; using HeapObjectRef::HeapObjectRef;
Handle<JSObject> object() const; Handle<JSObject> object() const;
uint64_t RawFastDoublePropertyAsBitsAt(FieldIndex index) const;
double RawFastDoublePropertyAt(FieldIndex index) const; double RawFastDoublePropertyAt(FieldIndex index) const;
ObjectRef RawFastPropertyAt(FieldIndex index) const; ObjectRef RawFastPropertyAt(FieldIndex index) const;
......
...@@ -2226,8 +2226,6 @@ JSNativeContextSpecialization::BuildPropertyStore( ...@@ -2226,8 +2226,6 @@ JSNativeContextSpecialization::BuildPropertyStore(
&control, if_exceptions, access_info); &control, if_exceptions, access_info);
} else { } else {
DCHECK(access_info.IsDataField() || access_info.IsDataConstant()); DCHECK(access_info.IsDataField() || access_info.IsDataConstant());
DCHECK(access_mode == AccessMode::kStore ||
access_mode == AccessMode::kStoreInLiteral);
FieldIndex const field_index = access_info.field_index(); FieldIndex const field_index = access_info.field_index();
Type const field_type = access_info.field_type(); Type const field_type = access_info.field_type();
MachineRepresentation const field_representation = MachineRepresentation const field_representation =
...@@ -2239,12 +2237,6 @@ JSNativeContextSpecialization::BuildPropertyStore( ...@@ -2239,12 +2237,6 @@ JSNativeContextSpecialization::BuildPropertyStore(
simplified()->LoadField(AccessBuilder::ForJSObjectPropertiesOrHash()), simplified()->LoadField(AccessBuilder::ForJSObjectPropertiesOrHash()),
storage, effect, control); storage, effect, control);
} }
PropertyConstness constness = access_info.IsDataConstant()
? PropertyConstness::kConst
: PropertyConstness::kMutable;
bool store_to_existing_constant_field = access_info.IsDataConstant() &&
access_mode == AccessMode::kStore &&
!access_info.HasTransitionMap();
FieldAccess field_access = { FieldAccess field_access = {
kTaggedBase, kTaggedBase,
field_index.offset(), field_index.offset(),
...@@ -2252,10 +2244,12 @@ JSNativeContextSpecialization::BuildPropertyStore( ...@@ -2252,10 +2244,12 @@ JSNativeContextSpecialization::BuildPropertyStore(
MaybeHandle<Map>(), MaybeHandle<Map>(),
field_type, field_type,
MachineType::TypeForRepresentation(field_representation), MachineType::TypeForRepresentation(field_representation),
kFullWriteBarrier, kFullWriteBarrier};
LoadSensitivity::kUnsafe, bool store_to_constant_field =
constness}; (access_mode == AccessMode::kStore) && access_info.IsDataConstant();
DCHECK(access_mode == AccessMode::kStore ||
access_mode == AccessMode::kStoreInLiteral);
switch (field_representation) { switch (field_representation) {
case MachineRepresentation::kFloat64: { case MachineRepresentation::kFloat64: {
value = effect = value = effect =
...@@ -2270,10 +2264,7 @@ JSNativeContextSpecialization::BuildPropertyStore( ...@@ -2270,10 +2264,7 @@ JSNativeContextSpecialization::BuildPropertyStore(
Type::OtherInternal()); Type::OtherInternal());
a.Store(AccessBuilder::ForMap(), a.Store(AccessBuilder::ForMap(),
factory()->mutable_heap_number_map()); factory()->mutable_heap_number_map());
FieldAccess value_field_access = a.Store(AccessBuilder::ForHeapNumberValue(), value);
AccessBuilder::ForHeapNumberValue();
value_field_access.constness = field_access.constness;
a.Store(value_field_access, value);
value = effect = a.Finish(); value = effect = a.Finish();
field_access.type = Type::Any(); field_access.type = Type::Any();
...@@ -2289,9 +2280,7 @@ JSNativeContextSpecialization::BuildPropertyStore( ...@@ -2289,9 +2280,7 @@ JSNativeContextSpecialization::BuildPropertyStore(
MaybeHandle<Map>(), MaybeHandle<Map>(),
Type::OtherInternal(), Type::OtherInternal(),
MachineType::TypeCompressedTaggedPointer(), MachineType::TypeCompressedTaggedPointer(),
kPointerWriteBarrier, kPointerWriteBarrier};
LoadSensitivity::kUnsafe,
constness};
storage = effect = storage = effect =
graph()->NewNode(simplified()->LoadField(storage_access), graph()->NewNode(simplified()->LoadField(storage_access),
storage, effect, control); storage, effect, control);
...@@ -2300,7 +2289,7 @@ JSNativeContextSpecialization::BuildPropertyStore( ...@@ -2300,7 +2289,7 @@ JSNativeContextSpecialization::BuildPropertyStore(
field_access.machine_type = MachineType::Float64(); field_access.machine_type = MachineType::Float64();
} }
} }
if (store_to_existing_constant_field) { if (store_to_constant_field) {
DCHECK(!access_info.HasTransitionMap()); DCHECK(!access_info.HasTransitionMap());
// If the field is constant check that the value we are going // If the field is constant check that the value we are going
// to store matches current value. // to store matches current value.
...@@ -2322,7 +2311,7 @@ JSNativeContextSpecialization::BuildPropertyStore( ...@@ -2322,7 +2311,7 @@ JSNativeContextSpecialization::BuildPropertyStore(
case MachineRepresentation::kCompressedSigned: case MachineRepresentation::kCompressedSigned:
case MachineRepresentation::kCompressedPointer: case MachineRepresentation::kCompressedPointer:
case MachineRepresentation::kCompressed: case MachineRepresentation::kCompressed:
if (store_to_existing_constant_field) { if (store_to_constant_field) {
DCHECK(!access_info.HasTransitionMap()); DCHECK(!access_info.HasTransitionMap());
// If the field is constant check that the value we are going // If the field is constant check that the value we are going
// to store matches current value. // to store matches current value.
......
...@@ -601,6 +601,9 @@ Node* LoadElimination::AbstractState::LookupField( ...@@ -601,6 +601,9 @@ Node* LoadElimination::AbstractState::LookupField(
if (AbstractField const* this_field = fields[index]) { if (AbstractField const* this_field = fields[index]) {
return this_field->Lookup(object); return this_field->Lookup(object);
} }
if (constness == PropertyConstness::kConst) {
return LookupField(object, index, PropertyConstness::kMutable);
}
return nullptr; return nullptr;
} }
...@@ -850,13 +853,8 @@ Reduction LoadElimination::ReduceLoadField(Node* node, ...@@ -850,13 +853,8 @@ Reduction LoadElimination::ReduceLoadField(Node* node,
} else { } else {
int field_index = FieldIndexOf(access); int field_index = FieldIndexOf(access);
if (field_index >= 0) { if (field_index >= 0) {
PropertyConstness constness = access.constness; if (Node* replacement =
Node* replacement = state->LookupField(object, field_index, constness); state->LookupField(object, field_index, access.constness)) {
if (!replacement && constness == PropertyConstness::kConst) {
replacement = state->LookupField(object, field_index,
PropertyConstness::kMutable);
}
if (replacement) {
// Make sure we don't resurrect dead {replacement} nodes. // Make sure we don't resurrect dead {replacement} nodes.
if (!replacement->IsDead()) { if (!replacement->IsDead()) {
// Introduce a TypeGuard if the type of the {replacement} node is not // Introduce a TypeGuard if the type of the {replacement} node is not
...@@ -875,8 +873,8 @@ Reduction LoadElimination::ReduceLoadField(Node* node, ...@@ -875,8 +873,8 @@ Reduction LoadElimination::ReduceLoadField(Node* node,
return Replace(replacement); return Replace(replacement);
} }
} }
state = state->AddField(object, field_index, node, access.name, constness, state = state->AddField(object, field_index, node, access.name,
zone()); access.constness, zone());
} }
} }
Handle<Map> field_map; Handle<Map> field_map;
...@@ -909,36 +907,16 @@ Reduction LoadElimination::ReduceStoreField(Node* node, ...@@ -909,36 +907,16 @@ Reduction LoadElimination::ReduceStoreField(Node* node,
} else { } else {
int field_index = FieldIndexOf(access); int field_index = FieldIndexOf(access);
if (field_index >= 0) { if (field_index >= 0) {
PropertyConstness constness = access.constness;
Node* const old_value = Node* const old_value =
state->LookupField(object, field_index, constness); state->LookupField(object, field_index, access.constness);
if (constness == PropertyConstness::kConst && old_value) {
// At runtime, we should never see two consecutive const stores, i.e.,
// DCHECK_NULL(old_value)
// ought to hold, but we might see such (unreachable) code statically.
Node* control = NodeProperties::GetControlInput(node);
Node* unreachable =
graph()->NewNode(common()->Unreachable(), effect, control);
return Replace(unreachable);
}
if (old_value == new_value) { if (old_value == new_value) {
// This store is fully redundant. // This store is fully redundant.
return Replace(effect); return Replace(effect);
} }
// Kill all potentially aliasing fields and record the new value. // Kill all potentially aliasing fields and record the new value.
state = state->KillField(object, field_index, access.name, zone()); state = state->KillField(object, field_index, access.name, zone());
state = state->AddField(object, field_index, new_value, access.name, state = state->AddField(object, field_index, new_value, access.name,
PropertyConstness::kMutable, zone()); access.constness, zone());
if (constness == PropertyConstness::kConst) {
// For const stores, we track information in both the const and the
// mutable world to guard against field accesses that should have
// been marked const, but were not.
state = state->AddField(object, field_index, new_value, access.name,
constness, zone());
}
} else { } else {
// Unsupported StoreField operator. // Unsupported StoreField operator.
state = state->KillFields(object, access.name, zone()); state = state->KillFields(object, access.name, zone());
...@@ -1221,13 +1199,10 @@ LoadElimination::AbstractState const* LoadElimination::ComputeLoopState( ...@@ -1221,13 +1199,10 @@ LoadElimination::AbstractState const* LoadElimination::ComputeLoopState(
MaybeHandle<Name>(), zone()); MaybeHandle<Name>(), zone());
break; break;
} }
case IrOpcode::kStoreField: { case IrOpcode::kStoreField:
FieldAccess access = FieldAccessOf(current->op()); state = ComputeLoopStateForStoreField(current, state,
if (access.constness == PropertyConstness::kMutable) { FieldAccessOf(current->op()));
state = ComputeLoopStateForStoreField(current, state, access);
}
break; break;
}
case IrOpcode::kStoreElement: { case IrOpcode::kStoreElement: {
Node* const object = NodeProperties::GetValueInput(current, 0); Node* const object = NodeProperties::GetValueInput(current, 0);
Node* const index = NodeProperties::GetValueInput(current, 1); Node* const index = NodeProperties::GetValueInput(current, 1);
......
...@@ -78,7 +78,7 @@ std::ostream& operator<<(std::ostream& os, FieldAccess const& access) { ...@@ -78,7 +78,7 @@ std::ostream& operator<<(std::ostream& os, FieldAccess const& access) {
} }
#endif #endif
os << access.type << ", " << access.machine_type << ", " os << access.type << ", " << access.machine_type << ", "
<< access.write_barrier_kind << ", " << access.constness; << access.write_barrier_kind;
if (FLAG_untrusted_code_mitigations) { if (FLAG_untrusted_code_mitigations) {
os << ", " << access.load_sensitivity; os << ", " << access.load_sensitivity;
} }
......
...@@ -401,8 +401,6 @@ inline PropertyConstness GeneralizeConstness(PropertyConstness a, ...@@ -401,8 +401,6 @@ inline PropertyConstness GeneralizeConstness(PropertyConstness a,
V8_EXPORT_PRIVATE std::ostream& operator<<( V8_EXPORT_PRIVATE std::ostream& operator<<(
std::ostream& os, const PropertyAttributes& attributes); std::ostream& os, const PropertyAttributes& attributes);
V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
PropertyConstness constness);
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -24,16 +24,6 @@ std::ostream& operator<<(std::ostream& os, ...@@ -24,16 +24,6 @@ std::ostream& operator<<(std::ostream& os,
return os; return os;
} }
std::ostream& operator<<(std::ostream& os, PropertyConstness constness) {
switch (constness) {
case PropertyConstness::kMutable:
return os << "mutable";
case PropertyConstness::kConst:
return os << "const";
}
UNREACHABLE();
}
Descriptor::Descriptor() : details_(Smi::zero()) {} Descriptor::Descriptor() : details_(Smi::zero()) {}
Descriptor::Descriptor(Handle<Name> key, const MaybeObjectHandle& value, Descriptor::Descriptor(Handle<Name> key, const MaybeObjectHandle& value,
......
...@@ -8,149 +8,21 @@ ...@@ -8,149 +8,21 @@
(function() { (function() {
function maybe_sideeffect(b) { return 42; } function maybe_sideeffect(b) { return 42; }
%NeverOptimizeFunction(maybe_sideeffect); function f(k) {
class B {
constructor(x) {
this.value = x;
}
}
%EnsureFeedbackVectorForFunction(B);
function lit_const_smi() {
let b = { value: 123 };
maybe_sideeffect(b);
let v1 = b.value;
maybe_sideeffect(b);
let v2 = b.value;
%TurbofanStaticAssert(Object.is(v1, v2));
%TurbofanStaticAssert(Object.is(v2, 123));
}
lit_const_smi(); lit_const_smi();
%OptimizeFunctionOnNextCall(lit_const_smi); lit_const_smi();
function lit_const_object() {
let o = {x: 123};
let b = { value: o };
maybe_sideeffect(b);
let v1 = b.value;
maybe_sideeffect(b);
let v2 = b.value;
%TurbofanStaticAssert(Object.is(v1, v2));
%TurbofanStaticAssert(Object.is(v2, o));
}
lit_const_object(); lit_const_object();
%OptimizeFunctionOnNextCall(lit_const_object); lit_const_object();
function lit_computed_smi(k) {
let kk = 2 * k;
let b = { value: kk };
maybe_sideeffect(b);
let v1 = b.value;
maybe_sideeffect(b);
let v2 = b.value;
%TurbofanStaticAssert(Object.is(v1, v2));
%TurbofanStaticAssert(Object.is(v2, kk));
}
lit_computed_smi(1); lit_computed_smi(2);
%OptimizeFunctionOnNextCall(lit_computed_smi); lit_computed_smi(3);
// TODO(bmeurer): Fix const tracking for double fields in object literals
// lit_computed_smi(1.1); lit_computed_smi(2.2);
// %OptimizeFunctionOnNextCall(lit_computed_smi); lit_computed_smi(3.3);
function lit_param_object(k) {
let b = { value: k }; let b = { value: k };
maybe_sideeffect(b); maybe_sideeffect(b);
let v1 = b.value; let v1 = b.value;
maybe_sideeffect(b); maybe_sideeffect(b);
let v2 = b.value; let v2 = b.value;
%TurbofanStaticAssert(Object.is(v1, v2)); %TurbofanStaticAssert(v1 == v2);
%TurbofanStaticAssert(Object.is(v2, k)); // TODO(gsps): Improve analysis to also propagate stored value
// Eventually, this should also work:
// %TurbofanStaticAssert(v2 == k);
} }
lit_param_object({x: 1}); lit_param_object({x: 2}); %NeverOptimizeFunction(maybe_sideeffect);
%OptimizeFunctionOnNextCall(lit_param_object); lit_param_object({x: 3}); f(1);
f(2);
%OptimizeFunctionOnNextCall(f);
function nested_lit_param(k) { f(3);
let b = { x: { value: k } };
maybe_sideeffect(b);
let v1 = b.x.value;
maybe_sideeffect(b);
let v2 = b.x.value;
%TurbofanStaticAssert(Object.is(v1, v2));
%TurbofanStaticAssert(Object.is(v2, k));
}
nested_lit_param(1); nested_lit_param(2);
%OptimizeFunctionOnNextCall(nested_lit_param); nested_lit_param(3);
// TODO(bmeurer): Fix const tracking for double fields in object literals
// nested_lit_param(1.1); nested_lit_param(2.2);
// %OptimizeFunctionOnNextCall(nested_lit_param); nested_lit_param(3.3);
function nested_lit_param_object(k) {
let b = { x: { value: k } };
maybe_sideeffect(b);
let v1 = b.x.value;
maybe_sideeffect(b);
let v2 = b.x.value;
%TurbofanStaticAssert(Object.is(v1, v2));
%TurbofanStaticAssert(Object.is(v2, k));
}
nested_lit_param_object({x: 1}); nested_lit_param_object({x: 2});
%OptimizeFunctionOnNextCall(nested_lit_param_object);
nested_lit_param_object({x: 3});
%EnsureFeedbackVectorForFunction(inst_param);
function inst_param(k) {
let b = new B(k);
maybe_sideeffect(b);
let v1 = b.value;
maybe_sideeffect(b);
let v2 = b.value;
%TurbofanStaticAssert(Object.is(v1, v2));
%TurbofanStaticAssert(Object.is(v2, k));
}
inst_param(1); inst_param(2);
%OptimizeFunctionOnNextCall(inst_param); inst_param(3);
// TODO(gsps): Reenable once we fully support const field information
// tracking in the presence of pointer compression.
// inst_param(1.1); inst_param(2.2);
// %OptimizeFunctionOnNextCall(inst_param); inst_param(3.3);
inst_param({x: 1}); inst_param({x: 2});
%OptimizeFunctionOnNextCall(inst_param); inst_param({x: 3});
%EnsureFeedbackVectorForFunction(inst_computed);
function inst_computed(k) {
let kk = 2 * k;
let b = new B(kk);
maybe_sideeffect(b);
let v1 = b.value;
maybe_sideeffect(b);
let v2 = b.value;
%TurbofanStaticAssert(Object.is(v1, v2));
%TurbofanStaticAssert(Object.is(v2, kk));
}
inst_computed(1); inst_computed(2);
%OptimizeFunctionOnNextCall(inst_computed); inst_computed(3);
inst_computed(1.1); inst_computed(2.2);
%OptimizeFunctionOnNextCall(inst_computed); inst_computed(3.3);
})(); })();
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