| OLD | NEW |
| (Empty) |
| 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-specialization.h" | |
| 6 | |
| 7 #include "src/compilation-dependencies.h" | |
| 8 #include "src/compiler/access-builder.h" | |
| 9 #include "src/compiler/js-graph.h" | |
| 10 #include "src/compiler/js-operator.h" | |
| 11 #include "src/contexts.h" | |
| 12 #include "src/lookup.h" | |
| 13 #include "src/objects-inl.h" | |
| 14 | |
| 15 namespace v8 { | |
| 16 namespace internal { | |
| 17 namespace compiler { | |
| 18 | |
| 19 JSGlobalSpecialization::JSGlobalSpecialization( | |
| 20 Editor* editor, JSGraph* jsgraph, Flags flags, | |
| 21 Handle<GlobalObject> global_object, CompilationDependencies* dependencies) | |
| 22 : AdvancedReducer(editor), | |
| 23 jsgraph_(jsgraph), | |
| 24 flags_(flags), | |
| 25 global_object_(global_object), | |
| 26 dependencies_(dependencies), | |
| 27 simplified_(graph()->zone()) {} | |
| 28 | |
| 29 | |
| 30 Reduction JSGlobalSpecialization::Reduce(Node* node) { | |
| 31 switch (node->opcode()) { | |
| 32 case IrOpcode::kJSLoadGlobal: | |
| 33 return ReduceJSLoadGlobal(node); | |
| 34 case IrOpcode::kJSStoreGlobal: | |
| 35 return ReduceJSStoreGlobal(node); | |
| 36 default: | |
| 37 break; | |
| 38 } | |
| 39 return NoChange(); | |
| 40 } | |
| 41 | |
| 42 | |
| 43 Reduction JSGlobalSpecialization::ReduceJSLoadGlobal(Node* node) { | |
| 44 DCHECK_EQ(IrOpcode::kJSLoadGlobal, node->opcode()); | |
| 45 Handle<Name> name = LoadGlobalParametersOf(node->op()).name(); | |
| 46 Node* effect = NodeProperties::GetEffectInput(node); | |
| 47 | |
| 48 // Try to lookup the name on the script context table first (lexical scoping). | |
| 49 if (name->IsString()) { | |
| 50 Handle<ScriptContextTable> script_context_table( | |
| 51 global_object()->native_context()->script_context_table()); | |
| 52 ScriptContextTable::LookupResult result; | |
| 53 if (ScriptContextTable::Lookup(script_context_table, | |
| 54 Handle<String>::cast(name), &result)) { | |
| 55 Handle<Context> script_context = ScriptContextTable::GetContext( | |
| 56 script_context_table, result.context_index); | |
| 57 if (script_context->is_the_hole(result.slot_index)) { | |
| 58 // TODO(bmeurer): Is this relevant in practice? | |
| 59 return NoChange(); | |
| 60 } | |
| 61 Node* context = jsgraph()->Constant(script_context); | |
| 62 Node* value = effect = graph()->NewNode( | |
| 63 javascript()->LoadContext(0, result.slot_index, | |
| 64 IsImmutableVariableMode(result.mode)), | |
| 65 context, context, effect); | |
| 66 return Replace(node, value, effect); | |
| 67 } | |
| 68 } | |
| 69 | |
| 70 // Lookup on the global object instead. | |
| 71 LookupIterator it(global_object(), name, LookupIterator::OWN); | |
| 72 if (it.state() == LookupIterator::DATA) { | |
| 73 return ReduceLoadFromPropertyCell(node, it.GetPropertyCell()); | |
| 74 } | |
| 75 | |
| 76 return NoChange(); | |
| 77 } | |
| 78 | |
| 79 | |
| 80 Reduction JSGlobalSpecialization::ReduceJSStoreGlobal(Node* node) { | |
| 81 DCHECK_EQ(IrOpcode::kJSStoreGlobal, node->opcode()); | |
| 82 Handle<Name> name = StoreGlobalParametersOf(node->op()).name(); | |
| 83 Node* value = NodeProperties::GetValueInput(node, 2); | |
| 84 Node* effect = NodeProperties::GetEffectInput(node); | |
| 85 Node* control = NodeProperties::GetControlInput(node); | |
| 86 | |
| 87 // Try to lookup the name on the script context table first (lexical scoping). | |
| 88 if (name->IsString()) { | |
| 89 Handle<ScriptContextTable> script_context_table( | |
| 90 global_object()->native_context()->script_context_table()); | |
| 91 ScriptContextTable::LookupResult result; | |
| 92 if (ScriptContextTable::Lookup(script_context_table, | |
| 93 Handle<String>::cast(name), &result)) { | |
| 94 if (IsImmutableVariableMode(result.mode)) return NoChange(); | |
| 95 Handle<Context> script_context = ScriptContextTable::GetContext( | |
| 96 script_context_table, result.context_index); | |
| 97 if (script_context->is_the_hole(result.slot_index)) { | |
| 98 // TODO(bmeurer): Is this relevant in practice? | |
| 99 return NoChange(); | |
| 100 } | |
| 101 Node* context = jsgraph()->Constant(script_context); | |
| 102 effect = | |
| 103 graph()->NewNode(javascript()->StoreContext(0, result.slot_index), | |
| 104 context, value, context, effect, control); | |
| 105 return Replace(node, value, effect, control); | |
| 106 } | |
| 107 } | |
| 108 | |
| 109 // Lookup on the global object instead. | |
| 110 LookupIterator it(global_object(), name, LookupIterator::OWN); | |
| 111 if (it.state() == LookupIterator::DATA) { | |
| 112 return ReduceStoreToPropertyCell(node, it.GetPropertyCell()); | |
| 113 } | |
| 114 | |
| 115 return NoChange(); | |
| 116 } | |
| 117 | |
| 118 | |
| 119 Reduction JSGlobalSpecialization::ReduceLoadFromPropertyCell( | |
| 120 Node* node, Handle<PropertyCell> property_cell) { | |
| 121 Node* effect = NodeProperties::GetEffectInput(node); | |
| 122 Node* control = NodeProperties::GetControlInput(node); | |
| 123 // We only specialize global data property access. | |
| 124 PropertyDetails property_details = property_cell->property_details(); | |
| 125 DCHECK_EQ(kData, property_details.kind()); | |
| 126 Handle<Object> property_cell_value(property_cell->value(), isolate()); | |
| 127 DCHECK(!property_cell_value->IsTheHole()); | |
| 128 // Load from non-configurable, read-only data property on the global | |
| 129 // object can be constant-folded, even without deoptimization support. | |
| 130 if (!property_details.IsConfigurable() && property_details.IsReadOnly()) { | |
| 131 return Replace(node, property_cell_value); | |
| 132 } | |
| 133 // Load from constant/undefined global property can be constant-folded | |
| 134 // with deoptimization support, by adding a code dependency on the cell. | |
| 135 if ((property_details.cell_type() == PropertyCellType::kConstant || | |
| 136 property_details.cell_type() == PropertyCellType::kUndefined) && | |
| 137 (flags() & kDeoptimizationEnabled)) { | |
| 138 dependencies()->AssumePropertyCell(property_cell); | |
| 139 return Replace(node, property_cell_value); | |
| 140 } | |
| 141 // Not much we can do if we run the generic pipeline here. | |
| 142 if (!(flags() & kTypingEnabled)) return NoChange(); | |
| 143 // Load from constant type global property can benefit from representation | |
| 144 // (and map) feedback with deoptimization support (requires code dependency). | |
| 145 if (property_details.cell_type() == PropertyCellType::kConstantType && | |
| 146 (flags() & kDeoptimizationEnabled)) { | |
| 147 dependencies()->AssumePropertyCell(property_cell); | |
| 148 Type* property_cell_value_type = Type::Any(); | |
| 149 switch (property_cell->GetConstantType()) { | |
| 150 case PropertyCellConstantType::kSmi: | |
| 151 property_cell_value_type = Type::Intersect( | |
| 152 Type::SignedSmall(), Type::TaggedSigned(), graph()->zone()); | |
| 153 break; | |
| 154 case PropertyCellConstantType::kStableMap: { | |
| 155 // TODO(bmeurer): Determine type based on the map's instance type. | |
| 156 property_cell_value_type = Type::TaggedPointer(); | |
| 157 break; | |
| 158 } | |
| 159 } | |
| 160 Node* value = effect = graph()->NewNode( | |
| 161 simplified()->LoadField( | |
| 162 AccessBuilder::ForPropertyCellValue(property_cell_value_type)), | |
| 163 jsgraph()->Constant(property_cell), effect, control); | |
| 164 return Replace(node, value, effect); | |
| 165 } | |
| 166 // Load from non-configurable, data property on the global can be lowered to | |
| 167 // a field load, even without deoptimization, because the property cannot be | |
| 168 // deleted or reconfigured to an accessor/interceptor property. | |
| 169 if (property_details.IsConfigurable()) { | |
| 170 // With deoptimization support, we can lower loads even from configurable | |
| 171 // data properties on the global object, by adding a code dependency on | |
| 172 // the cell. | |
| 173 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); | |
| 174 dependencies()->AssumePropertyCell(property_cell); | |
| 175 } | |
| 176 Node* value = effect = graph()->NewNode( | |
| 177 simplified()->LoadField(AccessBuilder::ForPropertyCellValue()), | |
| 178 jsgraph()->Constant(property_cell), effect, control); | |
| 179 return Replace(node, value, effect); | |
| 180 } | |
| 181 | |
| 182 | |
| 183 Reduction JSGlobalSpecialization::ReduceStoreToPropertyCell( | |
| 184 Node* node, Handle<PropertyCell> property_cell) { | |
| 185 Node* value = NodeProperties::GetValueInput(node, 2); | |
| 186 Node* effect = NodeProperties::GetEffectInput(node); | |
| 187 Node* control = NodeProperties::GetControlInput(node); | |
| 188 // We only specialize global data property access. | |
| 189 PropertyDetails property_details = property_cell->property_details(); | |
| 190 DCHECK_EQ(kData, property_details.kind()); | |
| 191 Handle<Object> property_cell_value(property_cell->value(), isolate()); | |
| 192 DCHECK(!property_cell_value->IsTheHole()); | |
| 193 // Don't even bother trying to lower stores to read-only data properties. | |
| 194 if (property_details.IsReadOnly()) return NoChange(); | |
| 195 // Not much we can do if we run the generic pipeline here. | |
| 196 if (!(flags() & kTypingEnabled)) return NoChange(); | |
| 197 // TODO(bmeurer): For now we deal only with cells in mutable state. | |
| 198 if (property_details.cell_type() != PropertyCellType::kMutable) { | |
| 199 return NoChange(); | |
| 200 } | |
| 201 // Store to non-configurable, data property on the global can be lowered to | |
| 202 // a field store, even without deoptimization, because the property cannot be | |
| 203 // deleted or reconfigured to an accessor/interceptor property. | |
| 204 if (property_details.IsConfigurable()) { | |
| 205 // With deoptimization support, we can lower stores even to configurable | |
| 206 // data properties on the global object, by adding a code dependency on | |
| 207 // the cell. | |
| 208 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); | |
| 209 dependencies()->AssumePropertyCell(property_cell); | |
| 210 } | |
| 211 effect = graph()->NewNode( | |
| 212 simplified()->StoreField(AccessBuilder::ForPropertyCellValue()), | |
| 213 jsgraph()->Constant(property_cell), value, effect, control); | |
| 214 return Replace(node, value, effect, control); | |
| 215 } | |
| 216 | |
| 217 | |
| 218 Reduction JSGlobalSpecialization::Replace(Node* node, Handle<Object> value) { | |
| 219 if (value->IsConsString()) { | |
| 220 value = String::Flatten(Handle<String>::cast(value), TENURED); | |
| 221 } | |
| 222 return Replace(node, jsgraph()->Constant(value)); | |
| 223 } | |
| 224 | |
| 225 | |
| 226 Graph* JSGlobalSpecialization::graph() const { return jsgraph()->graph(); } | |
| 227 | |
| 228 | |
| 229 Isolate* JSGlobalSpecialization::isolate() const { | |
| 230 return jsgraph()->isolate(); | |
| 231 } | |
| 232 | |
| 233 | |
| 234 JSOperatorBuilder* JSGlobalSpecialization::javascript() const { | |
| 235 return jsgraph()->javascript(); | |
| 236 } | |
| 237 | |
| 238 } // namespace compiler | |
| 239 } // namespace internal | |
| 240 } // namespace v8 | |
| OLD | NEW |