| 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" | 
| 11 #include "src/contexts.h" | 11 #include "src/contexts.h" | 
| 12 #include "src/field-index-inl.h" |  | 
| 13 #include "src/lookup.h" | 12 #include "src/lookup.h" | 
| 14 #include "src/objects-inl.h"  // TODO(mstarzinger): Temporary cycle breaker! | 13 #include "src/objects-inl.h"  // TODO(mstarzinger): Temporary cycle breaker! | 
| 15 #include "src/type-feedback-vector.h" |  | 
| 16 | 14 | 
| 17 namespace v8 { | 15 namespace v8 { | 
| 18 namespace internal { | 16 namespace internal { | 
| 19 namespace compiler { | 17 namespace compiler { | 
| 20 | 18 | 
| 21 struct JSGlobalSpecialization::ScriptContextTableLookupResult { | 19 struct JSGlobalSpecialization::ScriptContextTableLookupResult { | 
| 22   Handle<Context> context; | 20   Handle<Context> context; | 
| 23   bool immutable; | 21   bool immutable; | 
| 24   int index; | 22   int index; | 
| 25 }; | 23 }; | 
| 26 | 24 | 
| 27 | 25 | 
| 28 JSGlobalSpecialization::JSGlobalSpecialization( | 26 JSGlobalSpecialization::JSGlobalSpecialization( | 
| 29     Editor* editor, JSGraph* jsgraph, Flags flags, | 27     Editor* editor, JSGraph* jsgraph, Flags flags, | 
| 30     Handle<GlobalObject> global_object, CompilationDependencies* dependencies, | 28     Handle<GlobalObject> global_object, CompilationDependencies* dependencies) | 
| 31     Zone* zone) |  | 
| 32     : AdvancedReducer(editor), | 29     : AdvancedReducer(editor), | 
| 33       jsgraph_(jsgraph), | 30       jsgraph_(jsgraph), | 
| 34       flags_(flags), | 31       flags_(flags), | 
| 35       global_object_(global_object), | 32       global_object_(global_object), | 
| 36       dependencies_(dependencies), | 33       dependencies_(dependencies) {} | 
| 37       zone_(zone) {} |  | 
| 38 | 34 | 
| 39 | 35 | 
| 40 Reduction JSGlobalSpecialization::Reduce(Node* node) { | 36 Reduction JSGlobalSpecialization::Reduce(Node* node) { | 
| 41   switch (node->opcode()) { | 37   switch (node->opcode()) { | 
| 42     case IrOpcode::kJSLoadGlobal: | 38     case IrOpcode::kJSLoadGlobal: | 
| 43       return ReduceJSLoadGlobal(node); | 39       return ReduceJSLoadGlobal(node); | 
| 44     case IrOpcode::kJSStoreGlobal: | 40     case IrOpcode::kJSStoreGlobal: | 
| 45       return ReduceJSStoreGlobal(node); | 41       return ReduceJSStoreGlobal(node); | 
| 46     case IrOpcode::kJSLoadNamed: |  | 
| 47       return ReduceJSLoadNamed(node); |  | 
| 48     default: | 42     default: | 
| 49       break; | 43       break; | 
| 50   } | 44   } | 
| 51   return NoChange(); | 45   return NoChange(); | 
| 52 } | 46 } | 
| 53 | 47 | 
| 54 | 48 | 
| 55 Reduction JSGlobalSpecialization::ReduceJSLoadGlobal(Node* node) { | 49 Reduction JSGlobalSpecialization::ReduceJSLoadGlobal(Node* node) { | 
| 56   DCHECK_EQ(IrOpcode::kJSLoadGlobal, node->opcode()); | 50   DCHECK_EQ(IrOpcode::kJSLoadGlobal, node->opcode()); | 
| 57   Handle<Name> name = LoadGlobalParametersOf(node->op()).name(); | 51   Handle<Name> name = LoadGlobalParametersOf(node->op()).name(); | 
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 229       break; | 223       break; | 
| 230     } | 224     } | 
| 231   } | 225   } | 
| 232   effect = graph()->NewNode( | 226   effect = graph()->NewNode( | 
| 233       simplified()->StoreField(AccessBuilder::ForPropertyCellValue()), | 227       simplified()->StoreField(AccessBuilder::ForPropertyCellValue()), | 
| 234       jsgraph()->Constant(property_cell), value, effect, control); | 228       jsgraph()->Constant(property_cell), value, effect, control); | 
| 235   return Replace(node, value, effect, control); | 229   return Replace(node, value, effect, control); | 
| 236 } | 230 } | 
| 237 | 231 | 
| 238 | 232 | 
| 239 // This class encapsulates all information required to access a certain |  | 
| 240 // object property, either on the object itself or on the prototype chain. |  | 
| 241 class JSGlobalSpecialization::PropertyAccessInfo final { |  | 
| 242  public: |  | 
| 243   enum Kind { kInvalid, kData, kDataConstant }; |  | 
| 244 |  | 
| 245   static PropertyAccessInfo DataConstant(Type* receiver_type, |  | 
| 246                                          Handle<Object> constant, |  | 
| 247                                          MaybeHandle<JSObject> holder) { |  | 
| 248     return PropertyAccessInfo(holder, constant, receiver_type); |  | 
| 249   } |  | 
| 250   static PropertyAccessInfo Data(Type* receiver_type, FieldIndex field_index, |  | 
| 251                                  Representation field_representation, |  | 
| 252                                  MaybeHandle<JSObject> holder) { |  | 
| 253     return PropertyAccessInfo(holder, field_index, field_representation, |  | 
| 254                               receiver_type); |  | 
| 255   } |  | 
| 256 |  | 
| 257   PropertyAccessInfo() : kind_(kInvalid) {} |  | 
| 258   PropertyAccessInfo(MaybeHandle<JSObject> holder, Handle<Object> constant, |  | 
| 259                      Type* receiver_type) |  | 
| 260       : kind_(kDataConstant), |  | 
| 261         receiver_type_(receiver_type), |  | 
| 262         constant_(constant), |  | 
| 263         holder_(holder) {} |  | 
| 264   PropertyAccessInfo(MaybeHandle<JSObject> holder, FieldIndex field_index, |  | 
| 265                      Representation field_representation, Type* receiver_type) |  | 
| 266       : kind_(kData), |  | 
| 267         receiver_type_(receiver_type), |  | 
| 268         holder_(holder), |  | 
| 269         field_index_(field_index), |  | 
| 270         field_representation_(field_representation) {} |  | 
| 271 |  | 
| 272   bool IsDataConstant() const { return kind() == kDataConstant; } |  | 
| 273   bool IsData() const { return kind() == kData; } |  | 
| 274 |  | 
| 275   Kind kind() const { return kind_; } |  | 
| 276   MaybeHandle<JSObject> holder() const { return holder_; } |  | 
| 277   Handle<Object> constant() const { return constant_; } |  | 
| 278   FieldIndex field_index() const { return field_index_; } |  | 
| 279   Representation field_representation() const { return field_representation_; } |  | 
| 280   Type* receiver_type() const { return receiver_type_; } |  | 
| 281 |  | 
| 282  private: |  | 
| 283   Kind kind_; |  | 
| 284   Type* receiver_type_; |  | 
| 285   Handle<Object> constant_; |  | 
| 286   MaybeHandle<JSObject> holder_; |  | 
| 287   FieldIndex field_index_; |  | 
| 288   Representation field_representation_; |  | 
| 289 }; |  | 
| 290 |  | 
| 291 |  | 
| 292 namespace { |  | 
| 293 |  | 
| 294 bool CanInlinePropertyAccess(Handle<Map> map) { |  | 
| 295   // TODO(bmeurer): Do something about the number stuff. |  | 
| 296   if (map->instance_type() == HEAP_NUMBER_TYPE) return false; |  | 
| 297   if (map->instance_type() < FIRST_NONSTRING_TYPE) return true; |  | 
| 298   return map->IsJSObjectMap() && !map->is_dictionary_map() && |  | 
| 299          !map->has_named_interceptor() && |  | 
| 300          // TODO(verwaest): Whitelist contexts to which we have access. |  | 
| 301          !map->is_access_check_needed(); |  | 
| 302 } |  | 
| 303 |  | 
| 304 }  // namespace |  | 
| 305 |  | 
| 306 |  | 
| 307 bool JSGlobalSpecialization::ComputePropertyAccessInfo( |  | 
| 308     Handle<Map> map, Handle<Name> name, PropertyAccessInfo* access_info) { |  | 
| 309   MaybeHandle<JSObject> holder; |  | 
| 310   Type* receiver_type = Type::Class(map, graph()->zone()); |  | 
| 311   while (CanInlinePropertyAccess(map)) { |  | 
| 312     // Lookup the named property on the {map}. |  | 
| 313     Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate()); |  | 
| 314     int const number = descriptors->SearchWithCache(*name, *map); |  | 
| 315     if (number != DescriptorArray::kNotFound) { |  | 
| 316       PropertyDetails const details = descriptors->GetDetails(number); |  | 
| 317       if (details.type() == DATA_CONSTANT) { |  | 
| 318         *access_info = PropertyAccessInfo::DataConstant( |  | 
| 319             receiver_type, handle(descriptors->GetValue(number), isolate()), |  | 
| 320             holder); |  | 
| 321         return true; |  | 
| 322       } else if (details.type() == DATA) { |  | 
| 323         int index = descriptors->GetFieldIndex(number); |  | 
| 324         Representation field_representation = details.representation(); |  | 
| 325         FieldIndex field_index = FieldIndex::ForPropertyIndex( |  | 
| 326             *map, index, field_representation.IsDouble()); |  | 
| 327         *access_info = PropertyAccessInfo::Data(receiver_type, field_index, |  | 
| 328                                                 field_representation, holder); |  | 
| 329         return true; |  | 
| 330       } else { |  | 
| 331         // TODO(bmeurer): Add support for accessors. |  | 
| 332         break; |  | 
| 333       } |  | 
| 334     } |  | 
| 335 |  | 
| 336     // Don't search on the prototype chain for special indices in case of |  | 
| 337     // integer indexed exotic objects (see ES6 section 9.4.5). |  | 
| 338     if (map->IsJSTypedArrayMap() && name->IsString() && |  | 
| 339         IsSpecialIndex(isolate()->unicode_cache(), String::cast(*name))) { |  | 
| 340       break; |  | 
| 341     } |  | 
| 342 |  | 
| 343     // Walk up the prototype chain. |  | 
| 344     if (!map->prototype()->IsJSObject()) { |  | 
| 345       // TODO(bmeurer): Handle the not found case if the prototype is null. |  | 
| 346       break; |  | 
| 347     } |  | 
| 348     Handle<JSObject> map_prototype(JSObject::cast(map->prototype()), isolate()); |  | 
| 349     if (map_prototype->map()->is_deprecated()) { |  | 
| 350       // Try to migrate the prototype object so we don't embed the deprecated |  | 
| 351       // map into the optimized code. |  | 
| 352       JSObject::TryMigrateInstance(map_prototype); |  | 
| 353     } |  | 
| 354     map = handle(map_prototype->map(), isolate()); |  | 
| 355     holder = map_prototype; |  | 
| 356   } |  | 
| 357   return false; |  | 
| 358 } |  | 
| 359 |  | 
| 360 |  | 
| 361 bool JSGlobalSpecialization::ComputePropertyAccessInfos( |  | 
| 362     MapHandleList const& maps, Handle<Name> name, |  | 
| 363     ZoneVector<PropertyAccessInfo>* access_infos) { |  | 
| 364   for (Handle<Map> map : maps) { |  | 
| 365     PropertyAccessInfo access_info; |  | 
| 366     if (!ComputePropertyAccessInfo(map, name, &access_info)) return false; |  | 
| 367     access_infos->push_back(access_info); |  | 
| 368   } |  | 
| 369   return true; |  | 
| 370 } |  | 
| 371 |  | 
| 372 |  | 
| 373 Reduction JSGlobalSpecialization::ReduceJSLoadNamed(Node* node) { |  | 
| 374   DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode()); |  | 
| 375   LoadNamedParameters const p = LoadNamedParametersOf(node->op()); |  | 
| 376   Handle<Name> name = p.name(); |  | 
| 377   Node* receiver = NodeProperties::GetValueInput(node, 0); |  | 
| 378   Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); |  | 
| 379   Node* effect = NodeProperties::GetEffectInput(node); |  | 
| 380   Node* control = NodeProperties::GetControlInput(node); |  | 
| 381 |  | 
| 382   // Not much we can do if deoptimization support is disabled. |  | 
| 383   if (!(flags() & kDeoptimizationEnabled)) return NoChange(); |  | 
| 384 |  | 
| 385   // Extract receiver maps from the LOAD_IC using the LoadICNexus. |  | 
| 386   MapHandleList receiver_maps; |  | 
| 387   if (!p.feedback().IsValid()) return NoChange(); |  | 
| 388   LoadICNexus nexus(p.feedback().vector(), p.feedback().slot()); |  | 
| 389   if (nexus.ExtractMaps(&receiver_maps) == 0) return NoChange(); |  | 
| 390   DCHECK_LT(0, receiver_maps.length()); |  | 
| 391 |  | 
| 392   // Compute property access infos for the receiver maps. |  | 
| 393   ZoneVector<PropertyAccessInfo> access_infos(zone()); |  | 
| 394   if (!ComputePropertyAccessInfos(receiver_maps, name, &access_infos)) { |  | 
| 395     return NoChange(); |  | 
| 396   } |  | 
| 397   DCHECK(!access_infos.empty()); |  | 
| 398 |  | 
| 399   // The final states for every polymorphic branch. We join them with |  | 
| 400   // Merge+Phi+EffectPhi at the bottom. |  | 
| 401   ZoneVector<Node*> values(zone()); |  | 
| 402   ZoneVector<Node*> effects(zone()); |  | 
| 403   ZoneVector<Node*> controls(zone()); |  | 
| 404 |  | 
| 405   // The list of "exiting" controls, which currently go to a single deoptimize. |  | 
| 406   // TODO(bmeurer): Consider using an IC as fallback. |  | 
| 407   Node* const exit_effect = effect; |  | 
| 408   ZoneVector<Node*> exit_controls(zone()); |  | 
| 409 |  | 
| 410   // Ensure that {receiver} is a heap object. |  | 
| 411   Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver); |  | 
| 412   Node* branch = |  | 
| 413       graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control); |  | 
| 414   exit_controls.push_back(graph()->NewNode(common()->IfTrue(), branch)); |  | 
| 415   control = graph()->NewNode(common()->IfFalse(), branch); |  | 
| 416 |  | 
| 417   // Load the {receiver} map. The resulting effect is the dominating effect for |  | 
| 418   // all (polymorphic) branches. |  | 
| 419   Node* receiver_map = effect = |  | 
| 420       graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), |  | 
| 421                        receiver, effect, control); |  | 
| 422 |  | 
| 423   // Generate code for the various different property access patterns. |  | 
| 424   Node* fallthrough_control = control; |  | 
| 425   for (PropertyAccessInfo const& access_info : access_infos) { |  | 
| 426     Node* this_value = receiver; |  | 
| 427     Node* this_effect = effect; |  | 
| 428     Node* this_control; |  | 
| 429 |  | 
| 430     // Perform map check on {receiver}. |  | 
| 431     Type* receiver_type = access_info.receiver_type(); |  | 
| 432     if (receiver_type->Is(Type::String())) { |  | 
| 433       // Emit an instance type check for strings. |  | 
| 434       Node* receiver_instance_type = this_effect = graph()->NewNode( |  | 
| 435           simplified()->LoadField(AccessBuilder::ForMapInstanceType()), |  | 
| 436           receiver_map, this_effect, fallthrough_control); |  | 
| 437       Node* check = |  | 
| 438           graph()->NewNode(machine()->Uint32LessThan(), receiver_instance_type, |  | 
| 439                            jsgraph()->Uint32Constant(FIRST_NONSTRING_TYPE)); |  | 
| 440       Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), |  | 
| 441                                       check, fallthrough_control); |  | 
| 442       fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); |  | 
| 443       this_control = graph()->NewNode(common()->IfTrue(), branch); |  | 
| 444     } else { |  | 
| 445       // Emit a (sequence of) map checks for other properties. |  | 
| 446       ZoneVector<Node*> this_controls(zone()); |  | 
| 447       for (auto i = access_info.receiver_type()->Classes(); !i.Done(); |  | 
| 448            i.Advance()) { |  | 
| 449         Handle<Map> map = i.Current(); |  | 
| 450         Node* check = |  | 
| 451             graph()->NewNode(simplified()->ReferenceEqual(Type::Internal()), |  | 
| 452                              receiver_map, jsgraph()->Constant(map)); |  | 
| 453         Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), |  | 
| 454                                         check, fallthrough_control); |  | 
| 455         this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch)); |  | 
| 456         fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); |  | 
| 457       } |  | 
| 458       int const this_control_count = static_cast<int>(this_controls.size()); |  | 
| 459       this_control = |  | 
| 460           (this_control_count == 1) |  | 
| 461               ? this_controls.front() |  | 
| 462               : graph()->NewNode(common()->Merge(this_control_count), |  | 
| 463                                  this_control_count, &this_controls.front()); |  | 
| 464     } |  | 
| 465 |  | 
| 466     // Determine actual holder and perform prototype chain checks. |  | 
| 467     Handle<JSObject> holder; |  | 
| 468     if (access_info.holder().ToHandle(&holder)) { |  | 
| 469       this_value = jsgraph()->Constant(holder); |  | 
| 470       for (auto i = access_info.receiver_type()->Classes(); !i.Done(); |  | 
| 471            i.Advance()) { |  | 
| 472         Handle<Map> map = i.Current(); |  | 
| 473         PrototypeIterator j(map); |  | 
| 474         while (true) { |  | 
| 475           // Check that the {prototype} still has the same map. For stable |  | 
| 476           // maps, we can add a stability dependency on the prototype map; |  | 
| 477           // for everything else we need to perform a map check at runtime. |  | 
| 478           Handle<JSReceiver> prototype = |  | 
| 479               PrototypeIterator::GetCurrent<JSReceiver>(j); |  | 
| 480           if (prototype->map()->is_stable()) { |  | 
| 481             dependencies()->AssumeMapStable( |  | 
| 482                 handle(prototype->map(), isolate())); |  | 
| 483           } else { |  | 
| 484             Node* prototype_map = this_effect = graph()->NewNode( |  | 
| 485                 simplified()->LoadField(AccessBuilder::ForMap()), |  | 
| 486                 jsgraph()->Constant(prototype), this_effect, this_control); |  | 
| 487             Node* check = graph()->NewNode( |  | 
| 488                 simplified()->ReferenceEqual(Type::Internal()), prototype_map, |  | 
| 489                 jsgraph()->Constant(handle(prototype->map(), isolate()))); |  | 
| 490             Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), |  | 
| 491                                             check, this_control); |  | 
| 492             exit_controls.push_back( |  | 
| 493                 graph()->NewNode(common()->IfFalse(), branch)); |  | 
| 494             this_control = graph()->NewNode(common()->IfTrue(), branch); |  | 
| 495           } |  | 
| 496           // Stop once we get to the holder. |  | 
| 497           if (prototype.is_identical_to(holder)) break; |  | 
| 498           j.Advance(); |  | 
| 499         } |  | 
| 500       } |  | 
| 501     } |  | 
| 502 |  | 
| 503     // Generate the actual property access. |  | 
| 504     if (access_info.IsDataConstant()) { |  | 
| 505       this_value = jsgraph()->Constant(access_info.constant()); |  | 
| 506     } else { |  | 
| 507       // TODO(bmeurer): This is sort of adhoc, and must be refactored into some |  | 
| 508       // common code once we also have support for stores. |  | 
| 509       DCHECK(access_info.IsData()); |  | 
| 510       FieldIndex const field_index = access_info.field_index(); |  | 
| 511       Representation const field_representation = |  | 
| 512           access_info.field_representation(); |  | 
| 513       if (!field_index.is_inobject()) { |  | 
| 514         this_value = this_effect = graph()->NewNode( |  | 
| 515             simplified()->LoadField(AccessBuilder::ForJSObjectProperties()), |  | 
| 516             this_value, this_effect, this_control); |  | 
| 517       } |  | 
| 518       FieldAccess field_access; |  | 
| 519       field_access.base_is_tagged = kTaggedBase; |  | 
| 520       field_access.offset = field_index.offset(); |  | 
| 521       field_access.name = name; |  | 
| 522       field_access.type = Type::Any(); |  | 
| 523       field_access.machine_type = kMachAnyTagged; |  | 
| 524       if (field_representation.IsSmi()) { |  | 
| 525         field_access.type = Type::Intersect( |  | 
| 526             Type::SignedSmall(), Type::TaggedSigned(), graph()->zone()); |  | 
| 527       } else if (field_representation.IsDouble()) { |  | 
| 528         if (!field_index.is_inobject() || field_index.is_hidden_field() || |  | 
| 529             !FLAG_unbox_double_fields) { |  | 
| 530           this_value = this_effect = |  | 
| 531               graph()->NewNode(simplified()->LoadField(field_access), |  | 
| 532                                this_value, this_effect, this_control); |  | 
| 533           field_access.offset = HeapNumber::kValueOffset; |  | 
| 534           field_access.name = MaybeHandle<Name>(); |  | 
| 535         } |  | 
| 536         field_access.type = Type::Intersect( |  | 
| 537             Type::Number(), Type::UntaggedFloat64(), graph()->zone()); |  | 
| 538         field_access.machine_type = kMachFloat64; |  | 
| 539       } else if (field_representation.IsHeapObject()) { |  | 
| 540         field_access.type = Type::TaggedPointer(); |  | 
| 541       } |  | 
| 542       this_value = this_effect = |  | 
| 543           graph()->NewNode(simplified()->LoadField(field_access), this_value, |  | 
| 544                            this_effect, this_control); |  | 
| 545     } |  | 
| 546 |  | 
| 547     // Remember the final state for this property access. |  | 
| 548     values.push_back(this_value); |  | 
| 549     effects.push_back(this_effect); |  | 
| 550     controls.push_back(this_control); |  | 
| 551   } |  | 
| 552 |  | 
| 553   // Generate the single "exit" point, where we get if either all map/instance |  | 
| 554   // type checks failed, or one of the assumptions inside one of the cases |  | 
| 555   // failes (i.e. failing prototype chain check). |  | 
| 556   // TODO(bmeurer): Consider falling back to IC here if deoptimization is |  | 
| 557   // disabled. |  | 
| 558   exit_controls.push_back(fallthrough_control); |  | 
| 559   int const exit_control_count = static_cast<int>(exit_controls.size()); |  | 
| 560   Node* exit_control = |  | 
| 561       (exit_control_count == 1) |  | 
| 562           ? exit_controls.front() |  | 
| 563           : graph()->NewNode(common()->Merge(exit_control_count), |  | 
| 564                              exit_control_count, &exit_controls.front()); |  | 
| 565   Node* deoptimize = graph()->NewNode(common()->Deoptimize(), frame_state, |  | 
| 566                                       exit_effect, exit_control); |  | 
| 567   // TODO(bmeurer): This should be on the AdvancedReducer somehow. |  | 
| 568   NodeProperties::MergeControlToEnd(graph(), common(), deoptimize); |  | 
| 569 |  | 
| 570   // Generate the final merge point for all (polymorphic) branches. |  | 
| 571   Node* value; |  | 
| 572   int const control_count = static_cast<int>(controls.size()); |  | 
| 573   if (control_count == 1) { |  | 
| 574     value = values.front(); |  | 
| 575     effect = effects.front(); |  | 
| 576     control = controls.front(); |  | 
| 577   } else { |  | 
| 578     control = graph()->NewNode(common()->Merge(control_count), control_count, |  | 
| 579                                &controls.front()); |  | 
| 580     values.push_back(control); |  | 
| 581     value = graph()->NewNode(common()->Phi(kMachAnyTagged, control_count), |  | 
| 582                              control_count + 1, &values.front()); |  | 
| 583     effects.push_back(control); |  | 
| 584     effect = graph()->NewNode(common()->EffectPhi(control_count), |  | 
| 585                               control_count + 1, &effects.front()); |  | 
| 586   } |  | 
| 587   return Replace(node, value, effect, control); |  | 
| 588 } |  | 
| 589 |  | 
| 590 |  | 
| 591 Reduction JSGlobalSpecialization::Replace(Node* node, Handle<Object> value) { | 233 Reduction JSGlobalSpecialization::Replace(Node* node, Handle<Object> value) { | 
|  | 234   // TODO(bmeurer): Move this to JSGraph::HeapConstant instead? | 
|  | 235   if (value->IsConsString()) { | 
|  | 236     value = String::Flatten(Handle<String>::cast(value), TENURED); | 
|  | 237   } | 
| 592   return Replace(node, jsgraph()->Constant(value)); | 238   return Replace(node, jsgraph()->Constant(value)); | 
| 593 } | 239 } | 
| 594 | 240 | 
| 595 | 241 | 
| 596 bool JSGlobalSpecialization::LookupInScriptContextTable( | 242 bool JSGlobalSpecialization::LookupInScriptContextTable( | 
| 597     Handle<Name> name, ScriptContextTableLookupResult* result) { | 243     Handle<Name> name, ScriptContextTableLookupResult* result) { | 
| 598   if (!name->IsString()) return false; | 244   if (!name->IsString()) return false; | 
| 599   Handle<ScriptContextTable> script_context_table( | 245   Handle<ScriptContextTable> script_context_table( | 
| 600       global_object()->native_context()->script_context_table()); | 246       global_object()->native_context()->script_context_table()); | 
| 601   ScriptContextTable::LookupResult lookup_result; | 247   ScriptContextTable::LookupResult lookup_result; | 
| (...skipping 12 matching lines...) Expand all  Loading... | 
| 614 | 260 | 
| 615 | 261 | 
| 616 Graph* JSGlobalSpecialization::graph() const { return jsgraph()->graph(); } | 262 Graph* JSGlobalSpecialization::graph() const { return jsgraph()->graph(); } | 
| 617 | 263 | 
| 618 | 264 | 
| 619 Isolate* JSGlobalSpecialization::isolate() const { | 265 Isolate* JSGlobalSpecialization::isolate() const { | 
| 620   return jsgraph()->isolate(); | 266   return jsgraph()->isolate(); | 
| 621 } | 267 } | 
| 622 | 268 | 
| 623 | 269 | 
| 624 MachineOperatorBuilder* JSGlobalSpecialization::machine() const { |  | 
| 625   return jsgraph()->machine(); |  | 
| 626 } |  | 
| 627 |  | 
| 628 |  | 
| 629 CommonOperatorBuilder* JSGlobalSpecialization::common() const { | 270 CommonOperatorBuilder* JSGlobalSpecialization::common() const { | 
| 630   return jsgraph()->common(); | 271   return jsgraph()->common(); | 
| 631 } | 272 } | 
| 632 | 273 | 
| 633 | 274 | 
| 634 JSOperatorBuilder* JSGlobalSpecialization::javascript() const { | 275 JSOperatorBuilder* JSGlobalSpecialization::javascript() const { | 
| 635   return jsgraph()->javascript(); | 276   return jsgraph()->javascript(); | 
| 636 } | 277 } | 
| 637 | 278 | 
| 638 | 279 | 
| 639 SimplifiedOperatorBuilder* JSGlobalSpecialization::simplified() const { | 280 SimplifiedOperatorBuilder* JSGlobalSpecialization::simplified() const { | 
| 640   return jsgraph()->simplified(); | 281   return jsgraph()->simplified(); | 
| 641 } | 282 } | 
| 642 | 283 | 
| 643 }  // namespace compiler | 284 }  // namespace compiler | 
| 644 }  // namespace internal | 285 }  // namespace internal | 
| 645 }  // namespace v8 | 286 }  // namespace v8 | 
| OLD | NEW | 
|---|