[turbofan] Decouple inlining and native context specialization.
Retrieve the native context/global object from the Node being specialized in the JSNativeContextSpecialization and the JSGlobalObjectSpecialization classes. For this we introduce two new methods NodeProperties::GetSpecializationNativeContext and NodeProperties::GetSpecializationGlobalObject, which walk up the context chain and might in the end take the native context from the outermost activation (if native context specialization is enabled). This allows us to run the native context specialization pass as part of the inlining phase without hacking some of that into the JSInliner. Also refactor the NodeProperties::GetSpecializationContext method that was previously local to the JSContextSpecialization. Also refactor two other oddities in JSNativeContextSpecialization. R=jarin@chromium.org BUG=v8:4470, v8:4493 LOG=n Review URL: https://codereview.chromium.org/1451143005 Cr-Commit-Position: refs/heads/master@{#32076}
This commit is contained in:
parent
a9fa0498e1
commit
9b14e5bb63
@ -124,6 +124,20 @@ void CompilationDependencies::AssumeMapStable(Handle<Map> map) {
|
||||
}
|
||||
|
||||
|
||||
void CompilationDependencies::AssumePrototypeMapsStable(
|
||||
Handle<Map> map, MaybeHandle<JSReceiver> prototype) {
|
||||
for (PrototypeIterator i(map); !i.IsAtEnd(); i.Advance()) {
|
||||
Handle<JSReceiver> const current =
|
||||
PrototypeIterator::GetCurrent<JSReceiver>(i);
|
||||
AssumeMapStable(handle(current->map()));
|
||||
Handle<JSReceiver> last;
|
||||
if (prototype.ToHandle(&last) && last.is_identical_to(current)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CompilationDependencies::AssumeTransitionStable(
|
||||
Handle<AllocationSite> site) {
|
||||
// Do nothing if the object doesn't have any useful element transitions left.
|
||||
@ -135,5 +149,6 @@ void CompilationDependencies::AssumeTransitionStable(
|
||||
Insert(DependentCode::kAllocationSiteTransitionChangedGroup, site);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -32,6 +32,9 @@ class CompilationDependencies {
|
||||
Insert(DependentCode::kFieldTypeGroup, map);
|
||||
}
|
||||
void AssumeMapStable(Handle<Map> map);
|
||||
void AssumePrototypeMapsStable(
|
||||
Handle<Map> map,
|
||||
MaybeHandle<JSReceiver> prototype = MaybeHandle<JSReceiver>());
|
||||
void AssumeMapNotDeprecated(Handle<Map> map);
|
||||
void AssumePropertyCell(Handle<PropertyCell> cell) {
|
||||
Insert(DependentCode::kPropertyCellChangedGroup, cell);
|
||||
|
@ -297,6 +297,12 @@ class CompilationInfo {
|
||||
return has_global_object() ? closure()->context()->global_object() : NULL;
|
||||
}
|
||||
|
||||
bool has_native_context() const { return has_global_object(); }
|
||||
|
||||
Context* native_context() const {
|
||||
return has_native_context() ? global_object()->native_context() : nullptr;
|
||||
}
|
||||
|
||||
// Accessors for the different compilation modes.
|
||||
bool IsOptimizing() const { return mode_ == OPTIMIZE; }
|
||||
bool IsStub() const { return mode_ == STUB; }
|
||||
|
@ -73,6 +73,20 @@ FieldAccess AccessBuilder::ForJSFunctionSharedFunctionInfo() {
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
FieldAccess AccessBuilder::ForJSArrayLength(ElementsKind elements_kind) {
|
||||
TypeCache const& type_cache = TypeCache::Get();
|
||||
FieldAccess access = {kTaggedBase, JSArray::kLengthOffset, Handle<Name>(),
|
||||
type_cache.kJSArrayLengthType, kMachAnyTagged};
|
||||
if (IsFastDoubleElementsKind(elements_kind)) {
|
||||
access.type = type_cache.kFixedDoubleArrayLengthType;
|
||||
} else if (IsFastElementsKind(elements_kind)) {
|
||||
access.type = type_cache.kFixedArrayLengthType;
|
||||
}
|
||||
return access;
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
FieldAccess AccessBuilder::ForJSArrayBufferBackingStore() {
|
||||
FieldAccess access = {kTaggedBase, JSArrayBuffer::kBackingStoreOffset,
|
||||
|
@ -40,6 +40,9 @@ class AccessBuilder final : public AllStatic {
|
||||
// Provides access to JSFunction::shared() field.
|
||||
static FieldAccess ForJSFunctionSharedFunctionInfo();
|
||||
|
||||
// Provides access to JSArray::length() field.
|
||||
static FieldAccess ForJSArrayLength(ElementsKind elements_kind);
|
||||
|
||||
// Provides access to JSArrayBuffer::backing_store() field.
|
||||
static FieldAccess ForJSArrayBufferBackingStore();
|
||||
|
||||
|
@ -135,7 +135,9 @@ AccessInfoFactory::AccessInfoFactory(CompilationDependencies* dependencies,
|
||||
native_context_(native_context),
|
||||
isolate_(native_context->GetIsolate()),
|
||||
type_cache_(TypeCache::Get()),
|
||||
zone_(zone) {}
|
||||
zone_(zone) {
|
||||
DCHECK(native_context->IsNativeContext());
|
||||
}
|
||||
|
||||
|
||||
bool AccessInfoFactory::ComputeElementAccessInfo(
|
||||
|
@ -34,25 +34,7 @@ MaybeHandle<Context> JSContextSpecialization::GetSpecializationContext(
|
||||
DCHECK(node->opcode() == IrOpcode::kJSLoadContext ||
|
||||
node->opcode() == IrOpcode::kJSStoreContext);
|
||||
Node* const object = NodeProperties::GetValueInput(node, 0);
|
||||
switch (object->opcode()) {
|
||||
case IrOpcode::kHeapConstant:
|
||||
return Handle<Context>::cast(OpParameter<Handle<HeapObject>>(object));
|
||||
case IrOpcode::kParameter: {
|
||||
Node* const start = NodeProperties::GetValueInput(object, 0);
|
||||
DCHECK_EQ(IrOpcode::kStart, start->opcode());
|
||||
int const index = ParameterIndexOf(object->op());
|
||||
// The context is always the last parameter to a JavaScript function, and
|
||||
// {Parameter} indices start at -1, so value outputs of {Start} look like
|
||||
// this: closure, receiver, param0, ..., paramN, context.
|
||||
if (index == start->op()->ValueOutputCount() - 2) {
|
||||
return context();
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return MaybeHandle<Context>();
|
||||
return NodeProperties::GetSpecializationContext(object, context());
|
||||
}
|
||||
|
||||
|
||||
|
@ -28,13 +28,11 @@ struct JSGlobalObjectSpecialization::ScriptContextTableLookupResult {
|
||||
|
||||
JSGlobalObjectSpecialization::JSGlobalObjectSpecialization(
|
||||
Editor* editor, JSGraph* jsgraph, Flags flags,
|
||||
Handle<JSGlobalObject> global_object, CompilationDependencies* dependencies)
|
||||
MaybeHandle<Context> native_context, CompilationDependencies* dependencies)
|
||||
: AdvancedReducer(editor),
|
||||
jsgraph_(jsgraph),
|
||||
flags_(flags),
|
||||
global_object_(global_object),
|
||||
script_context_table_(
|
||||
global_object->native_context()->script_context_table(), isolate()),
|
||||
native_context_(native_context),
|
||||
dependencies_(dependencies),
|
||||
type_cache_(TypeCache::Get()) {}
|
||||
|
||||
@ -58,9 +56,13 @@ Reduction JSGlobalObjectSpecialization::ReduceJSLoadGlobal(Node* node) {
|
||||
Node* effect = NodeProperties::GetEffectInput(node);
|
||||
Node* control = NodeProperties::GetControlInput(node);
|
||||
|
||||
// Retrieve the global object from the given {node}.
|
||||
Handle<JSGlobalObject> global_object;
|
||||
if (!GetGlobalObject(node).ToHandle(&global_object)) return NoChange();
|
||||
|
||||
// Try to lookup the name on the script context table first (lexical scoping).
|
||||
ScriptContextTableLookupResult result;
|
||||
if (LookupInScriptContextTable(name, &result)) {
|
||||
if (LookupInScriptContextTable(global_object, name, &result)) {
|
||||
if (result.context->is_the_hole(result.index)) return NoChange();
|
||||
Node* context = jsgraph()->HeapConstant(result.context);
|
||||
Node* value = effect = graph()->NewNode(
|
||||
@ -72,7 +74,7 @@ Reduction JSGlobalObjectSpecialization::ReduceJSLoadGlobal(Node* node) {
|
||||
|
||||
// Lookup on the global object instead. We only deal with own data
|
||||
// properties of the global object here (represented as PropertyCell).
|
||||
LookupIterator it(global_object(), name, LookupIterator::OWN);
|
||||
LookupIterator it(global_object, name, LookupIterator::OWN);
|
||||
if (it.state() != LookupIterator::DATA) return NoChange();
|
||||
Handle<PropertyCell> property_cell = it.GetPropertyCell();
|
||||
PropertyDetails property_details = property_cell->property_details();
|
||||
@ -145,9 +147,13 @@ Reduction JSGlobalObjectSpecialization::ReduceJSStoreGlobal(Node* node) {
|
||||
Node* effect = NodeProperties::GetEffectInput(node);
|
||||
Node* control = NodeProperties::GetControlInput(node);
|
||||
|
||||
// Retrieve the global object from the given {node}.
|
||||
Handle<JSGlobalObject> global_object;
|
||||
if (!GetGlobalObject(node).ToHandle(&global_object)) return NoChange();
|
||||
|
||||
// Try to lookup the name on the script context table first (lexical scoping).
|
||||
ScriptContextTableLookupResult result;
|
||||
if (LookupInScriptContextTable(name, &result)) {
|
||||
if (LookupInScriptContextTable(global_object, name, &result)) {
|
||||
if (result.context->is_the_hole(result.index)) return NoChange();
|
||||
if (result.immutable) return NoChange();
|
||||
Node* context = jsgraph()->HeapConstant(result.context);
|
||||
@ -159,7 +165,7 @@ Reduction JSGlobalObjectSpecialization::ReduceJSStoreGlobal(Node* node) {
|
||||
|
||||
// Lookup on the global object instead. We only deal with own data
|
||||
// properties of the global object here (represented as PropertyCell).
|
||||
LookupIterator it(global_object(), name, LookupIterator::OWN);
|
||||
LookupIterator it(global_object, name, LookupIterator::OWN);
|
||||
if (it.state() != LookupIterator::DATA) return NoChange();
|
||||
Handle<PropertyCell> property_cell = it.GetPropertyCell();
|
||||
PropertyDetails property_details = property_cell->property_details();
|
||||
@ -254,16 +260,27 @@ Reduction JSGlobalObjectSpecialization::ReduceJSStoreGlobal(Node* node) {
|
||||
}
|
||||
|
||||
|
||||
MaybeHandle<JSGlobalObject> JSGlobalObjectSpecialization::GetGlobalObject(
|
||||
Node* node) {
|
||||
Node* const context = NodeProperties::GetContextInput(node);
|
||||
return NodeProperties::GetSpecializationGlobalObject(context,
|
||||
native_context());
|
||||
}
|
||||
|
||||
|
||||
bool JSGlobalObjectSpecialization::LookupInScriptContextTable(
|
||||
Handle<Name> name, ScriptContextTableLookupResult* result) {
|
||||
Handle<JSGlobalObject> global_object, Handle<Name> name,
|
||||
ScriptContextTableLookupResult* result) {
|
||||
if (!name->IsString()) return false;
|
||||
Handle<ScriptContextTable> script_context_table(
|
||||
global_object->native_context()->script_context_table(), isolate());
|
||||
ScriptContextTable::LookupResult lookup_result;
|
||||
if (!ScriptContextTable::Lookup(script_context_table(),
|
||||
if (!ScriptContextTable::Lookup(script_context_table,
|
||||
Handle<String>::cast(name), &lookup_result)) {
|
||||
return false;
|
||||
}
|
||||
Handle<Context> script_context = ScriptContextTable::GetContext(
|
||||
script_context_table(), lookup_result.context_index);
|
||||
script_context_table, lookup_result.context_index);
|
||||
result->context = script_context;
|
||||
result->immutable = IsImmutableVariableMode(lookup_result.mode);
|
||||
result->index = lookup_result.slot_index;
|
||||
|
@ -13,7 +13,6 @@ namespace internal {
|
||||
|
||||
// Forward declarations.
|
||||
class CompilationDependencies;
|
||||
class ScriptContextTable;
|
||||
class TypeCache;
|
||||
|
||||
|
||||
@ -39,7 +38,7 @@ class JSGlobalObjectSpecialization final : public AdvancedReducer {
|
||||
typedef base::Flags<Flag> Flags;
|
||||
|
||||
JSGlobalObjectSpecialization(Editor* editor, JSGraph* jsgraph, Flags flags,
|
||||
Handle<JSGlobalObject> global_object,
|
||||
MaybeHandle<Context> native_context,
|
||||
CompilationDependencies* dependencies);
|
||||
|
||||
Reduction Reduce(Node* node) final;
|
||||
@ -48,8 +47,12 @@ class JSGlobalObjectSpecialization final : public AdvancedReducer {
|
||||
Reduction ReduceJSLoadGlobal(Node* node);
|
||||
Reduction ReduceJSStoreGlobal(Node* node);
|
||||
|
||||
// Retrieve the global object from the given {node} if known.
|
||||
MaybeHandle<JSGlobalObject> GetGlobalObject(Node* node);
|
||||
|
||||
struct ScriptContextTableLookupResult;
|
||||
bool LookupInScriptContextTable(Handle<Name> name,
|
||||
bool LookupInScriptContextTable(Handle<JSGlobalObject> global_object,
|
||||
Handle<Name> name,
|
||||
ScriptContextTableLookupResult* result);
|
||||
|
||||
Graph* graph() const;
|
||||
@ -59,16 +62,12 @@ class JSGlobalObjectSpecialization final : public AdvancedReducer {
|
||||
JSOperatorBuilder* javascript() const;
|
||||
SimplifiedOperatorBuilder* simplified() const;
|
||||
Flags flags() const { return flags_; }
|
||||
Handle<JSGlobalObject> global_object() const { return global_object_; }
|
||||
Handle<ScriptContextTable> script_context_table() const {
|
||||
return script_context_table_;
|
||||
}
|
||||
MaybeHandle<Context> native_context() const { return native_context_; }
|
||||
CompilationDependencies* dependencies() const { return dependencies_; }
|
||||
|
||||
JSGraph* const jsgraph_;
|
||||
Flags const flags_;
|
||||
Handle<JSGlobalObject> global_object_;
|
||||
Handle<ScriptContextTable> script_context_table_;
|
||||
MaybeHandle<Context> native_context_;
|
||||
CompilationDependencies* const dependencies_;
|
||||
TypeCache const& type_cache_;
|
||||
|
||||
|
@ -10,11 +10,7 @@
|
||||
#include "src/compiler/all-nodes.h"
|
||||
#include "src/compiler/ast-graph-builder.h"
|
||||
#include "src/compiler/common-operator.h"
|
||||
#include "src/compiler/common-operator-reducer.h"
|
||||
#include "src/compiler/dead-code-elimination.h"
|
||||
#include "src/compiler/graph-reducer.h"
|
||||
#include "src/compiler/js-global-object-specialization.h"
|
||||
#include "src/compiler/js-native-context-specialization.h"
|
||||
#include "src/compiler/js-operator.h"
|
||||
#include "src/compiler/node-matchers.h"
|
||||
#include "src/compiler/node-properties.h"
|
||||
@ -356,9 +352,6 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) {
|
||||
if (info_->is_deoptimization_enabled()) {
|
||||
info.MarkAsDeoptimizationEnabled();
|
||||
}
|
||||
if (info_->is_native_context_specializing()) {
|
||||
info.MarkAsNativeContextSpecializing();
|
||||
}
|
||||
|
||||
if (!Compiler::ParseAndAnalyze(info.parse_info())) {
|
||||
TRACE("Not inlining %s into %s because parsing failed\n",
|
||||
@ -410,34 +403,6 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) {
|
||||
AstGraphBuilder graph_builder(local_zone_, &info, &jsgraph);
|
||||
graph_builder.CreateGraph(false);
|
||||
|
||||
// TODO(mstarzinger): Unify this with the Pipeline once JSInliner refactoring
|
||||
// starts.
|
||||
if (info.is_native_context_specializing()) {
|
||||
GraphReducer graph_reducer(local_zone_, &graph, jsgraph.Dead());
|
||||
DeadCodeElimination dead_code_elimination(&graph_reducer, &graph,
|
||||
jsgraph.common());
|
||||
CommonOperatorReducer common_reducer(&graph_reducer, &graph,
|
||||
jsgraph.common(), jsgraph.machine());
|
||||
JSGlobalObjectSpecialization global_object_specialization(
|
||||
&graph_reducer, &jsgraph,
|
||||
info.is_deoptimization_enabled()
|
||||
? JSGlobalObjectSpecialization::kDeoptimizationEnabled
|
||||
: JSGlobalObjectSpecialization::kNoFlags,
|
||||
handle(info.global_object(), info.isolate()), info_->dependencies());
|
||||
JSNativeContextSpecialization native_context_specialization(
|
||||
&graph_reducer, &jsgraph,
|
||||
info.is_deoptimization_enabled()
|
||||
? JSNativeContextSpecialization::kDeoptimizationEnabled
|
||||
: JSNativeContextSpecialization::kNoFlags,
|
||||
handle(info.global_object()->native_context(), info.isolate()),
|
||||
info_->dependencies(), local_zone_);
|
||||
graph_reducer.AddReducer(&dead_code_elimination);
|
||||
graph_reducer.AddReducer(&common_reducer);
|
||||
graph_reducer.AddReducer(&global_object_specialization);
|
||||
graph_reducer.AddReducer(&native_context_specialization);
|
||||
graph_reducer.ReduceGraph();
|
||||
}
|
||||
|
||||
CopyVisitor visitor(&graph, jsgraph_->graph(), &zone);
|
||||
visitor.CopyGraph();
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "src/code-factory.h"
|
||||
#include "src/compilation-dependencies.h"
|
||||
#include "src/compiler/access-builder.h"
|
||||
#include "src/compiler/access-info.h"
|
||||
#include "src/compiler/js-graph.h"
|
||||
#include "src/compiler/js-operator.h"
|
||||
#include "src/compiler/linkage.h"
|
||||
@ -24,7 +25,7 @@ namespace compiler {
|
||||
|
||||
JSNativeContextSpecialization::JSNativeContextSpecialization(
|
||||
Editor* editor, JSGraph* jsgraph, Flags flags,
|
||||
Handle<Context> native_context, CompilationDependencies* dependencies,
|
||||
MaybeHandle<Context> native_context, CompilationDependencies* dependencies,
|
||||
Zone* zone)
|
||||
: AdvancedReducer(editor),
|
||||
jsgraph_(jsgraph),
|
||||
@ -32,8 +33,7 @@ JSNativeContextSpecialization::JSNativeContextSpecialization(
|
||||
native_context_(native_context),
|
||||
dependencies_(dependencies),
|
||||
zone_(zone),
|
||||
type_cache_(TypeCache::Get()),
|
||||
access_info_factory_(dependencies, native_context, graph()->zone()) {}
|
||||
type_cache_(TypeCache::Get()) {}
|
||||
|
||||
|
||||
Reduction JSNativeContextSpecialization::Reduce(Node* node) {
|
||||
@ -69,9 +69,15 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
|
||||
// Not much we can do if deoptimization support is disabled.
|
||||
if (!(flags() & kDeoptimizationEnabled)) return NoChange();
|
||||
|
||||
// Retrieve the native context from the given {node}.
|
||||
Handle<Context> native_context;
|
||||
if (!GetNativeContext(node).ToHandle(&native_context)) return NoChange();
|
||||
|
||||
// Compute property access infos for the receiver maps.
|
||||
AccessInfoFactory access_info_factory(dependencies(), native_context,
|
||||
graph()->zone());
|
||||
ZoneVector<PropertyAccessInfo> access_infos(zone());
|
||||
if (!access_info_factory().ComputePropertyAccessInfos(
|
||||
if (!access_info_factory.ComputePropertyAccessInfos(
|
||||
receiver_maps, name, access_mode, &access_infos)) {
|
||||
return NoChange();
|
||||
}
|
||||
@ -183,7 +189,7 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
|
||||
// Determine actual holder and perform prototype chain checks.
|
||||
Handle<JSObject> holder;
|
||||
if (access_info.holder().ToHandle(&holder)) {
|
||||
AssumePrototypesStable(receiver_type, holder);
|
||||
AssumePrototypesStable(receiver_type, native_context, holder);
|
||||
}
|
||||
|
||||
// Generate the actual property access.
|
||||
@ -487,10 +493,16 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
|
||||
// TODO(bmeurer): Add support for non-standard stores.
|
||||
if (store_mode != STANDARD_STORE) return NoChange();
|
||||
|
||||
// Retrieve the native context from the given {node}.
|
||||
Handle<Context> native_context;
|
||||
if (!GetNativeContext(node).ToHandle(&native_context)) return NoChange();
|
||||
|
||||
// Compute element access infos for the receiver maps.
|
||||
AccessInfoFactory access_info_factory(dependencies(), native_context,
|
||||
graph()->zone());
|
||||
ZoneVector<ElementAccessInfo> access_infos(zone());
|
||||
if (!access_info_factory().ComputeElementAccessInfos(
|
||||
receiver_maps, access_mode, &access_infos)) {
|
||||
if (!access_info_factory.ComputeElementAccessInfos(receiver_maps, access_mode,
|
||||
&access_infos)) {
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
@ -613,7 +625,7 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
|
||||
// not compatible with (monomorphic) keyed stores.
|
||||
Handle<JSObject> holder;
|
||||
if (access_info.holder().ToHandle(&holder)) {
|
||||
AssumePrototypesStable(receiver_type, holder);
|
||||
AssumePrototypesStable(receiver_type, native_context, holder);
|
||||
}
|
||||
|
||||
// Check that the {index} is actually a Number.
|
||||
@ -667,24 +679,15 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
|
||||
}
|
||||
|
||||
// Load the length of the {receiver}.
|
||||
Node* this_length;
|
||||
if (receiver_is_jsarray) {
|
||||
FieldAccess length_access = {
|
||||
kTaggedBase, JSArray::kLengthOffset, factory()->name_string(),
|
||||
type_cache_.kJSArrayLengthType, kMachAnyTagged};
|
||||
if (IsFastDoubleElementsKind(elements_kind)) {
|
||||
length_access.type = type_cache_.kFixedDoubleArrayLengthType;
|
||||
} else if (IsFastElementsKind(elements_kind)) {
|
||||
length_access.type = type_cache_.kFixedArrayLengthType;
|
||||
}
|
||||
this_length = this_effect =
|
||||
graph()->NewNode(simplified()->LoadField(length_access),
|
||||
this_receiver, this_effect, this_control);
|
||||
} else {
|
||||
this_length = this_effect = graph()->NewNode(
|
||||
simplified()->LoadField(AccessBuilder::ForFixedArrayLength()),
|
||||
this_elements, this_effect, this_control);
|
||||
}
|
||||
Node* this_length = this_effect =
|
||||
receiver_is_jsarray
|
||||
? graph()->NewNode(
|
||||
simplified()->LoadField(
|
||||
AccessBuilder::ForJSArrayLength(elements_kind)),
|
||||
this_receiver, this_effect, this_control)
|
||||
: graph()->NewNode(
|
||||
simplified()->LoadField(AccessBuilder::ForFixedArrayLength()),
|
||||
this_elements, this_effect, this_control);
|
||||
|
||||
// Check that the {index} is in the valid range for the {receiver}.
|
||||
Node* check = graph()->NewNode(simplified()->NumberLessThan(), this_index,
|
||||
@ -742,7 +745,7 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
|
||||
if (receiver_type->NowIs(initial_holey_array_type) &&
|
||||
isolate()->IsFastArrayConstructorPrototypeChainIntact()) {
|
||||
// Add a code dependency on the array protector cell.
|
||||
AssumePrototypesStable(receiver_type,
|
||||
AssumePrototypesStable(receiver_type, native_context,
|
||||
isolate()->initial_object_prototype());
|
||||
dependencies()->AssumePropertyCell(factory()->array_protector());
|
||||
// Turn the hole into undefined.
|
||||
@ -773,7 +776,7 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
|
||||
if (receiver_type->NowIs(initial_holey_array_type) &&
|
||||
isolate()->IsFastArrayConstructorPrototypeChainIntact()) {
|
||||
// Add a code dependency on the array protector cell.
|
||||
AssumePrototypesStable(receiver_type,
|
||||
AssumePrototypesStable(receiver_type, native_context,
|
||||
isolate()->initial_object_prototype());
|
||||
dependencies()->AssumePropertyCell(factory()->array_protector());
|
||||
// Turn the hole into undefined.
|
||||
@ -945,27 +948,19 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreProperty(Node* node) {
|
||||
|
||||
|
||||
void JSNativeContextSpecialization::AssumePrototypesStable(
|
||||
Type* receiver_type, Handle<JSObject> holder) {
|
||||
Type* receiver_type, Handle<Context> native_context,
|
||||
Handle<JSObject> holder) {
|
||||
// Determine actual holder and perform prototype chain checks.
|
||||
for (auto i = receiver_type->Classes(); !i.Done(); i.Advance()) {
|
||||
Handle<Map> map = i.Current();
|
||||
// Perform the implicit ToObject for primitives here.
|
||||
// Implemented according to ES6 section 7.3.2 GetV (V, P).
|
||||
Handle<JSFunction> constructor;
|
||||
if (Map::GetConstructorFunction(map, native_context())
|
||||
if (Map::GetConstructorFunction(map, native_context)
|
||||
.ToHandle(&constructor)) {
|
||||
map = handle(constructor->initial_map(), isolate());
|
||||
}
|
||||
for (PrototypeIterator j(map); !j.IsAtEnd(); j.Advance()) {
|
||||
// Check that the {prototype} still has the same map. All prototype
|
||||
// maps are guaranteed to be stable, so it's sufficient to add a
|
||||
// stability dependency here.
|
||||
Handle<JSReceiver> const prototype =
|
||||
PrototypeIterator::GetCurrent<JSReceiver>(j);
|
||||
dependencies()->AssumeMapStable(handle(prototype->map(), isolate()));
|
||||
// Stop once we get to the holder.
|
||||
if (prototype.is_identical_to(holder)) break;
|
||||
}
|
||||
dependencies()->AssumePrototypeMapsStable(map, holder);
|
||||
}
|
||||
}
|
||||
|
||||
@ -982,6 +977,14 @@ void JSNativeContextSpecialization::MarkAsDeferred(Node* if_projection) {
|
||||
}
|
||||
|
||||
|
||||
MaybeHandle<Context> JSNativeContextSpecialization::GetNativeContext(
|
||||
Node* node) {
|
||||
Node* const context = NodeProperties::GetContextInput(node);
|
||||
return NodeProperties::GetSpecializationNativeContext(context,
|
||||
native_context());
|
||||
}
|
||||
|
||||
|
||||
Graph* JSNativeContextSpecialization::graph() const {
|
||||
return jsgraph()->graph();
|
||||
}
|
||||
|
@ -6,7 +6,6 @@
|
||||
#define V8_COMPILER_JS_NATIVE_CONTEXT_SPECIALIZATION_H_
|
||||
|
||||
#include "src/base/flags.h"
|
||||
#include "src/compiler/access-info.h"
|
||||
#include "src/compiler/graph-reducer.h"
|
||||
|
||||
namespace v8 {
|
||||
@ -22,6 +21,7 @@ class TypeCache;
|
||||
namespace compiler {
|
||||
|
||||
// Forward declarations.
|
||||
enum class AccessMode;
|
||||
class CommonOperatorBuilder;
|
||||
class JSGraph;
|
||||
class JSOperatorBuilder;
|
||||
@ -43,7 +43,7 @@ class JSNativeContextSpecialization final : public AdvancedReducer {
|
||||
typedef base::Flags<Flag> Flags;
|
||||
|
||||
JSNativeContextSpecialization(Editor* editor, JSGraph* jsgraph, Flags flags,
|
||||
Handle<Context> native_context,
|
||||
MaybeHandle<Context> native_context,
|
||||
CompilationDependencies* dependencies,
|
||||
Zone* zone);
|
||||
|
||||
@ -73,12 +73,17 @@ class JSNativeContextSpecialization final : public AdvancedReducer {
|
||||
|
||||
// Adds stability dependencies on all prototypes of every class in
|
||||
// {receiver_type} up to (and including) the {holder}.
|
||||
void AssumePrototypesStable(Type* receiver_type, Handle<JSObject> holder);
|
||||
void AssumePrototypesStable(Type* receiver_type,
|
||||
Handle<Context> native_context,
|
||||
Handle<JSObject> holder);
|
||||
|
||||
// Assuming that {if_projection} is either IfTrue or IfFalse, adds a hint on
|
||||
// the dominating Branch that {if_projection} is the unlikely (deferred) case.
|
||||
void MarkAsDeferred(Node* if_projection);
|
||||
|
||||
// Retrieve the native context from the given {node} if known.
|
||||
MaybeHandle<Context> GetNativeContext(Node* node);
|
||||
|
||||
Graph* graph() const;
|
||||
JSGraph* jsgraph() const { return jsgraph_; }
|
||||
Isolate* isolate() const;
|
||||
@ -88,18 +93,16 @@ class JSNativeContextSpecialization final : public AdvancedReducer {
|
||||
SimplifiedOperatorBuilder* simplified() const;
|
||||
MachineOperatorBuilder* machine() const;
|
||||
Flags flags() const { return flags_; }
|
||||
Handle<Context> native_context() const { return native_context_; }
|
||||
MaybeHandle<Context> native_context() const { return native_context_; }
|
||||
CompilationDependencies* dependencies() const { return dependencies_; }
|
||||
Zone* zone() const { return zone_; }
|
||||
AccessInfoFactory& access_info_factory() { return access_info_factory_; }
|
||||
|
||||
JSGraph* const jsgraph_;
|
||||
Flags const flags_;
|
||||
Handle<Context> native_context_;
|
||||
MaybeHandle<Context> native_context_;
|
||||
CompilationDependencies* const dependencies_;
|
||||
Zone* const zone_;
|
||||
TypeCache const& type_cache_;
|
||||
AccessInfoFactory access_info_factory_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(JSNativeContextSpecialization);
|
||||
};
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "src/compiler/common-operator.h"
|
||||
#include "src/compiler/graph.h"
|
||||
#include "src/compiler/linkage.h"
|
||||
#include "src/compiler/node-properties.h"
|
||||
#include "src/compiler/operator-properties.h"
|
||||
#include "src/compiler/verifier.h"
|
||||
@ -292,6 +293,90 @@ void NodeProperties::CollectControlProjections(Node* node, Node** projections,
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
MaybeHandle<Context> NodeProperties::GetSpecializationContext(
|
||||
Node* node, MaybeHandle<Context> context) {
|
||||
switch (node->opcode()) {
|
||||
case IrOpcode::kHeapConstant:
|
||||
return Handle<Context>::cast(OpParameter<Handle<HeapObject>>(node));
|
||||
case IrOpcode::kParameter: {
|
||||
Node* const start = NodeProperties::GetValueInput(node, 0);
|
||||
DCHECK_EQ(IrOpcode::kStart, start->opcode());
|
||||
int const index = ParameterIndexOf(node->op());
|
||||
// The context is always the last parameter to a JavaScript function, and
|
||||
// {Parameter} indices start at -1, so value outputs of {Start} look like
|
||||
// this: closure, receiver, param0, ..., paramN, context.
|
||||
if (index == start->op()->ValueOutputCount() - 2) {
|
||||
return context;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return MaybeHandle<Context>();
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
MaybeHandle<Context> NodeProperties::GetSpecializationNativeContext(
|
||||
Node* node, MaybeHandle<Context> native_context) {
|
||||
while (true) {
|
||||
switch (node->opcode()) {
|
||||
case IrOpcode::kJSCreateBlockContext:
|
||||
case IrOpcode::kJSCreateCatchContext:
|
||||
case IrOpcode::kJSCreateFunctionContext:
|
||||
case IrOpcode::kJSCreateModuleContext:
|
||||
case IrOpcode::kJSCreateScriptContext:
|
||||
case IrOpcode::kJSCreateWithContext: {
|
||||
// Skip over the intermediate contexts, we're only interested in the
|
||||
// very last context in the context chain anyway.
|
||||
node = NodeProperties::GetContextInput(node);
|
||||
break;
|
||||
}
|
||||
case IrOpcode::kHeapConstant: {
|
||||
// Extract the native context from the actual {context}.
|
||||
Handle<Context> context =
|
||||
Handle<Context>::cast(OpParameter<Handle<HeapObject>>(node));
|
||||
return handle(context->native_context());
|
||||
}
|
||||
case IrOpcode::kOsrValue: {
|
||||
int const index = OpParameter<int>(node);
|
||||
if (index == Linkage::kOsrContextSpillSlotIndex) {
|
||||
return native_context;
|
||||
}
|
||||
return MaybeHandle<Context>();
|
||||
}
|
||||
case IrOpcode::kParameter: {
|
||||
Node* const start = NodeProperties::GetValueInput(node, 0);
|
||||
DCHECK_EQ(IrOpcode::kStart, start->opcode());
|
||||
int const index = ParameterIndexOf(node->op());
|
||||
// The context is always the last parameter to a JavaScript function,
|
||||
// and {Parameter} indices start at -1, so value outputs of {Start}
|
||||
// look like this: closure, receiver, param0, ..., paramN, context.
|
||||
if (index == start->op()->ValueOutputCount() - 2) {
|
||||
return native_context;
|
||||
}
|
||||
return MaybeHandle<Context>();
|
||||
}
|
||||
default:
|
||||
return MaybeHandle<Context>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
MaybeHandle<JSGlobalObject> NodeProperties::GetSpecializationGlobalObject(
|
||||
Node* node, MaybeHandle<Context> native_context) {
|
||||
Handle<Context> context;
|
||||
if (GetSpecializationNativeContext(node, native_context).ToHandle(&context)) {
|
||||
return handle(context->global_object());
|
||||
}
|
||||
return MaybeHandle<JSGlobalObject>();
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
Type* NodeProperties::GetTypeOrAny(Node* node) {
|
||||
return IsTyped(node) ? node->type() : Type::Any();
|
||||
|
@ -115,6 +115,27 @@ class NodeProperties final {
|
||||
// - Switch: [ IfValue, ..., IfDefault ]
|
||||
static void CollectControlProjections(Node* node, Node** proj, size_t count);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Context.
|
||||
|
||||
// Try to retrieve the specialization context from the given {node},
|
||||
// optionally utilizing the knowledge about the (outermost) function
|
||||
// {context}.
|
||||
static MaybeHandle<Context> GetSpecializationContext(
|
||||
Node* node, MaybeHandle<Context> context = MaybeHandle<Context>());
|
||||
|
||||
// Try to retrieve the specialization native context from the given
|
||||
// {node}, optionally utilizing the knowledge about the (outermost)
|
||||
// {native_context}.
|
||||
static MaybeHandle<Context> GetSpecializationNativeContext(
|
||||
Node* node, MaybeHandle<Context> native_context = MaybeHandle<Context>());
|
||||
|
||||
// Try to retrieve the specialization global object from the given
|
||||
// {node}, optionally utilizing the knowledge about the (outermost)
|
||||
// {native_context}.
|
||||
static MaybeHandle<JSGlobalObject> GetSpecializationGlobalObject(
|
||||
Node* node, MaybeHandle<Context> native_context = MaybeHandle<Context>());
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Type.
|
||||
|
||||
|
@ -496,39 +496,6 @@ struct GraphBuilderPhase {
|
||||
};
|
||||
|
||||
|
||||
struct NativeContextSpecializationPhase {
|
||||
static const char* phase_name() { return "native context specialization"; }
|
||||
|
||||
void Run(PipelineData* data, Zone* temp_zone) {
|
||||
JSGraphReducer graph_reducer(data->jsgraph(), temp_zone);
|
||||
DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(),
|
||||
data->common());
|
||||
CommonOperatorReducer common_reducer(&graph_reducer, data->graph(),
|
||||
data->common(), data->machine());
|
||||
JSGlobalObjectSpecialization global_object_specialization(
|
||||
&graph_reducer, data->jsgraph(),
|
||||
data->info()->is_deoptimization_enabled()
|
||||
? JSGlobalObjectSpecialization::kDeoptimizationEnabled
|
||||
: JSGlobalObjectSpecialization::kNoFlags,
|
||||
handle(data->info()->global_object(), data->isolate()),
|
||||
data->info()->dependencies());
|
||||
JSNativeContextSpecialization native_context_specialization(
|
||||
&graph_reducer, data->jsgraph(),
|
||||
data->info()->is_deoptimization_enabled()
|
||||
? JSNativeContextSpecialization::kDeoptimizationEnabled
|
||||
: JSNativeContextSpecialization::kNoFlags,
|
||||
handle(data->info()->global_object()->native_context(),
|
||||
data->isolate()),
|
||||
data->info()->dependencies(), temp_zone);
|
||||
AddReducer(data, &graph_reducer, &dead_code_elimination);
|
||||
AddReducer(data, &graph_reducer, &common_reducer);
|
||||
AddReducer(data, &graph_reducer, &global_object_specialization);
|
||||
AddReducer(data, &graph_reducer, &native_context_specialization);
|
||||
graph_reducer.ReduceGraph();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct InliningPhase {
|
||||
static const char* phase_name() { return "inlining"; }
|
||||
|
||||
@ -549,6 +516,24 @@ struct InliningPhase {
|
||||
: MaybeHandle<Context>());
|
||||
JSFrameSpecialization frame_specialization(data->info()->osr_frame(),
|
||||
data->jsgraph());
|
||||
JSGlobalObjectSpecialization global_object_specialization(
|
||||
&graph_reducer, data->jsgraph(),
|
||||
data->info()->is_deoptimization_enabled()
|
||||
? JSGlobalObjectSpecialization::kDeoptimizationEnabled
|
||||
: JSGlobalObjectSpecialization::kNoFlags,
|
||||
data->info()->is_native_context_specializing()
|
||||
? handle(data->info()->native_context(), data->isolate())
|
||||
: MaybeHandle<Context>(),
|
||||
data->info()->dependencies());
|
||||
JSNativeContextSpecialization native_context_specialization(
|
||||
&graph_reducer, data->jsgraph(),
|
||||
data->info()->is_deoptimization_enabled()
|
||||
? JSNativeContextSpecialization::kDeoptimizationEnabled
|
||||
: JSNativeContextSpecialization::kNoFlags,
|
||||
data->info()->is_native_context_specializing()
|
||||
? handle(data->info()->native_context(), data->isolate())
|
||||
: MaybeHandle<Context>(),
|
||||
data->info()->dependencies(), temp_zone);
|
||||
JSInliningHeuristic inlining(&graph_reducer,
|
||||
data->info()->is_inlining_enabled()
|
||||
? JSInliningHeuristic::kGeneralInlining
|
||||
@ -559,6 +544,8 @@ struct InliningPhase {
|
||||
if (data->info()->is_frame_specializing()) {
|
||||
AddReducer(data, &graph_reducer, &frame_specialization);
|
||||
}
|
||||
AddReducer(data, &graph_reducer, &global_object_specialization);
|
||||
AddReducer(data, &graph_reducer, &native_context_specialization);
|
||||
AddReducer(data, &graph_reducer, &context_specialization);
|
||||
AddReducer(data, &graph_reducer, &call_reducer);
|
||||
AddReducer(data, &graph_reducer, &inlining);
|
||||
@ -1100,12 +1087,6 @@ Handle<Code> Pipeline::GenerateCode() {
|
||||
RunPrintAndVerify("OSR deconstruction", true);
|
||||
}
|
||||
|
||||
// Perform native context specialization (if enabled).
|
||||
if (info()->is_native_context_specializing()) {
|
||||
Run<NativeContextSpecializationPhase>();
|
||||
RunPrintAndVerify("Native context specialized", true);
|
||||
}
|
||||
|
||||
// Perform function context specialization and inlining (if enabled).
|
||||
Run<InliningPhase>();
|
||||
RunPrintAndVerify("Inlined", true);
|
||||
|
@ -171,8 +171,6 @@ V8_INLINE Handle<T> handle(T* object) {
|
||||
// into a Handle requires checking that it does not point to NULL. This
|
||||
// ensures NULL checks before use.
|
||||
//
|
||||
// Do not use MaybeHandle as argument type.
|
||||
//
|
||||
// Also note that Handles do not provide default equality comparison or hashing
|
||||
// operators on purpose. Such operators would be misleading, because intended
|
||||
// semantics is ambiguous between Handle location and object identity.
|
||||
|
Loading…
Reference in New Issue
Block a user