| 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-specialization.h" | 5 #include "src/compiler/js-global-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/js-graph.h" | 9 #include "src/compiler/js-graph.h" |
| 10 #include "src/compiler/js-operator.h" | 10 #include "src/compiler/js-operator.h" |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 177 jsgraph()->Constant(property_cell), effect, control); | 177 jsgraph()->Constant(property_cell), effect, control); |
| 178 return Replace(node, value, effect); | 178 return Replace(node, value, effect); |
| 179 } | 179 } |
| 180 | 180 |
| 181 | 181 |
| 182 Reduction JSGlobalSpecialization::ReduceStoreToPropertyCell( | 182 Reduction JSGlobalSpecialization::ReduceStoreToPropertyCell( |
| 183 Node* node, Handle<PropertyCell> property_cell) { | 183 Node* node, Handle<PropertyCell> property_cell) { |
| 184 Node* value = NodeProperties::GetValueInput(node, 2); | 184 Node* value = NodeProperties::GetValueInput(node, 2); |
| 185 Node* effect = NodeProperties::GetEffectInput(node); | 185 Node* effect = NodeProperties::GetEffectInput(node); |
| 186 Node* control = NodeProperties::GetControlInput(node); | 186 Node* control = NodeProperties::GetControlInput(node); |
| 187 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); |
| 187 // We only specialize global data property access. | 188 // We only specialize global data property access. |
| 188 PropertyDetails property_details = property_cell->property_details(); | 189 PropertyDetails property_details = property_cell->property_details(); |
| 189 DCHECK_EQ(kData, property_details.kind()); | 190 DCHECK_EQ(kData, property_details.kind()); |
| 190 Handle<Object> property_cell_value(property_cell->value(), isolate()); | 191 Handle<Object> property_cell_value(property_cell->value(), isolate()); |
| 191 DCHECK(!property_cell_value->IsTheHole()); | 192 DCHECK(!property_cell_value->IsTheHole()); |
| 192 // Don't even bother trying to lower stores to read-only data properties. | 193 // Don't even bother trying to lower stores to read-only data properties. |
| 193 if (property_details.IsReadOnly()) return NoChange(); | 194 if (property_details.IsReadOnly()) return NoChange(); |
| 194 // Not much we can do if we run the generic pipeline here. | 195 // Not much we can do if we run the generic pipeline here. |
| 195 if (!(flags() & kTypingEnabled)) return NoChange(); | 196 if (!(flags() & kTypingEnabled)) return NoChange(); |
| 196 // TODO(bmeurer): For now we deal only with cells in mutable state. | 197 switch (property_details.cell_type()) { |
| 197 if (property_details.cell_type() != PropertyCellType::kMutable) { | 198 case PropertyCellType::kUndefined: { |
| 198 return NoChange(); | 199 return NoChange(); |
| 199 } | 200 } |
| 200 // Store to non-configurable, data property on the global can be lowered to | 201 case PropertyCellType::kConstant: { |
| 201 // a field store, even without deoptimization, because the property cannot be | 202 // Store to constant property cell requires deoptimization support, |
| 202 // deleted or reconfigured to an accessor/interceptor property. | 203 // because we might even need to eager deoptimize for mismatch. |
| 203 if (property_details.IsConfigurable()) { | 204 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); |
| 204 // With deoptimization support, we can lower stores even to configurable | 205 dependencies()->AssumePropertyCell(property_cell); |
| 205 // data properties on the global object, by adding a code dependency on | 206 Node* check = |
| 206 // the cell. | 207 graph()->NewNode(simplified()->ReferenceEqual(Type::Tagged()), value, |
| 207 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); | 208 jsgraph()->Constant(property_cell_value)); |
| 208 dependencies()->AssumePropertyCell(property_cell); | 209 Node* branch = |
| 210 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); |
| 211 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
| 212 Node* deoptimize = graph()->NewNode(common()->Deoptimize(), frame_state, |
| 213 effect, if_false); |
| 214 // TODO(bmeurer): This should be on the AdvancedReducer somehow. |
| 215 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize); |
| 216 control = graph()->NewNode(common()->IfTrue(), branch); |
| 217 return Replace(node, value, effect, control); |
| 218 } |
| 219 case PropertyCellType::kConstantType: { |
| 220 // Store to constant-type property cell requires deoptimization support, |
| 221 // because we might even need to eager deoptimize for mismatch. |
| 222 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); |
| 223 dependencies()->AssumePropertyCell(property_cell); |
| 224 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value); |
| 225 if (property_cell_value->IsHeapObject()) { |
| 226 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kFalse), |
| 227 check, control); |
| 228 Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
| 229 Node* deoptimize = graph()->NewNode(common()->Deoptimize(), frame_state, |
| 230 effect, if_true); |
| 231 // TODO(bmeurer): This should be on the AdvancedReducer somehow. |
| 232 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize); |
| 233 control = graph()->NewNode(common()->IfFalse(), branch); |
| 234 Node* value_map = |
| 235 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), |
| 236 value, effect, control); |
| 237 Handle<Map> property_cell_value_map( |
| 238 Handle<HeapObject>::cast(property_cell_value)->map(), isolate()); |
| 239 check = graph()->NewNode(simplified()->ReferenceEqual(Type::Internal()), |
| 240 value_map, |
| 241 jsgraph()->Constant(property_cell_value_map)); |
| 242 } |
| 243 Node* branch = |
| 244 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); |
| 245 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
| 246 Node* deoptimize = graph()->NewNode(common()->Deoptimize(), frame_state, |
| 247 effect, if_false); |
| 248 // TODO(bmeurer): This should be on the AdvancedReducer somehow. |
| 249 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize); |
| 250 control = graph()->NewNode(common()->IfTrue(), branch); |
| 251 break; |
| 252 } |
| 253 case PropertyCellType::kMutable: { |
| 254 // Store to non-configurable, data property on the global can be lowered |
| 255 // to a field store, even without deoptimization, because the property |
| 256 // cannot be deleted or reconfigured to an accessor/interceptor property. |
| 257 if (property_details.IsConfigurable()) { |
| 258 // With deoptimization support, we can lower stores even to configurable |
| 259 // data properties on the global object, by adding a code dependency on |
| 260 // the cell. |
| 261 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); |
| 262 dependencies()->AssumePropertyCell(property_cell); |
| 263 } |
| 264 break; |
| 265 } |
| 209 } | 266 } |
| 210 effect = graph()->NewNode( | 267 effect = graph()->NewNode( |
| 211 simplified()->StoreField(AccessBuilder::ForPropertyCellValue()), | 268 simplified()->StoreField(AccessBuilder::ForPropertyCellValue()), |
| 212 jsgraph()->Constant(property_cell), value, effect, control); | 269 jsgraph()->Constant(property_cell), value, effect, control); |
| 213 return Replace(node, value, effect, control); | 270 return Replace(node, value, effect, control); |
| 214 } | 271 } |
| 215 | 272 |
| 216 | 273 |
| 217 Reduction JSGlobalSpecialization::Replace(Node* node, Handle<Object> value) { | 274 Reduction JSGlobalSpecialization::Replace(Node* node, Handle<Object> value) { |
| 218 if (value->IsConsString()) { | 275 if (value->IsConsString()) { |
| 219 value = String::Flatten(Handle<String>::cast(value), TENURED); | 276 value = String::Flatten(Handle<String>::cast(value), TENURED); |
| 220 } | 277 } |
| 221 return Replace(node, jsgraph()->Constant(value)); | 278 return Replace(node, jsgraph()->Constant(value)); |
| 222 } | 279 } |
| 223 | 280 |
| 224 | 281 |
| 225 Graph* JSGlobalSpecialization::graph() const { return jsgraph()->graph(); } | 282 Graph* JSGlobalSpecialization::graph() const { return jsgraph()->graph(); } |
| 226 | 283 |
| 227 | 284 |
| 228 Isolate* JSGlobalSpecialization::isolate() const { | 285 Isolate* JSGlobalSpecialization::isolate() const { |
| 229 return jsgraph()->isolate(); | 286 return jsgraph()->isolate(); |
| 230 } | 287 } |
| 231 | 288 |
| 232 | 289 |
| 290 CommonOperatorBuilder* JSGlobalSpecialization::common() const { |
| 291 return jsgraph()->common(); |
| 292 } |
| 293 |
| 294 |
| 233 JSOperatorBuilder* JSGlobalSpecialization::javascript() const { | 295 JSOperatorBuilder* JSGlobalSpecialization::javascript() const { |
| 234 return jsgraph()->javascript(); | 296 return jsgraph()->javascript(); |
| 235 } | 297 } |
| 236 | 298 |
| 237 } // namespace compiler | 299 } // namespace compiler |
| 238 } // namespace internal | 300 } // namespace internal |
| 239 } // namespace v8 | 301 } // namespace v8 |
| OLD | NEW |