Commit 4eb41ba7 authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Split JSGlobalObjectSpecialization into separate class.

The JSNativeContextSpecialization class is getting rather huge with all
the stuff related to property and element access going in. Splitting off
the global object related stuff into JSGlobalObjectSpecialization seems
like a natural separation, especially since the global object
specialization is sort of separate issue anyway.  This is neutral
functionality- and performance-wise.

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

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

Cr-Commit-Position: refs/heads/master@{#31748}
parent 1ca66908
...@@ -767,6 +767,8 @@ source_set("v8_base") { ...@@ -767,6 +767,8 @@ source_set("v8_base") {
"src/compiler/js-frame-specialization.h", "src/compiler/js-frame-specialization.h",
"src/compiler/js-generic-lowering.cc", "src/compiler/js-generic-lowering.cc",
"src/compiler/js-generic-lowering.h", "src/compiler/js-generic-lowering.h",
"src/compiler/js-global-object-specialization.cc",
"src/compiler/js-global-object-specialization.h",
"src/compiler/js-graph.cc", "src/compiler/js-graph.cc",
"src/compiler/js-graph.h", "src/compiler/js-graph.h",
"src/compiler/js-inlining.cc", "src/compiler/js-inlining.cc",
......
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/compiler/js-global-object-specialization.h"
#include "src/compilation-dependencies.h"
#include "src/compiler/access-builder.h"
#include "src/compiler/common-operator.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/js-operator.h"
#include "src/compiler/node-properties.h"
#include "src/compiler/simplified-operator.h"
#include "src/lookup.h"
#include "src/objects-inl.h" // TODO(mstarzinger): Temporary cycle breaker!
#include "src/type-cache.h"
namespace v8 {
namespace internal {
namespace compiler {
struct JSGlobalObjectSpecialization::ScriptContextTableLookupResult {
Handle<Context> context;
bool immutable;
int index;
};
JSGlobalObjectSpecialization::JSGlobalObjectSpecialization(
Editor* editor, JSGraph* jsgraph, Flags flags,
Handle<JSGlobalObject> global_object, CompilationDependencies* dependencies)
: AdvancedReducer(editor),
jsgraph_(jsgraph),
flags_(flags),
global_object_(global_object),
script_context_table_(
global_object->native_context()->script_context_table(), isolate()),
dependencies_(dependencies),
type_cache_(TypeCache::Get()) {}
Reduction JSGlobalObjectSpecialization::Reduce(Node* node) {
switch (node->opcode()) {
case IrOpcode::kJSLoadGlobal:
return ReduceJSLoadGlobal(node);
case IrOpcode::kJSStoreGlobal:
return ReduceJSStoreGlobal(node);
default:
break;
}
return NoChange();
}
Reduction JSGlobalObjectSpecialization::ReduceJSLoadGlobal(Node* node) {
DCHECK_EQ(IrOpcode::kJSLoadGlobal, node->opcode());
Handle<Name> name = LoadGlobalParametersOf(node->op()).name();
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
// Try to lookup the name on the script context table first (lexical scoping).
ScriptContextTableLookupResult result;
if (LookupInScriptContextTable(name, &result)) {
if (result.context->is_the_hole(result.index)) return NoChange();
Node* context = jsgraph()->HeapConstant(result.context);
Node* value = effect = graph()->NewNode(
javascript()->LoadContext(0, result.index, result.immutable), context,
context, effect);
ReplaceWithValue(node, value, effect);
return Replace(value);
}
// 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();
Handle<Object> property_cell_value(property_cell->value(), isolate());
// 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()) {
Node* value = jsgraph()->Constant(property_cell_value);
ReplaceWithValue(node, value);
return Replace(value);
}
// 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. Yet, if
// deoptimization support is available, we can constant-fold certain global
// properties or at least lower them to field loads annotated with more
// precise type feedback.
Type* property_cell_value_type = Type::Tagged();
if (flags() & kDeoptimizationEnabled) {
// Record a code dependency on the cell if we can benefit from the
// additional feedback, or the global property is configurable (i.e.
// can be deleted or reconfigured to an accessor property).
if (property_details.cell_type() != PropertyCellType::kMutable ||
property_details.IsConfigurable()) {
dependencies()->AssumePropertyCell(property_cell);
}
// Load from constant/undefined global property can be constant-folded.
if ((property_details.cell_type() == PropertyCellType::kConstant ||
property_details.cell_type() == PropertyCellType::kUndefined)) {
Node* value = jsgraph()->Constant(property_cell_value);
ReplaceWithValue(node, value);
return Replace(value);
}
// Load from constant type cell can benefit from type feedback.
if (property_details.cell_type() == PropertyCellType::kConstantType) {
// Compute proper type based on the current value in the cell.
if (property_cell_value->IsSmi()) {
property_cell_value_type = type_cache_.kSmi;
} else if (property_cell_value->IsNumber()) {
property_cell_value_type = type_cache_.kHeapNumber;
} else {
Handle<Map> property_cell_value_map(
Handle<HeapObject>::cast(property_cell_value)->map(), isolate());
property_cell_value_type =
Type::Class(property_cell_value_map, graph()->zone());
}
}
} else if (property_details.IsConfigurable()) {
// Access to configurable global properties requires deoptimization support.
return NoChange();
}
Node* value = effect = graph()->NewNode(
simplified()->LoadField(
AccessBuilder::ForPropertyCellValue(property_cell_value_type)),
jsgraph()->HeapConstant(property_cell), effect, control);
ReplaceWithValue(node, value, effect, control);
return Replace(value);
}
Reduction JSGlobalObjectSpecialization::ReduceJSStoreGlobal(Node* node) {
DCHECK_EQ(IrOpcode::kJSStoreGlobal, node->opcode());
Handle<Name> name = StoreGlobalParametersOf(node->op()).name();
Node* value = NodeProperties::GetValueInput(node, 0);
Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
// Try to lookup the name on the script context table first (lexical scoping).
ScriptContextTableLookupResult result;
if (LookupInScriptContextTable(name, &result)) {
if (result.context->is_the_hole(result.index)) return NoChange();
if (result.immutable) return NoChange();
Node* context = jsgraph()->HeapConstant(result.context);
effect = graph()->NewNode(javascript()->StoreContext(0, result.index),
context, value, context, effect, control);
ReplaceWithValue(node, value, effect, control);
return Replace(value);
}
// 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();
Handle<Object> property_cell_value(property_cell->value(), isolate());
// Don't even bother trying to lower stores to read-only data properties.
if (property_details.IsReadOnly()) return NoChange();
switch (property_details.cell_type()) {
case PropertyCellType::kUndefined: {
return NoChange();
}
case PropertyCellType::kConstant: {
// Store to constant property cell requires deoptimization support,
// because we might even need to eager deoptimize for mismatch.
if (!(flags() & kDeoptimizationEnabled)) return NoChange();
dependencies()->AssumePropertyCell(property_cell);
Node* check =
graph()->NewNode(simplified()->ReferenceEqual(Type::Tagged()), value,
jsgraph()->Constant(property_cell_value));
Node* branch =
graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* deoptimize = graph()->NewNode(common()->Deoptimize(), frame_state,
effect, if_false);
// TODO(bmeurer): This should be on the AdvancedReducer somehow.
NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
control = graph()->NewNode(common()->IfTrue(), branch);
break;
}
case PropertyCellType::kConstantType: {
// Store to constant-type property cell requires deoptimization support,
// because we might even need to eager deoptimize for mismatch.
if (!(flags() & kDeoptimizationEnabled)) return NoChange();
dependencies()->AssumePropertyCell(property_cell);
Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
if (property_cell_value->IsHeapObject()) {
Node* branch = graph()->NewNode(common()->Branch(BranchHint::kFalse),
check, control);
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* deoptimize = graph()->NewNode(common()->Deoptimize(), frame_state,
effect, if_true);
// TODO(bmeurer): This should be on the AdvancedReducer somehow.
NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
control = graph()->NewNode(common()->IfFalse(), branch);
Node* value_map =
graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
value, effect, control);
Handle<Map> property_cell_value_map(
Handle<HeapObject>::cast(property_cell_value)->map(), isolate());
check = graph()->NewNode(
simplified()->ReferenceEqual(Type::Any()), value_map,
jsgraph()->HeapConstant(property_cell_value_map));
}
Node* branch =
graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* deoptimize = graph()->NewNode(common()->Deoptimize(), frame_state,
effect, if_false);
// TODO(bmeurer): This should be on the AdvancedReducer somehow.
NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
control = graph()->NewNode(common()->IfTrue(), branch);
effect = graph()->NewNode(
simplified()->StoreField(AccessBuilder::ForPropertyCellValue()),
jsgraph()->HeapConstant(property_cell), value, effect, control);
break;
}
case PropertyCellType::kMutable: {
// Store to non-configurable, data property on the global can be lowered
// to a field store, even without deoptimization, because the property
// cannot be deleted or reconfigured to an accessor/interceptor property.
if (property_details.IsConfigurable()) {
// With deoptimization support, we can lower stores even to configurable
// data properties on the global object, by adding a code dependency on
// the cell.
if (!(flags() & kDeoptimizationEnabled)) return NoChange();
dependencies()->AssumePropertyCell(property_cell);
}
effect = graph()->NewNode(
simplified()->StoreField(AccessBuilder::ForPropertyCellValue()),
jsgraph()->HeapConstant(property_cell), value, effect, control);
break;
}
}
ReplaceWithValue(node, value, effect, control);
return Replace(value);
}
bool JSGlobalObjectSpecialization::LookupInScriptContextTable(
Handle<Name> name, ScriptContextTableLookupResult* result) {
if (!name->IsString()) return false;
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);
result->context = script_context;
result->immutable = IsImmutableVariableMode(lookup_result.mode);
result->index = lookup_result.slot_index;
return true;
}
Graph* JSGlobalObjectSpecialization::graph() const {
return jsgraph()->graph();
}
Isolate* JSGlobalObjectSpecialization::isolate() const {
return jsgraph()->isolate();
}
CommonOperatorBuilder* JSGlobalObjectSpecialization::common() const {
return jsgraph()->common();
}
JSOperatorBuilder* JSGlobalObjectSpecialization::javascript() const {
return jsgraph()->javascript();
}
SimplifiedOperatorBuilder* JSGlobalObjectSpecialization::simplified() const {
return jsgraph()->simplified();
}
} // namespace compiler
} // namespace internal
} // namespace v8
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_COMPILER_JS_GLOBAL_OBJECT_SPECIALIZATION_H_
#define V8_COMPILER_JS_GLOBAL_OBJECT_SPECIALIZATION_H_
#include "src/base/flags.h"
#include "src/compiler/graph-reducer.h"
namespace v8 {
namespace internal {
// Forward declarations.
class CompilationDependencies;
class ScriptContextTable;
class TypeCache;
namespace compiler {
// Forward declarations.
class CommonOperatorBuilder;
class JSGraph;
class JSOperatorBuilder;
class SimplifiedOperatorBuilder;
// Specializes a given JSGraph to a given global object, potentially constant
// folding some {JSLoadGlobal} nodes or strength reducing some {JSStoreGlobal}
// nodes.
class JSGlobalObjectSpecialization final : public AdvancedReducer {
public:
// Flags that control the mode of operation.
enum Flag {
kNoFlags = 0u,
kDeoptimizationEnabled = 1u << 0,
};
typedef base::Flags<Flag> Flags;
JSGlobalObjectSpecialization(Editor* editor, JSGraph* jsgraph, Flags flags,
Handle<JSGlobalObject> global_object,
CompilationDependencies* dependencies);
Reduction Reduce(Node* node) final;
private:
Reduction ReduceJSLoadGlobal(Node* node);
Reduction ReduceJSStoreGlobal(Node* node);
struct ScriptContextTableLookupResult;
bool LookupInScriptContextTable(Handle<Name> name,
ScriptContextTableLookupResult* result);
Graph* graph() const;
JSGraph* jsgraph() const { return jsgraph_; }
Isolate* isolate() const;
CommonOperatorBuilder* common() const;
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_;
}
CompilationDependencies* dependencies() const { return dependencies_; }
JSGraph* const jsgraph_;
Flags const flags_;
Handle<JSGlobalObject> global_object_;
Handle<ScriptContextTable> script_context_table_;
CompilationDependencies* const dependencies_;
TypeCache const& type_cache_;
DISALLOW_COPY_AND_ASSIGN(JSGlobalObjectSpecialization);
};
DEFINE_OPERATORS_FOR_FLAGS(JSGlobalObjectSpecialization::Flags)
} // namespace compiler
} // namespace internal
} // namespace v8
#endif // V8_COMPILER_JS_GLOBAL_OBJECT_SPECIALIZATION_H_
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "src/compiler/common-operator-reducer.h" #include "src/compiler/common-operator-reducer.h"
#include "src/compiler/dead-code-elimination.h" #include "src/compiler/dead-code-elimination.h"
#include "src/compiler/graph-reducer.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-native-context-specialization.h"
#include "src/compiler/js-operator.h" #include "src/compiler/js-operator.h"
#include "src/compiler/node-matchers.h" #include "src/compiler/node-matchers.h"
...@@ -390,15 +391,22 @@ Reduction JSInliner::ReduceJSCallFunction(Node* node, ...@@ -390,15 +391,22 @@ Reduction JSInliner::ReduceJSCallFunction(Node* node,
jsgraph.common()); jsgraph.common());
CommonOperatorReducer common_reducer(&graph_reducer, &graph, CommonOperatorReducer common_reducer(&graph_reducer, &graph,
jsgraph.common(), jsgraph.machine()); 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( JSNativeContextSpecialization native_context_specialization(
&graph_reducer, &jsgraph, &graph_reducer, &jsgraph,
info.is_deoptimization_enabled() info.is_deoptimization_enabled()
? JSNativeContextSpecialization::kDeoptimizationEnabled ? JSNativeContextSpecialization::kDeoptimizationEnabled
: JSNativeContextSpecialization::kNoFlags, : JSNativeContextSpecialization::kNoFlags,
handle(info.global_object(), info.isolate()), info_->dependencies(), handle(info.global_object()->native_context(), info.isolate()),
local_zone_); 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_object_specialization);
graph_reducer.AddReducer(&native_context_specialization); graph_reducer.AddReducer(&native_context_specialization);
graph_reducer.ReduceGraph(); graph_reducer.ReduceGraph();
} }
......
...@@ -12,9 +12,7 @@ ...@@ -12,9 +12,7 @@
#include "src/compiler/js-operator.h" #include "src/compiler/js-operator.h"
#include "src/compiler/linkage.h" #include "src/compiler/linkage.h"
#include "src/compiler/node-matchers.h" #include "src/compiler/node-matchers.h"
#include "src/contexts.h"
#include "src/field-index-inl.h" #include "src/field-index-inl.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-cache.h" #include "src/type-cache.h"
#include "src/type-feedback-vector.h" #include "src/type-feedback-vector.h"
...@@ -23,36 +21,24 @@ namespace v8 { ...@@ -23,36 +21,24 @@ namespace v8 {
namespace internal { namespace internal {
namespace compiler { namespace compiler {
struct JSNativeContextSpecialization::ScriptContextTableLookupResult {
Handle<Context> context;
bool immutable;
int index;
};
JSNativeContextSpecialization::JSNativeContextSpecialization( JSNativeContextSpecialization::JSNativeContextSpecialization(
Editor* editor, JSGraph* jsgraph, Flags flags, Editor* editor, JSGraph* jsgraph, Flags flags,
Handle<JSGlobalObject> global_object, CompilationDependencies* dependencies, Handle<Context> native_context, CompilationDependencies* dependencies,
Zone* zone) Zone* zone)
: AdvancedReducer(editor), : AdvancedReducer(editor),
jsgraph_(jsgraph), jsgraph_(jsgraph),
flags_(flags), flags_(flags),
global_object_(global_object), native_context_(native_context),
native_context_(global_object->native_context(), isolate()),
dependencies_(dependencies), dependencies_(dependencies),
zone_(zone), zone_(zone),
type_cache_(TypeCache::Get()), type_cache_(TypeCache::Get()),
access_info_factory_(dependencies, native_context(), graph()->zone()) {} access_info_factory_(dependencies, native_context, graph()->zone()) {}
Reduction JSNativeContextSpecialization::Reduce(Node* node) { Reduction JSNativeContextSpecialization::Reduce(Node* node) {
switch (node->opcode()) { switch (node->opcode()) {
case IrOpcode::kJSCallFunction: case IrOpcode::kJSCallFunction:
return ReduceJSCallFunction(node); return ReduceJSCallFunction(node);
case IrOpcode::kJSLoadGlobal:
return ReduceJSLoadGlobal(node);
case IrOpcode::kJSStoreGlobal:
return ReduceJSStoreGlobal(node);
case IrOpcode::kJSLoadNamed: case IrOpcode::kJSLoadNamed:
return ReduceJSLoadNamed(node); return ReduceJSLoadNamed(node);
case IrOpcode::kJSStoreNamed: case IrOpcode::kJSStoreNamed:
...@@ -90,8 +76,7 @@ Reduction JSNativeContextSpecialization::ReduceJSCallFunction(Node* node) { ...@@ -90,8 +76,7 @@ Reduction JSNativeContextSpecialization::ReduceJSCallFunction(Node* node) {
// Avoid cross-context leaks, meaning don't embed references to functions // Avoid cross-context leaks, meaning don't embed references to functions
// in other native contexts. // in other native contexts.
Handle<JSFunction> function(JSFunction::cast(cell->value()), isolate()); Handle<JSFunction> function(JSFunction::cast(cell->value()), isolate());
if (function->context()->native_context() != if (function->context()->native_context() != *native_context()) {
global_object()->native_context()) {
return NoChange(); return NoChange();
} }
...@@ -119,192 +104,6 @@ Reduction JSNativeContextSpecialization::ReduceJSCallFunction(Node* node) { ...@@ -119,192 +104,6 @@ Reduction JSNativeContextSpecialization::ReduceJSCallFunction(Node* node) {
} }
Reduction JSNativeContextSpecialization::ReduceJSLoadGlobal(Node* node) {
DCHECK_EQ(IrOpcode::kJSLoadGlobal, node->opcode());
Handle<Name> name = LoadGlobalParametersOf(node->op()).name();
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
// Try to lookup the name on the script context table first (lexical scoping).
ScriptContextTableLookupResult result;
if (LookupInScriptContextTable(name, &result)) {
if (result.context->is_the_hole(result.index)) return NoChange();
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. 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();
Handle<Object> property_cell_value(property_cell->value(), isolate());
// 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 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. Yet, if
// deoptimization support is available, we can constant-fold certain global
// properties or at least lower them to field loads annotated with more
// precise type feedback.
Type* property_cell_value_type =
Type::Intersect(Type::Any(), Type::Tagged(), graph()->zone());
if (flags() & kDeoptimizationEnabled) {
// Record a code dependency on the cell if we can benefit from the
// additional feedback, or the global property is configurable (i.e.
// can be deleted or reconfigured to an accessor property).
if (property_details.cell_type() != PropertyCellType::kMutable ||
property_details.IsConfigurable()) {
dependencies()->AssumePropertyCell(property_cell);
}
// Load from constant/undefined global property can be constant-folded.
if ((property_details.cell_type() == PropertyCellType::kConstant ||
property_details.cell_type() == PropertyCellType::kUndefined)) {
return Replace(node, property_cell_value);
}
// Load from constant type cell can benefit from type feedback.
if (property_details.cell_type() == PropertyCellType::kConstantType) {
// Compute proper type based on the current value in the cell.
if (property_cell_value->IsSmi()) {
property_cell_value_type = type_cache_.kSmi;
} else if (property_cell_value->IsNumber()) {
property_cell_value_type = type_cache_.kHeapNumber;
} else {
Handle<Map> property_cell_value_map(
Handle<HeapObject>::cast(property_cell_value)->map(), isolate());
property_cell_value_type =
Type::Class(property_cell_value_map, graph()->zone());
}
}
} else if (property_details.IsConfigurable()) {
// Access to configurable global properties requires deoptimization support.
return NoChange();
}
Node* value = effect = graph()->NewNode(
simplified()->LoadField(
AccessBuilder::ForPropertyCellValue(property_cell_value_type)),
jsgraph()->Constant(property_cell), effect, control);
return Replace(node, value, effect);
}
Reduction JSNativeContextSpecialization::ReduceJSStoreGlobal(Node* node) {
DCHECK_EQ(IrOpcode::kJSStoreGlobal, node->opcode());
Handle<Name> name = StoreGlobalParametersOf(node->op()).name();
Node* value = NodeProperties::GetValueInput(node, 0);
Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
// Try to lookup the name on the script context table first (lexical scoping).
ScriptContextTableLookupResult result;
if (LookupInScriptContextTable(name, &result)) {
if (result.context->is_the_hole(result.index)) return NoChange();
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();
Handle<Object> property_cell_value(property_cell->value(), isolate());
// Don't even bother trying to lower stores to read-only data properties.
if (property_details.IsReadOnly()) return NoChange();
switch (property_details.cell_type()) {
case PropertyCellType::kUndefined: {
return NoChange();
}
case PropertyCellType::kConstant: {
// Store to constant property cell requires deoptimization support,
// because we might even need to eager deoptimize for mismatch.
if (!(flags() & kDeoptimizationEnabled)) return NoChange();
dependencies()->AssumePropertyCell(property_cell);
Node* check =
graph()->NewNode(simplified()->ReferenceEqual(Type::Tagged()), value,
jsgraph()->Constant(property_cell_value));
Node* branch =
graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* deoptimize = graph()->NewNode(common()->Deoptimize(), frame_state,
effect, if_false);
// TODO(bmeurer): This should be on the AdvancedReducer somehow.
NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
control = graph()->NewNode(common()->IfTrue(), branch);
return Replace(node, value, effect, control);
}
case PropertyCellType::kConstantType: {
// Store to constant-type property cell requires deoptimization support,
// because we might even need to eager deoptimize for mismatch.
if (!(flags() & kDeoptimizationEnabled)) return NoChange();
dependencies()->AssumePropertyCell(property_cell);
Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
if (property_cell_value->IsHeapObject()) {
Node* branch = graph()->NewNode(common()->Branch(BranchHint::kFalse),
check, control);
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* deoptimize = graph()->NewNode(common()->Deoptimize(), frame_state,
effect, if_true);
// TODO(bmeurer): This should be on the AdvancedReducer somehow.
NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
control = graph()->NewNode(common()->IfFalse(), branch);
Node* value_map =
graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
value, effect, control);
Handle<Map> property_cell_value_map(
Handle<HeapObject>::cast(property_cell_value)->map(), isolate());
check = graph()->NewNode(simplified()->ReferenceEqual(Type::Internal()),
value_map,
jsgraph()->Constant(property_cell_value_map));
}
Node* branch =
graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* deoptimize = graph()->NewNode(common()->Deoptimize(), frame_state,
effect, if_false);
// TODO(bmeurer): This should be on the AdvancedReducer somehow.
NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
control = graph()->NewNode(common()->IfTrue(), branch);
break;
}
case PropertyCellType::kMutable: {
// Store to non-configurable, data property on the global can be lowered
// to a field store, even without deoptimization, because the property
// cannot be deleted or reconfigured to an accessor/interceptor property.
if (property_details.IsConfigurable()) {
// With deoptimization support, we can lower stores even to configurable
// data properties on the global object, by adding a code dependency on
// the cell.
if (!(flags() & kDeoptimizationEnabled)) return NoChange();
dependencies()->AssumePropertyCell(property_cell);
}
break;
}
}
effect = graph()->NewNode(
simplified()->StoreField(AccessBuilder::ForPropertyCellValue()),
jsgraph()->Constant(property_cell), value, effect, control);
return Replace(node, value, effect, control);
}
Reduction JSNativeContextSpecialization::ReduceNamedAccess( Reduction JSNativeContextSpecialization::ReduceNamedAccess(
Node* node, Node* value, MapHandleList const& receiver_maps, Node* node, Node* value, MapHandleList const& receiver_maps,
Handle<Name> name, AccessMode access_mode, LanguageMode language_mode, Handle<Name> name, AccessMode access_mode, LanguageMode language_mode,
...@@ -654,7 +453,8 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess( ...@@ -654,7 +453,8 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
effect = graph()->NewNode(common()->EffectPhi(control_count), effect = graph()->NewNode(common()->EffectPhi(control_count),
control_count + 1, &effects.front()); control_count + 1, &effects.front());
} }
return Replace(node, value, effect, control); ReplaceWithValue(node, value, effect, control);
return Replace(value);
} }
...@@ -939,7 +739,8 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess( ...@@ -939,7 +739,8 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
effect = graph()->NewNode(common()->EffectPhi(control_count), effect = graph()->NewNode(common()->EffectPhi(control_count),
control_count + 1, &effects.front()); control_count + 1, &effects.front());
} }
return Replace(node, value, effect, control); ReplaceWithValue(node, value, effect, control);
return Replace(value);
} }
...@@ -1020,31 +821,6 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreProperty(Node* node) { ...@@ -1020,31 +821,6 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreProperty(Node* node) {
} }
Reduction JSNativeContextSpecialization::Replace(Node* node,
Handle<Object> value) {
return Replace(node, jsgraph()->Constant(value));
}
bool JSNativeContextSpecialization::LookupInScriptContextTable(
Handle<Name> name, ScriptContextTableLookupResult* result) {
if (!name->IsString()) return false;
Handle<ScriptContextTable> script_context_table(
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);
result->context = script_context;
result->immutable = IsImmutableVariableMode(lookup_result.mode);
result->index = lookup_result.slot_index;
return true;
}
void JSNativeContextSpecialization::AssumePrototypesStable( void JSNativeContextSpecialization::AssumePrototypesStable(
Type* receiver_type, Handle<JSObject> holder) { Type* receiver_type, Handle<JSObject> holder) {
// Determine actual holder and perform prototype chain checks. // Determine actual holder and perform prototype chain checks.
......
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#include "src/base/flags.h" #include "src/base/flags.h"
#include "src/compiler/access-info.h" #include "src/compiler/access-info.h"
#include "src/compiler/graph-reducer.h" #include "src/compiler/graph-reducer.h"
#include "src/compiler/simplified-operator.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -27,6 +26,7 @@ class CommonOperatorBuilder; ...@@ -27,6 +26,7 @@ class CommonOperatorBuilder;
class JSGraph; class JSGraph;
class JSOperatorBuilder; class JSOperatorBuilder;
class MachineOperatorBuilder; class MachineOperatorBuilder;
class SimplifiedOperatorBuilder;
// Specializes a given JSGraph to a given native context, potentially constant // Specializes a given JSGraph to a given native context, potentially constant
...@@ -43,7 +43,7 @@ class JSNativeContextSpecialization final : public AdvancedReducer { ...@@ -43,7 +43,7 @@ class JSNativeContextSpecialization final : public AdvancedReducer {
typedef base::Flags<Flag> Flags; typedef base::Flags<Flag> Flags;
JSNativeContextSpecialization(Editor* editor, JSGraph* jsgraph, Flags flags, JSNativeContextSpecialization(Editor* editor, JSGraph* jsgraph, Flags flags,
Handle<JSGlobalObject> global_object, Handle<Context> native_context,
CompilationDependencies* dependencies, CompilationDependencies* dependencies,
Zone* zone); Zone* zone);
...@@ -51,20 +51,11 @@ class JSNativeContextSpecialization final : public AdvancedReducer { ...@@ -51,20 +51,11 @@ class JSNativeContextSpecialization final : public AdvancedReducer {
private: private:
Reduction ReduceJSCallFunction(Node* node); Reduction ReduceJSCallFunction(Node* node);
Reduction ReduceJSLoadGlobal(Node* node);
Reduction ReduceJSStoreGlobal(Node* node);
Reduction ReduceJSLoadNamed(Node* node); Reduction ReduceJSLoadNamed(Node* node);
Reduction ReduceJSStoreNamed(Node* node); Reduction ReduceJSStoreNamed(Node* node);
Reduction ReduceJSLoadProperty(Node* node); Reduction ReduceJSLoadProperty(Node* node);
Reduction ReduceJSStoreProperty(Node* node); Reduction ReduceJSStoreProperty(Node* node);
Reduction Replace(Node* node, Node* value, Node* effect = nullptr,
Node* control = nullptr) {
ReplaceWithValue(node, value, effect, control);
return Changed(value);
}
Reduction Replace(Node* node, Handle<Object> value);
Reduction ReduceElementAccess(Node* node, Node* index, Node* value, Reduction ReduceElementAccess(Node* node, Node* index, Node* value,
MapHandleList const& receiver_maps, MapHandleList const& receiver_maps,
AccessMode access_mode, AccessMode access_mode,
...@@ -79,10 +70,6 @@ class JSNativeContextSpecialization final : public AdvancedReducer { ...@@ -79,10 +70,6 @@ class JSNativeContextSpecialization final : public AdvancedReducer {
LanguageMode language_mode, LanguageMode language_mode,
Node* index = nullptr); Node* index = nullptr);
struct ScriptContextTableLookupResult;
bool LookupInScriptContextTable(Handle<Name> name,
ScriptContextTableLookupResult* result);
// Adds stability dependencies on all prototypes of every class in // Adds stability dependencies on all prototypes of every class in
// {receiver_type} up to (and including) the {holder}. // {receiver_type} up to (and including) the {holder}.
void AssumePrototypesStable(Type* receiver_type, Handle<JSObject> holder); void AssumePrototypesStable(Type* receiver_type, Handle<JSObject> holder);
...@@ -100,7 +87,6 @@ class JSNativeContextSpecialization final : public AdvancedReducer { ...@@ -100,7 +87,6 @@ class JSNativeContextSpecialization final : public AdvancedReducer {
SimplifiedOperatorBuilder* simplified() const; SimplifiedOperatorBuilder* simplified() const;
MachineOperatorBuilder* machine() const; MachineOperatorBuilder* machine() const;
Flags flags() const { return flags_; } Flags flags() const { return flags_; }
Handle<JSGlobalObject> global_object() const { return global_object_; }
Handle<Context> native_context() const { return native_context_; } Handle<Context> native_context() const { return native_context_; }
CompilationDependencies* dependencies() const { return dependencies_; } CompilationDependencies* dependencies() const { return dependencies_; }
Zone* zone() const { return zone_; } Zone* zone() const { return zone_; }
...@@ -108,7 +94,6 @@ class JSNativeContextSpecialization final : public AdvancedReducer { ...@@ -108,7 +94,6 @@ class JSNativeContextSpecialization final : public AdvancedReducer {
JSGraph* const jsgraph_; JSGraph* const jsgraph_;
Flags const flags_; Flags const flags_;
Handle<JSGlobalObject> global_object_;
Handle<Context> native_context_; Handle<Context> native_context_;
CompilationDependencies* const dependencies_; CompilationDependencies* const dependencies_;
Zone* const zone_; Zone* const zone_;
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include "src/compiler/js-context-specialization.h" #include "src/compiler/js-context-specialization.h"
#include "src/compiler/js-frame-specialization.h" #include "src/compiler/js-frame-specialization.h"
#include "src/compiler/js-generic-lowering.h" #include "src/compiler/js-generic-lowering.h"
#include "src/compiler/js-global-object-specialization.h"
#include "src/compiler/js-inlining-heuristic.h" #include "src/compiler/js-inlining-heuristic.h"
#include "src/compiler/js-intrinsic-lowering.h" #include "src/compiler/js-intrinsic-lowering.h"
#include "src/compiler/js-native-context-specialization.h" #include "src/compiler/js-native-context-specialization.h"
...@@ -500,15 +501,24 @@ struct NativeContextSpecializationPhase { ...@@ -500,15 +501,24 @@ struct NativeContextSpecializationPhase {
data->common()); data->common());
CommonOperatorReducer common_reducer(&graph_reducer, data->graph(), CommonOperatorReducer common_reducer(&graph_reducer, data->graph(),
data->common(), data->machine()); 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( JSNativeContextSpecialization native_context_specialization(
&graph_reducer, data->jsgraph(), &graph_reducer, data->jsgraph(),
data->info()->is_deoptimization_enabled() data->info()->is_deoptimization_enabled()
? JSNativeContextSpecialization::kDeoptimizationEnabled ? JSNativeContextSpecialization::kDeoptimizationEnabled
: JSNativeContextSpecialization::kNoFlags, : JSNativeContextSpecialization::kNoFlags,
handle(data->info()->global_object(), data->isolate()), handle(data->info()->global_object()->native_context(),
data->isolate()),
data->info()->dependencies(), temp_zone); 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_object_specialization);
AddReducer(data, &graph_reducer, &native_context_specialization); AddReducer(data, &graph_reducer, &native_context_specialization);
graph_reducer.ReduceGraph(); graph_reducer.ReduceGraph();
} }
......
...@@ -526,6 +526,8 @@ ...@@ -526,6 +526,8 @@
'../../src/compiler/js-frame-specialization.h', '../../src/compiler/js-frame-specialization.h',
'../../src/compiler/js-generic-lowering.cc', '../../src/compiler/js-generic-lowering.cc',
'../../src/compiler/js-generic-lowering.h', '../../src/compiler/js-generic-lowering.h',
'../../src/compiler/js-global-object-specialization.cc',
'../../src/compiler/js-global-object-specialization.h',
'../../src/compiler/js-graph.cc', '../../src/compiler/js-graph.cc',
'../../src/compiler/js-graph.h', '../../src/compiler/js-graph.h',
'../../src/compiler/js-inlining.cc', '../../src/compiler/js-inlining.cc',
......
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