| 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-native-context-specialization.h" | 5 #include "src/compiler/js-native-context-specialization.h" |
| 6 | 6 |
| 7 #include "src/accessors.h" | 7 #include "src/accessors.h" |
| 8 #include "src/compilation-dependencies.h" | 8 #include "src/compilation-dependencies.h" |
| 9 #include "src/compiler/access-builder.h" | 9 #include "src/compiler/access-builder.h" |
| 10 #include "src/compiler/js-graph.h" | 10 #include "src/compiler/js-graph.h" |
| (...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 305 !map->is_access_check_needed(); | 305 !map->is_access_check_needed(); |
| 306 } | 306 } |
| 307 | 307 |
| 308 } // namespace | 308 } // namespace |
| 309 | 309 |
| 310 | 310 |
| 311 bool JSNativeContextSpecialization::ComputePropertyAccessInfo( | 311 bool JSNativeContextSpecialization::ComputePropertyAccessInfo( |
| 312 Handle<Map> map, Handle<Name> name, PropertyAccessMode access_mode, | 312 Handle<Map> map, Handle<Name> name, PropertyAccessMode access_mode, |
| 313 PropertyAccessInfo* access_info) { | 313 PropertyAccessInfo* access_info) { |
| 314 MaybeHandle<JSObject> holder; | 314 MaybeHandle<JSObject> holder; |
| 315 Handle<Map> receiver_map = map; | 315 Type* receiver_type = Type::Class(map, graph()->zone()); |
| 316 Type* receiver_type = Type::Class(receiver_map, graph()->zone()); | |
| 317 while (CanInlinePropertyAccess(map)) { | 316 while (CanInlinePropertyAccess(map)) { |
| 318 // Check for special JSObject field accessors. | 317 // Check for special JSObject field accessors. |
| 319 int offset; | 318 int offset; |
| 320 if (Accessors::IsJSObjectFieldAccessor(map, name, &offset)) { | 319 if (Accessors::IsJSObjectFieldAccessor(map, name, &offset)) { |
| 321 // Don't bother optimizing stores to special JSObject field accessors. | 320 // Don't bother optimizing stores to special JSObject field accessors. |
| 322 if (access_mode == kStore) { | 321 if (access_mode == kStore) { |
| 323 break; | 322 break; |
| 324 } | 323 } |
| 325 FieldIndex field_index = FieldIndex::ForInObjectOffset(offset); | 324 FieldIndex field_index = FieldIndex::ForInObjectOffset(offset); |
| 326 Type* field_type = Type::Tagged(); | 325 Type* field_type = Type::Tagged(); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 350 } | 349 } |
| 351 *access_info = PropertyAccessInfo::DataField(receiver_type, field_index, | 350 *access_info = PropertyAccessInfo::DataField(receiver_type, field_index, |
| 352 field_type, holder); | 351 field_type, holder); |
| 353 return true; | 352 return true; |
| 354 } | 353 } |
| 355 | 354 |
| 356 // Lookup the named property on the {map}. | 355 // Lookup the named property on the {map}. |
| 357 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate()); | 356 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate()); |
| 358 int const number = descriptors->SearchWithCache(*name, *map); | 357 int const number = descriptors->SearchWithCache(*name, *map); |
| 359 if (number != DescriptorArray::kNotFound) { | 358 if (number != DescriptorArray::kNotFound) { |
| 360 if (access_mode == kStore && !map.is_identical_to(receiver_map)) { | |
| 361 return false; | |
| 362 } | |
| 363 PropertyDetails const details = descriptors->GetDetails(number); | 359 PropertyDetails const details = descriptors->GetDetails(number); |
| 364 if (details.type() == DATA_CONSTANT) { | 360 if (details.type() == DATA_CONSTANT) { |
| 365 *access_info = PropertyAccessInfo::DataConstant( | 361 *access_info = PropertyAccessInfo::DataConstant( |
| 366 receiver_type, handle(descriptors->GetValue(number), isolate()), | 362 receiver_type, handle(descriptors->GetValue(number), isolate()), |
| 367 holder); | 363 holder); |
| 368 return true; | 364 return true; |
| 369 } else if (details.type() == DATA) { | 365 } else if (details.type() == DATA) { |
| 370 // Don't bother optimizing stores to read-only properties. | 366 // Don't bother optimizing stores to read-only properties. |
| 371 if (access_mode == kStore && details.IsReadOnly()) { | 367 if (access_mode == kStore) { |
| 372 break; | 368 break; |
| 373 } | 369 } |
| 374 int index = descriptors->GetFieldIndex(number); | 370 int index = descriptors->GetFieldIndex(number); |
| 375 Representation field_representation = details.representation(); | 371 Representation field_representation = details.representation(); |
| 376 FieldIndex field_index = FieldIndex::ForPropertyIndex( | 372 FieldIndex field_index = FieldIndex::ForPropertyIndex( |
| 377 *map, index, field_representation.IsDouble()); | 373 *map, index, field_representation.IsDouble()); |
| 378 Type* field_type = Type::Tagged(); | 374 Type* field_type = Type::Any(); |
| 379 if (field_representation.IsSmi()) { | 375 if (field_representation.IsSmi()) { |
| 380 field_type = Type::Intersect(Type::SignedSmall(), | 376 field_type = Type::Intersect(Type::SignedSmall(), |
| 381 Type::TaggedSigned(), graph()->zone()); | 377 Type::TaggedSigned(), graph()->zone()); |
| 382 } else if (field_representation.IsDouble()) { | 378 } else if (field_representation.IsDouble()) { |
| 383 if (access_mode == kStore) { | 379 if (access_mode == kStore) { |
| 384 // TODO(bmeurer): Add support for storing to double fields. | 380 // TODO(bmeurer): Add support for storing to double fields. |
| 385 break; | 381 break; |
| 386 } | 382 } |
| 387 field_type = Type::Intersect(Type::Number(), Type::UntaggedFloat64(), | 383 field_type = Type::Intersect(Type::Number(), Type::UntaggedFloat64(), |
| 388 graph()->zone()); | 384 graph()->zone()); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 451 } | 447 } |
| 452 return false; | 448 return false; |
| 453 } | 449 } |
| 454 | 450 |
| 455 | 451 |
| 456 bool JSNativeContextSpecialization::ComputePropertyAccessInfos( | 452 bool JSNativeContextSpecialization::ComputePropertyAccessInfos( |
| 457 MapHandleList const& maps, Handle<Name> name, | 453 MapHandleList const& maps, Handle<Name> name, |
| 458 PropertyAccessMode access_mode, | 454 PropertyAccessMode access_mode, |
| 459 ZoneVector<PropertyAccessInfo>* access_infos) { | 455 ZoneVector<PropertyAccessInfo>* access_infos) { |
| 460 for (Handle<Map> map : maps) { | 456 for (Handle<Map> map : maps) { |
| 461 if (Map::TryUpdate(map).ToHandle(&map)) { | 457 PropertyAccessInfo access_info; |
| 462 PropertyAccessInfo access_info; | 458 if (!ComputePropertyAccessInfo(map, name, access_mode, &access_info)) { |
| 463 if (!ComputePropertyAccessInfo(map, name, access_mode, &access_info)) { | 459 return false; |
| 464 return false; | |
| 465 } | |
| 466 access_infos->push_back(access_info); | |
| 467 } | 460 } |
| 461 access_infos->push_back(access_info); |
| 468 } | 462 } |
| 469 return true; | 463 return true; |
| 470 } | 464 } |
| 471 | 465 |
| 472 | 466 |
| 473 Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) { | 467 Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) { |
| 474 DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode()); | 468 DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode()); |
| 475 NamedAccess const& p = NamedAccessOf(node->op()); | 469 NamedAccess const& p = NamedAccessOf(node->op()); |
| 476 Handle<Name> name = p.name(); | 470 Handle<Name> name = p.name(); |
| 477 Node* receiver = NodeProperties::GetValueInput(node, 0); | 471 Node* receiver = NodeProperties::GetValueInput(node, 0); |
| 478 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); | 472 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); |
| 479 Node* effect = NodeProperties::GetEffectInput(node); | 473 Node* effect = NodeProperties::GetEffectInput(node); |
| 480 Node* control = NodeProperties::GetControlInput(node); | 474 Node* control = NodeProperties::GetControlInput(node); |
| 481 | 475 |
| 482 // Not much we can do if deoptimization support is disabled. | 476 // Not much we can do if deoptimization support is disabled. |
| 483 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); | 477 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); |
| 484 | 478 |
| 485 // Extract receiver maps from the LOAD_IC using the LoadICNexus. | 479 // Extract receiver maps from the LOAD_IC using the LoadICNexus. |
| 486 MapHandleList receiver_maps; | 480 MapHandleList receiver_maps; |
| 487 if (!p.feedback().IsValid()) return NoChange(); | 481 if (!p.feedback().IsValid()) return NoChange(); |
| 488 LoadICNexus nexus(p.feedback().vector(), p.feedback().slot()); | 482 LoadICNexus nexus(p.feedback().vector(), p.feedback().slot()); |
| 489 if (nexus.ExtractMaps(&receiver_maps) == 0) return NoChange(); | 483 if (nexus.ExtractMaps(&receiver_maps) == 0) return NoChange(); |
| 490 DCHECK_LT(0, receiver_maps.length()); | 484 DCHECK_LT(0, receiver_maps.length()); |
| 491 | 485 |
| 492 // Compute property access infos for the receiver maps. | 486 // Compute property access infos for the receiver maps. |
| 493 ZoneVector<PropertyAccessInfo> access_infos(zone()); | 487 ZoneVector<PropertyAccessInfo> access_infos(zone()); |
| 494 if (!ComputePropertyAccessInfos(receiver_maps, name, kLoad, &access_infos)) { | 488 if (!ComputePropertyAccessInfos(receiver_maps, name, kLoad, &access_infos)) { |
| 495 return NoChange(); | 489 return NoChange(); |
| 496 } | 490 } |
| 497 | 491 DCHECK(!access_infos.empty()); |
| 498 // Nothing to do if we have no non-deprecated maps. | |
| 499 if (access_infos.empty()) return NoChange(); | |
| 500 | 492 |
| 501 // The final states for every polymorphic branch. We join them with | 493 // The final states for every polymorphic branch. We join them with |
| 502 // Merge+Phi+EffectPhi at the bottom. | 494 // Merge+Phi+EffectPhi at the bottom. |
| 503 ZoneVector<Node*> values(zone()); | 495 ZoneVector<Node*> values(zone()); |
| 504 ZoneVector<Node*> effects(zone()); | 496 ZoneVector<Node*> effects(zone()); |
| 505 ZoneVector<Node*> controls(zone()); | 497 ZoneVector<Node*> controls(zone()); |
| 506 | 498 |
| 507 // The list of "exiting" controls, which currently go to a single deoptimize. | 499 // The list of "exiting" controls, which currently go to a single deoptimize. |
| 508 // TODO(bmeurer): Consider using an IC as fallback. | 500 // TODO(bmeurer): Consider using an IC as fallback. |
| 509 Node* const exit_effect = effect; | 501 Node* const exit_effect = effect; |
| (...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 773 this_control = | 765 this_control = |
| 774 (this_control_count == 1) | 766 (this_control_count == 1) |
| 775 ? this_controls.front() | 767 ? this_controls.front() |
| 776 : graph()->NewNode(common()->Merge(this_control_count), | 768 : graph()->NewNode(common()->Merge(this_control_count), |
| 777 this_control_count, &this_controls.front()); | 769 this_control_count, &this_controls.front()); |
| 778 } | 770 } |
| 779 | 771 |
| 780 // Determine actual holder and perform prototype chain checks. | 772 // Determine actual holder and perform prototype chain checks. |
| 781 Handle<JSObject> holder; | 773 Handle<JSObject> holder; |
| 782 if (access_info.holder().ToHandle(&holder)) { | 774 if (access_info.holder().ToHandle(&holder)) { |
| 775 this_receiver = jsgraph()->Constant(holder); |
| 783 for (auto i = access_info.receiver_type()->Classes(); !i.Done(); | 776 for (auto i = access_info.receiver_type()->Classes(); !i.Done(); |
| 784 i.Advance()) { | 777 i.Advance()) { |
| 785 Handle<Map> map = i.Current(); | 778 Handle<Map> map = i.Current(); |
| 786 PrototypeIterator j(map); | 779 PrototypeIterator j(map); |
| 787 while (true) { | 780 while (true) { |
| 788 // Check that the {prototype} still has the same map. For stable | 781 // Check that the {prototype} still has the same map. For stable |
| 789 // maps, we can add a stability dependency on the prototype map; | 782 // maps, we can add a stability dependency on the prototype map; |
| 790 // for everything else we need to perform a map check at runtime. | 783 // for everything else we need to perform a map check at runtime. |
| 791 Handle<JSReceiver> prototype = | 784 Handle<JSReceiver> prototype = |
| 792 PrototypeIterator::GetCurrent<JSReceiver>(j); | 785 PrototypeIterator::GetCurrent<JSReceiver>(j); |
| (...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 979 } | 972 } |
| 980 | 973 |
| 981 | 974 |
| 982 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { | 975 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { |
| 983 return jsgraph()->simplified(); | 976 return jsgraph()->simplified(); |
| 984 } | 977 } |
| 985 | 978 |
| 986 } // namespace compiler | 979 } // namespace compiler |
| 987 } // namespace internal | 980 } // namespace internal |
| 988 } // namespace v8 | 981 } // namespace v8 |
| OLD | NEW |