OLD | NEW |
---|---|
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 3431 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3442 instr = BuildStoreNamedGeneric(object, name, value); | 3442 instr = BuildStoreNamedGeneric(object, name, value); |
3443 } | 3443 } |
3444 | 3444 |
3445 } else { | 3445 } else { |
3446 // Keyed store. | 3446 // Keyed store. |
3447 CHECK_ALIVE(VisitForValue(prop->key())); | 3447 CHECK_ALIVE(VisitForValue(prop->key())); |
3448 CHECK_ALIVE(VisitForValue(expr->value())); | 3448 CHECK_ALIVE(VisitForValue(expr->value())); |
3449 value = Pop(); | 3449 value = Pop(); |
3450 HValue* key = Pop(); | 3450 HValue* key = Pop(); |
3451 HValue* object = Pop(); | 3451 HValue* object = Pop(); |
3452 instr = BuildStoreKeyed(object, key, value, expr); | 3452 bool has_side_effects = false; |
3453 HandleKeyedElementAccess(object, key, value, expr, expr->AssignmentId(), | |
3454 expr->position(), | |
3455 true, // is_store | |
3456 &has_side_effects); | |
3457 Push(value); | |
3458 ASSERT(has_side_effects); // Stores always have side effects. | |
3459 AddSimulate(expr->AssignmentId()); | |
3460 ast_context()->ReturnValue(Pop()); | |
3461 return; | |
3453 } | 3462 } |
3454 Push(value); | 3463 Push(value); |
3455 instr->set_position(expr->position()); | 3464 instr->set_position(expr->position()); |
3456 AddInstruction(instr); | 3465 AddInstruction(instr); |
3457 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); | 3466 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
3458 ast_context()->ReturnValue(Pop()); | 3467 ast_context()->ReturnValue(Pop()); |
3459 } | 3468 } |
3460 | 3469 |
3461 | 3470 |
3462 // Because not every expression has a position and there is not common | 3471 // Because not every expression has a position and there is not common |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3566 if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); | 3575 if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
3567 ast_context()->ReturnValue(Pop()); | 3576 ast_context()->ReturnValue(Pop()); |
3568 | 3577 |
3569 } else { | 3578 } else { |
3570 // Keyed property. | 3579 // Keyed property. |
3571 CHECK_ALIVE(VisitForValue(prop->obj())); | 3580 CHECK_ALIVE(VisitForValue(prop->obj())); |
3572 CHECK_ALIVE(VisitForValue(prop->key())); | 3581 CHECK_ALIVE(VisitForValue(prop->key())); |
3573 HValue* obj = environment()->ExpressionStackAt(1); | 3582 HValue* obj = environment()->ExpressionStackAt(1); |
3574 HValue* key = environment()->ExpressionStackAt(0); | 3583 HValue* key = environment()->ExpressionStackAt(0); |
3575 | 3584 |
3576 HInstruction* load = BuildLoadKeyed(obj, key, prop); | 3585 bool has_side_effects = false; |
3577 PushAndAdd(load); | 3586 HValue* load = HandleKeyedElementAccess( |
3578 if (load->HasSideEffects()) AddSimulate(expr->CompoundLoadId()); | 3587 obj, key, NULL, prop, expr->CompoundLoadId(), RelocInfo::kNoPosition, |
3588 false, // is_store | |
3589 &has_side_effects); | |
3590 Push(load); | |
3591 if (has_side_effects) AddSimulate(expr->CompoundLoadId()); | |
3592 | |
3579 | 3593 |
3580 CHECK_ALIVE(VisitForValue(expr->value())); | 3594 CHECK_ALIVE(VisitForValue(expr->value())); |
3581 HValue* right = Pop(); | 3595 HValue* right = Pop(); |
3582 HValue* left = Pop(); | 3596 HValue* left = Pop(); |
3583 | 3597 |
3584 HInstruction* instr = BuildBinaryOperation(operation, left, right); | 3598 HInstruction* instr = BuildBinaryOperation(operation, left, right); |
3585 PushAndAdd(instr); | 3599 PushAndAdd(instr); |
3586 if (instr->HasSideEffects()) AddSimulate(operation->id()); | 3600 if (instr->HasSideEffects()) AddSimulate(operation->id()); |
3587 | 3601 |
3588 expr->RecordTypeFeedback(oracle()); | 3602 expr->RecordTypeFeedback(oracle()); |
3589 HInstruction* store = BuildStoreKeyed(obj, key, instr, expr); | 3603 HandleKeyedElementAccess(obj, key, instr, expr, expr->AssignmentId(), |
3590 AddInstruction(store); | 3604 RelocInfo::kNoPosition, |
3605 true, // is_store | |
3606 &has_side_effects); | |
3607 | |
3591 // Drop the simulated receiver, key, and value. Return the value. | 3608 // Drop the simulated receiver, key, and value. Return the value. |
3592 Drop(3); | 3609 Drop(3); |
3593 Push(instr); | 3610 Push(instr); |
3594 if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); | 3611 ASSERT(has_side_effects); // Stores always have side effects. |
3612 AddSimulate(expr->AssignmentId()); | |
3595 ast_context()->ReturnValue(Pop()); | 3613 ast_context()->ReturnValue(Pop()); |
3596 } | 3614 } |
3597 | 3615 |
3598 } else { | 3616 } else { |
3599 return Bailout("invalid lhs in compound assignment"); | 3617 return Bailout("invalid lhs in compound assignment"); |
3600 } | 3618 } |
3601 } | 3619 } |
3602 | 3620 |
3603 | 3621 |
3604 void HGraphBuilder::VisitAssignment(Assignment* expr) { | 3622 void HGraphBuilder::VisitAssignment(Assignment* expr) { |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3748 } | 3766 } |
3749 | 3767 |
3750 | 3768 |
3751 HInstruction* HGraphBuilder::BuildLoadKeyedGeneric(HValue* object, | 3769 HInstruction* HGraphBuilder::BuildLoadKeyedGeneric(HValue* object, |
3752 HValue* key) { | 3770 HValue* key) { |
3753 HValue* context = environment()->LookupContext(); | 3771 HValue* context = environment()->LookupContext(); |
3754 return new(zone()) HLoadKeyedGeneric(context, object, key); | 3772 return new(zone()) HLoadKeyedGeneric(context, object, key); |
3755 } | 3773 } |
3756 | 3774 |
3757 | 3775 |
3758 HInstruction* HGraphBuilder::BuildLoadKeyedFastElement(HValue* object, | 3776 HInstruction* HGraphBuilder::BuildExternalArrayElementAccess( |
3759 HValue* key, | 3777 HValue* external_elements, |
3760 Property* expr) { | 3778 HValue* checked_key, |
3761 ASSERT(!expr->key()->IsPropertyName() && expr->IsMonomorphic()); | 3779 HValue* val, |
3780 JSObject::ElementsKind elements_kind, | |
3781 bool is_store) { | |
3782 if (is_store) { | |
3783 ASSERT(val != NULL); | |
3784 switch (elements_kind) { | |
3785 case JSObject::EXTERNAL_PIXEL_ELEMENTS: { | |
3786 HClampToUint8* clamp = new(zone()) HClampToUint8(val); | |
3787 AddInstruction(clamp); | |
3788 val = clamp; | |
3789 break; | |
3790 } | |
3791 case JSObject::EXTERNAL_BYTE_ELEMENTS: | |
3792 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | |
3793 case JSObject::EXTERNAL_SHORT_ELEMENTS: | |
3794 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | |
3795 case JSObject::EXTERNAL_INT_ELEMENTS: | |
3796 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: { | |
3797 HToInt32* floor_val = new(zone()) HToInt32(val); | |
3798 AddInstruction(floor_val); | |
3799 val = floor_val; | |
3800 break; | |
3801 } | |
3802 case JSObject::EXTERNAL_FLOAT_ELEMENTS: | |
3803 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: | |
3804 break; | |
3805 case JSObject::FAST_ELEMENTS: | |
3806 case JSObject::FAST_DOUBLE_ELEMENTS: | |
3807 case JSObject::DICTIONARY_ELEMENTS: | |
3808 UNREACHABLE(); | |
3809 break; | |
3810 } | |
3811 return new(zone()) HStoreKeyedSpecializedArrayElement( | |
3812 external_elements, checked_key, val, elements_kind); | |
3813 } else { | |
3814 return new(zone()) HLoadKeyedSpecializedArrayElement( | |
3815 external_elements, checked_key, elements_kind); | |
3816 } | |
3817 } | |
3818 | |
3819 | |
3820 HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, | |
3821 HValue* key, | |
3822 HValue* val, | |
3823 Expression* expr, | |
3824 bool is_store) { | |
3825 ASSERT(expr->IsMonomorphic()); | |
3826 Handle<Map> map = expr->GetMonomorphicReceiverType(); | |
3827 if (!map->has_fast_elements() && !map->has_external_array_elements()) { | |
3828 return is_store ? BuildStoreKeyedGeneric(object, key, val) | |
3829 : BuildLoadKeyedGeneric(object, key); | |
3830 } | |
3762 AddInstruction(new(zone()) HCheckNonSmi(object)); | 3831 AddInstruction(new(zone()) HCheckNonSmi(object)); |
3763 Handle<Map> map = expr->GetMonomorphicReceiverType(); | |
3764 ASSERT(map->has_fast_elements()); | |
3765 AddInstruction(new(zone()) HCheckMap(object, map)); | 3832 AddInstruction(new(zone()) HCheckMap(object, map)); |
3766 bool is_array = (map->instance_type() == JS_ARRAY_TYPE); | 3833 HInstruction* elements = new(zone()) HLoadElements(object); |
3767 HLoadElements* elements = new(zone()) HLoadElements(object); | |
3768 HInstruction* length = NULL; | 3834 HInstruction* length = NULL; |
3769 HInstruction* checked_key = NULL; | 3835 HInstruction* checked_key = NULL; |
3770 if (is_array) { | 3836 if (map->has_external_array_elements()) { |
3837 AddInstruction(elements); | |
3838 length = AddInstruction(new(zone()) HExternalArrayLength(elements)); | |
3839 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); | |
3840 HLoadExternalArrayPointer* external_elements = | |
3841 new(zone()) HLoadExternalArrayPointer(elements); | |
3842 AddInstruction(external_elements); | |
3843 return BuildExternalArrayElementAccess(external_elements, checked_key, | |
3844 val, map->elements_kind(), is_store); | |
3845 } | |
3846 ASSERT(map->has_fast_elements()); | |
3847 if (map->instance_type() == JS_ARRAY_TYPE) { | |
3771 length = AddInstruction(new(zone()) HJSArrayLength(object)); | 3848 length = AddInstruction(new(zone()) HJSArrayLength(object)); |
3772 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); | 3849 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); |
3773 AddInstruction(elements); | 3850 AddInstruction(elements); |
3774 } else { | 3851 } else { |
3775 AddInstruction(elements); | 3852 AddInstruction(elements); |
3776 length = AddInstruction(new(zone()) HFixedArrayLength(elements)); | 3853 length = AddInstruction(new(zone()) HFixedArrayLength(elements)); |
3777 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); | 3854 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); |
3778 } | 3855 } |
3779 return new(zone()) HLoadKeyedFastElement(elements, checked_key); | 3856 if (is_store) { |
3857 return new(zone()) HStoreKeyedFastElement(elements, checked_key, val); | |
3858 } else { | |
3859 return new(zone()) HLoadKeyedFastElement(elements, checked_key); | |
3860 } | |
3780 } | 3861 } |
3781 | 3862 |
3782 | 3863 |
3783 HInstruction* HGraphBuilder::BuildLoadKeyedSpecializedArrayElement( | 3864 HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, |
3784 HValue* object, | 3865 HValue* key, |
3785 HValue* key, | 3866 HValue* val, |
3786 Property* expr) { | 3867 Expression* prop, |
3787 ASSERT(!expr->key()->IsPropertyName() && expr->IsMonomorphic()); | 3868 int ast_id, |
3869 int position, | |
3870 bool is_store, | |
3871 bool* has_side_effects) { | |
3872 *has_side_effects = false; | |
3788 AddInstruction(new(zone()) HCheckNonSmi(object)); | 3873 AddInstruction(new(zone()) HCheckNonSmi(object)); |
3789 Handle<Map> map = expr->GetMonomorphicReceiverType(); | 3874 AddInstruction(HCheckInstanceType::NewIsSpecObject(object)); |
3790 ASSERT(!map->has_fast_elements()); | 3875 ZoneMapList* maps = prop->GetReceiverTypes(); |
3791 ASSERT(map->has_external_array_elements()); | 3876 bool todo_external_array = false; |
3792 AddInstruction(new(zone()) HCheckMap(object, map)); | 3877 |
3793 HLoadElements* elements = new(zone()) HLoadElements(object); | 3878 static const int kNumElementTypes = JSObject::kElementsKindCount; |
3794 AddInstruction(elements); | 3879 bool type_todo[kNumElementTypes]; |
3795 HInstruction* length = new(zone()) HExternalArrayLength(elements); | 3880 for (int i = 0; i < kNumElementTypes; ++i) { |
3796 AddInstruction(length); | 3881 type_todo[i] = false; |
3797 HInstruction* checked_key = | 3882 } |
3798 AddInstruction(new(zone()) HBoundsCheck(key, length)); | 3883 |
3799 HLoadExternalArrayPointer* external_elements = | 3884 for (int i = 0; i < maps->length(); ++i) { |
3800 new(zone()) HLoadExternalArrayPointer(elements); | 3885 ASSERT(maps->at(i)->IsMap()); |
3801 AddInstruction(external_elements); | 3886 type_todo[maps->at(i)->elements_kind()] = true; |
3802 HLoadKeyedSpecializedArrayElement* pixel_array_value = | 3887 if (maps->at(i)->elements_kind() |
3803 new(zone()) HLoadKeyedSpecializedArrayElement( | 3888 >= JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND) { |
3804 external_elements, checked_key, map->elements_kind()); | 3889 todo_external_array = true; |
3805 return pixel_array_value; | 3890 } |
3891 } | |
3892 // We can't treat dictionary elements here (need to deopt instead). | |
3893 type_todo[JSObject::DICTIONARY_ELEMENTS] = false; | |
3894 // Support for FAST_DOUBLE_ELEMENTS isn't implemented yet, so we deopt. | |
3895 type_todo[JSObject::FAST_DOUBLE_ELEMENTS] = false; | |
3896 | |
3897 HBasicBlock* join = graph()->CreateBasicBlock(); | |
3898 | |
3899 HInstruction* elements_kind_instr = | |
3900 AddInstruction(new(zone()) HElementsKind(object)); | |
3901 HInstruction* elements = NULL; | |
3902 HLoadExternalArrayPointer* external_elements = NULL; | |
3903 HInstruction* checked_key = NULL; | |
3904 | |
3905 // FAST_ELEMENTS is assumed to be the first case. | |
3906 STATIC_ASSERT(JSObject::FAST_ELEMENTS == 0); | |
3907 | |
3908 for (JSObject::ElementsKind elements_kind = JSObject::FAST_ELEMENTS; | |
3909 elements_kind <= JSObject::LAST_ELEMENTS_KIND; | |
3910 elements_kind = JSObject::ElementsKind(elements_kind + 1)) { | |
3911 // After having handled FAST_ELEMENTS in the first run of the loop, we | |
3912 // need to add some code that's executed for all other cases. | |
3913 if (elements_kind == 1 && todo_external_array) { | |
Søren Thygesen Gjesse
2011/06/21 07:09:04
Shouldn't the constant 1 here be JSObject::FAST_EL
Jakob Kummerow
2011/06/21 07:49:23
No. FAST_ELEMENTS == 0. As the comment indicates,
Søren Thygesen Gjesse
2011/06/21 10:01:53
I see.
I think it should stay at the beginning of
| |
3914 elements = AddInstruction(new(zone()) HLoadElements(object)); | |
3915 // We need to forcibly prevent some ElementsKind-dependent instructions | |
3916 // from being hoisted out of any loops they might occur in, because | |
3917 // the current loop-invariant-code-motion algorithm isn't clever enough | |
3918 // to deal with them properly. | |
3919 // There's some performance to be gained by developing a smarter | |
3920 // solution for this. | |
3921 elements->ClearFlag(HValue::kUseGVN); | |
3922 HInstruction* length = | |
3923 AddInstruction(new(zone()) HExternalArrayLength(elements)); | |
3924 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); | |
3925 external_elements = new(zone()) HLoadExternalArrayPointer(elements); | |
3926 AddInstruction(external_elements); | |
3927 } | |
3928 if (type_todo[elements_kind]) { | |
3929 HBasicBlock* if_true = graph()->CreateBasicBlock(); | |
3930 HBasicBlock* if_false = graph()->CreateBasicBlock(); | |
3931 HCompareConstantEq* compare = new(zone()) HCompareConstantEq( | |
3932 elements_kind_instr, | |
3933 elements_kind, | |
3934 Token::EQ_STRICT); | |
3935 AddInstruction(compare); | |
3936 HTest* branch = new(zone()) HTest(compare, if_true, if_false); | |
3937 current_block()->Finish(branch); | |
3938 | |
3939 set_current_block(if_true); | |
3940 HInstruction* access; | |
3941 if (elements_kind == JSObject::FAST_ELEMENTS) { | |
3942 HBasicBlock* if_jsarray = graph()->CreateBasicBlock(); | |
3943 HBasicBlock* if_fastobject = graph()->CreateBasicBlock(); | |
3944 HInstruction* typecheck = | |
3945 AddInstruction(new(zone()) HHasInstanceType(object, JS_ARRAY_TYPE)); | |
3946 HTest* test = new(zone()) HTest(typecheck, if_jsarray, if_fastobject); | |
3947 current_block()->Finish(test); | |
3948 | |
3949 set_current_block(if_jsarray); | |
3950 HInstruction* length = new(zone()) HJSArrayLength(object); | |
3951 AddInstruction(length); | |
3952 length->ClearFlag(HValue::kUseGVN); | |
3953 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); | |
3954 elements = AddInstruction(new(zone()) HLoadElements(object)); | |
3955 elements->ClearFlag(HValue::kUseGVN); | |
3956 if (is_store) { | |
3957 access = AddInstruction( | |
3958 new(zone()) HStoreKeyedFastElement(elements, checked_key, val)); | |
3959 } else { | |
3960 access = AddInstruction( | |
3961 new(zone()) HLoadKeyedFastElement(elements, checked_key)); | |
3962 Push(access); | |
3963 } | |
3964 *has_side_effects |= access->HasSideEffects(); | |
3965 if (position != -1) { | |
3966 access->set_position(position); | |
3967 } | |
3968 if_jsarray->Goto(join); | |
3969 | |
3970 set_current_block(if_fastobject); | |
3971 elements = AddInstruction(new(zone()) HLoadElements(object)); | |
3972 elements->ClearFlag(HValue::kUseGVN); | |
3973 length = AddInstruction(new(zone()) HFixedArrayLength(elements)); | |
3974 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); | |
3975 if (is_store) { | |
3976 access = AddInstruction( | |
3977 new(zone()) HStoreKeyedFastElement(elements, checked_key, val)); | |
3978 } else { | |
3979 access = AddInstruction( | |
3980 new(zone()) HLoadKeyedFastElement(elements, checked_key)); | |
3981 } | |
3982 } else { // External array elements. | |
3983 access = AddInstruction(BuildExternalArrayElementAccess( | |
3984 external_elements, checked_key, val, elements_kind, is_store)); | |
3985 } | |
3986 *has_side_effects |= access->HasSideEffects(); | |
3987 access->set_position(position); | |
3988 if (!is_store) { | |
3989 Push(access); | |
3990 } | |
3991 current_block()->Goto(join); | |
3992 set_current_block(if_false); | |
3993 } | |
3994 } | |
3995 | |
3996 // Deopt if none of the cases matched. | |
3997 current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses); | |
3998 join->SetJoinId(ast_id); | |
3999 set_current_block(join); | |
4000 return is_store ? NULL : Pop(); | |
3806 } | 4001 } |
3807 | 4002 |
3808 | 4003 |
3809 HInstruction* HGraphBuilder::BuildLoadKeyed(HValue* obj, | 4004 HValue* HGraphBuilder::HandleKeyedElementAccess(HValue* obj, |
3810 HValue* key, | 4005 HValue* key, |
3811 Property* prop) { | 4006 HValue* val, |
3812 if (prop->IsMonomorphic()) { | 4007 Expression* expr, |
3813 Handle<Map> receiver_type(prop->GetMonomorphicReceiverType()); | 4008 int ast_id, |
3814 // An object has either fast elements or pixel array elements, but never | 4009 int position, |
3815 // both. Pixel array maps that are assigned to pixel array elements are | 4010 bool is_store, |
3816 // always created with the fast elements flag cleared. | 4011 bool* has_side_effects) { |
3817 if (receiver_type->has_external_array_elements()) { | 4012 ASSERT(!expr->IsPropertyName()); |
3818 return BuildLoadKeyedSpecializedArrayElement(obj, key, prop); | 4013 HInstruction* instr = NULL; |
3819 } else if (receiver_type->has_fast_elements()) { | 4014 if (expr->IsMonomorphic()) { |
3820 return BuildLoadKeyedFastElement(obj, key, prop); | 4015 instr = BuildMonomorphicElementAccess(obj, key, val, expr, is_store); |
4016 } else if (expr->GetReceiverTypes() != NULL && | |
4017 !expr->GetReceiverTypes()->is_empty()) { | |
4018 return HandlePolymorphicElementAccess( | |
4019 obj, key, val, expr, ast_id, position, is_store, has_side_effects); | |
4020 } else { | |
4021 if (is_store) { | |
4022 instr = BuildStoreKeyedGeneric(obj, key, val); | |
4023 } else { | |
4024 instr = BuildLoadKeyedGeneric(obj, key); | |
3821 } | 4025 } |
3822 } | 4026 } |
3823 return BuildLoadKeyedGeneric(obj, key); | 4027 instr->set_position(position); |
4028 AddInstruction(instr); | |
4029 *has_side_effects = instr->HasSideEffects(); | |
4030 return instr; | |
3824 } | 4031 } |
3825 | 4032 |
3826 | 4033 |
3827 HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object, | 4034 HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object, |
3828 HValue* key, | 4035 HValue* key, |
3829 HValue* value) { | 4036 HValue* value) { |
3830 HValue* context = environment()->LookupContext(); | 4037 HValue* context = environment()->LookupContext(); |
3831 return new(zone()) HStoreKeyedGeneric( | 4038 return new(zone()) HStoreKeyedGeneric( |
3832 context, | 4039 context, |
3833 object, | 4040 object, |
3834 key, | 4041 key, |
3835 value, | 4042 value, |
3836 function_strict_mode()); | 4043 function_strict_mode()); |
3837 } | 4044 } |
3838 | 4045 |
3839 | |
3840 HInstruction* HGraphBuilder::BuildStoreKeyedFastElement(HValue* object, | |
3841 HValue* key, | |
3842 HValue* val, | |
3843 Expression* expr) { | |
3844 ASSERT(expr->IsMonomorphic()); | |
3845 AddInstruction(new(zone()) HCheckNonSmi(object)); | |
3846 Handle<Map> map = expr->GetMonomorphicReceiverType(); | |
3847 ASSERT(map->has_fast_elements()); | |
3848 AddInstruction(new(zone()) HCheckMap(object, map)); | |
3849 HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object)); | |
3850 AddInstruction(new(zone()) HCheckMap( | |
3851 elements, isolate()->factory()->fixed_array_map())); | |
3852 bool is_array = (map->instance_type() == JS_ARRAY_TYPE); | |
3853 HInstruction* length = NULL; | |
3854 if (is_array) { | |
3855 length = AddInstruction(new(zone()) HJSArrayLength(object)); | |
3856 } else { | |
3857 length = AddInstruction(new(zone()) HFixedArrayLength(elements)); | |
3858 } | |
3859 HInstruction* checked_key = | |
3860 AddInstruction(new(zone()) HBoundsCheck(key, length)); | |
3861 return new(zone()) HStoreKeyedFastElement(elements, checked_key, val); | |
3862 } | |
3863 | |
3864 | |
3865 HInstruction* HGraphBuilder::BuildStoreKeyedSpecializedArrayElement( | |
3866 HValue* object, | |
3867 HValue* key, | |
3868 HValue* val, | |
3869 Expression* expr) { | |
3870 ASSERT(expr->IsMonomorphic()); | |
3871 AddInstruction(new(zone()) HCheckNonSmi(object)); | |
3872 Handle<Map> map = expr->GetMonomorphicReceiverType(); | |
3873 ASSERT(!map->has_fast_elements()); | |
3874 ASSERT(map->has_external_array_elements()); | |
3875 AddInstruction(new(zone()) HCheckMap(object, map)); | |
3876 HLoadElements* elements = new(zone()) HLoadElements(object); | |
3877 AddInstruction(elements); | |
3878 HInstruction* length = AddInstruction( | |
3879 new(zone()) HExternalArrayLength(elements)); | |
3880 HInstruction* checked_key = | |
3881 AddInstruction(new(zone()) HBoundsCheck(key, length)); | |
3882 HLoadExternalArrayPointer* external_elements = | |
3883 new(zone()) HLoadExternalArrayPointer(elements); | |
3884 AddInstruction(external_elements); | |
3885 JSObject::ElementsKind elements_kind = map->elements_kind(); | |
3886 switch (elements_kind) { | |
3887 case JSObject::EXTERNAL_PIXEL_ELEMENTS: { | |
3888 HClampToUint8* clamp = new(zone()) HClampToUint8(val); | |
3889 AddInstruction(clamp); | |
3890 val = clamp; | |
3891 break; | |
3892 } | |
3893 case JSObject::EXTERNAL_BYTE_ELEMENTS: | |
3894 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | |
3895 case JSObject::EXTERNAL_SHORT_ELEMENTS: | |
3896 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | |
3897 case JSObject::EXTERNAL_INT_ELEMENTS: | |
3898 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: { | |
3899 HToInt32* floor_val = new(zone()) HToInt32(val); | |
3900 AddInstruction(floor_val); | |
3901 val = floor_val; | |
3902 break; | |
3903 } | |
3904 case JSObject::EXTERNAL_FLOAT_ELEMENTS: | |
3905 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: | |
3906 break; | |
3907 | |
3908 case JSObject::FAST_ELEMENTS: | |
3909 case JSObject::FAST_DOUBLE_ELEMENTS: | |
3910 case JSObject::DICTIONARY_ELEMENTS: | |
3911 UNREACHABLE(); | |
3912 break; | |
3913 } | |
3914 return new(zone()) HStoreKeyedSpecializedArrayElement( | |
3915 external_elements, | |
3916 checked_key, | |
3917 val, | |
3918 map->elements_kind()); | |
3919 } | |
3920 | |
3921 | |
3922 HInstruction* HGraphBuilder::BuildStoreKeyed(HValue* object, | |
3923 HValue* key, | |
3924 HValue* value, | |
3925 Expression* expr) { | |
3926 if (expr->IsMonomorphic()) { | |
3927 Handle<Map> receiver_type(expr->GetMonomorphicReceiverType()); | |
3928 // An object has either fast elements or external array elements, but | |
3929 // never both. Pixel array maps that are assigned to pixel array elements | |
3930 // are always created with the fast elements flag cleared. | |
3931 if (receiver_type->has_external_array_elements()) { | |
3932 return BuildStoreKeyedSpecializedArrayElement(object, | |
3933 key, | |
3934 value, | |
3935 expr); | |
3936 } else if (receiver_type->has_fast_elements()) { | |
3937 return BuildStoreKeyedFastElement(object, key, value, expr); | |
3938 } | |
3939 } | |
3940 return BuildStoreKeyedGeneric(object, key, value); | |
3941 } | |
3942 | |
3943 | |
3944 bool HGraphBuilder::TryArgumentsAccess(Property* expr) { | 4046 bool HGraphBuilder::TryArgumentsAccess(Property* expr) { |
3945 VariableProxy* proxy = expr->obj()->AsVariableProxy(); | 4047 VariableProxy* proxy = expr->obj()->AsVariableProxy(); |
3946 if (proxy == NULL) return false; | 4048 if (proxy == NULL) return false; |
3947 if (!proxy->var()->IsStackAllocated()) return false; | 4049 if (!proxy->var()->IsStackAllocated()) return false; |
3948 if (!environment()->Lookup(proxy->var())->CheckFlag(HValue::kIsArguments)) { | 4050 if (!environment()->Lookup(proxy->var())->CheckFlag(HValue::kIsArguments)) { |
3949 return false; | 4051 return false; |
3950 } | 4052 } |
3951 | 4053 |
3952 // Our implementation of arguments (based on this stack frame or an | 4054 // Our implementation of arguments (based on this stack frame or an |
3953 // adapter below it) does not work for inlined functions. | 4055 // adapter below it) does not work for inlined functions. |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4027 instr = new(zone()) HLoadNamedFieldPolymorphic(obj, types, name); | 4129 instr = new(zone()) HLoadNamedFieldPolymorphic(obj, types, name); |
4028 } else { | 4130 } else { |
4029 instr = BuildLoadNamedGeneric(obj, expr); | 4131 instr = BuildLoadNamedGeneric(obj, expr); |
4030 } | 4132 } |
4031 | 4133 |
4032 } else { | 4134 } else { |
4033 CHECK_ALIVE(VisitForValue(expr->key())); | 4135 CHECK_ALIVE(VisitForValue(expr->key())); |
4034 | 4136 |
4035 HValue* key = Pop(); | 4137 HValue* key = Pop(); |
4036 HValue* obj = Pop(); | 4138 HValue* obj = Pop(); |
4037 instr = BuildLoadKeyed(obj, key, expr); | 4139 |
4140 bool has_side_effects = false; | |
4141 HValue* load = HandleKeyedElementAccess( | |
4142 obj, key, NULL, expr, expr->id(), expr->position(), | |
4143 false, // is_store | |
4144 &has_side_effects); | |
4145 if (has_side_effects) { | |
4146 if (ast_context()->IsEffect()) { | |
4147 AddSimulate(expr->id()); | |
4148 } else { | |
4149 Push(load); | |
4150 AddSimulate(expr->id()); | |
4151 Drop(1); | |
4152 } | |
4153 } | |
4154 ast_context()->ReturnValue(load); | |
4155 return; | |
4038 } | 4156 } |
4039 instr->set_position(expr->position()); | 4157 instr->set_position(expr->position()); |
4040 ast_context()->ReturnInstruction(instr, expr->id()); | 4158 ast_context()->ReturnInstruction(instr, expr->id()); |
4041 } | 4159 } |
4042 | 4160 |
4043 | 4161 |
4044 void HGraphBuilder::AddCheckConstantFunction(Call* expr, | 4162 void HGraphBuilder::AddCheckConstantFunction(Call* expr, |
4045 HValue* receiver, | 4163 HValue* receiver, |
4046 Handle<Map> receiver_map, | 4164 Handle<Map> receiver_map, |
4047 bool smi_and_map_check) { | 4165 bool smi_and_map_check) { |
(...skipping 989 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5037 | 5155 |
5038 } else { | 5156 } else { |
5039 // Keyed property. | 5157 // Keyed property. |
5040 if (returns_original_input) Push(graph_->GetConstantUndefined()); | 5158 if (returns_original_input) Push(graph_->GetConstantUndefined()); |
5041 | 5159 |
5042 CHECK_ALIVE(VisitForValue(prop->obj())); | 5160 CHECK_ALIVE(VisitForValue(prop->obj())); |
5043 CHECK_ALIVE(VisitForValue(prop->key())); | 5161 CHECK_ALIVE(VisitForValue(prop->key())); |
5044 HValue* obj = environment()->ExpressionStackAt(1); | 5162 HValue* obj = environment()->ExpressionStackAt(1); |
5045 HValue* key = environment()->ExpressionStackAt(0); | 5163 HValue* key = environment()->ExpressionStackAt(0); |
5046 | 5164 |
5047 HInstruction* load = BuildLoadKeyed(obj, key, prop); | 5165 bool has_side_effects = false; |
5048 PushAndAdd(load); | 5166 HValue* load = HandleKeyedElementAccess( |
5049 if (load->HasSideEffects()) AddSimulate(expr->CountId()); | 5167 obj, key, NULL, prop, expr->CountId(), RelocInfo::kNoPosition, |
5168 false, // is_store | |
5169 &has_side_effects); | |
5170 Push(load); | |
5171 if (has_side_effects) AddSimulate(expr->CountId()); | |
5050 | 5172 |
5051 after = BuildIncrement(returns_original_input, expr); | 5173 after = BuildIncrement(returns_original_input, expr); |
5052 input = Pop(); | 5174 input = Pop(); |
5053 | 5175 |
5054 expr->RecordTypeFeedback(oracle()); | 5176 expr->RecordTypeFeedback(oracle()); |
5055 HInstruction* store = BuildStoreKeyed(obj, key, after, expr); | 5177 HandleKeyedElementAccess(obj, key, after, expr, expr->AssignmentId(), |
5056 AddInstruction(store); | 5178 RelocInfo::kNoPosition, |
5179 true, // is_store | |
5180 &has_side_effects); | |
5057 | 5181 |
5058 // Drop the key from the bailout environment. Overwrite the receiver | 5182 // Drop the key from the bailout environment. Overwrite the receiver |
5059 // with the result of the operation, and the placeholder with the | 5183 // with the result of the operation, and the placeholder with the |
5060 // original value if necessary. | 5184 // original value if necessary. |
5061 Drop(1); | 5185 Drop(1); |
5062 environment()->SetExpressionStackAt(0, after); | 5186 environment()->SetExpressionStackAt(0, after); |
5063 if (returns_original_input) environment()->SetExpressionStackAt(1, input); | 5187 if (returns_original_input) environment()->SetExpressionStackAt(1, input); |
5064 if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); | 5188 ASSERT(has_side_effects); // Stores always have side effects. |
5189 AddSimulate(expr->AssignmentId()); | |
5065 } | 5190 } |
5066 } | 5191 } |
5067 | 5192 |
5068 Drop(returns_original_input ? 2 : 1); | 5193 Drop(returns_original_input ? 2 : 1); |
5069 ast_context()->ReturnValue(expr->is_postfix() ? input : after); | 5194 ast_context()->ReturnValue(expr->is_postfix() ? input : after); |
5070 } | 5195 } |
5071 | 5196 |
5072 | 5197 |
5073 HCompareSymbolEq* HGraphBuilder::BuildSymbolCompare(HValue* left, | 5198 HCompareSymbolEq* HGraphBuilder::BuildSymbolCompare(HValue* left, |
5074 HValue* right, | 5199 HValue* right, |
(...skipping 1332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6407 } | 6532 } |
6408 } | 6533 } |
6409 | 6534 |
6410 #ifdef DEBUG | 6535 #ifdef DEBUG |
6411 if (graph_ != NULL) graph_->Verify(); | 6536 if (graph_ != NULL) graph_->Verify(); |
6412 if (allocator_ != NULL) allocator_->Verify(); | 6537 if (allocator_ != NULL) allocator_->Verify(); |
6413 #endif | 6538 #endif |
6414 } | 6539 } |
6415 | 6540 |
6416 } } // namespace v8::internal | 6541 } } // namespace v8::internal |
OLD | NEW |