Index: src/compiler/js-type-feedback.cc |
diff --git a/src/compiler/js-type-feedback.cc b/src/compiler/js-type-feedback.cc |
deleted file mode 100644 |
index 349987a35636b86ffe23dc13fd7e95da9ff88dbf..0000000000000000000000000000000000000000 |
--- a/src/compiler/js-type-feedback.cc |
+++ /dev/null |
@@ -1,354 +0,0 @@ |
-// 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/compiler.h" |
-#include "src/type-info.h" |
- |
-#include "src/compiler/access-builder.h" |
-#include "src/compiler/common-operator.h" |
-#include "src/compiler/frame-states.h" |
-#include "src/compiler/node-aux-data.h" |
-#include "src/compiler/node-matchers.h" |
-#include "src/compiler/operator-properties.h" |
-#include "src/compiler/simplified-operator.h" |
- |
-namespace v8 { |
-namespace internal { |
-namespace compiler { |
- |
-enum LoadOrStore { LOAD, STORE }; |
- |
-// TODO(turbofan): fix deoptimization problems |
-#define ENABLE_FAST_PROPERTY_LOADS false |
-#define ENABLE_FAST_PROPERTY_STORES false |
- |
-JSTypeFeedbackTable::JSTypeFeedbackTable(Zone* zone) |
- : type_feedback_id_map_(TypeFeedbackIdMap::key_compare(), |
- TypeFeedbackIdMap::allocator_type(zone)), |
- feedback_vector_slot_map_(TypeFeedbackIdMap::key_compare(), |
- TypeFeedbackIdMap::allocator_type(zone)) {} |
- |
- |
-void JSTypeFeedbackTable::Record(Node* node, TypeFeedbackId id) { |
- type_feedback_id_map_.insert(std::make_pair(node->id(), id)); |
-} |
- |
- |
-void JSTypeFeedbackTable::Record(Node* node, FeedbackVectorSlot slot) { |
- feedback_vector_slot_map_.insert(std::make_pair(node->id(), slot)); |
-} |
- |
- |
-Reduction JSTypeFeedbackSpecializer::Reduce(Node* node) { |
- switch (node->opcode()) { |
- case IrOpcode::kJSLoadProperty: |
- return ReduceJSLoadProperty(node); |
- case IrOpcode::kJSLoadNamed: |
- return ReduceJSLoadNamed(node); |
- case IrOpcode::kJSLoadGlobal: |
- return ReduceJSLoadGlobal(node); |
- case IrOpcode::kJSStoreNamed: |
- return ReduceJSStoreNamed(node); |
- case IrOpcode::kJSStoreProperty: |
- return ReduceJSStoreProperty(node); |
- default: |
- break; |
- } |
- return NoChange(); |
-} |
- |
- |
-static void AddFieldAccessTypes(FieldAccess* access, |
- PropertyDetails property_details) { |
- if (property_details.representation().IsSmi()) { |
- access->type = Type::SignedSmall(); |
- access->machine_type = static_cast<MachineType>(kTypeInt32 | kRepTagged); |
- } else if (property_details.representation().IsDouble()) { |
- access->type = Type::Number(); |
- access->machine_type = kMachFloat64; |
- } |
-} |
- |
- |
-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; |
- } |
- |
- // Transfer known types from property details. |
- AddFieldAccessTypes(access, property_details); |
- |
- if (mode == STORE) { |
- if (property_details.IsReadOnly()) { |
- // TODO(turbofan): deopt, ignore or throw on readonly stores. |
- return false; |
- } |
- if (is_smi || is_double) { |
- // TODO(turbofan): check type and deopt for SMI/double stores. |
- return false; |
- } |
- } |
- |
- int index = map->instance_descriptors()->GetFieldIndex(number); |
- FieldIndex field_index = FieldIndex::ForPropertyIndex(*map, index, is_double); |
- |
- if (field_index.is_inobject()) { |
- if (is_double && !map->IsUnboxedDoubleField(field_index)) { |
- // TODO(turbofan): support for out-of-line (MutableHeapNumber) loads. |
- return false; |
- } |
- 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); |
- if (mode() != kDeoptimizationEnabled) return NoChange(); |
- Node* frame_state_before = GetFrameStateBefore(node); |
- if (frame_state_before == nullptr) return NoChange(); |
- |
- NamedAccess const& p = NamedAccessOf(node->op()); |
- SmallMapList maps; |
- |
- FeedbackVectorSlot slot = js_type_feedback_->FindFeedbackVectorSlot(node); |
- if (slot.IsInvalid() || |
- oracle()->LoadInlineCacheState(slot) == UNINITIALIZED) { |
- // No type feedback ids or the load is uninitialized. |
- return NoChange(); |
- } |
- oracle()->PropertyReceiverTypes(slot, p.name(), &maps); |
- |
- Node* receiver = node->InputAt(0); |
- Node* effect = NodeProperties::GetEffectInput(node); |
- |
- if (maps.length() != 1) return NoChange(); // TODO(turbofan): polymorphism |
- if (!ENABLE_FAST_PROPERTY_LOADS) return NoChange(); |
- |
- Handle<Map> map = maps.first(); |
- FieldAccess field_access; |
- if (!GetInObjectFieldAccess(LOAD, map, p.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. |
- Node* deopt = graph()->NewNode(common()->Deoptimize(), frame_state_before, |
- effect, check_failed); |
- NodeProperties::MergeControlToEnd(graph(), common(), deopt); |
- ReplaceWithValue(node, load, load, check_success); |
- return Replace(load); |
-} |
- |
- |
-Reduction JSTypeFeedbackSpecializer::ReduceJSLoadGlobal(Node* node) { |
- DCHECK(node->opcode() == IrOpcode::kJSLoadGlobal); |
- Handle<String> name = |
- Handle<String>::cast(LoadGlobalParametersOf(node->op()).name()); |
- if (global_object_.is_null()) { |
- // Nothing else can be done if we don't have a global object. |
- return NoChange(); |
- } |
- |
- if (mode() == kDeoptimizationEnabled) { |
- // Handle lookups in the script context. |
- { |
- Handle<ScriptContextTable> script_contexts( |
- global_object_->native_context()->script_context_table()); |
- ScriptContextTable::LookupResult lookup; |
- if (ScriptContextTable::Lookup(script_contexts, name, &lookup)) { |
- // TODO(turbofan): introduce a LoadContext here. |
- return NoChange(); |
- } |
- } |
- |
- // Constant promotion or cell access requires lazy deoptimization support. |
- LookupIterator it(global_object_, name, LookupIterator::OWN); |
- |
- if (it.state() == LookupIterator::DATA) { |
- Handle<PropertyCell> cell = it.GetPropertyCell(); |
- dependencies_->AssumePropertyCell(cell); |
- |
- if (it.property_details().cell_type() == PropertyCellType::kConstant) { |
- // Constant promote the global's current value. |
- Handle<Object> constant_value(cell->value(), jsgraph()->isolate()); |
- if (constant_value->IsConsString()) { |
- constant_value = |
- String::Flatten(Handle<String>::cast(constant_value)); |
- } |
- Node* constant = jsgraph()->Constant(constant_value); |
- ReplaceWithValue(node, constant); |
- return Replace(constant); |
- } else { |
- // Load directly from the property cell. |
- FieldAccess access = AccessBuilder::ForPropertyCellValue(); |
- Node* control = NodeProperties::GetControlInput(node); |
- Node* load_field = graph()->NewNode( |
- simplified()->LoadField(access), jsgraph()->Constant(cell), |
- NodeProperties::GetEffectInput(node), control); |
- ReplaceWithValue(node, load_field, load_field, control); |
- return Replace(load_field); |
- } |
- } |
- } else { |
- // TODO(turbofan): non-configurable properties on the global object |
- // should be loadable through a cell without deoptimization support. |
- } |
- |
- return NoChange(); |
-} |
- |
- |
-Reduction JSTypeFeedbackSpecializer::ReduceJSLoadProperty(Node* node) { |
- return NoChange(); |
-} |
- |
- |
-Reduction JSTypeFeedbackSpecializer::ReduceJSStoreNamed(Node* node) { |
- DCHECK(node->opcode() == IrOpcode::kJSStoreNamed); |
- Node* frame_state_before = GetFrameStateBefore(node); |
- if (frame_state_before == nullptr) return NoChange(); |
- |
- NamedAccess const& p = NamedAccessOf(node->op()); |
- SmallMapList maps; |
- TypeFeedbackId id = js_type_feedback_->FindTypeFeedbackId(node); |
- if (id.IsNone() || oracle()->StoreIsUninitialized(id) == UNINITIALIZED) { |
- // No type feedback ids or the store is uninitialized. |
- // TODO(titzer): no feedback from vector ICs from stores. |
- return NoChange(); |
- } else { |
- oracle()->AssignmentReceiverTypes(id, p.name(), &maps); |
- } |
- |
- Node* receiver = node->InputAt(0); |
- Node* effect = NodeProperties::GetEffectInput(node); |
- |
- if (maps.length() != 1) return NoChange(); // TODO(turbofan): polymorphism |
- |
- if (!ENABLE_FAST_PROPERTY_STORES) return NoChange(); |
- |
- Handle<Map> map = maps.first(); |
- FieldAccess field_access; |
- if (!GetInObjectFieldAccess(STORE, map, p.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. |
- Node* deopt = graph()->NewNode(common()->Deoptimize(), frame_state_before, |
- effect, check_failed); |
- NodeProperties::MergeControlToEnd(graph(), common(), deopt); |
- 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); |
- } |
-} |
- |
- |
-// Get the frame state before an operation if it exists and has a valid |
-// bailout id. |
-Node* JSTypeFeedbackSpecializer::GetFrameStateBefore(Node* node) { |
- int count = OperatorProperties::GetFrameStateInputCount(node->op()); |
- DCHECK_LE(count, 2); |
- if (count == 2) { |
- Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); |
- if (frame_state->opcode() == IrOpcode::kFrameState) { |
- BailoutId id = OpParameter<FrameStateInfo>(node).bailout_id(); |
- if (id != BailoutId::None()) return frame_state; |
- } |
- } |
- return nullptr; |
-} |
- |
-} // namespace compiler |
-} // namespace internal |
-} // namespace v8 |