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 |