Chromium Code Reviews| Index: src/compiler/js-type-feedback.cc |
| diff --git a/src/compiler/js-type-feedback.cc b/src/compiler/js-type-feedback.cc |
| index d93dc5c11f3f38aa4b6fe71a0b541003058e3a81..23967f03387b10911ae95fe24fc273422b1ac376 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" |
| @@ -70,6 +71,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; |
| @@ -101,26 +114,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); |
| @@ -136,8 +141,19 @@ 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 ReduceJSLoadNamedFromGlobalObject(node); |
| + } |
| + |
| // TODO(turbofan): type feedback currently requires deoptimization. |
| if (!FLAG_turbo_deoptimization) return NoChange(); |
| @@ -150,7 +166,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); |
| @@ -183,6 +198,62 @@ Reduction JSTypeFeedbackSpecializer::ReduceJSLoadNamed(Node* node) { |
| } |
| +Reduction JSTypeFeedbackSpecializer::ReduceJSLoadNamedFromGlobalObject( |
| + Node* node) { |
| + Handle<Name> name = 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) { |
| + // 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)); |
|
Michael Starzinger
2015/04/21 12:34:01
rant: We need to flatten strings here? SRSLY? OMG!
titzer
2015/04/21 12:56:52
Agreed, cribbed this one from Crankyshaft.
|
| + } |
| + 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(); |
| } |