Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(449)

Unified Diff: src/compiler/js-global-object-specialization.cc

Issue 1417043006: [turbofan] Split JSGlobalObjectSpecialization into separate class. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/compiler/js-global-object-specialization.h ('k') | src/compiler/js-inlining.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/compiler/js-global-object-specialization.cc
diff --git a/src/compiler/js-global-object-specialization.cc b/src/compiler/js-global-object-specialization.cc
new file mode 100644
index 0000000000000000000000000000000000000000..59f0401f66ec06fb0583d6321e9ec382c7e38448
--- /dev/null
+++ b/src/compiler/js-global-object-specialization.cc
@@ -0,0 +1,294 @@
+// 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
« no previous file with comments | « src/compiler/js-global-object-specialization.h ('k') | src/compiler/js-inlining.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698