Home | History | Annotate | Download | only in compiler
      1 // Copyright 2015 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "src/compiler/js-global-object-specialization.h"
      6 
      7 #include "src/compilation-dependencies.h"
      8 #include "src/compiler/access-builder.h"
      9 #include "src/compiler/common-operator.h"
     10 #include "src/compiler/js-graph.h"
     11 #include "src/compiler/js-operator.h"
     12 #include "src/compiler/node-properties.h"
     13 #include "src/compiler/simplified-operator.h"
     14 #include "src/compiler/type-cache.h"
     15 #include "src/lookup.h"
     16 #include "src/objects-inl.h"
     17 
     18 namespace v8 {
     19 namespace internal {
     20 namespace compiler {
     21 
     22 struct JSGlobalObjectSpecialization::ScriptContextTableLookupResult {
     23   Handle<Context> context;
     24   bool immutable;
     25   int index;
     26 };
     27 
     28 JSGlobalObjectSpecialization::JSGlobalObjectSpecialization(
     29     Editor* editor, JSGraph* jsgraph, Handle<JSGlobalObject> global_object,
     30     CompilationDependencies* dependencies)
     31     : AdvancedReducer(editor),
     32       jsgraph_(jsgraph),
     33       global_object_(global_object),
     34       dependencies_(dependencies),
     35       type_cache_(TypeCache::Get()) {}
     36 
     37 Reduction JSGlobalObjectSpecialization::Reduce(Node* node) {
     38   switch (node->opcode()) {
     39     case IrOpcode::kJSLoadGlobal:
     40       return ReduceJSLoadGlobal(node);
     41     case IrOpcode::kJSStoreGlobal:
     42       return ReduceJSStoreGlobal(node);
     43     default:
     44       break;
     45   }
     46   return NoChange();
     47 }
     48 
     49 namespace {
     50 
     51 FieldAccess ForPropertyCellValue(MachineRepresentation representation,
     52                                  Type* type, Handle<Name> name) {
     53   WriteBarrierKind kind = kFullWriteBarrier;
     54   if (representation == MachineRepresentation::kTaggedSigned) {
     55     kind = kNoWriteBarrier;
     56   } else if (representation == MachineRepresentation::kTaggedPointer) {
     57     kind = kPointerWriteBarrier;
     58   }
     59   MachineType r = MachineType::TypeForRepresentation(representation);
     60   FieldAccess access = {kTaggedBase, PropertyCell::kValueOffset, name, type, r,
     61                         kind};
     62   return access;
     63 }
     64 }  // namespace
     65 
     66 Reduction JSGlobalObjectSpecialization::ReduceJSLoadGlobal(Node* node) {
     67   DCHECK_EQ(IrOpcode::kJSLoadGlobal, node->opcode());
     68   Handle<Name> name = LoadGlobalParametersOf(node->op()).name();
     69   Node* effect = NodeProperties::GetEffectInput(node);
     70   Node* control = NodeProperties::GetControlInput(node);
     71 
     72   // Try to lookup the name on the script context table first (lexical scoping).
     73   ScriptContextTableLookupResult result;
     74   if (LookupInScriptContextTable(name, &result)) {
     75     if (result.context->is_the_hole(isolate(), result.index)) return NoChange();
     76     Node* context = jsgraph()->HeapConstant(result.context);
     77     Node* value = effect = graph()->NewNode(
     78         javascript()->LoadContext(0, result.index, result.immutable), context,
     79         context, effect);
     80     ReplaceWithValue(node, value, effect);
     81     return Replace(value);
     82   }
     83 
     84   // Lookup on the global object instead.  We only deal with own data
     85   // properties of the global object here (represented as PropertyCell).
     86   LookupIterator it(global_object(), name, LookupIterator::OWN);
     87   if (it.state() != LookupIterator::DATA) return NoChange();
     88   if (!it.GetHolder<JSObject>()->IsJSGlobalObject()) return NoChange();
     89   Handle<PropertyCell> property_cell = it.GetPropertyCell();
     90   PropertyDetails property_details = property_cell->property_details();
     91   Handle<Object> property_cell_value(property_cell->value(), isolate());
     92 
     93   // Load from non-configurable, read-only data property on the global
     94   // object can be constant-folded, even without deoptimization support.
     95   if (!property_details.IsConfigurable() && property_details.IsReadOnly()) {
     96     Node* value = jsgraph()->Constant(property_cell_value);
     97     ReplaceWithValue(node, value);
     98     return Replace(value);
     99   }
    100 
    101   // Record a code dependency on the cell if we can benefit from the
    102   // additional feedback, or the global property is configurable (i.e.
    103   // can be deleted or reconfigured to an accessor property).
    104   if (property_details.cell_type() != PropertyCellType::kMutable ||
    105       property_details.IsConfigurable()) {
    106     dependencies()->AssumePropertyCell(property_cell);
    107   }
    108 
    109   // Load from constant/undefined global property can be constant-folded.
    110   if (property_details.cell_type() == PropertyCellType::kConstant ||
    111       property_details.cell_type() == PropertyCellType::kUndefined) {
    112     Node* value = jsgraph()->Constant(property_cell_value);
    113     ReplaceWithValue(node, value);
    114     return Replace(value);
    115   }
    116 
    117   // Load from constant type cell can benefit from type feedback.
    118   Type* property_cell_value_type = Type::NonInternal();
    119   MachineRepresentation representation = MachineRepresentation::kTagged;
    120   if (property_details.cell_type() == PropertyCellType::kConstantType) {
    121     // Compute proper type based on the current value in the cell.
    122     if (property_cell_value->IsSmi()) {
    123       property_cell_value_type = Type::SignedSmall();
    124       representation = MachineRepresentation::kTaggedSigned;
    125     } else if (property_cell_value->IsNumber()) {
    126       property_cell_value_type = Type::Number();
    127       representation = MachineRepresentation::kTaggedPointer;
    128     } else {
    129       // TODO(turbofan): Track the property_cell_value_map on the FieldAccess
    130       // below and use it in LoadElimination to eliminate map checks.
    131       Handle<Map> property_cell_value_map(
    132           Handle<HeapObject>::cast(property_cell_value)->map(), isolate());
    133       property_cell_value_type = Type::For(property_cell_value_map);
    134       representation = MachineRepresentation::kTaggedPointer;
    135     }
    136   }
    137   Node* value = effect =
    138       graph()->NewNode(simplified()->LoadField(ForPropertyCellValue(
    139                            representation, property_cell_value_type, name)),
    140                        jsgraph()->HeapConstant(property_cell), effect, control);
    141   ReplaceWithValue(node, value, effect, control);
    142   return Replace(value);
    143 }
    144 
    145 
    146 Reduction JSGlobalObjectSpecialization::ReduceJSStoreGlobal(Node* node) {
    147   DCHECK_EQ(IrOpcode::kJSStoreGlobal, node->opcode());
    148   Handle<Name> name = StoreGlobalParametersOf(node->op()).name();
    149   Node* value = NodeProperties::GetValueInput(node, 0);
    150   Node* effect = NodeProperties::GetEffectInput(node);
    151   Node* control = NodeProperties::GetControlInput(node);
    152 
    153   // Try to lookup the name on the script context table first (lexical scoping).
    154   ScriptContextTableLookupResult result;
    155   if (LookupInScriptContextTable(name, &result)) {
    156     if (result.context->is_the_hole(isolate(), result.index)) return NoChange();
    157     if (result.immutable) return NoChange();
    158     Node* context = jsgraph()->HeapConstant(result.context);
    159     effect = graph()->NewNode(javascript()->StoreContext(0, result.index),
    160                               context, value, context, effect, control);
    161     ReplaceWithValue(node, value, effect, control);
    162     return Replace(value);
    163   }
    164 
    165   // Lookup on the global object instead.  We only deal with own data
    166   // properties of the global object here (represented as PropertyCell).
    167   LookupIterator it(global_object(), name, LookupIterator::OWN);
    168   if (it.state() != LookupIterator::DATA) return NoChange();
    169   if (!it.GetHolder<JSObject>()->IsJSGlobalObject()) return NoChange();
    170   Handle<PropertyCell> property_cell = it.GetPropertyCell();
    171   PropertyDetails property_details = property_cell->property_details();
    172   Handle<Object> property_cell_value(property_cell->value(), isolate());
    173 
    174   // Don't even bother trying to lower stores to read-only data properties.
    175   if (property_details.IsReadOnly()) return NoChange();
    176   switch (property_details.cell_type()) {
    177     case PropertyCellType::kUndefined: {
    178       return NoChange();
    179     }
    180     case PropertyCellType::kConstant: {
    181       // Record a code dependency on the cell, and just deoptimize if the new
    182       // value doesn't match the previous value stored inside the cell.
    183       dependencies()->AssumePropertyCell(property_cell);
    184       Node* check = graph()->NewNode(simplified()->ReferenceEqual(), value,
    185                                      jsgraph()->Constant(property_cell_value));
    186       effect =
    187           graph()->NewNode(simplified()->CheckIf(), check, effect, control);
    188       break;
    189     }
    190     case PropertyCellType::kConstantType: {
    191       // Record a code dependency on the cell, and just deoptimize if the new
    192       // values' type doesn't match the type of the previous value in the cell.
    193       dependencies()->AssumePropertyCell(property_cell);
    194       Type* property_cell_value_type;
    195       MachineRepresentation representation = MachineRepresentation::kTagged;
    196       if (property_cell_value->IsHeapObject()) {
    197         // We cannot do anything if the {property_cell_value}s map is no
    198         // longer stable.
    199         Handle<Map> property_cell_value_map(
    200             Handle<HeapObject>::cast(property_cell_value)->map(), isolate());
    201         if (!property_cell_value_map->is_stable()) return NoChange();
    202         dependencies()->AssumeMapStable(property_cell_value_map);
    203 
    204         // Check that the {value} is a HeapObject.
    205         value = effect = graph()->NewNode(simplified()->CheckHeapObject(),
    206                                           value, effect, control);
    207 
    208         // Check {value} map agains the {property_cell} map.
    209         effect = graph()->NewNode(
    210             simplified()->CheckMaps(1), value,
    211             jsgraph()->HeapConstant(property_cell_value_map), effect, control);
    212         property_cell_value_type = Type::OtherInternal();
    213         representation = MachineRepresentation::kTaggedPointer;
    214       } else {
    215         // Check that the {value} is a Smi.
    216         value = effect =
    217             graph()->NewNode(simplified()->CheckSmi(), value, effect, control);
    218         property_cell_value_type = Type::SignedSmall();
    219         representation = MachineRepresentation::kTaggedSigned;
    220       }
    221       effect = graph()->NewNode(
    222           simplified()->StoreField(ForPropertyCellValue(
    223               representation, property_cell_value_type, name)),
    224           jsgraph()->HeapConstant(property_cell), value, effect, control);
    225       break;
    226     }
    227     case PropertyCellType::kMutable: {
    228       // Store to non-configurable, data property on the global can be lowered
    229       // to a field store, even without recording a code dependency on the cell,
    230       // because the property cannot be deleted or reconfigured to an accessor
    231       // or interceptor property.
    232       if (property_details.IsConfigurable()) {
    233         // Protect lowering by recording a code dependency on the cell.
    234         dependencies()->AssumePropertyCell(property_cell);
    235       }
    236       effect = graph()->NewNode(
    237           simplified()->StoreField(ForPropertyCellValue(
    238               MachineRepresentation::kTagged, Type::NonInternal(), name)),
    239           jsgraph()->HeapConstant(property_cell), value, effect, control);
    240       break;
    241     }
    242   }
    243   ReplaceWithValue(node, value, effect, control);
    244   return Replace(value);
    245 }
    246 
    247 bool JSGlobalObjectSpecialization::LookupInScriptContextTable(
    248     Handle<Name> name, ScriptContextTableLookupResult* result) {
    249   if (!name->IsString()) return false;
    250   Handle<ScriptContextTable> script_context_table(
    251       global_object()->native_context()->script_context_table(), isolate());
    252   ScriptContextTable::LookupResult lookup_result;
    253   if (!ScriptContextTable::Lookup(script_context_table,
    254                                   Handle<String>::cast(name), &lookup_result)) {
    255     return false;
    256   }
    257   Handle<Context> script_context = ScriptContextTable::GetContext(
    258       script_context_table, lookup_result.context_index);
    259   result->context = script_context;
    260   result->immutable = lookup_result.mode == CONST;
    261   result->index = lookup_result.slot_index;
    262   return true;
    263 }
    264 
    265 Graph* JSGlobalObjectSpecialization::graph() const {
    266   return jsgraph()->graph();
    267 }
    268 
    269 Isolate* JSGlobalObjectSpecialization::isolate() const {
    270   return jsgraph()->isolate();
    271 }
    272 
    273 CommonOperatorBuilder* JSGlobalObjectSpecialization::common() const {
    274   return jsgraph()->common();
    275 }
    276 
    277 JSOperatorBuilder* JSGlobalObjectSpecialization::javascript() const {
    278   return jsgraph()->javascript();
    279 }
    280 
    281 SimplifiedOperatorBuilder* JSGlobalObjectSpecialization::simplified() const {
    282   return jsgraph()->simplified();
    283 }
    284 
    285 }  // namespace compiler
    286 }  // namespace internal
    287 }  // namespace v8
    288