Index: src/compiler/js-type-feedback.cc |
diff --git a/src/compiler/js-type-feedback.cc b/src/compiler/js-type-feedback.cc |
index fa5e33f840e107e8acbedd472c446d5ad826c41c..749eebab290919e9fc5338a9734f62ca72dfb49e 100644 |
--- a/src/compiler/js-type-feedback.cc |
+++ b/src/compiler/js-type-feedback.cc |
@@ -8,6 +8,7 @@ |
#include "src/accessors.h" |
#include "src/ast.h" |
+#include "src/compiler.h" |
#include "src/type-info.h" |
#include "src/compiler/access-builder.h" |
@@ -78,6 +79,18 @@ Reduction JSTypeFeedbackSpecializer::Reduce(Node* node) { |
} |
+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; |
@@ -109,26 +122,18 @@ static bool GetInObjectFieldAccess(LoadOrStore mode, Handle<Map> map, |
return false; |
} |
+ // Transfer known types from property details. |
+ AddFieldAccessTypes(access, property_details); |
+ |
if (mode == STORE) { |
- if (property_details.IsReadOnly()) return false; |
- if (is_smi) { |
- // TODO(turbofan): SMI stores. |
+ if (property_details.IsReadOnly()) { |
+ // TODO(turbofan): deopt, ignore or throw on readonly stores. |
return false; |
} |
- if (is_double) { |
- // TODO(turbofan): double stores. |
+ if (is_smi || is_double) { |
+ // TODO(turbofan): check type and deopt for SMI/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); |
@@ -144,8 +149,20 @@ static bool GetInObjectFieldAccess(LoadOrStore mode, Handle<Map> map, |
} |
+static bool IsGlobalObject(Node* node) { |
+ return NodeProperties::IsTyped(node) && |
+ NodeProperties::GetBounds(node).upper->Is(Type::GlobalObject()); |
+} |
+ |
+ |
Reduction JSTypeFeedbackSpecializer::ReduceJSLoadNamed(Node* node) { |
DCHECK(node->opcode() == IrOpcode::kJSLoadNamed); |
+ Node* receiver = node->InputAt(0); |
+ if (IsGlobalObject(receiver)) { |
+ return ReduceJSLoadNamedForGlobalVariable(node); |
+ } |
+ |
+ if (!FLAG_turbo_deoptimization) return NoChange(); |
// TODO(titzer): deopt locations are wrong for property accesses |
if (!EAGER_DEOPT_LOCATIONS_FOR_PROPERTY_ACCESS_ARE_CORRECT) return NoChange(); |
@@ -158,7 +175,6 @@ Reduction JSTypeFeedbackSpecializer::ReduceJSLoadNamed(Node* node) { |
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); |
@@ -191,6 +207,74 @@ Reduction JSTypeFeedbackSpecializer::ReduceJSLoadNamed(Node* node) { |
} |
+Reduction JSTypeFeedbackSpecializer::ReduceJSLoadNamedForGlobalVariable( |
+ Node* node) { |
+ Handle<String> name = |
+ Handle<String>::cast(LoadNamedParametersOf(node->op()).name().handle()); |
+ // Try to optimize loads from the global object. |
+ Handle<Object> constant_value = |
+ jsgraph()->isolate()->factory()->GlobalConstantFor(name); |
+ if (!constant_value.is_null()) { |
+ // Always optimize global constants. |
+ Node* constant = jsgraph()->Constant(constant_value); |
+ NodeProperties::ReplaceWithValue(node, constant); |
+ return Replace(constant); |
+ } |
+ |
+ if (global_object_.is_null()) { |
+ // Nothing else can be done if we don't have a global object. |
+ return NoChange(); |
+ } |
+ |
+ if (FLAG_turbo_deoptimization) { |
+ // 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); |
+ NodeProperties::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); |
+ NodeProperties::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(); |
} |