Index: src/compiler/js-global-specialization.cc |
diff --git a/src/compiler/js-global-specialization.cc b/src/compiler/js-global-specialization.cc |
index 01a837b3450a02c33f4484564bfe511e6af2202e..9b11767be6c4c7eb342a17ab34e02ba705bf4be8 100644 |
--- a/src/compiler/js-global-specialization.cc |
+++ b/src/compiler/js-global-specialization.cc |
@@ -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(); } |