Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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/crankshaft/hydrogen.h" | 5 #include "src/crankshaft/hydrogen.h" |
| 6 | 6 |
| 7 #include <sstream> | 7 #include <sstream> |
| 8 | 8 |
| 9 #include "src/allocation-site-scopes.h" | 9 #include "src/allocation-site-scopes.h" |
| 10 #include "src/ast/ast-numbering.h" | 10 #include "src/ast/ast-numbering.h" |
| (...skipping 2862 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2873 elements, isolate()->factory()->fixed_array_map()); | 2873 elements, isolate()->factory()->fixed_array_map()); |
| 2874 check_cow_map->ClearDependsOnFlag(kElementsKind); | 2874 check_cow_map->ClearDependsOnFlag(kElementsKind); |
| 2875 } | 2875 } |
| 2876 } | 2876 } |
| 2877 } | 2877 } |
| 2878 return AddElementAccess(elements, checked_key, val, checked_object, nullptr, | 2878 return AddElementAccess(elements, checked_key, val, checked_object, nullptr, |
| 2879 elements_kind, access_type, load_mode); | 2879 elements_kind, access_type, load_mode); |
| 2880 } | 2880 } |
| 2881 | 2881 |
| 2882 | 2882 |
| 2883 HValue* HGraphBuilder::BuildAllocateArrayFromLength( | |
| 2884 JSArrayBuilder* array_builder, | |
| 2885 HValue* length_argument) { | |
| 2886 if (length_argument->IsConstant() && | |
| 2887 HConstant::cast(length_argument)->HasSmiValue()) { | |
| 2888 int array_length = HConstant::cast(length_argument)->Integer32Value(); | |
| 2889 if (array_length == 0) { | |
| 2890 return array_builder->AllocateEmptyArray(); | |
| 2891 } else { | |
| 2892 return array_builder->AllocateArray(length_argument, | |
| 2893 length_argument); | |
| 2894 } | |
| 2895 } | |
| 2896 | |
| 2897 HValue* constant_zero = graph()->GetConstant0(); | |
| 2898 HConstant* max_alloc_length = | |
| 2899 Add<HConstant>(JSArray::kInitialMaxFastElementArray); | |
| 2900 HInstruction* checked_length = Add<HBoundsCheck>(length_argument, | |
| 2901 max_alloc_length); | |
| 2902 IfBuilder if_builder(this); | |
| 2903 if_builder.If<HCompareNumericAndBranch>(checked_length, constant_zero, | |
| 2904 Token::EQ); | |
| 2905 if_builder.Then(); | |
| 2906 const int initial_capacity = JSArray::kPreallocatedArrayElements; | |
| 2907 HConstant* initial_capacity_node = Add<HConstant>(initial_capacity); | |
| 2908 Push(initial_capacity_node); // capacity | |
| 2909 Push(constant_zero); // length | |
| 2910 if_builder.Else(); | |
| 2911 if (!(top_info()->IsStub()) && | |
| 2912 IsFastPackedElementsKind(array_builder->kind())) { | |
| 2913 // We'll come back later with better (holey) feedback. | |
| 2914 if_builder.Deopt( | |
| 2915 Deoptimizer::kHoleyArrayDespitePackedElements_kindFeedback); | |
| 2916 } else { | |
| 2917 Push(checked_length); // capacity | |
| 2918 Push(checked_length); // length | |
| 2919 } | |
| 2920 if_builder.End(); | |
| 2921 | |
| 2922 // Figure out total size | |
| 2923 HValue* length = Pop(); | |
| 2924 HValue* capacity = Pop(); | |
| 2925 return array_builder->AllocateArray(capacity, length); | |
| 2926 } | |
| 2927 | |
| 2928 | |
| 2929 HValue* HGraphBuilder::BuildCalculateElementsSize(ElementsKind kind, | 2883 HValue* HGraphBuilder::BuildCalculateElementsSize(ElementsKind kind, |
| 2930 HValue* capacity) { | 2884 HValue* capacity) { |
| 2931 int elements_size = IsFastDoubleElementsKind(kind) | 2885 int elements_size = IsFastDoubleElementsKind(kind) |
| 2932 ? kDoubleSize | 2886 ? kDoubleSize |
| 2933 : kPointerSize; | 2887 : kPointerSize; |
| 2934 | 2888 |
| 2935 HConstant* elements_size_value = Add<HConstant>(elements_size); | 2889 HConstant* elements_size_value = Add<HConstant>(elements_size); |
| 2936 HInstruction* mul = | 2890 HInstruction* mul = |
| 2937 HMul::NewImul(isolate(), zone(), context(), capacity->ActualValue(), | 2891 HMul::NewImul(isolate(), zone(), context(), capacity->ActualValue(), |
| 2938 elements_size_value); | 2892 elements_size_value); |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3009 | 2963 |
| 3010 void HGraphBuilder::BuildJSArrayHeader(HValue* array, | 2964 void HGraphBuilder::BuildJSArrayHeader(HValue* array, |
| 3011 HValue* array_map, | 2965 HValue* array_map, |
| 3012 HValue* elements, | 2966 HValue* elements, |
| 3013 AllocationSiteMode mode, | 2967 AllocationSiteMode mode, |
| 3014 ElementsKind elements_kind, | 2968 ElementsKind elements_kind, |
| 3015 HValue* allocation_site_payload, | 2969 HValue* allocation_site_payload, |
| 3016 HValue* length_field) { | 2970 HValue* length_field) { |
| 3017 Add<HStoreNamedField>(array, HObjectAccess::ForMap(), array_map); | 2971 Add<HStoreNamedField>(array, HObjectAccess::ForMap(), array_map); |
| 3018 | 2972 |
| 3019 HConstant* empty_fixed_array = | 2973 HValue* empty_fixed_array = Add<HLoadRoot>(Heap::kEmptyFixedArrayRootIndex); |
| 3020 Add<HConstant>(isolate()->factory()->empty_fixed_array()); | |
| 3021 | 2974 |
| 3022 Add<HStoreNamedField>( | 2975 Add<HStoreNamedField>( |
| 3023 array, HObjectAccess::ForPropertiesPointer(), empty_fixed_array); | 2976 array, HObjectAccess::ForPropertiesPointer(), empty_fixed_array); |
| 3024 | 2977 |
| 3025 Add<HStoreNamedField>( | 2978 Add<HStoreNamedField>(array, HObjectAccess::ForElementsPointer(), |
| 3026 array, HObjectAccess::ForElementsPointer(), | 2979 elements != nullptr ? elements : empty_fixed_array); |
| 3027 elements != NULL ? elements : empty_fixed_array); | |
| 3028 | 2980 |
| 3029 Add<HStoreNamedField>( | 2981 Add<HStoreNamedField>( |
| 3030 array, HObjectAccess::ForArrayLength(elements_kind), length_field); | 2982 array, HObjectAccess::ForArrayLength(elements_kind), length_field); |
| 3031 | 2983 |
| 3032 if (mode == TRACK_ALLOCATION_SITE) { | 2984 if (mode == TRACK_ALLOCATION_SITE) { |
| 3033 BuildCreateAllocationMemento( | 2985 BuildCreateAllocationMemento( |
| 3034 array, Add<HConstant>(JSArray::kSize), allocation_site_payload); | 2986 array, Add<HConstant>(JSArray::kSize), allocation_site_payload); |
| 3035 } | 2987 } |
| 3036 } | 2988 } |
| 3037 | 2989 |
| (...skipping 490 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3528 was_neutered_test, graph()->GetConstant0(), Token::NE); | 3480 was_neutered_test, graph()->GetConstant0(), Token::NE); |
| 3529 if_was_neutered.Then(); | 3481 if_was_neutered.Then(); |
| 3530 Push(graph()->GetConstant0()); | 3482 Push(graph()->GetConstant0()); |
| 3531 if_was_neutered.Else(); | 3483 if_was_neutered.Else(); |
| 3532 Push(field); | 3484 Push(field); |
| 3533 if_was_neutered.End(); | 3485 if_was_neutered.End(); |
| 3534 | 3486 |
| 3535 return Pop(); | 3487 return Pop(); |
| 3536 } | 3488 } |
| 3537 | 3489 |
| 3538 | |
| 3539 HGraphBuilder::JSArrayBuilder::JSArrayBuilder(HGraphBuilder* builder, | |
| 3540 ElementsKind kind, | |
| 3541 HValue* allocation_site_payload, | |
| 3542 HValue* constructor_function, | |
| 3543 AllocationSiteOverrideMode override_mode) : | |
| 3544 builder_(builder), | |
| 3545 kind_(kind), | |
| 3546 allocation_site_payload_(allocation_site_payload), | |
| 3547 constructor_function_(constructor_function) { | |
| 3548 DCHECK(!allocation_site_payload->IsConstant() || | |
| 3549 HConstant::cast(allocation_site_payload)->handle( | |
| 3550 builder_->isolate())->IsAllocationSite()); | |
| 3551 mode_ = override_mode == DISABLE_ALLOCATION_SITES | |
| 3552 ? DONT_TRACK_ALLOCATION_SITE | |
| 3553 : AllocationSite::GetMode(kind); | |
| 3554 } | |
| 3555 | |
| 3556 | |
| 3557 HGraphBuilder::JSArrayBuilder::JSArrayBuilder(HGraphBuilder* builder, | |
| 3558 ElementsKind kind, | |
| 3559 HValue* constructor_function) : | |
| 3560 builder_(builder), | |
| 3561 kind_(kind), | |
| 3562 mode_(DONT_TRACK_ALLOCATION_SITE), | |
| 3563 allocation_site_payload_(NULL), | |
| 3564 constructor_function_(constructor_function) { | |
| 3565 } | |
| 3566 | |
| 3567 | |
| 3568 HValue* HGraphBuilder::JSArrayBuilder::EmitMapCode() { | |
| 3569 if (!builder()->top_info()->IsStub()) { | |
| 3570 // A constant map is fine. | |
| 3571 Handle<Map> map(builder()->isolate()->get_initial_js_array_map(kind_), | |
| 3572 builder()->isolate()); | |
| 3573 return builder()->Add<HConstant>(map); | |
| 3574 } | |
| 3575 | |
| 3576 if (constructor_function_ != NULL && kind_ == GetInitialFastElementsKind()) { | |
| 3577 // No need for a context lookup if the kind_ matches the initial | |
| 3578 // map, because we can just load the map in that case. | |
| 3579 HObjectAccess access = HObjectAccess::ForPrototypeOrInitialMap(); | |
| 3580 return builder()->Add<HLoadNamedField>(constructor_function_, nullptr, | |
| 3581 access); | |
| 3582 } | |
| 3583 | |
| 3584 // TODO(mvstanton): we should always have a constructor function if we | |
| 3585 // are creating a stub. | |
| 3586 HInstruction* native_context = constructor_function_ != NULL | |
| 3587 ? builder()->BuildGetNativeContext(constructor_function_) | |
| 3588 : builder()->BuildGetNativeContext(); | |
| 3589 | |
| 3590 HObjectAccess access = | |
| 3591 HObjectAccess::ForContextSlot(Context::ArrayMapIndex(kind_)); | |
| 3592 return builder()->Add<HLoadNamedField>(native_context, nullptr, access); | |
| 3593 } | |
| 3594 | |
| 3595 | |
| 3596 HValue* HGraphBuilder::JSArrayBuilder::EmitInternalMapCode() { | |
| 3597 // Find the map near the constructor function | |
| 3598 HObjectAccess access = HObjectAccess::ForPrototypeOrInitialMap(); | |
| 3599 return builder()->Add<HLoadNamedField>(constructor_function_, nullptr, | |
| 3600 access); | |
| 3601 } | |
| 3602 | |
| 3603 | |
| 3604 HAllocate* HGraphBuilder::JSArrayBuilder::AllocateEmptyArray() { | |
| 3605 HConstant* capacity = builder()->Add<HConstant>(initial_capacity()); | |
| 3606 return AllocateArray(capacity, | |
| 3607 builder()->graph()->GetConstant0()); | |
| 3608 } | |
| 3609 | |
| 3610 | |
| 3611 HAllocate* HGraphBuilder::JSArrayBuilder::AllocateArray( | |
| 3612 HValue* capacity, | |
| 3613 HValue* length_field, | |
| 3614 FillMode fill_mode) { | |
| 3615 // These HForceRepresentations are because we store these as fields in the | |
| 3616 // objects we construct, and an int32-to-smi HChange could deopt. Accept | |
| 3617 // the deopt possibility now, before allocation occurs. | |
| 3618 capacity = | |
| 3619 builder()->AddUncasted<HForceRepresentation>(capacity, | |
| 3620 Representation::Smi()); | |
| 3621 length_field = | |
| 3622 builder()->AddUncasted<HForceRepresentation>(length_field, | |
| 3623 Representation::Smi()); | |
| 3624 | |
| 3625 // Generate size calculation code here in order to make it dominate | |
| 3626 // the JSArray allocation. | |
| 3627 HValue* elements_size = | |
| 3628 builder()->BuildCalculateElementsSize(kind_, capacity); | |
| 3629 | |
| 3630 // Bail out for large objects. | |
| 3631 HValue* max_regular_heap_object_size = | |
| 3632 builder()->Add<HConstant>(Page::kMaxRegularHeapObjectSize); | |
| 3633 builder()->Add<HBoundsCheck>(elements_size, max_regular_heap_object_size); | |
| 3634 | |
| 3635 // Allocate (dealing with failure appropriately) | |
| 3636 HAllocate* array_object = builder()->AllocateJSArrayObject(mode_); | |
| 3637 | |
| 3638 // Fill in the fields: map, properties, length | |
| 3639 HValue* map; | |
| 3640 if (allocation_site_payload_ == NULL) { | |
| 3641 map = EmitInternalMapCode(); | |
| 3642 } else { | |
| 3643 map = EmitMapCode(); | |
| 3644 } | |
| 3645 | |
| 3646 builder()->BuildJSArrayHeader(array_object, | |
| 3647 map, | |
| 3648 NULL, // set elements to empty fixed array | |
| 3649 mode_, | |
| 3650 kind_, | |
| 3651 allocation_site_payload_, | |
| 3652 length_field); | |
| 3653 | |
| 3654 // Allocate and initialize the elements | |
| 3655 elements_location_ = builder()->BuildAllocateElements(kind_, elements_size); | |
| 3656 | |
| 3657 builder()->BuildInitializeElementsHeader(elements_location_, kind_, capacity); | |
| 3658 | |
| 3659 // Set the elements | |
| 3660 builder()->Add<HStoreNamedField>( | |
| 3661 array_object, HObjectAccess::ForElementsPointer(), elements_location_); | |
| 3662 | |
| 3663 if (fill_mode == FILL_WITH_HOLE) { | |
| 3664 builder()->BuildFillElementsWithHole(elements_location_, kind_, | |
| 3665 graph()->GetConstant0(), capacity); | |
| 3666 } | |
| 3667 | |
| 3668 return array_object; | |
| 3669 } | |
| 3670 | |
| 3671 | |
| 3672 HValue* HGraphBuilder::AddLoadJSBuiltin(int context_index) { | 3490 HValue* HGraphBuilder::AddLoadJSBuiltin(int context_index) { |
| 3673 HValue* native_context = BuildGetNativeContext(); | 3491 HValue* native_context = BuildGetNativeContext(); |
| 3674 HObjectAccess function_access = HObjectAccess::ForContextSlot(context_index); | 3492 HObjectAccess function_access = HObjectAccess::ForContextSlot(context_index); |
| 3675 return Add<HLoadNamedField>(native_context, nullptr, function_access); | 3493 return Add<HLoadNamedField>(native_context, nullptr, function_access); |
| 3676 } | 3494 } |
| 3677 | 3495 |
| 3678 HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info) | 3496 HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info) |
| 3679 : HGraphBuilder(info, CallInterfaceDescriptor()), | 3497 : HGraphBuilder(info, CallInterfaceDescriptor()), |
| 3680 function_state_(NULL), | 3498 function_state_(NULL), |
| 3681 initial_function_state_(this, info, NORMAL_RETURN, 0, | 3499 initial_function_state_(this, info, NORMAL_RETURN, 0, |
| (...skipping 6015 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 9697 // Cannot embed a direct reference to the global proxy | 9515 // Cannot embed a direct reference to the global proxy |
| 9698 // as is it dropped on deserialization. | 9516 // as is it dropped on deserialization. |
| 9699 CHECK(!isolate()->serializer_enabled()); | 9517 CHECK(!isolate()->serializer_enabled()); |
| 9700 Handle<JSObject> global_proxy(target->context()->global_proxy()); | 9518 Handle<JSObject> global_proxy(target->context()->global_proxy()); |
| 9701 return Add<HConstant>(global_proxy); | 9519 return Add<HConstant>(global_proxy); |
| 9702 } | 9520 } |
| 9703 return graph()->GetConstantUndefined(); | 9521 return graph()->GetConstantUndefined(); |
| 9704 } | 9522 } |
| 9705 | 9523 |
| 9706 | 9524 |
| 9707 void HOptimizedGraphBuilder::BuildArrayCall(Expression* expression, | |
| 9708 int arguments_count, | |
| 9709 HValue* function, | |
| 9710 Handle<AllocationSite> site) { | |
| 9711 Add<HCheckValue>(function, array_function()); | |
| 9712 | |
| 9713 if (IsCallArrayInlineable(arguments_count, site)) { | |
| 9714 BuildInlinedCallArray(expression, arguments_count, site); | |
| 9715 return; | |
| 9716 } | |
| 9717 | |
| 9718 HInstruction* call = PreProcessCall(New<HCallNewArray>( | |
| 9719 function, arguments_count + 1, site->GetElementsKind(), site)); | |
| 9720 if (expression->IsCall()) { | |
| 9721 Drop(1); | |
| 9722 } | |
| 9723 ast_context()->ReturnInstruction(call, expression->id()); | |
| 9724 } | |
| 9725 | |
| 9726 | |
| 9727 HValue* HOptimizedGraphBuilder::BuildArrayIndexOf(HValue* receiver, | 9525 HValue* HOptimizedGraphBuilder::BuildArrayIndexOf(HValue* receiver, |
| 9728 HValue* search_element, | 9526 HValue* search_element, |
| 9729 ElementsKind kind, | 9527 ElementsKind kind, |
| 9730 ArrayIndexOfMode mode) { | 9528 ArrayIndexOfMode mode) { |
| 9731 DCHECK(IsFastElementsKind(kind)); | 9529 DCHECK(IsFastElementsKind(kind)); |
| 9732 | 9530 |
| 9733 NoObservableSideEffectsScope no_effects(this); | 9531 NoObservableSideEffectsScope no_effects(this); |
| 9734 | 9532 |
| 9735 HValue* elements = AddLoadElements(receiver); | 9533 HValue* elements = AddLoadElements(receiver); |
| 9736 HValue* length = AddLoadArrayLength(receiver, kind); | 9534 HValue* length = AddLoadArrayLength(receiver, kind); |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 9863 loop.EndBody(); | 9661 loop.EndBody(); |
| 9864 } | 9662 } |
| 9865 if_isnumber.End(); | 9663 if_isnumber.End(); |
| 9866 } | 9664 } |
| 9867 if_isstring.End(); | 9665 if_isstring.End(); |
| 9868 } | 9666 } |
| 9869 | 9667 |
| 9870 return Pop(); | 9668 return Pop(); |
| 9871 } | 9669 } |
| 9872 | 9670 |
| 9873 | 9671 template <class T> |
| 9874 bool HOptimizedGraphBuilder::TryHandleArrayCall(Call* expr, HValue* function) { | 9672 bool HOptimizedGraphBuilder::TryHandleArrayCall(T* expr, HValue* function) { |
| 9875 if (!array_function().is_identical_to(expr->target())) { | 9673 if (!array_function().is_identical_to(expr->target())) { |
| 9876 return false; | 9674 return false; |
| 9877 } | 9675 } |
| 9878 | 9676 |
| 9879 Handle<AllocationSite> site = expr->allocation_site(); | 9677 Handle<AllocationSite> site = expr->allocation_site(); |
| 9880 if (site.is_null()) return false; | 9678 if (site.is_null()) return false; |
| 9881 | 9679 |
| 9882 BuildArrayCall(expr, | 9680 Add<HCheckValue>(function, array_function()); |
| 9883 expr->arguments()->length(), | 9681 |
| 9884 function, | 9682 int arguments_count = expr->arguments()->length(); |
| 9885 site); | 9683 if (TryInlineArrayCall(expr, arguments_count, site)) return true; |
| 9684 | |
| 9685 HInstruction* call = PreProcessCall(New<HCallNewArray>( | |
| 9686 function, arguments_count + 1, site->GetElementsKind(), site)); | |
| 9687 if (expr->IsCall()) Drop(1); | |
| 9688 ast_context()->ReturnInstruction(call, expr->id()); | |
| 9689 | |
| 9886 return true; | 9690 return true; |
| 9887 } | 9691 } |
| 9888 | 9692 |
| 9889 | |
| 9890 bool HOptimizedGraphBuilder::TryHandleArrayCallNew(CallNew* expr, | |
| 9891 HValue* function) { | |
| 9892 if (!array_function().is_identical_to(expr->target())) { | |
| 9893 return false; | |
| 9894 } | |
| 9895 | |
| 9896 Handle<AllocationSite> site = expr->allocation_site(); | |
| 9897 if (site.is_null()) return false; | |
| 9898 | |
| 9899 BuildArrayCall(expr, expr->arguments()->length(), function, site); | |
| 9900 return true; | |
| 9901 } | |
| 9902 | |
| 9903 | 9693 |
| 9904 bool HOptimizedGraphBuilder::CanBeFunctionApplyArguments(Call* expr) { | 9694 bool HOptimizedGraphBuilder::CanBeFunctionApplyArguments(Call* expr) { |
| 9905 ZoneList<Expression*>* args = expr->arguments(); | 9695 ZoneList<Expression*>* args = expr->arguments(); |
| 9906 if (args->length() != 2) return false; | 9696 if (args->length() != 2) return false; |
| 9907 VariableProxy* arg_two = args->at(1)->AsVariableProxy(); | 9697 VariableProxy* arg_two = args->at(1)->AsVariableProxy(); |
| 9908 if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false; | 9698 if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false; |
| 9909 HValue* arg_two_value = LookupAndMakeLive(arg_two->var()); | 9699 HValue* arg_two_value = LookupAndMakeLive(arg_two->var()); |
| 9910 if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; | 9700 if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; |
| 9911 return true; | 9701 return true; |
| 9912 } | 9702 } |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 10075 function, argument_count, syntactic_tail_call_mode, | 9865 function, argument_count, syntactic_tail_call_mode, |
| 10076 ConvertReceiverMode::kNullOrUndefined, tail_call_mode); | 9866 ConvertReceiverMode::kNullOrUndefined, tail_call_mode); |
| 10077 } | 9867 } |
| 10078 } | 9868 } |
| 10079 } | 9869 } |
| 10080 | 9870 |
| 10081 Drop(1); // Drop the function. | 9871 Drop(1); // Drop the function. |
| 10082 return ast_context()->ReturnInstruction(call, expr->id()); | 9872 return ast_context()->ReturnInstruction(call, expr->id()); |
| 10083 } | 9873 } |
| 10084 | 9874 |
| 9875 bool HOptimizedGraphBuilder::TryInlineArrayCall(Expression* expression, | |
| 9876 int argument_count, | |
| 9877 Handle<AllocationSite> site) { | |
| 9878 Handle<JSFunction> caller = current_info()->closure(); | |
| 9879 Handle<JSFunction> target = array_function(); | |
| 10085 | 9880 |
| 10086 void HOptimizedGraphBuilder::BuildInlinedCallArray( | 9881 if (!site->CanInlineCall()) { |
| 10087 Expression* expression, | 9882 TraceInline(target, caller, "AllocationSite requested no inlining."); |
| 10088 int argument_count, | 9883 return false; |
| 10089 Handle<AllocationSite> site) { | 9884 } |
| 10090 DCHECK(!site.is_null()); | 9885 |
| 10091 DCHECK(argument_count >= 0 && argument_count <= 1); | 9886 if (argument_count > 1) { |
| 9887 TraceInline(target, caller, "Too many arguments to inline."); | |
| 9888 return false; | |
| 9889 } | |
| 9890 | |
| 9891 int array_length = 0; | |
| 9892 // Do not inline if the constant length argument is not a smi or outside the | |
| 9893 // valid range for unrolled loop initialization. | |
| 9894 if (argument_count == 1) { | |
| 9895 HValue* argument = Top(); | |
| 9896 if (!argument->IsConstant()) { | |
| 9897 TraceInline(target, caller, | |
| 9898 "Dont inline [new] Array(n) where n isn't constant."); | |
| 9899 return false; | |
| 9900 } | |
| 9901 | |
| 9902 HConstant* constant_argument = HConstant::cast(argument); | |
| 9903 if (!constant_argument->HasSmiValue()) { | |
| 9904 TraceInline(target, caller, | |
| 9905 "Constant length outside of valid inlining range."); | |
| 9906 return false; | |
| 9907 } | |
| 9908 array_length = constant_argument->Integer32Value(); | |
| 9909 if (array_length < 0 || array_length > kElementLoopUnrollThreshold) { | |
| 9910 TraceInline(target, caller, | |
| 9911 "Constant length outside of valid inlining range."); | |
| 9912 return false; | |
| 9913 } | |
| 9914 } | |
| 9915 | |
| 10092 NoObservableSideEffectsScope no_effects(this); | 9916 NoObservableSideEffectsScope no_effects(this); |
| 10093 | 9917 |
| 10094 // We should at least have the constructor on the expression stack. | |
| 10095 HValue* constructor = environment()->ExpressionStackAt(argument_count); | |
| 10096 | |
| 10097 // Register on the site for deoptimization if the transition feedback changes. | 9918 // Register on the site for deoptimization if the transition feedback changes. |
| 10098 top_info()->dependencies()->AssumeTransitionStable(site); | 9919 top_info()->dependencies()->AssumeTransitionStable(site); |
| 9920 | |
| 9921 // Build the array. | |
| 10099 ElementsKind kind = site->GetElementsKind(); | 9922 ElementsKind kind = site->GetElementsKind(); |
| 10100 HInstruction* site_instruction = Add<HConstant>(site); | 9923 HValue* capacity; |
| 10101 | 9924 HValue* length; |
| 10102 // In the single constant argument case, we may have to adjust elements kind | 9925 if (array_length == 0) { |
| 10103 // to avoid creating a packed non-empty array. | 9926 STATIC_ASSERT(0 < JSArray::kPreallocatedArrayElements); |
| 10104 if (argument_count == 1 && !IsHoleyElementsKind(kind)) { | 9927 const int initial_capacity = JSArray::kPreallocatedArrayElements; |
| 10105 HValue* argument = environment()->Top(); | 9928 capacity = Add<HConstant>(initial_capacity); |
| 10106 if (argument->IsConstant()) { | 9929 length = graph()->GetConstant0(); |
| 10107 HConstant* constant_argument = HConstant::cast(argument); | 9930 } else { |
| 10108 DCHECK(constant_argument->HasSmiValue()); | 9931 length = Top(); |
| 10109 int constant_array_size = constant_argument->Integer32Value(); | 9932 capacity = length; |
| 10110 if (constant_array_size != 0) { | 9933 kind = GetHoleyElementsKind(kind); |
| 10111 kind = GetHoleyElementsKind(kind); | |
| 10112 } | |
| 10113 } | |
| 10114 } | 9934 } |
| 10115 | 9935 |
| 10116 // Build the array. | 9936 // These HForceRepresentations are because we store these as fields in the |
| 10117 JSArrayBuilder array_builder(this, | 9937 // objects we construct, and an int32-to-smi HChange could deopt. Accept |
| 10118 kind, | 9938 // the deopt possibility now, before allocation occurs. |
| 10119 site_instruction, | 9939 length = AddUncasted<HForceRepresentation>(length, Representation::Smi()); |
| 10120 constructor, | 9940 capacity = AddUncasted<HForceRepresentation>(capacity, Representation::Smi()); |
| 10121 DISABLE_ALLOCATION_SITES); | 9941 |
| 10122 HValue* new_object = argument_count == 0 | 9942 // Generate size calculation code here in order to make it dominate |
| 10123 ? array_builder.AllocateEmptyArray() | 9943 // the JSArray allocation. |
| 10124 : BuildAllocateArrayFromLength(&array_builder, Top()); | 9944 HValue* elements_size = BuildCalculateElementsSize(kind, capacity); |
| 9945 | |
| 9946 // Bail out for large objects. | |
| 9947 HValue* max_size = Add<HConstant>(Page::kMaxRegularHeapObjectSize); | |
| 9948 Add<HBoundsCheck>(elements_size, max_size); | |
| 9949 | |
| 9950 // Allocate (dealing with failure appropriately) | |
|
Jakob Kummerow
2016/07/05 15:18:06
nit: trailing full stop (4 more times below).
| |
| 9951 AllocationSiteMode mode = DONT_TRACK_ALLOCATION_SITE; | |
| 9952 HAllocate* new_object = AllocateJSArrayObject(mode); | |
| 9953 | |
| 9954 // Fill in the fields: map, properties, length | |
| 9955 Handle<Map> map_constant(isolate()->get_initial_js_array_map(kind)); | |
| 9956 HValue* map = Add<HConstant>(map_constant); | |
| 9957 | |
| 9958 BuildJSArrayHeader(new_object, map, | |
| 9959 nullptr, // set elements to empty fixed array | |
| 9960 mode, kind, nullptr, length); | |
| 9961 | |
| 9962 // Allocate and initialize the elements | |
| 9963 HAllocate* elements = BuildAllocateElements(kind, elements_size); | |
| 9964 BuildInitializeElementsHeader(elements, kind, capacity); | |
| 9965 BuildFillElementsWithHole(elements, kind, graph()->GetConstant0(), capacity); | |
| 9966 | |
| 9967 // Set the elements | |
| 9968 Add<HStoreNamedField>(new_object, HObjectAccess::ForElementsPointer(), | |
| 9969 elements); | |
| 10125 | 9970 |
| 10126 int args_to_drop = argument_count + (expression->IsCall() ? 2 : 1); | 9971 int args_to_drop = argument_count + (expression->IsCall() ? 2 : 1); |
| 10127 Drop(args_to_drop); | 9972 Drop(args_to_drop); |
| 10128 ast_context()->ReturnValue(new_object); | 9973 ast_context()->ReturnValue(new_object); |
| 9974 return true; | |
| 10129 } | 9975 } |
| 10130 | 9976 |
| 10131 | 9977 |
| 10132 // Checks whether allocation using the given constructor can be inlined. | 9978 // Checks whether allocation using the given constructor can be inlined. |
| 10133 static bool IsAllocationInlineable(Handle<JSFunction> constructor) { | 9979 static bool IsAllocationInlineable(Handle<JSFunction> constructor) { |
| 10134 return constructor->has_initial_map() && | 9980 return constructor->has_initial_map() && |
| 10135 !IsSubclassConstructor(constructor->shared()->kind()) && | 9981 !IsSubclassConstructor(constructor->shared()->kind()) && |
| 10136 constructor->initial_map()->instance_type() == JS_OBJECT_TYPE && | 9982 constructor->initial_map()->instance_type() == JS_OBJECT_TYPE && |
| 10137 constructor->initial_map()->instance_size() < | 9983 constructor->initial_map()->instance_size() < |
| 10138 HAllocate::kMaxInlineSize; | 9984 HAllocate::kMaxInlineSize; |
| 10139 } | 9985 } |
| 10140 | 9986 |
| 10141 | |
| 10142 bool HOptimizedGraphBuilder::IsCallArrayInlineable( | |
| 10143 int argument_count, | |
| 10144 Handle<AllocationSite> site) { | |
| 10145 Handle<JSFunction> caller = current_info()->closure(); | |
| 10146 Handle<JSFunction> target = array_function(); | |
| 10147 // We should have the function plus array arguments on the environment stack. | |
| 10148 DCHECK(environment()->length() >= (argument_count + 1)); | |
| 10149 DCHECK(!site.is_null()); | |
| 10150 | |
| 10151 bool inline_ok = false; | |
| 10152 if (site->CanInlineCall()) { | |
| 10153 // We also want to avoid inlining in certain 1 argument scenarios. | |
| 10154 if (argument_count == 1) { | |
| 10155 HValue* argument = Top(); | |
| 10156 if (argument->IsConstant()) { | |
| 10157 // Do not inline if the constant length argument is not a smi or | |
| 10158 // outside the valid range for unrolled loop initialization. | |
| 10159 HConstant* constant_argument = HConstant::cast(argument); | |
| 10160 if (constant_argument->HasSmiValue()) { | |
| 10161 int value = constant_argument->Integer32Value(); | |
| 10162 inline_ok = value >= 0 && value <= kElementLoopUnrollThreshold; | |
| 10163 if (!inline_ok) { | |
| 10164 TraceInline(target, caller, | |
| 10165 "Constant length outside of valid inlining range."); | |
| 10166 } | |
| 10167 } | |
| 10168 } else { | |
| 10169 TraceInline(target, caller, | |
| 10170 "Dont inline [new] Array(n) where n isn't constant."); | |
| 10171 } | |
| 10172 } else if (argument_count == 0) { | |
| 10173 inline_ok = true; | |
| 10174 } else { | |
| 10175 TraceInline(target, caller, "Too many arguments to inline."); | |
| 10176 } | |
| 10177 } else { | |
| 10178 TraceInline(target, caller, "AllocationSite requested no inlining."); | |
| 10179 } | |
| 10180 | |
| 10181 if (inline_ok) { | |
| 10182 TraceInline(target, caller, NULL); | |
|
Jakob Kummerow
2016/07/05 15:18:06
Where'd this go?
| |
| 10183 } | |
| 10184 return inline_ok; | |
| 10185 } | |
| 10186 | |
| 10187 | |
| 10188 void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) { | 9987 void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) { |
| 10189 DCHECK(!HasStackOverflow()); | 9988 DCHECK(!HasStackOverflow()); |
| 10190 DCHECK(current_block() != NULL); | 9989 DCHECK(current_block() != NULL); |
| 10191 DCHECK(current_block()->HasPredecessor()); | 9990 DCHECK(current_block()->HasPredecessor()); |
| 10192 if (!top_info()->is_tracking_positions()) SetSourcePosition(expr->position()); | 9991 if (!top_info()->is_tracking_positions()) SetSourcePosition(expr->position()); |
| 10193 int argument_count = expr->arguments()->length() + 1; // Plus constructor. | 9992 int argument_count = expr->arguments()->length() + 1; // Plus constructor. |
| 10194 Factory* factory = isolate()->factory(); | 9993 Factory* factory = isolate()->factory(); |
| 10195 | 9994 |
| 10196 // The constructor function is on the stack in the unoptimized code | 9995 // The constructor function is on the stack in the unoptimized code |
| 10197 // during evaluation of the arguments. | 9996 // during evaluation of the arguments. |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 10271 HInstruction* instr = current_block()->last(); | 10070 HInstruction* instr = current_block()->last(); |
| 10272 do { | 10071 do { |
| 10273 HInstruction* prev_instr = instr->previous(); | 10072 HInstruction* prev_instr = instr->previous(); |
| 10274 instr->DeleteAndReplaceWith(NULL); | 10073 instr->DeleteAndReplaceWith(NULL); |
| 10275 instr = prev_instr; | 10074 instr = prev_instr; |
| 10276 } while (instr != check); | 10075 } while (instr != check); |
| 10277 environment()->SetExpressionStackAt(receiver_index, function); | 10076 environment()->SetExpressionStackAt(receiver_index, function); |
| 10278 } else { | 10077 } else { |
| 10279 // The constructor function is both an operand to the instruction and an | 10078 // The constructor function is both an operand to the instruction and an |
| 10280 // argument to the construct call. | 10079 // argument to the construct call. |
| 10281 if (TryHandleArrayCallNew(expr, function)) return; | 10080 if (TryHandleArrayCall(expr, function)) return; |
| 10282 } | 10081 } |
| 10283 | 10082 |
| 10284 HValue* arity = Add<HConstant>(argument_count - 1); | 10083 HValue* arity = Add<HConstant>(argument_count - 1); |
| 10285 HValue* op_vals[] = {context(), function, function, arity}; | 10084 HValue* op_vals[] = {context(), function, function, arity}; |
| 10286 Callable callable = CodeFactory::Construct(isolate()); | 10085 Callable callable = CodeFactory::Construct(isolate()); |
| 10287 HConstant* stub = Add<HConstant>(callable.code()); | 10086 HConstant* stub = Add<HConstant>(callable.code()); |
| 10288 PushArgumentsFromEnvironment(argument_count); | 10087 PushArgumentsFromEnvironment(argument_count); |
| 10289 HInstruction* construct = New<HCallWithDescriptor>( | 10088 HInstruction* construct = New<HCallWithDescriptor>( |
| 10290 stub, argument_count, callable.descriptor(), ArrayVector(op_vals)); | 10089 stub, argument_count, callable.descriptor(), ArrayVector(op_vals)); |
| 10291 return ast_context()->ReturnInstruction(construct, expr->id()); | 10090 return ast_context()->ReturnInstruction(construct, expr->id()); |
| (...skipping 3335 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 13627 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 13426 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
| 13628 } | 13427 } |
| 13629 | 13428 |
| 13630 #ifdef DEBUG | 13429 #ifdef DEBUG |
| 13631 graph_->Verify(false); // No full verify. | 13430 graph_->Verify(false); // No full verify. |
| 13632 #endif | 13431 #endif |
| 13633 } | 13432 } |
| 13634 | 13433 |
| 13635 } // namespace internal | 13434 } // namespace internal |
| 13636 } // namespace v8 | 13435 } // namespace v8 |
| OLD | NEW |