Commit e1088b27 authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Initial support for monomorphic/polymorphic property loads.

Native context specialization now lowers monomorphic and
polymorphic accesses to data and constant data properties on
object and/or prototype chain. We don't deal with accessors
yet, and we also completely ignore proxies (which is compatible
with what Crankshaft does).

The code is more or less the straightforward implementation. We
will need to refactor that and extract common patterns once the
remaining bits for full load/store support is in.

CQ_INCLUDE_TRYBOTS=tryserver.v8:v8_linux_nosnap_rel
R=jarin@chromium.org
BUG=v8:4470
LOG=n

Committed: https://crrev.com/3a0bf860b7177f7abef01ff308a53603389d958e
Cr-Commit-Position: refs/heads/master@{#31340}

Review URL: https://codereview.chromium.org/1396333010

Cr-Commit-Position: refs/heads/master@{#31352}
parent fc4da977
...@@ -106,6 +106,15 @@ void CompilationDependencies::Rollback() { ...@@ -106,6 +106,15 @@ void CompilationDependencies::Rollback() {
} }
void CompilationDependencies::AssumeMapStable(Handle<Map> map) {
DCHECK(map->is_stable());
// Do nothing if the map cannot transition.
if (map->CanTransition()) {
Insert(DependentCode::kPrototypeCheckGroup, map);
}
}
void CompilationDependencies::AssumeTransitionStable( void CompilationDependencies::AssumeTransitionStable(
Handle<AllocationSite> site) { Handle<AllocationSite> site) {
// Do nothing if the object doesn't have any useful element transitions left. // Do nothing if the object doesn't have any useful element transitions left.
......
...@@ -31,6 +31,7 @@ class CompilationDependencies { ...@@ -31,6 +31,7 @@ class CompilationDependencies {
void AssumeFieldType(Handle<Map> map) { void AssumeFieldType(Handle<Map> map) {
Insert(DependentCode::kFieldTypeGroup, map); Insert(DependentCode::kFieldTypeGroup, map);
} }
void AssumeMapStable(Handle<Map> map);
void AssumePropertyCell(Handle<PropertyCell> cell) { void AssumePropertyCell(Handle<PropertyCell> cell) {
Insert(DependentCode::kPropertyCellChangedGroup, cell); Insert(DependentCode::kPropertyCellChangedGroup, cell);
} }
......
...@@ -9,8 +9,10 @@ ...@@ -9,8 +9,10 @@
#include "src/compiler/js-graph.h" #include "src/compiler/js-graph.h"
#include "src/compiler/js-operator.h" #include "src/compiler/js-operator.h"
#include "src/contexts.h" #include "src/contexts.h"
#include "src/field-index-inl.h"
#include "src/lookup.h" #include "src/lookup.h"
#include "src/objects-inl.h" // TODO(mstarzinger): Temporary cycle breaker! #include "src/objects-inl.h" // TODO(mstarzinger): Temporary cycle breaker!
#include "src/type-feedback-vector.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -25,12 +27,14 @@ struct JSGlobalSpecialization::ScriptContextTableLookupResult { ...@@ -25,12 +27,14 @@ struct JSGlobalSpecialization::ScriptContextTableLookupResult {
JSGlobalSpecialization::JSGlobalSpecialization( JSGlobalSpecialization::JSGlobalSpecialization(
Editor* editor, JSGraph* jsgraph, Flags flags, Editor* editor, JSGraph* jsgraph, Flags flags,
Handle<GlobalObject> global_object, CompilationDependencies* dependencies) Handle<GlobalObject> global_object, CompilationDependencies* dependencies,
Zone* zone)
: AdvancedReducer(editor), : AdvancedReducer(editor),
jsgraph_(jsgraph), jsgraph_(jsgraph),
flags_(flags), flags_(flags),
global_object_(global_object), global_object_(global_object),
dependencies_(dependencies) {} dependencies_(dependencies),
zone_(zone) {}
Reduction JSGlobalSpecialization::Reduce(Node* node) { Reduction JSGlobalSpecialization::Reduce(Node* node) {
...@@ -39,6 +43,8 @@ Reduction JSGlobalSpecialization::Reduce(Node* node) { ...@@ -39,6 +43,8 @@ Reduction JSGlobalSpecialization::Reduce(Node* node) {
return ReduceJSLoadGlobal(node); return ReduceJSLoadGlobal(node);
case IrOpcode::kJSStoreGlobal: case IrOpcode::kJSStoreGlobal:
return ReduceJSStoreGlobal(node); return ReduceJSStoreGlobal(node);
case IrOpcode::kJSLoadNamed:
return ReduceJSLoadNamed(node);
default: default:
break; break;
} }
...@@ -230,11 +236,375 @@ Reduction JSGlobalSpecialization::ReduceJSStoreGlobal(Node* node) { ...@@ -230,11 +236,375 @@ Reduction JSGlobalSpecialization::ReduceJSStoreGlobal(Node* node) {
} }
Reduction JSGlobalSpecialization::Replace(Node* node, Handle<Object> value) { // This class encapsulates all information required to access a certain
// TODO(bmeurer): Move this to JSGraph::HeapConstant instead? // object property, either on the object itself or on the prototype chain.
if (value->IsConsString()) { class JSGlobalSpecialization::PropertyAccessInfo final {
value = String::Flatten(Handle<String>::cast(value), TENURED); public:
enum Kind { kInvalid, kData, kDataConstant };
static PropertyAccessInfo DataConstant(Type* receiver_type,
Handle<Object> constant,
MaybeHandle<JSObject> holder) {
return PropertyAccessInfo(holder, constant, receiver_type);
}
static PropertyAccessInfo Data(Type* receiver_type, FieldIndex field_index,
Representation field_representation,
MaybeHandle<JSObject> holder) {
return PropertyAccessInfo(holder, field_index, field_representation,
receiver_type);
}
PropertyAccessInfo() : kind_(kInvalid) {}
PropertyAccessInfo(MaybeHandle<JSObject> holder, Handle<Object> constant,
Type* receiver_type)
: kind_(kDataConstant),
receiver_type_(receiver_type),
constant_(constant),
holder_(holder) {}
PropertyAccessInfo(MaybeHandle<JSObject> holder, FieldIndex field_index,
Representation field_representation, Type* receiver_type)
: kind_(kData),
receiver_type_(receiver_type),
holder_(holder),
field_index_(field_index),
field_representation_(field_representation) {}
bool IsDataConstant() const { return kind() == kDataConstant; }
bool IsData() const { return kind() == kData; }
Kind kind() const { return kind_; }
MaybeHandle<JSObject> holder() const { return holder_; }
Handle<Object> constant() const { return constant_; }
FieldIndex field_index() const { return field_index_; }
Representation field_representation() const { return field_representation_; }
Type* receiver_type() const { return receiver_type_; }
private:
Kind kind_;
Type* receiver_type_;
Handle<Object> constant_;
MaybeHandle<JSObject> holder_;
FieldIndex field_index_;
Representation field_representation_;
};
namespace {
bool CanInlinePropertyAccess(Handle<Map> map) {
// TODO(bmeurer): Do something about the number stuff.
if (map->instance_type() == HEAP_NUMBER_TYPE) return false;
if (map->instance_type() < FIRST_NONSTRING_TYPE) return true;
return map->IsJSObjectMap() && !map->is_dictionary_map() &&
!map->has_named_interceptor() &&
// TODO(verwaest): Whitelist contexts to which we have access.
!map->is_access_check_needed();
}
} // namespace
bool JSGlobalSpecialization::ComputePropertyAccessInfo(
Handle<Map> map, Handle<Name> name, PropertyAccessInfo* access_info) {
MaybeHandle<JSObject> holder;
Type* receiver_type = Type::Class(map, graph()->zone());
while (CanInlinePropertyAccess(map)) {
// Lookup the named property on the {map}.
Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate());
int const number = descriptors->SearchWithCache(*name, *map);
if (number != DescriptorArray::kNotFound) {
PropertyDetails const details = descriptors->GetDetails(number);
if (details.type() == DATA_CONSTANT) {
*access_info = PropertyAccessInfo::DataConstant(
receiver_type, handle(descriptors->GetValue(number), isolate()),
holder);
return true;
} else if (details.type() == DATA) {
int index = descriptors->GetFieldIndex(number);
Representation field_representation = details.representation();
FieldIndex field_index = FieldIndex::ForPropertyIndex(
*map, index, field_representation.IsDouble());
*access_info = PropertyAccessInfo::Data(receiver_type, field_index,
field_representation, holder);
return true;
} else {
// TODO(bmeurer): Add support for accessors.
break;
}
}
// Don't search on the prototype chain for special indices in case of
// integer indexed exotic objects (see ES6 section 9.4.5).
if (map->IsJSTypedArrayMap() && name->IsString() &&
IsSpecialIndex(isolate()->unicode_cache(), String::cast(*name))) {
break;
}
// Walk up the prototype chain.
if (!map->prototype()->IsJSObject()) {
// TODO(bmeurer): Handle the not found case if the prototype is null.
break;
}
Handle<JSObject> map_prototype(JSObject::cast(map->prototype()), isolate());
if (map_prototype->map()->is_deprecated()) {
// Try to migrate the prototype object so we don't embed the deprecated
// map into the optimized code.
JSObject::TryMigrateInstance(map_prototype);
}
map = handle(map_prototype->map(), isolate());
holder = map_prototype;
}
return false;
}
bool JSGlobalSpecialization::ComputePropertyAccessInfos(
MapHandleList const& maps, Handle<Name> name,
ZoneVector<PropertyAccessInfo>* access_infos) {
for (Handle<Map> map : maps) {
PropertyAccessInfo access_info;
if (!ComputePropertyAccessInfo(map, name, &access_info)) return false;
access_infos->push_back(access_info);
}
return true;
}
Reduction JSGlobalSpecialization::ReduceJSLoadNamed(Node* node) {
DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode());
LoadNamedParameters const p = LoadNamedParametersOf(node->op());
Handle<Name> name = p.name();
Node* receiver = NodeProperties::GetValueInput(node, 0);
Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
// Not much we can do if deoptimization support is disabled.
if (!(flags() & kDeoptimizationEnabled)) return NoChange();
// Extract receiver maps from the LOAD_IC using the LoadICNexus.
MapHandleList receiver_maps;
if (!p.feedback().IsValid()) return NoChange();
LoadICNexus nexus(p.feedback().vector(), p.feedback().slot());
if (nexus.ExtractMaps(&receiver_maps) == 0) return NoChange();
DCHECK_LT(0, receiver_maps.length());
// Compute property access infos for the receiver maps.
ZoneVector<PropertyAccessInfo> access_infos(zone());
if (!ComputePropertyAccessInfos(receiver_maps, name, &access_infos)) {
return NoChange();
}
DCHECK(!access_infos.empty());
// The final states for every polymorphic branch. We join them with
// Merge+Phi+EffectPhi at the bottom.
ZoneVector<Node*> values(zone());
ZoneVector<Node*> effects(zone());
ZoneVector<Node*> controls(zone());
// The list of "exiting" controls, which currently go to a single deoptimize.
// TODO(bmeurer): Consider using an IC as fallback.
Node* const exit_effect = effect;
ZoneVector<Node*> exit_controls(zone());
// Ensure that {receiver} is a heap object.
Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver);
Node* branch =
graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
exit_controls.push_back(graph()->NewNode(common()->IfTrue(), branch));
control = graph()->NewNode(common()->IfFalse(), branch);
// Load the {receiver} map. The resulting effect is the dominating effect for
// all (polymorphic) branches.
Node* receiver_map = effect =
graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
receiver, effect, control);
// Generate code for the various different property access patterns.
Node* fallthrough_control = control;
for (PropertyAccessInfo const& access_info : access_infos) {
Node* this_value = receiver;
Node* this_effect = effect;
Node* this_control;
// Perform map check on {receiver}.
Type* receiver_type = access_info.receiver_type();
if (receiver_type->Is(Type::String())) {
// Emit an instance type check for strings.
Node* receiver_instance_type = this_effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
receiver_map, this_effect, fallthrough_control);
Node* check =
graph()->NewNode(machine()->Uint32LessThan(), receiver_instance_type,
jsgraph()->Uint32Constant(FIRST_NONSTRING_TYPE));
Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
check, fallthrough_control);
fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
this_control = graph()->NewNode(common()->IfTrue(), branch);
} else {
// Emit a (sequence of) map checks for other properties.
ZoneVector<Node*> this_controls(zone());
for (auto i = access_info.receiver_type()->Classes(); !i.Done();
i.Advance()) {
Handle<Map> map = i.Current();
Node* check =
graph()->NewNode(simplified()->ReferenceEqual(Type::Internal()),
receiver_map, jsgraph()->Constant(map));
Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
check, fallthrough_control);
this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch));
fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
}
int const this_control_count = static_cast<int>(this_controls.size());
this_control =
(this_control_count == 1)
? this_controls.front()
: graph()->NewNode(common()->Merge(this_control_count),
this_control_count, &this_controls.front());
}
// Determine actual holder and perform prototype chain checks.
Handle<JSObject> holder;
if (access_info.holder().ToHandle(&holder)) {
this_value = jsgraph()->Constant(holder);
for (auto i = access_info.receiver_type()->Classes(); !i.Done();
i.Advance()) {
Handle<Map> map = i.Current();
PrototypeIterator j(map);
while (true) {
// Check that the {prototype} still has the same map. For stable
// maps, we can add a stability dependency on the prototype map;
// for everything else we need to perform a map check at runtime.
Handle<JSReceiver> prototype =
PrototypeIterator::GetCurrent<JSReceiver>(j);
if (prototype->map()->is_stable()) {
dependencies()->AssumeMapStable(
handle(prototype->map(), isolate()));
} else {
Node* prototype_map = this_effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForMap()),
jsgraph()->Constant(prototype), this_effect, this_control);
Node* check = graph()->NewNode(
simplified()->ReferenceEqual(Type::Internal()), prototype_map,
jsgraph()->Constant(handle(prototype->map(), isolate())));
Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
check, this_control);
exit_controls.push_back(
graph()->NewNode(common()->IfFalse(), branch));
this_control = graph()->NewNode(common()->IfTrue(), branch);
}
// Stop once we get to the holder.
if (prototype.is_identical_to(holder)) break;
j.Advance();
}
}
}
// Generate the actual property access.
if (access_info.IsDataConstant()) {
this_value = jsgraph()->Constant(access_info.constant());
} else {
// TODO(bmeurer): This is sort of adhoc, and must be refactored into some
// common code once we also have support for stores.
DCHECK(access_info.IsData());
FieldIndex const field_index = access_info.field_index();
Representation const field_representation =
access_info.field_representation();
if (!field_index.is_inobject()) {
this_value = this_effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSObjectProperties()),
this_value, this_effect, this_control);
}
FieldAccess field_access;
field_access.base_is_tagged = kTaggedBase;
field_access.offset = field_index.offset();
field_access.name = name;
field_access.type = Type::Any();
field_access.machine_type = kMachAnyTagged;
if (field_representation.IsSmi()) {
field_access.type = Type::Intersect(
Type::SignedSmall(), Type::TaggedSigned(), graph()->zone());
} else if (field_representation.IsDouble()) {
if (!field_index.is_inobject() || field_index.is_hidden_field() ||
!FLAG_unbox_double_fields) {
this_value = this_effect =
graph()->NewNode(simplified()->LoadField(field_access),
this_value, this_effect, this_control);
field_access.offset = HeapNumber::kValueOffset;
field_access.name = MaybeHandle<Name>();
}
field_access.type = Type::Intersect(
Type::Number(), Type::UntaggedFloat64(), graph()->zone());
field_access.machine_type = kMachFloat64;
} else if (field_representation.IsHeapObject()) {
field_access.type = Type::TaggedPointer();
}
this_value = this_effect =
graph()->NewNode(simplified()->LoadField(field_access), this_value,
this_effect, this_control);
}
// Remember the final state for this property access.
values.push_back(this_value);
effects.push_back(this_effect);
controls.push_back(this_control);
} }
// Collect the fallthru control as final "exit" control.
exit_controls.push_back(fallthrough_control);
// TODO(bmeurer/mtrofin): Splintering cannot currently deal with deferred
// blocks that contain only a single non-deoptimize instruction (i.e. a
// jump). Generating a single Merge here, which joins all the deoptimizing
// controls would generate a lot of these basic blocks, however. So this
// is disabled for now until splintering is fixed.
#if 0
// Generate the single "exit" point, where we get if either all map/instance
// type checks failed, or one of the assumptions inside one of the cases
// failes (i.e. failing prototype chain check).
// TODO(bmeurer): Consider falling back to IC here if deoptimization is
// disabled.
int const exit_control_count = static_cast<int>(exit_controls.size());
Node* exit_control =
(exit_control_count == 1)
? exit_controls.front()
: graph()->NewNode(common()->Merge(exit_control_count),
exit_control_count, &exit_controls.front());
Node* deoptimize = graph()->NewNode(common()->Deoptimize(), frame_state,
exit_effect, exit_control);
// TODO(bmeurer): This should be on the AdvancedReducer somehow.
NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
#else
for (Node* const exit_control : exit_controls) {
Node* deoptimize = graph()->NewNode(common()->Deoptimize(), frame_state,
exit_effect, exit_control);
// TODO(bmeurer): This should be on the AdvancedReducer somehow.
NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
}
#endif
// Generate the final merge point for all (polymorphic) branches.
Node* value;
int const control_count = static_cast<int>(controls.size());
if (control_count == 1) {
value = values.front();
effect = effects.front();
control = controls.front();
} else {
control = graph()->NewNode(common()->Merge(control_count), control_count,
&controls.front());
values.push_back(control);
value = graph()->NewNode(common()->Phi(kMachAnyTagged, control_count),
control_count + 1, &values.front());
effects.push_back(control);
effect = graph()->NewNode(common()->EffectPhi(control_count),
control_count + 1, &effects.front());
}
return Replace(node, value, effect, control);
}
Reduction JSGlobalSpecialization::Replace(Node* node, Handle<Object> value) {
return Replace(node, jsgraph()->Constant(value)); return Replace(node, jsgraph()->Constant(value));
} }
...@@ -267,6 +637,11 @@ Isolate* JSGlobalSpecialization::isolate() const { ...@@ -267,6 +637,11 @@ Isolate* JSGlobalSpecialization::isolate() const {
} }
MachineOperatorBuilder* JSGlobalSpecialization::machine() const {
return jsgraph()->machine();
}
CommonOperatorBuilder* JSGlobalSpecialization::common() const { CommonOperatorBuilder* JSGlobalSpecialization::common() const {
return jsgraph()->common(); return jsgraph()->common();
} }
......
...@@ -22,6 +22,7 @@ namespace compiler { ...@@ -22,6 +22,7 @@ namespace compiler {
class CommonOperatorBuilder; class CommonOperatorBuilder;
class JSGraph; class JSGraph;
class JSOperatorBuilder; class JSOperatorBuilder;
class MachineOperatorBuilder;
// Specializes a given JSGraph to a given GlobalObject, potentially constant // Specializes a given JSGraph to a given GlobalObject, potentially constant
...@@ -38,13 +39,14 @@ class JSGlobalSpecialization final : public AdvancedReducer { ...@@ -38,13 +39,14 @@ class JSGlobalSpecialization final : public AdvancedReducer {
JSGlobalSpecialization(Editor* editor, JSGraph* jsgraph, Flags flags, JSGlobalSpecialization(Editor* editor, JSGraph* jsgraph, Flags flags,
Handle<GlobalObject> global_object, Handle<GlobalObject> global_object,
CompilationDependencies* dependencies); CompilationDependencies* dependencies, Zone* zone);
Reduction Reduce(Node* node) final; Reduction Reduce(Node* node) final;
private: private:
Reduction ReduceJSLoadGlobal(Node* node); Reduction ReduceJSLoadGlobal(Node* node);
Reduction ReduceJSStoreGlobal(Node* node); Reduction ReduceJSStoreGlobal(Node* node);
Reduction ReduceJSLoadNamed(Node* node);
Reduction Replace(Node* node, Node* value, Node* effect = nullptr, Reduction Replace(Node* node, Node* value, Node* effect = nullptr,
Node* control = nullptr) { Node* control = nullptr) {
...@@ -53,6 +55,12 @@ class JSGlobalSpecialization final : public AdvancedReducer { ...@@ -53,6 +55,12 @@ class JSGlobalSpecialization final : public AdvancedReducer {
} }
Reduction Replace(Node* node, Handle<Object> value); Reduction Replace(Node* node, Handle<Object> value);
class PropertyAccessInfo;
bool ComputePropertyAccessInfo(Handle<Map> map, Handle<Name> name,
PropertyAccessInfo* access_info);
bool ComputePropertyAccessInfos(MapHandleList const& maps, Handle<Name> name,
ZoneVector<PropertyAccessInfo>* access_infos);
struct ScriptContextTableLookupResult; struct ScriptContextTableLookupResult;
bool LookupInScriptContextTable(Handle<Name> name, bool LookupInScriptContextTable(Handle<Name> name,
ScriptContextTableLookupResult* result); ScriptContextTableLookupResult* result);
...@@ -63,14 +71,17 @@ class JSGlobalSpecialization final : public AdvancedReducer { ...@@ -63,14 +71,17 @@ class JSGlobalSpecialization final : public AdvancedReducer {
CommonOperatorBuilder* common() const; CommonOperatorBuilder* common() const;
JSOperatorBuilder* javascript() const; JSOperatorBuilder* javascript() const;
SimplifiedOperatorBuilder* simplified() const; SimplifiedOperatorBuilder* simplified() const;
MachineOperatorBuilder* machine() const;
Flags flags() const { return flags_; } Flags flags() const { return flags_; }
Handle<GlobalObject> global_object() const { return global_object_; } Handle<GlobalObject> global_object() const { return global_object_; }
CompilationDependencies* dependencies() const { return dependencies_; } CompilationDependencies* dependencies() const { return dependencies_; }
Zone* zone() const { return zone_; }
JSGraph* const jsgraph_; JSGraph* const jsgraph_;
Flags const flags_; Flags const flags_;
Handle<GlobalObject> global_object_; Handle<GlobalObject> global_object_;
CompilationDependencies* const dependencies_; CompilationDependencies* const dependencies_;
Zone* const zone_;
DISALLOW_COPY_AND_ASSIGN(JSGlobalSpecialization); DISALLOW_COPY_AND_ASSIGN(JSGlobalSpecialization);
}; };
......
...@@ -11,8 +11,11 @@ namespace v8 { ...@@ -11,8 +11,11 @@ namespace v8 {
namespace internal { namespace internal {
namespace compiler { namespace compiler {
Node* JSGraph::ImmovableHeapConstant(Handle<HeapObject> object) { Node* JSGraph::ImmovableHeapConstant(Handle<HeapObject> value) {
return graph()->NewNode(common()->HeapConstant(object)); if (value->IsConsString()) {
value = String::Flatten(Handle<String>::cast(value), TENURED);
}
return graph()->NewNode(common()->HeapConstant(value));
} }
...@@ -78,7 +81,7 @@ Node* JSGraph::HeapConstant(Handle<HeapObject> value) { ...@@ -78,7 +81,7 @@ Node* JSGraph::HeapConstant(Handle<HeapObject> value) {
// TODO(titzer): We could also match against the addresses of immortable // TODO(titzer): We could also match against the addresses of immortable
// immovables here, even without access to the heap, thus always // immovables here, even without access to the heap, thus always
// canonicalizing references to them. // canonicalizing references to them.
return graph()->NewNode(common()->HeapConstant(value)); return ImmovableHeapConstant(value);
} }
......
...@@ -369,7 +369,8 @@ Reduction JSInliner::ReduceJSCallFunction(Node* node, ...@@ -369,7 +369,8 @@ Reduction JSInliner::ReduceJSCallFunction(Node* node,
info.is_deoptimization_enabled() info.is_deoptimization_enabled()
? JSGlobalSpecialization::kDeoptimizationEnabled ? JSGlobalSpecialization::kDeoptimizationEnabled
: JSGlobalSpecialization::kNoFlags, : JSGlobalSpecialization::kNoFlags,
handle(info.global_object(), info.isolate()), info_->dependencies()); handle(info.global_object(), info.isolate()), info_->dependencies(),
local_zone_);
graph_reducer.AddReducer(&dead_code_elimination); graph_reducer.AddReducer(&dead_code_elimination);
graph_reducer.AddReducer(&common_reducer); graph_reducer.AddReducer(&common_reducer);
graph_reducer.AddReducer(&global_specialization); graph_reducer.AddReducer(&global_specialization);
......
...@@ -519,7 +519,7 @@ struct NativeContextSpecializationPhase { ...@@ -519,7 +519,7 @@ struct NativeContextSpecializationPhase {
? JSGlobalSpecialization::kDeoptimizationEnabled ? JSGlobalSpecialization::kDeoptimizationEnabled
: JSGlobalSpecialization::kNoFlags, : JSGlobalSpecialization::kNoFlags,
handle(data->info()->global_object(), data->isolate()), handle(data->info()->global_object(), data->isolate()),
data->info()->dependencies()); data->info()->dependencies(), temp_zone);
AddReducer(data, &graph_reducer, &dead_code_elimination); AddReducer(data, &graph_reducer, &dead_code_elimination);
AddReducer(data, &graph_reducer, &common_reducer); AddReducer(data, &graph_reducer, &common_reducer);
AddReducer(data, &graph_reducer, &global_specialization); AddReducer(data, &graph_reducer, &global_specialization);
......
...@@ -19,6 +19,8 @@ class Map; ...@@ -19,6 +19,8 @@ class Map;
// index it was originally generated from. // index it was originally generated from.
class FieldIndex final { class FieldIndex final {
public: public:
FieldIndex() : bit_field_(0) {}
static FieldIndex ForPropertyIndex(Map* map, static FieldIndex ForPropertyIndex(Map* map,
int index, int index,
bool is_double = false); bool is_double = false);
......
...@@ -4905,6 +4905,7 @@ bool Map::IsJSGlobalProxyMap() { ...@@ -4905,6 +4905,7 @@ bool Map::IsJSGlobalProxyMap() {
bool Map::IsJSGlobalObjectMap() { bool Map::IsJSGlobalObjectMap() {
return instance_type() == JS_GLOBAL_OBJECT_TYPE; return instance_type() == JS_GLOBAL_OBJECT_TYPE;
} }
bool Map::IsJSTypedArrayMap() { return instance_type() == JS_TYPED_ARRAY_TYPE; }
bool Map::IsGlobalObjectMap() { bool Map::IsGlobalObjectMap() {
const InstanceType type = instance_type(); const InstanceType type = instance_type();
return type == JS_GLOBAL_OBJECT_TYPE || type == JS_BUILTINS_OBJECT_TYPE; return type == JS_GLOBAL_OBJECT_TYPE || type == JS_BUILTINS_OBJECT_TYPE;
......
...@@ -5878,6 +5878,7 @@ class Map: public HeapObject { ...@@ -5878,6 +5878,7 @@ class Map: public HeapObject {
inline bool IsJSProxyMap(); inline bool IsJSProxyMap();
inline bool IsJSGlobalProxyMap(); inline bool IsJSGlobalProxyMap();
inline bool IsJSGlobalObjectMap(); inline bool IsJSGlobalObjectMap();
inline bool IsJSTypedArrayMap();
inline bool IsGlobalObjectMap(); inline bool IsGlobalObjectMap();
inline bool CanOmitMapChecks(); inline bool CanOmitMapChecks();
......
...@@ -90,7 +90,6 @@ function f3(one) { ...@@ -90,7 +90,6 @@ function f3(one) {
for (var j = 0; j < 5; ++j) f3(1); for (var j = 0; j < 5; ++j) f3(1);
%OptimizeFunctionOnNextCall(f3); %OptimizeFunctionOnNextCall(f3);
f3(1); f3(1);
assertTrue(%GetOptimizationStatus(f3) != 2);
......
...@@ -88,7 +88,6 @@ function f3(one) { ...@@ -88,7 +88,6 @@ function f3(one) {
for (var j = 0; j < 5; ++j) f3(1); for (var j = 0; j < 5; ++j) f3(1);
%OptimizeFunctionOnNextCall(f3); %OptimizeFunctionOnNextCall(f3);
f3(1); f3(1);
assertTrue(%GetOptimizationStatus(f3) != 2);
......
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