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

[turbofan] Make native context specialization dependent on the typed pipeline.

Also refactor the JSGlobalSpecialization somewhat to reduce the amount
of duplicated code somewhat.

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

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

Cr-Commit-Position: refs/heads/master@{#31286}
parent 558f1441
......@@ -442,6 +442,7 @@ OptimizedCompileJob::Status OptimizedCompileJob::CreateGraph() {
} else if (info()->has_global_object() &&
FLAG_native_context_specialization) {
info()->MarkAsNativeContextSpecializing();
info()->MarkAsTypingEnabled();
} else if (FLAG_turbo_type_feedback) {
info()->MarkAsTypeFeedbackEnabled();
info()->EnsureFeedbackVector();
......
......@@ -10,12 +10,19 @@
#include "src/compiler/js-operator.h"
#include "src/contexts.h"
#include "src/lookup.h"
#include "src/objects-inl.h"
#include "src/objects-inl.h" // TODO(mstarzinger): Temporary cycle breaker!
namespace v8 {
namespace internal {
namespace compiler {
struct JSGlobalSpecialization::ScriptContextTableLookupResult {
Handle<Context> context;
bool immutable;
int index;
};
JSGlobalSpecialization::JSGlobalSpecialization(
Editor* editor, JSGraph* jsgraph, Flags flags,
Handle<GlobalObject> global_object, CompilationDependencies* dependencies)
......@@ -44,92 +51,32 @@ Reduction JSGlobalSpecialization::ReduceJSLoadGlobal(Node* node) {
DCHECK_EQ(IrOpcode::kJSLoadGlobal, node->opcode());
Handle<Name> name = LoadGlobalParametersOf(node->op()).name();
Node* effect = NodeProperties::GetEffectInput(node);
// Try to lookup the name on the script context table first (lexical scoping).
if (name->IsString()) {
Handle<ScriptContextTable> script_context_table(
global_object()->native_context()->script_context_table());
ScriptContextTable::LookupResult result;
if (ScriptContextTable::Lookup(script_context_table,
Handle<String>::cast(name), &result)) {
Handle<Context> script_context = ScriptContextTable::GetContext(
script_context_table, result.context_index);
if (script_context->is_the_hole(result.slot_index)) {
// TODO(bmeurer): Is this relevant in practice?
return NoChange();
}
Node* context = jsgraph()->Constant(script_context);
Node* value = effect = graph()->NewNode(
javascript()->LoadContext(0, result.slot_index,
IsImmutableVariableMode(result.mode)),
context, context, effect);
return Replace(node, value, effect);
}
}
// Lookup on the global object instead.
LookupIterator it(global_object(), name, LookupIterator::OWN);
if (it.state() == LookupIterator::DATA) {
return ReduceLoadFromPropertyCell(node, it.GetPropertyCell());
}
return NoChange();
}
Reduction JSGlobalSpecialization::ReduceJSStoreGlobal(Node* node) {
DCHECK_EQ(IrOpcode::kJSStoreGlobal, node->opcode());
Handle<Name> name = StoreGlobalParametersOf(node->op()).name();
Node* value = NodeProperties::GetValueInput(node, 2);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
// Try to lookup the name on the script context table first (lexical scoping).
if (name->IsString()) {
Handle<ScriptContextTable> script_context_table(
global_object()->native_context()->script_context_table());
ScriptContextTable::LookupResult result;
if (ScriptContextTable::Lookup(script_context_table,
Handle<String>::cast(name), &result)) {
if (IsImmutableVariableMode(result.mode)) return NoChange();
Handle<Context> script_context = ScriptContextTable::GetContext(
script_context_table, result.context_index);
if (script_context->is_the_hole(result.slot_index)) {
// TODO(bmeurer): Is this relevant in practice?
return NoChange();
}
Node* context = jsgraph()->Constant(script_context);
effect =
graph()->NewNode(javascript()->StoreContext(0, result.slot_index),
context, value, context, effect, control);
return Replace(node, value, effect, control);
}
ScriptContextTableLookupResult result;
if (LookupInScriptContextTable(name, &result)) {
Node* context = jsgraph()->Constant(result.context);
Node* value = effect = graph()->NewNode(
javascript()->LoadContext(0, result.index, result.immutable), context,
context, effect);
return Replace(node, value, effect);
}
// Lookup on the global object instead.
// 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);
if (it.state() == LookupIterator::DATA) {
return ReduceStoreToPropertyCell(node, it.GetPropertyCell());
}
return NoChange();
}
Reduction JSGlobalSpecialization::ReduceLoadFromPropertyCell(
Node* node, Handle<PropertyCell> property_cell) {
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
// We only specialize global data property access.
if (it.state() != LookupIterator::DATA) return NoChange();
Handle<PropertyCell> property_cell = it.GetPropertyCell();
PropertyDetails property_details = property_cell->property_details();
DCHECK_EQ(kData, property_details.kind());
Handle<Object> property_cell_value(property_cell->value(), isolate());
DCHECK(!property_cell_value->IsTheHole());
// Load from non-configurable, read-only data property on the global
// object can be constant-folded, even without deoptimization support.
if (!property_details.IsConfigurable() && property_details.IsReadOnly()) {
return Replace(node, property_cell_value);
}
// Load from constant/undefined global property can be constant-folded
// with deoptimization support, by adding a code dependency on the cell.
if ((property_details.cell_type() == PropertyCellType::kConstant ||
......@@ -138,8 +85,7 @@ Reduction JSGlobalSpecialization::ReduceLoadFromPropertyCell(
dependencies()->AssumePropertyCell(property_cell);
return Replace(node, property_cell_value);
}
// Not much we can do if we run the generic pipeline here.
if (!(flags() & kTypingEnabled)) return NoChange();
// Load from constant type global property can benefit from representation
// (and map) feedback with deoptimization support (requires code dependency).
if (property_details.cell_type() == PropertyCellType::kConstantType &&
......@@ -162,6 +108,7 @@ Reduction JSGlobalSpecialization::ReduceLoadFromPropertyCell(
jsgraph()->Constant(property_cell), effect, control);
return Replace(node, value, effect);
}
// Load from non-configurable, data property on the global can be lowered to
// a field load, even without deoptimization, because the property cannot be
// deleted or reconfigured to an accessor/interceptor property.
......@@ -179,21 +126,34 @@ Reduction JSGlobalSpecialization::ReduceLoadFromPropertyCell(
}
Reduction JSGlobalSpecialization::ReduceStoreToPropertyCell(
Node* node, Handle<PropertyCell> property_cell) {
Reduction JSGlobalSpecialization::ReduceJSStoreGlobal(Node* node) {
DCHECK_EQ(IrOpcode::kJSStoreGlobal, node->opcode());
Handle<Name> name = StoreGlobalParametersOf(node->op()).name();
Node* value = NodeProperties::GetValueInput(node, 2);
Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
// We only specialize global data property access.
// Try to lookup the name on the script context table first (lexical scoping).
ScriptContextTableLookupResult result;
if (LookupInScriptContextTable(name, &result)) {
if (result.immutable) return NoChange();
Node* context = jsgraph()->Constant(result.context);
effect = graph()->NewNode(javascript()->StoreContext(0, result.index),
context, value, context, effect, control);
return Replace(node, value, effect, control);
}
// 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);
if (it.state() != LookupIterator::DATA) return NoChange();
Handle<PropertyCell> property_cell = it.GetPropertyCell();
PropertyDetails property_details = property_cell->property_details();
DCHECK_EQ(kData, property_details.kind());
Handle<Object> property_cell_value(property_cell->value(), isolate());
DCHECK(!property_cell_value->IsTheHole());
// Don't even bother trying to lower stores to read-only data properties.
if (property_details.IsReadOnly()) return NoChange();
// Not much we can do if we run the generic pipeline here.
if (!(flags() & kTypingEnabled)) return NoChange();
switch (property_details.cell_type()) {
case PropertyCellType::kUndefined: {
return NoChange();
......@@ -272,6 +232,7 @@ Reduction JSGlobalSpecialization::ReduceStoreToPropertyCell(
Reduction JSGlobalSpecialization::Replace(Node* node, Handle<Object> value) {
// TODO(bmeurer): Move this to JSGraph::HeapConstant instead?
if (value->IsConsString()) {
value = String::Flatten(Handle<String>::cast(value), TENURED);
}
......@@ -279,6 +240,26 @@ Reduction JSGlobalSpecialization::Replace(Node* node, Handle<Object> value) {
}
bool JSGlobalSpecialization::LookupInScriptContextTable(
Handle<Name> name, ScriptContextTableLookupResult* result) {
if (!name->IsString()) return false;
Handle<ScriptContextTable> script_context_table(
global_object()->native_context()->script_context_table());
ScriptContextTable::LookupResult lookup_result;
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);
if (script_context->is_the_hole(lookup_result.slot_index)) return false;
result->context = script_context;
result->immutable = IsImmutableVariableMode(lookup_result.mode);
result->index = lookup_result.slot_index;
return true;
}
Graph* JSGlobalSpecialization::graph() const { return jsgraph()->graph(); }
......
......@@ -33,7 +33,6 @@ class JSGlobalSpecialization final : public AdvancedReducer {
enum Flag {
kNoFlags = 0u,
kDeoptimizationEnabled = 1u << 0,
kTypingEnabled = 1u << 1
};
typedef base::Flags<Flag> Flags;
......@@ -46,10 +45,6 @@ class JSGlobalSpecialization final : public AdvancedReducer {
private:
Reduction ReduceJSLoadGlobal(Node* node);
Reduction ReduceJSStoreGlobal(Node* node);
Reduction ReduceLoadFromPropertyCell(Node* node,
Handle<PropertyCell> property_cell);
Reduction ReduceStoreToPropertyCell(Node* node,
Handle<PropertyCell> property_cell);
Reduction Replace(Node* node, Node* value, Node* effect = nullptr,
Node* control = nullptr) {
......@@ -58,6 +53,10 @@ class JSGlobalSpecialization final : public AdvancedReducer {
}
Reduction Replace(Node* node, Handle<Object> value);
struct ScriptContextTableLookupResult;
bool LookupInScriptContextTable(Handle<Name> name,
ScriptContextTableLookupResult* result);
Graph* graph() const;
JSGraph* jsgraph() const { return jsgraph_; }
Isolate* isolate() const;
......
......@@ -319,9 +319,6 @@ Reduction JSInliner::ReduceJSCallFunction(Node* node,
if (info_->is_native_context_specializing()) {
info.MarkAsNativeContextSpecializing();
}
if (info_->is_typing_enabled()) {
info.MarkAsTypingEnabled();
}
if (!Compiler::ParseAndAnalyze(info.parse_info())) {
TRACE("Not inlining %s into %s because parsing failed\n",
......@@ -358,15 +355,11 @@ Reduction JSInliner::ReduceJSCallFunction(Node* node,
jsgraph.common());
CommonOperatorReducer common_reducer(&graph_reducer, &graph,
jsgraph.common(), jsgraph.machine());
JSGlobalSpecialization::Flags flags = JSGlobalSpecialization::kNoFlags;
if (info.is_deoptimization_enabled()) {
flags |= JSGlobalSpecialization::kDeoptimizationEnabled;
}
if (info.is_typing_enabled()) {
flags |= JSGlobalSpecialization::kTypingEnabled;
}
JSGlobalSpecialization global_specialization(
&graph_reducer, &jsgraph, flags,
&graph_reducer, &jsgraph,
info.is_deoptimization_enabled()
? JSGlobalSpecialization::kDeoptimizationEnabled
: JSGlobalSpecialization::kNoFlags,
handle(info.global_object(), info.isolate()), info_->dependencies());
graph_reducer.AddReducer(&dead_code_elimination);
graph_reducer.AddReducer(&common_reducer);
......
......@@ -505,15 +505,11 @@ struct NativeContextSpecializationPhase {
data->common());
CommonOperatorReducer common_reducer(&graph_reducer, data->graph(),
data->common(), data->machine());
JSGlobalSpecialization::Flags flags = JSGlobalSpecialization::kNoFlags;
if (data->info()->is_deoptimization_enabled()) {
flags |= JSGlobalSpecialization::kDeoptimizationEnabled;
}
if (data->info()->is_typing_enabled()) {
flags |= JSGlobalSpecialization::kTypingEnabled;
}
JSGlobalSpecialization global_specialization(
&graph_reducer, data->jsgraph(), flags,
&graph_reducer, data->jsgraph(),
data->info()->is_deoptimization_enabled()
? JSGlobalSpecialization::kDeoptimizationEnabled
: JSGlobalSpecialization::kNoFlags,
handle(data->info()->global_object(), data->isolate()),
data->info()->dependencies());
AddReducer(data, &graph_reducer, &dead_code_elimination);
......
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