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

Unified Diff: src/compiler/js-type-feedback.cc

Issue 1021713005: [turbofan]: Integrate basic type feedback for property accesses. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years, 9 months 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-type-feedback.h ('k') | src/compiler/node-properties.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/compiler/js-type-feedback.cc
diff --git a/src/compiler/js-type-feedback.cc b/src/compiler/js-type-feedback.cc
new file mode 100644
index 0000000000000000000000000000000000000000..bdd61df87e8a4c2b868a7abc9f18da430d18b1f1
--- /dev/null
+++ b/src/compiler/js-type-feedback.cc
@@ -0,0 +1,256 @@
+// 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-type-feedback.h"
+
+#include "src/property-details.h"
+
+#include "src/accessors.h"
+#include "src/ast.h"
+#include "src/type-info.h"
+
+#include "src/compiler/access-builder.h"
+#include "src/compiler/common-operator.h"
+#include "src/compiler/node-aux-data.h"
+#include "src/compiler/simplified-operator.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+enum LoadOrStore { LOAD, STORE };
+
+JSTypeFeedbackTable::JSTypeFeedbackTable(Zone* zone)
+ : map_(TypeFeedbackIdMap::key_compare(),
+ TypeFeedbackIdMap::allocator_type(zone)) {}
+
+
+void JSTypeFeedbackTable::Record(Node* node, TypeFeedbackId id) {
+ map_.insert(std::make_pair(node->id(), id));
+}
+
+
+Reduction JSTypeFeedbackSpecializer::Reduce(Node* node) {
+ // TODO(turbofan): type feedback currently requires deoptimization.
+ if (!FLAG_turbo_deoptimization) return NoChange();
+ switch (node->opcode()) {
+ case IrOpcode::kJSLoadProperty:
+ return ReduceJSLoadProperty(node);
+ case IrOpcode::kJSLoadNamed:
+ return ReduceJSLoadNamed(node);
+ case IrOpcode::kJSStoreNamed:
+ return ReduceJSStoreNamed(node);
+ case IrOpcode::kJSStoreProperty:
+ return ReduceJSStoreProperty(node);
+ default:
+ break;
+ }
+ return NoChange();
+}
+
+
+static bool GetInObjectFieldAccess(LoadOrStore mode, Handle<Map> map,
+ Handle<Name> name, FieldAccess* access) {
+ access->base_is_tagged = kTaggedBase;
+ access->offset = -1;
+ access->name = name;
+ access->type = Type::Any();
+ access->machine_type = kMachAnyTagged;
+
+ // Check for properties that have accessors but are JSObject fields.
+ if (Accessors::IsJSObjectFieldAccessor(map, name, &access->offset)) {
+ // TODO(turbofan): fill in types for special JSObject field accesses.
+ return true;
+ }
+
+ // Check if the map is a dictionary.
+ if (map->is_dictionary_map()) return false;
+
+ // Search the descriptor array.
+ DescriptorArray* descriptors = map->instance_descriptors();
+ int number = descriptors->SearchWithCache(*name, *map);
+ if (number == DescriptorArray::kNotFound) return false;
+ PropertyDetails property_details = descriptors->GetDetails(number);
+
+ bool is_smi = property_details.representation().IsSmi();
+ bool is_double = property_details.representation().IsDouble();
+
+ if (property_details.type() != DATA) {
+ // TODO(turbofan): constant loads and stores.
+ return false;
+ }
+
+ if (mode == STORE) {
+ if (property_details.IsReadOnly()) return false;
+ if (is_smi) {
+ // TODO(turbofan): SMI stores.
+ return false;
+ }
+ if (is_double) {
+ // TODO(turbofan): double stores.
+ return false;
+ }
+ } else {
+ // Check property details for loads.
+ if (is_smi) {
+ access->type = Type::SignedSmall();
+ access->machine_type = static_cast<MachineType>(kTypeInt32 | kRepTagged);
+ }
+ if (is_double) {
+ access->type = Type::Number();
+ access->machine_type = kMachFloat64;
+ }
+ }
+
+ int index = map->instance_descriptors()->GetFieldIndex(number);
+ FieldIndex field_index = FieldIndex::ForPropertyIndex(*map, index, is_double);
+
+ if (field_index.is_inobject()) {
+ access->offset = field_index.offset();
+ return true;
+ }
+
+ // TODO(turbofan): handle out of object properties.
+ return false;
+}
+
+
+Reduction JSTypeFeedbackSpecializer::ReduceJSLoadNamed(Node* node) {
+ DCHECK(node->opcode() == IrOpcode::kJSLoadNamed);
+ TypeFeedbackId id = js_type_feedback_->find(node);
+ if (id.IsNone() || oracle()->LoadIsUninitialized(id)) return NoChange();
+
+ const LoadNamedParameters& p = LoadNamedParametersOf(node->op());
+ SmallMapList maps;
+ Handle<Name> name = p.name().handle();
+ Node* receiver = node->InputAt(0);
+ Node* effect = NodeProperties::GetEffectInput(node);
+ GatherReceiverTypes(receiver, effect, id, name, &maps);
+
+ if (maps.length() != 1) return NoChange(); // TODO(turbofan): polymorphism
+
+ Handle<Map> map = maps.first();
+ FieldAccess field_access;
+ if (!GetInObjectFieldAccess(LOAD, map, name, &field_access)) {
+ return NoChange();
+ }
+
+ Node* control = NodeProperties::GetControlInput(node);
+ Node* check_success;
+ Node* check_failed;
+ BuildMapCheck(receiver, map, true, effect, control, &check_success,
+ &check_failed);
+
+ // Build the actual load.
+ Node* load = graph()->NewNode(simplified()->LoadField(field_access), receiver,
+ effect, check_success);
+
+ // TODO(turbofan): handle slow case instead of deoptimizing.
+ // TODO(titzer): frame state should be from before the load.
+ Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
+ Node* deopt = graph()->NewNode(common()->Deoptimize(), frame_state, effect,
+ check_failed);
+ NodeProperties::MergeControlToEnd(graph(), common(), deopt);
+ NodeProperties::ReplaceWithValue(node, load, load, check_success);
+ return Replace(load);
+}
+
+
+Reduction JSTypeFeedbackSpecializer::ReduceJSLoadProperty(Node* node) {
+ return NoChange();
+}
+
+
+Reduction JSTypeFeedbackSpecializer::ReduceJSStoreNamed(Node* node) {
+ DCHECK(node->opcode() == IrOpcode::kJSStoreNamed);
+ TypeFeedbackId id = js_type_feedback_->find(node);
+ if (id.IsNone() || oracle()->StoreIsUninitialized(id)) return NoChange();
+
+ const StoreNamedParameters& p = StoreNamedParametersOf(node->op());
+ SmallMapList maps;
+ Handle<Name> name = p.name().handle();
+ Node* receiver = node->InputAt(0);
+ Node* effect = NodeProperties::GetEffectInput(node);
+ GatherReceiverTypes(receiver, effect, id, name, &maps);
+
+ if (maps.length() != 1) return NoChange(); // TODO(turbofan): polymorphism
+
+ Handle<Map> map = maps.first();
+ FieldAccess field_access;
+ if (!GetInObjectFieldAccess(STORE, map, name, &field_access)) {
+ return NoChange();
+ }
+
+ Node* control = NodeProperties::GetControlInput(node);
+ Node* check_success;
+ Node* check_failed;
+ BuildMapCheck(receiver, map, true, effect, control, &check_success,
+ &check_failed);
+
+ // Build the actual load.
+ Node* value = node->InputAt(1);
+ Node* store = graph()->NewNode(simplified()->StoreField(field_access),
+ receiver, value, effect, check_success);
+
+ // TODO(turbofan): handle slow case instead of deoptimizing.
+ // TODO(titzer): frame state should be from before the store.
+ Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
+ Node* deopt = graph()->NewNode(common()->Deoptimize(), frame_state, effect,
+ check_failed);
+ NodeProperties::MergeControlToEnd(graph(), common(), deopt);
+ NodeProperties::ReplaceWithValue(node, store, store, check_success);
+ return Replace(store);
+}
+
+
+Reduction JSTypeFeedbackSpecializer::ReduceJSStoreProperty(Node* node) {
+ return NoChange();
+}
+
+
+void JSTypeFeedbackSpecializer::BuildMapCheck(Node* receiver, Handle<Map> map,
+ bool smi_check, Node* effect,
+ Node* control, Node** success,
+ Node** fail) {
+ Node* if_smi = nullptr;
+ if (smi_check) {
+ Node* branch_smi = graph()->NewNode(
+ common()->Branch(BranchHint::kFalse),
+ graph()->NewNode(simplified()->ObjectIsSmi(), receiver), control);
+ if_smi = graph()->NewNode(common()->IfTrue(), branch_smi);
+ control = graph()->NewNode(common()->IfFalse(), branch_smi);
+ }
+
+ FieldAccess map_access = AccessBuilder::ForMap();
+ Node* receiver_map = graph()->NewNode(simplified()->LoadField(map_access),
+ receiver, effect, control);
+ Node* map_const = jsgraph_->Constant(map);
+ Node* cmp = graph()->NewNode(simplified()->ReferenceEqual(Type::Internal()),
+ receiver_map, map_const);
+ Node* branch =
+ graph()->NewNode(common()->Branch(BranchHint::kTrue), cmp, control);
+ *success = graph()->NewNode(common()->IfTrue(), branch);
+ *fail = graph()->NewNode(common()->IfFalse(), branch);
+
+ if (if_smi) {
+ *fail = graph()->NewNode(common()->Merge(2), *fail, if_smi);
+ }
+}
+
+
+void JSTypeFeedbackSpecializer::GatherReceiverTypes(Node* receiver,
+ Node* effect,
+ TypeFeedbackId id,
+ Handle<Name> name,
+ SmallMapList* maps) {
+ // TODO(turbofan): filter maps by initial receiver map if known
+ // TODO(turbofan): filter maps by native context (if specializing)
+ // TODO(turbofan): filter maps by effect chain
+ oracle()->PropertyReceiverTypes(id, name, maps);
+}
+
+
+} // namespace compiler
+} // namespace internal
+} // namespace v8
« no previous file with comments | « src/compiler/js-type-feedback.h ('k') | src/compiler/node-properties.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698