| OLD | NEW |
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/compiler/js-global-object-specialization.h" | 5 #include "src/compiler/js-global-object-specialization.h" |
| 6 | 6 |
| 7 #include "src/compilation-dependencies.h" | 7 #include "src/compilation-dependencies.h" |
| 8 #include "src/compiler/access-builder.h" | 8 #include "src/compiler/access-builder.h" |
| 9 #include "src/compiler/common-operator.h" | 9 #include "src/compiler/common-operator.h" |
| 10 #include "src/compiler/js-graph.h" | 10 #include "src/compiler/js-graph.h" |
| 11 #include "src/compiler/js-operator.h" | 11 #include "src/compiler/js-operator.h" |
| 12 #include "src/compiler/node-properties.h" | 12 #include "src/compiler/node-properties.h" |
| 13 #include "src/compiler/simplified-operator.h" | 13 #include "src/compiler/simplified-operator.h" |
| 14 #include "src/lookup.h" | 14 #include "src/lookup.h" |
| 15 #include "src/objects-inl.h" // TODO(mstarzinger): Temporary cycle breaker! | 15 #include "src/objects-inl.h" // TODO(mstarzinger): Temporary cycle breaker! |
| 16 #include "src/type-cache.h" | 16 #include "src/type-cache.h" |
| 17 | 17 |
| 18 namespace v8 { | 18 namespace v8 { |
| 19 namespace internal { | 19 namespace internal { |
| 20 namespace compiler { | 20 namespace compiler { |
| 21 | 21 |
| 22 struct JSGlobalObjectSpecialization::ScriptContextTableLookupResult { | 22 struct JSGlobalObjectSpecialization::ScriptContextTableLookupResult { |
| 23 Handle<Context> context; | 23 Handle<Context> context; |
| 24 bool immutable; | 24 bool immutable; |
| 25 int index; | 25 int index; |
| 26 }; | 26 }; |
| 27 | 27 |
| 28 | 28 |
| 29 JSGlobalObjectSpecialization::JSGlobalObjectSpecialization( | 29 JSGlobalObjectSpecialization::JSGlobalObjectSpecialization( |
| 30 Editor* editor, JSGraph* jsgraph, Flags flags, | 30 Editor* editor, JSGraph* jsgraph, |
| 31 MaybeHandle<Context> native_context, CompilationDependencies* dependencies) | 31 MaybeHandle<Context> native_context, CompilationDependencies* dependencies) |
| 32 : AdvancedReducer(editor), | 32 : AdvancedReducer(editor), |
| 33 jsgraph_(jsgraph), | 33 jsgraph_(jsgraph), |
| 34 flags_(flags), | |
| 35 native_context_(native_context), | 34 native_context_(native_context), |
| 36 dependencies_(dependencies), | 35 dependencies_(dependencies), |
| 37 type_cache_(TypeCache::Get()) {} | 36 type_cache_(TypeCache::Get()) {} |
| 38 | 37 |
| 39 | 38 |
| 40 Reduction JSGlobalObjectSpecialization::Reduce(Node* node) { | 39 Reduction JSGlobalObjectSpecialization::Reduce(Node* node) { |
| 41 switch (node->opcode()) { | 40 switch (node->opcode()) { |
| 42 case IrOpcode::kJSLoadGlobal: | 41 case IrOpcode::kJSLoadGlobal: |
| 43 return ReduceJSLoadGlobal(node); | 42 return ReduceJSLoadGlobal(node); |
| 44 case IrOpcode::kJSStoreGlobal: | 43 case IrOpcode::kJSStoreGlobal: |
| 45 return ReduceJSStoreGlobal(node); | 44 return ReduceJSStoreGlobal(node); |
| 46 default: | 45 default: |
| 47 break; | 46 break; |
| 48 } | 47 } |
| 49 return NoChange(); | 48 return NoChange(); |
| 50 } | 49 } |
| 51 | 50 |
| 52 | |
| 53 Reduction JSGlobalObjectSpecialization::ReduceJSLoadGlobal(Node* node) { | 51 Reduction JSGlobalObjectSpecialization::ReduceJSLoadGlobal(Node* node) { |
| 54 DCHECK_EQ(IrOpcode::kJSLoadGlobal, node->opcode()); | 52 DCHECK_EQ(IrOpcode::kJSLoadGlobal, node->opcode()); |
| 55 Handle<Name> name = LoadGlobalParametersOf(node->op()).name(); | 53 Handle<Name> name = LoadGlobalParametersOf(node->op()).name(); |
| 56 Node* effect = NodeProperties::GetEffectInput(node); | 54 Node* effect = NodeProperties::GetEffectInput(node); |
| 57 Node* control = NodeProperties::GetControlInput(node); | 55 Node* control = NodeProperties::GetControlInput(node); |
| 58 | 56 |
| 59 // Retrieve the global object from the given {node}. | 57 // Retrieve the global object from the given {node}. |
| 60 Handle<JSGlobalObject> global_object; | 58 Handle<JSGlobalObject> global_object; |
| 61 if (!GetGlobalObject(node).ToHandle(&global_object)) return NoChange(); | 59 if (!GetGlobalObject(node).ToHandle(&global_object)) return NoChange(); |
| 62 | 60 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 81 Handle<Object> property_cell_value(property_cell->value(), isolate()); | 79 Handle<Object> property_cell_value(property_cell->value(), isolate()); |
| 82 | 80 |
| 83 // Load from non-configurable, read-only data property on the global | 81 // Load from non-configurable, read-only data property on the global |
| 84 // object can be constant-folded, even without deoptimization support. | 82 // object can be constant-folded, even without deoptimization support. |
| 85 if (!property_details.IsConfigurable() && property_details.IsReadOnly()) { | 83 if (!property_details.IsConfigurable() && property_details.IsReadOnly()) { |
| 86 Node* value = jsgraph()->Constant(property_cell_value); | 84 Node* value = jsgraph()->Constant(property_cell_value); |
| 87 ReplaceWithValue(node, value); | 85 ReplaceWithValue(node, value); |
| 88 return Replace(value); | 86 return Replace(value); |
| 89 } | 87 } |
| 90 | 88 |
| 91 // Load from non-configurable, data property on the global can be lowered to | 89 // Record a code dependency on the cell if we can benefit from the |
| 92 // a field load, even without deoptimization, because the property cannot be | 90 // additional feedback, or the global property is configurable (i.e. |
| 93 // deleted or reconfigured to an accessor/interceptor property. Yet, if | 91 // can be deleted or reconfigured to an accessor property). |
| 94 // deoptimization support is available, we can constant-fold certain global | 92 if (property_details.cell_type() != PropertyCellType::kMutable || |
| 95 // properties or at least lower them to field loads annotated with more | 93 property_details.IsConfigurable()) { |
| 96 // precise type feedback. | 94 dependencies()->AssumePropertyCell(property_cell); |
| 95 } |
| 96 |
| 97 // Load from constant/undefined global property can be constant-folded. |
| 98 if (property_details.cell_type() == PropertyCellType::kConstant || |
| 99 property_details.cell_type() == PropertyCellType::kUndefined) { |
| 100 Node* value = jsgraph()->Constant(property_cell_value); |
| 101 ReplaceWithValue(node, value); |
| 102 return Replace(value); |
| 103 } |
| 104 |
| 105 // Load from constant type cell can benefit from type feedback. |
| 97 Type* property_cell_value_type = Type::Tagged(); | 106 Type* property_cell_value_type = Type::Tagged(); |
| 98 if (flags() & kDeoptimizationEnabled) { | 107 if (property_details.cell_type() == PropertyCellType::kConstantType) { |
| 99 // Record a code dependency on the cell if we can benefit from the | 108 // Compute proper type based on the current value in the cell. |
| 100 // additional feedback, or the global property is configurable (i.e. | 109 if (property_cell_value->IsSmi()) { |
| 101 // can be deleted or reconfigured to an accessor property). | 110 property_cell_value_type = type_cache_.kSmi; |
| 102 if (property_details.cell_type() != PropertyCellType::kMutable || | 111 } else if (property_cell_value->IsNumber()) { |
| 103 property_details.IsConfigurable()) { | 112 property_cell_value_type = type_cache_.kHeapNumber; |
| 104 dependencies()->AssumePropertyCell(property_cell); | 113 } else { |
| 114 Handle<Map> property_cell_value_map( |
| 115 Handle<HeapObject>::cast(property_cell_value)->map(), isolate()); |
| 116 property_cell_value_type = |
| 117 Type::Class(property_cell_value_map, graph()->zone()); |
| 105 } | 118 } |
| 106 | |
| 107 // Load from constant/undefined global property can be constant-folded. | |
| 108 if ((property_details.cell_type() == PropertyCellType::kConstant || | |
| 109 property_details.cell_type() == PropertyCellType::kUndefined)) { | |
| 110 Node* value = jsgraph()->Constant(property_cell_value); | |
| 111 ReplaceWithValue(node, value); | |
| 112 return Replace(value); | |
| 113 } | |
| 114 | |
| 115 // Load from constant type cell can benefit from type feedback. | |
| 116 if (property_details.cell_type() == PropertyCellType::kConstantType) { | |
| 117 // Compute proper type based on the current value in the cell. | |
| 118 if (property_cell_value->IsSmi()) { | |
| 119 property_cell_value_type = type_cache_.kSmi; | |
| 120 } else if (property_cell_value->IsNumber()) { | |
| 121 property_cell_value_type = type_cache_.kHeapNumber; | |
| 122 } else { | |
| 123 Handle<Map> property_cell_value_map( | |
| 124 Handle<HeapObject>::cast(property_cell_value)->map(), isolate()); | |
| 125 property_cell_value_type = | |
| 126 Type::Class(property_cell_value_map, graph()->zone()); | |
| 127 } | |
| 128 } | |
| 129 } else if (property_details.IsConfigurable()) { | |
| 130 // Access to configurable global properties requires deoptimization support. | |
| 131 return NoChange(); | |
| 132 } | 119 } |
| 133 Node* value = effect = graph()->NewNode( | 120 Node* value = effect = graph()->NewNode( |
| 134 simplified()->LoadField( | 121 simplified()->LoadField( |
| 135 AccessBuilder::ForPropertyCellValue(property_cell_value_type)), | 122 AccessBuilder::ForPropertyCellValue(property_cell_value_type)), |
| 136 jsgraph()->HeapConstant(property_cell), effect, control); | 123 jsgraph()->HeapConstant(property_cell), effect, control); |
| 137 ReplaceWithValue(node, value, effect, control); | 124 ReplaceWithValue(node, value, effect, control); |
| 138 return Replace(value); | 125 return Replace(value); |
| 139 } | 126 } |
| 140 | 127 |
| 141 | 128 |
| (...skipping 29 matching lines...) Expand all Loading... |
| 171 PropertyDetails property_details = property_cell->property_details(); | 158 PropertyDetails property_details = property_cell->property_details(); |
| 172 Handle<Object> property_cell_value(property_cell->value(), isolate()); | 159 Handle<Object> property_cell_value(property_cell->value(), isolate()); |
| 173 | 160 |
| 174 // Don't even bother trying to lower stores to read-only data properties. | 161 // Don't even bother trying to lower stores to read-only data properties. |
| 175 if (property_details.IsReadOnly()) return NoChange(); | 162 if (property_details.IsReadOnly()) return NoChange(); |
| 176 switch (property_details.cell_type()) { | 163 switch (property_details.cell_type()) { |
| 177 case PropertyCellType::kUndefined: { | 164 case PropertyCellType::kUndefined: { |
| 178 return NoChange(); | 165 return NoChange(); |
| 179 } | 166 } |
| 180 case PropertyCellType::kConstant: { | 167 case PropertyCellType::kConstant: { |
| 181 // Store to constant property cell requires deoptimization support, | 168 // Record a code dependency on the cell, and just deoptimize if the new |
| 182 // because we might even need to eager deoptimize for mismatch. | 169 // value doesn't match the previous value stored inside the cell. |
| 183 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); | |
| 184 dependencies()->AssumePropertyCell(property_cell); | 170 dependencies()->AssumePropertyCell(property_cell); |
| 185 Node* check = | 171 Node* check = |
| 186 graph()->NewNode(simplified()->ReferenceEqual(Type::Tagged()), value, | 172 graph()->NewNode(simplified()->ReferenceEqual(Type::Tagged()), value, |
| 187 jsgraph()->Constant(property_cell_value)); | 173 jsgraph()->Constant(property_cell_value)); |
| 188 Node* branch = | 174 Node* branch = |
| 189 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); | 175 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); |
| 190 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); | 176 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
| 191 Node* deoptimize = | 177 Node* deoptimize = |
| 192 graph()->NewNode(common()->Deoptimize(DeoptimizeKind::kEager), | 178 graph()->NewNode(common()->Deoptimize(DeoptimizeKind::kEager), |
| 193 frame_state, effect, if_false); | 179 frame_state, effect, if_false); |
| 194 // TODO(bmeurer): This should be on the AdvancedReducer somehow. | 180 // TODO(bmeurer): This should be on the AdvancedReducer somehow. |
| 195 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize); | 181 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize); |
| 196 control = graph()->NewNode(common()->IfTrue(), branch); | 182 control = graph()->NewNode(common()->IfTrue(), branch); |
| 197 break; | 183 break; |
| 198 } | 184 } |
| 199 case PropertyCellType::kConstantType: { | 185 case PropertyCellType::kConstantType: { |
| 200 // Store to constant-type property cell requires deoptimization support, | 186 // Record a code dependency on the cell, and just deoptimize if the new |
| 201 // because we might even need to eager deoptimize for mismatch. | 187 // values' type doesn't match the type of the previous value in the cell. |
| 202 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); | |
| 203 dependencies()->AssumePropertyCell(property_cell); | 188 dependencies()->AssumePropertyCell(property_cell); |
| 204 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value); | 189 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value); |
| 205 Type* property_cell_value_type = Type::TaggedSigned(); | 190 Type* property_cell_value_type = Type::TaggedSigned(); |
| 206 if (property_cell_value->IsHeapObject()) { | 191 if (property_cell_value->IsHeapObject()) { |
| 207 // Deoptimize if the {value} is a Smi. | 192 // Deoptimize if the {value} is a Smi. |
| 208 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kFalse), | 193 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kFalse), |
| 209 check, control); | 194 check, control); |
| 210 Node* if_true = graph()->NewNode(common()->IfTrue(), branch); | 195 Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
| 211 Node* deoptimize = | 196 Node* deoptimize = |
| 212 graph()->NewNode(common()->Deoptimize(DeoptimizeKind::kEager), | 197 graph()->NewNode(common()->Deoptimize(DeoptimizeKind::kEager), |
| (...skipping 23 matching lines...) Expand all Loading... |
| 236 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize); | 221 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize); |
| 237 control = graph()->NewNode(common()->IfTrue(), branch); | 222 control = graph()->NewNode(common()->IfTrue(), branch); |
| 238 effect = graph()->NewNode( | 223 effect = graph()->NewNode( |
| 239 simplified()->StoreField( | 224 simplified()->StoreField( |
| 240 AccessBuilder::ForPropertyCellValue(property_cell_value_type)), | 225 AccessBuilder::ForPropertyCellValue(property_cell_value_type)), |
| 241 jsgraph()->HeapConstant(property_cell), value, effect, control); | 226 jsgraph()->HeapConstant(property_cell), value, effect, control); |
| 242 break; | 227 break; |
| 243 } | 228 } |
| 244 case PropertyCellType::kMutable: { | 229 case PropertyCellType::kMutable: { |
| 245 // Store to non-configurable, data property on the global can be lowered | 230 // Store to non-configurable, data property on the global can be lowered |
| 246 // to a field store, even without deoptimization, because the property | 231 // to a field store, even without recording a code dependency on the cell, |
| 247 // cannot be deleted or reconfigured to an accessor/interceptor property. | 232 // because the property cannot be deleted or reconfigured to an accessor |
| 233 // or interceptor property. |
| 248 if (property_details.IsConfigurable()) { | 234 if (property_details.IsConfigurable()) { |
| 249 // With deoptimization support, we can lower stores even to configurable | 235 // Protect lowering by recording a code dependency on the cell. |
| 250 // data properties on the global object, by adding a code dependency on | |
| 251 // the cell. | |
| 252 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); | |
| 253 dependencies()->AssumePropertyCell(property_cell); | 236 dependencies()->AssumePropertyCell(property_cell); |
| 254 } | 237 } |
| 255 effect = graph()->NewNode( | 238 effect = graph()->NewNode( |
| 256 simplified()->StoreField(AccessBuilder::ForPropertyCellValue()), | 239 simplified()->StoreField(AccessBuilder::ForPropertyCellValue()), |
| 257 jsgraph()->HeapConstant(property_cell), value, effect, control); | 240 jsgraph()->HeapConstant(property_cell), value, effect, control); |
| 258 break; | 241 break; |
| 259 } | 242 } |
| 260 } | 243 } |
| 261 ReplaceWithValue(node, value, effect, control); | 244 ReplaceWithValue(node, value, effect, control); |
| 262 return Replace(value); | 245 return Replace(value); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 311 } | 294 } |
| 312 | 295 |
| 313 | 296 |
| 314 SimplifiedOperatorBuilder* JSGlobalObjectSpecialization::simplified() const { | 297 SimplifiedOperatorBuilder* JSGlobalObjectSpecialization::simplified() const { |
| 315 return jsgraph()->simplified(); | 298 return jsgraph()->simplified(); |
| 316 } | 299 } |
| 317 | 300 |
| 318 } // namespace compiler | 301 } // namespace compiler |
| 319 } // namespace internal | 302 } // namespace internal |
| 320 } // namespace v8 | 303 } // namespace v8 |
| OLD | NEW |