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 if (has_side_effects) AddSimulate(expr->AssignmentId()); | |
3459 ast_context()->ReturnValue(Pop()); | |
3460 return; | |
3453 } | 3461 } |
3454 Push(value); | 3462 Push(value); |
3455 instr->set_position(expr->position()); | 3463 instr->set_position(expr->position()); |
3456 AddInstruction(instr); | 3464 AddInstruction(instr); |
3457 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); | 3465 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
3458 ast_context()->ReturnValue(Pop()); | 3466 ast_context()->ReturnValue(Pop()); |
3459 } | 3467 } |
3460 | 3468 |
3461 | 3469 |
3462 // Because not every expression has a position and there is not common | 3470 // 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()); | 3574 if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
3567 ast_context()->ReturnValue(Pop()); | 3575 ast_context()->ReturnValue(Pop()); |
3568 | 3576 |
3569 } else { | 3577 } else { |
3570 // Keyed property. | 3578 // Keyed property. |
3571 CHECK_ALIVE(VisitForValue(prop->obj())); | 3579 CHECK_ALIVE(VisitForValue(prop->obj())); |
3572 CHECK_ALIVE(VisitForValue(prop->key())); | 3580 CHECK_ALIVE(VisitForValue(prop->key())); |
3573 HValue* obj = environment()->ExpressionStackAt(1); | 3581 HValue* obj = environment()->ExpressionStackAt(1); |
3574 HValue* key = environment()->ExpressionStackAt(0); | 3582 HValue* key = environment()->ExpressionStackAt(0); |
3575 | 3583 |
3576 HInstruction* load = BuildLoadKeyed(obj, key, prop); | 3584 bool has_side_effects = false; |
3577 PushAndAdd(load); | 3585 HValue* load = HandleKeyedElementAccess( |
3578 if (load->HasSideEffects()) AddSimulate(expr->CompoundLoadId()); | 3586 obj, key, NULL, prop, expr->CompoundLoadId(), -1, |
3587 false, // is_store | |
3588 &has_side_effects); | |
3589 Push(load); | |
3590 if (has_side_effects) AddSimulate(expr->CompoundLoadId()); | |
3591 | |
3579 | 3592 |
3580 CHECK_ALIVE(VisitForValue(expr->value())); | 3593 CHECK_ALIVE(VisitForValue(expr->value())); |
3581 HValue* right = Pop(); | 3594 HValue* right = Pop(); |
3582 HValue* left = Pop(); | 3595 HValue* left = Pop(); |
3583 | 3596 |
3584 HInstruction* instr = BuildBinaryOperation(operation, left, right); | 3597 HInstruction* instr = BuildBinaryOperation(operation, left, right); |
3585 PushAndAdd(instr); | 3598 PushAndAdd(instr); |
3586 if (instr->HasSideEffects()) AddSimulate(operation->id()); | 3599 if (instr->HasSideEffects()) AddSimulate(operation->id()); |
3587 | 3600 |
3588 expr->RecordTypeFeedback(oracle()); | 3601 expr->RecordTypeFeedback(oracle()); |
3589 HInstruction* store = BuildStoreKeyed(obj, key, instr, expr); | 3602 HandleKeyedElementAccess(obj, key, instr, expr, expr->AssignmentId(), -1, |
3590 AddInstruction(store); | 3603 true, // is_store |
3604 &has_side_effects); | |
3605 | |
3591 // Drop the simulated receiver, key, and value. Return the value. | 3606 // Drop the simulated receiver, key, and value. Return the value. |
3592 Drop(3); | 3607 Drop(3); |
3593 Push(instr); | 3608 Push(instr); |
3594 if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); | 3609 if (has_side_effects) AddSimulate(expr->AssignmentId()); |
3595 ast_context()->ReturnValue(Pop()); | 3610 ast_context()->ReturnValue(Pop()); |
3596 } | 3611 } |
3597 | 3612 |
3598 } else { | 3613 } else { |
3599 return Bailout("invalid lhs in compound assignment"); | 3614 return Bailout("invalid lhs in compound assignment"); |
3600 } | 3615 } |
3601 } | 3616 } |
3602 | 3617 |
3603 | 3618 |
3604 void HGraphBuilder::VisitAssignment(Assignment* expr) { | 3619 void HGraphBuilder::VisitAssignment(Assignment* expr) { |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3748 } | 3763 } |
3749 | 3764 |
3750 | 3765 |
3751 HInstruction* HGraphBuilder::BuildLoadKeyedGeneric(HValue* object, | 3766 HInstruction* HGraphBuilder::BuildLoadKeyedGeneric(HValue* object, |
3752 HValue* key) { | 3767 HValue* key) { |
3753 HValue* context = environment()->LookupContext(); | 3768 HValue* context = environment()->LookupContext(); |
3754 return new(zone()) HLoadKeyedGeneric(context, object, key); | 3769 return new(zone()) HLoadKeyedGeneric(context, object, key); |
3755 } | 3770 } |
3756 | 3771 |
3757 | 3772 |
3758 HInstruction* HGraphBuilder::BuildLoadKeyedFastElement(HValue* object, | 3773 HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, |
3759 HValue* key, | 3774 HValue* key, |
3760 Property* expr) { | 3775 HValue* val, |
3761 ASSERT(!expr->key()->IsPropertyName() && expr->IsMonomorphic()); | 3776 Expression* expr, |
3777 bool is_store) { | |
3778 ASSERT(expr->IsMonomorphic()); | |
3779 Handle<Map> map = expr->GetMonomorphicReceiverType(); | |
3780 if (!map->has_fast_elements() && !map->has_external_array_elements()) { | |
3781 if (is_store) { | |
fschneider
2011/06/16 13:21:28
maybe shorten to:
return is_store ? BuildStoreKey
Jakob Kummerow
2011/06/17 08:06:09
Done.
| |
3782 return BuildStoreKeyedGeneric(object, key, val); | |
3783 } else { | |
3784 return BuildLoadKeyedGeneric(object, key); | |
3785 } | |
3786 } | |
3762 AddInstruction(new(zone()) HCheckNonSmi(object)); | 3787 AddInstruction(new(zone()) HCheckNonSmi(object)); |
3763 Handle<Map> map = expr->GetMonomorphicReceiverType(); | |
3764 ASSERT(map->has_fast_elements()); | |
3765 AddInstruction(new(zone()) HCheckMap(object, map)); | 3788 AddInstruction(new(zone()) HCheckMap(object, map)); |
3766 bool is_array = (map->instance_type() == JS_ARRAY_TYPE); | 3789 HInstruction* elements = new(zone()) HLoadElements(object); |
3767 HLoadElements* elements = new(zone()) HLoadElements(object); | |
3768 HInstruction* length = NULL; | 3790 HInstruction* length = NULL; |
3769 HInstruction* checked_key = NULL; | 3791 HInstruction* checked_key = NULL; |
3770 if (is_array) { | 3792 if (map->has_external_array_elements()) { |
3793 AddInstruction(elements); | |
3794 length = AddInstruction(new(zone()) HExternalArrayLength(elements)); | |
3795 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); | |
3796 HLoadExternalArrayPointer* external_elements = | |
3797 new(zone()) HLoadExternalArrayPointer(elements); | |
3798 AddInstruction(external_elements); | |
3799 JSObject::ElementsKind elements_kind = map->elements_kind(); | |
3800 if (is_store) { | |
3801 ASSERT(val != NULL); | |
3802 switch (elements_kind) { | |
3803 case JSObject::EXTERNAL_PIXEL_ELEMENTS: { | |
3804 HClampToUint8* clamp = new(zone()) HClampToUint8(val); | |
3805 AddInstruction(clamp); | |
3806 val = clamp; | |
3807 break; | |
3808 } | |
3809 case JSObject::EXTERNAL_BYTE_ELEMENTS: | |
3810 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | |
3811 case JSObject::EXTERNAL_SHORT_ELEMENTS: | |
3812 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | |
3813 case JSObject::EXTERNAL_INT_ELEMENTS: | |
3814 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: { | |
3815 HToInt32* floor_val = new(zone()) HToInt32(val); | |
3816 AddInstruction(floor_val); | |
3817 val = floor_val; | |
3818 break; | |
3819 } | |
3820 case JSObject::EXTERNAL_FLOAT_ELEMENTS: | |
3821 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: | |
3822 break; | |
3823 case JSObject::FAST_ELEMENTS: | |
3824 case JSObject::FAST_DOUBLE_ELEMENTS: | |
3825 case JSObject::DICTIONARY_ELEMENTS: | |
3826 UNREACHABLE(); | |
3827 break; | |
3828 } | |
3829 return new(zone()) HStoreKeyedSpecializedArrayElement( | |
3830 external_elements, checked_key, val, elements_kind); | |
3831 } else { | |
3832 return new(zone()) HLoadKeyedSpecializedArrayElement( | |
3833 external_elements, checked_key, elements_kind); | |
3834 } | |
3835 } | |
3836 ASSERT(map->has_fast_elements()); | |
3837 if (map->instance_type() == JS_ARRAY_TYPE) { | |
3771 length = AddInstruction(new(zone()) HJSArrayLength(object)); | 3838 length = AddInstruction(new(zone()) HJSArrayLength(object)); |
3772 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); | 3839 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); |
3773 AddInstruction(elements); | 3840 AddInstruction(elements); |
3774 } else { | 3841 } else { |
3775 AddInstruction(elements); | 3842 AddInstruction(elements); |
3776 length = AddInstruction(new(zone()) HFixedArrayLength(elements)); | 3843 length = AddInstruction(new(zone()) HFixedArrayLength(elements)); |
3777 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); | 3844 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); |
3778 } | 3845 } |
3779 return new(zone()) HLoadKeyedFastElement(elements, checked_key); | 3846 if (is_store) { |
3780 } | 3847 return new(zone()) HStoreKeyedFastElement(elements, checked_key, val); |
3781 | 3848 } else { |
3782 | 3849 return new(zone()) HLoadKeyedFastElement(elements, checked_key); |
3783 HInstruction* HGraphBuilder::BuildLoadKeyedSpecializedArrayElement( | 3850 } |
3784 HValue* object, | 3851 } |
3785 HValue* key, | 3852 |
3786 Property* expr) { | 3853 |
3787 ASSERT(!expr->key()->IsPropertyName() && expr->IsMonomorphic()); | 3854 HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, |
3855 HValue* key, | |
fschneider
2011/06/16 13:21:28
Align parameters in it fits 80 chars or else newli
Jakob Kummerow
2011/06/17 08:06:09
Done.
| |
3856 HValue* val, | |
3857 Expression* prop, | |
3858 int ast_id, | |
3859 int position, | |
3860 bool is_store, | |
3861 bool* has_side_effects) { | |
3862 *has_side_effects = false; | |
3788 AddInstruction(new(zone()) HCheckNonSmi(object)); | 3863 AddInstruction(new(zone()) HCheckNonSmi(object)); |
3789 Handle<Map> map = expr->GetMonomorphicReceiverType(); | 3864 AddInstruction(HCheckInstanceType::NewIsSpecObject(object)); |
3790 ASSERT(!map->has_fast_elements()); | 3865 ZoneMapList* maps = prop->GetReceiverTypes(); |
3791 ASSERT(map->has_external_array_elements()); | 3866 bool todo_external_array = false; |
3792 AddInstruction(new(zone()) HCheckMap(object, map)); | 3867 |
3793 HLoadElements* elements = new(zone()) HLoadElements(object); | 3868 static const int kNumElementTypes = JSObject::kElementsKindCount; |
3794 AddInstruction(elements); | 3869 bool type_todo[kNumElementTypes]; |
3795 HInstruction* length = new(zone()) HExternalArrayLength(elements); | 3870 for (int i = 0; i < kNumElementTypes; ++i) { |
3796 AddInstruction(length); | 3871 type_todo[i] = false; |
3797 HInstruction* checked_key = | 3872 } |
3798 AddInstruction(new(zone()) HBoundsCheck(key, length)); | 3873 |
3799 HLoadExternalArrayPointer* external_elements = | 3874 for (int i = 0; i < maps->length(); ++i) { |
3800 new(zone()) HLoadExternalArrayPointer(elements); | 3875 ASSERT(maps->at(i)->IsMap()); |
3801 AddInstruction(external_elements); | 3876 type_todo[maps->at(i)->elements_kind()] = true; |
3802 HLoadKeyedSpecializedArrayElement* pixel_array_value = | 3877 if (maps->at(i)->elements_kind() |
3803 new(zone()) HLoadKeyedSpecializedArrayElement( | 3878 >= JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND) { |
3804 external_elements, checked_key, map->elements_kind()); | 3879 todo_external_array = true; |
3805 return pixel_array_value; | 3880 } |
3806 } | 3881 } |
3807 | 3882 // We can't treat dictionary elements here (need to deopt instead). |
3808 | 3883 type_todo[JSObject::DICTIONARY_ELEMENTS] = false; |
3809 HInstruction* HGraphBuilder::BuildLoadKeyed(HValue* obj, | 3884 |
3810 HValue* key, | 3885 HBasicBlock* join = graph()->CreateBasicBlock(); |
3811 Property* prop) { | 3886 |
3812 if (prop->IsMonomorphic()) { | 3887 HInstruction* elements_kind_instr = |
3813 Handle<Map> receiver_type(prop->GetMonomorphicReceiverType()); | 3888 AddInstruction(new(zone()) HElementsKind(object)); |
3814 // An object has either fast elements or pixel array elements, but never | 3889 HInstruction* elements = NULL; |
3815 // both. Pixel array maps that are assigned to pixel array elements are | 3890 HLoadExternalArrayPointer* external_elements = NULL; |
3816 // always created with the fast elements flag cleared. | 3891 HInstruction* checked_key = NULL; |
3817 if (receiver_type->has_external_array_elements()) { | 3892 |
3818 return BuildLoadKeyedSpecializedArrayElement(obj, key, prop); | 3893 // FAST_ELEMENTS is assumed to be the first case. |
3819 } else if (receiver_type->has_fast_elements()) { | 3894 STATIC_ASSERT(JSObject::FAST_ELEMENTS == 0); |
3820 return BuildLoadKeyedFastElement(obj, key, prop); | 3895 |
3821 } | 3896 for (JSObject::ElementsKind elements_kind = JSObject::FAST_ELEMENTS; |
3822 } | 3897 elements_kind <= JSObject::LAST_ELEMENTS_KIND; |
3823 return BuildLoadKeyedGeneric(obj, key); | 3898 elements_kind = JSObject::ElementsKind(elements_kind + 1)) { |
fschneider
2011/06/16 13:21:28
Too bad that ++ doesn't work ;)
Jakob Kummerow
2011/06/17 08:06:09
Yeah...
| |
3899 // After having handled FAST_ELEMENTS in the first run of the loop, we | |
3900 // need to add some code that's executed for all other cases. | |
3901 if (elements_kind == 1 && todo_external_array) { | |
fschneider
2011/06/16 13:21:28
Maybe write
if (elements_kind > JSObject::FAST_E
Jakob Kummerow
2011/06/17 08:06:09
No, because I only want to execute this if-block o
| |
3902 elements = AddInstruction(new(zone()) HLoadElements(object)); | |
3903 // We need to forcibly prevent some ElementsKind-dependent instructions | |
3904 // from being hoisted out of any loops they might occur in, because | |
3905 // the current loop-invariant-code-motion algorithm isn't clever enough | |
3906 // to deal with them properly. | |
3907 // There's some performance to be gained by developing a smarter | |
3908 // solution for this. | |
3909 elements->ClearFlag(HValue::kUseGVN); | |
3910 HInstruction* length = | |
3911 AddInstruction(new(zone()) HExternalArrayLength(elements)); | |
3912 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); | |
3913 external_elements = new(zone()) HLoadExternalArrayPointer(elements); | |
3914 AddInstruction(external_elements); | |
3915 } | |
3916 if (type_todo[elements_kind]) { | |
3917 HBasicBlock* if_true = graph()->CreateBasicBlock(); | |
3918 HBasicBlock* if_false = graph()->CreateBasicBlock(); | |
3919 HCompareWithConstant* compare = new(zone()) HCompareWithConstant( | |
3920 elements_kind_instr, | |
3921 elements_kind, | |
3922 Token::EQ); | |
3923 AddInstruction(compare); | |
3924 HTest* branch = new(zone()) HTest(compare, if_true, if_false); | |
3925 current_block()->Finish(branch); | |
3926 | |
3927 set_current_block(if_true); | |
3928 HInstruction* access; | |
3929 if (elements_kind == JSObject::FAST_ELEMENTS) { | |
3930 HBasicBlock* if_jsarray = graph()->CreateBasicBlock(); | |
3931 HBasicBlock* if_fastobject = graph()->CreateBasicBlock(); | |
3932 HInstruction* typecheck = | |
3933 AddInstruction(new(zone()) HHasInstanceType(object, JS_ARRAY_TYPE)); | |
3934 HTest* test = new(zone()) HTest(typecheck, if_jsarray, if_fastobject); | |
3935 current_block()->Finish(test); | |
3936 | |
3937 set_current_block(if_jsarray); | |
3938 HInstruction* length = new(zone()) HJSArrayLength(object); | |
3939 AddInstruction(length); | |
3940 length->ClearFlag(HValue::kUseGVN); | |
3941 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); | |
3942 elements = AddInstruction(new(zone()) HLoadElements(object)); | |
3943 elements->ClearFlag(HValue::kUseGVN); | |
3944 if (is_store) { | |
3945 access = AddInstruction( | |
3946 new(zone()) HStoreKeyedFastElement(elements, checked_key, val)); | |
3947 } else { | |
3948 access = AddInstruction( | |
3949 new(zone()) HLoadKeyedFastElement(elements, checked_key)); | |
3950 Push(access); | |
3951 } | |
3952 *has_side_effects |= access->HasSideEffects(); | |
3953 if (position != -1) { | |
3954 access->set_position(position); | |
3955 } | |
3956 if_jsarray->Goto(join); | |
3957 | |
3958 set_current_block(if_fastobject); | |
3959 elements = AddInstruction(new(zone()) HLoadElements(object)); | |
3960 elements->ClearFlag(HValue::kUseGVN); | |
3961 length = AddInstruction(new(zone()) HFixedArrayLength(elements)); | |
3962 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); | |
3963 if (is_store) { | |
3964 access = AddInstruction( | |
3965 new(zone()) HStoreKeyedFastElement(elements, checked_key, val)); | |
3966 } else { | |
3967 access = AddInstruction( | |
3968 new(zone()) HLoadKeyedFastElement(elements, checked_key)); | |
3969 } | |
3970 } else { | |
fschneider
2011/06/16 13:21:28
Do you handle FAST_DOUBLE_ELEMENTS at all? For now
Jakob Kummerow
2011/06/17 08:06:09
Uhm... no, I don't handle them, because Hydrogen h
| |
3971 if (is_store) { | |
3972 ASSERT(val != NULL); | |
3973 switch (elements_kind) { | |
fschneider
2011/06/16 13:21:28
Could you have a helper inserting the conversion i
Jakob Kummerow
2011/06/17 08:06:09
Good idea. Done.
| |
3974 case JSObject::EXTERNAL_PIXEL_ELEMENTS: { | |
3975 HClampToUint8* clamp = new(zone()) HClampToUint8(val); | |
3976 AddInstruction(clamp); | |
3977 val = clamp; | |
3978 break; | |
3979 } | |
3980 case JSObject::EXTERNAL_BYTE_ELEMENTS: | |
3981 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | |
3982 case JSObject::EXTERNAL_SHORT_ELEMENTS: | |
3983 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | |
3984 case JSObject::EXTERNAL_INT_ELEMENTS: | |
3985 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: { | |
3986 HToInt32* floor_val = new(zone()) HToInt32(val); | |
3987 AddInstruction(floor_val); | |
3988 val = floor_val; | |
3989 break; | |
3990 } | |
3991 case JSObject::EXTERNAL_FLOAT_ELEMENTS: | |
3992 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: | |
3993 break; | |
3994 case JSObject::FAST_ELEMENTS: | |
3995 case JSObject::FAST_DOUBLE_ELEMENTS: | |
3996 case JSObject::DICTIONARY_ELEMENTS: | |
3997 UNREACHABLE(); | |
3998 break; | |
3999 } | |
4000 access = AddInstruction( | |
4001 new(zone()) HStoreKeyedSpecializedArrayElement( | |
4002 external_elements, checked_key, val, elements_kind)); | |
4003 } else { | |
4004 access = AddInstruction( | |
4005 new(zone()) HLoadKeyedSpecializedArrayElement( | |
4006 external_elements, checked_key, elements_kind)); | |
4007 } | |
4008 } | |
4009 *has_side_effects |= access->HasSideEffects(); | |
fschneider
2011/06/16 13:21:28
Isn't it always the case that (*has_side_effects =
Jakob Kummerow
2011/06/17 08:06:09
That assumption does indeed seem to be true in all
| |
4010 if (position != -1) { | |
4011 access->set_position(position); | |
4012 } | |
4013 if (!is_store) { | |
4014 Push(access); | |
4015 } | |
4016 current_block()->Goto(join); | |
4017 set_current_block(if_false); | |
4018 } | |
4019 } | |
4020 | |
4021 // Deopt if none of the cases matched. | |
4022 current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses); | |
4023 join->SetJoinId(ast_id); | |
4024 set_current_block(join); | |
4025 if (!is_store) { | |
fschneider
2011/06/16 13:21:28
Maybe shorten this to:
return is_store ? NULL : P
Jakob Kummerow
2011/06/17 08:06:09
Done.
| |
4026 return Pop(); | |
4027 } | |
4028 return NULL; | |
4029 } | |
4030 | |
4031 | |
4032 HValue* HGraphBuilder::HandleKeyedElementAccess(HValue* obj, | |
4033 HValue* key, | |
4034 HValue* val, | |
4035 Expression* expr, | |
4036 int ast_id, | |
4037 int position, | |
4038 bool is_store, | |
4039 bool* has_side_effects) { | |
4040 ASSERT(!expr->IsPropertyName()); | |
4041 HInstruction* instr = NULL; | |
4042 if (expr->IsMonomorphic()) { | |
4043 instr = BuildMonomorphicElementAccess(obj, key, val, expr, is_store); | |
4044 } else if (expr->GetReceiverTypes() != NULL && | |
4045 !expr->GetReceiverTypes()->is_empty()) { | |
4046 return HandlePolymorphicElementAccess( | |
4047 obj, key, val, expr, ast_id, position, is_store, has_side_effects); | |
4048 } else { | |
4049 if (is_store) { | |
4050 instr = BuildStoreKeyedGeneric(obj, key, val); | |
4051 } else { | |
4052 instr = BuildLoadKeyedGeneric(obj, key); | |
4053 } | |
4054 } | |
4055 if (position != -1) { | |
fschneider
2011/06/16 13:21:28
Not sure, that you actually need to check for -1 (
Jakob Kummerow
2011/06/17 08:06:09
Done. Since kNoPosition is the default value anywa
| |
4056 instr->set_position(position); | |
4057 } | |
4058 AddInstruction(instr); | |
4059 *has_side_effects = instr->HasSideEffects(); | |
4060 return instr; | |
3824 } | 4061 } |
3825 | 4062 |
3826 | 4063 |
3827 HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object, | 4064 HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object, |
3828 HValue* key, | 4065 HValue* key, |
3829 HValue* value) { | 4066 HValue* value) { |
3830 HValue* context = environment()->LookupContext(); | 4067 HValue* context = environment()->LookupContext(); |
3831 return new(zone()) HStoreKeyedGeneric( | 4068 return new(zone()) HStoreKeyedGeneric( |
3832 context, | 4069 context, |
3833 object, | 4070 object, |
3834 key, | 4071 key, |
3835 value, | 4072 value, |
3836 function_strict_mode()); | 4073 function_strict_mode()); |
3837 } | 4074 } |
3838 | 4075 |
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) { | 4076 bool HGraphBuilder::TryArgumentsAccess(Property* expr) { |
3945 VariableProxy* proxy = expr->obj()->AsVariableProxy(); | 4077 VariableProxy* proxy = expr->obj()->AsVariableProxy(); |
3946 if (proxy == NULL) return false; | 4078 if (proxy == NULL) return false; |
3947 if (!proxy->var()->IsStackAllocated()) return false; | 4079 if (!proxy->var()->IsStackAllocated()) return false; |
3948 if (!environment()->Lookup(proxy->var())->CheckFlag(HValue::kIsArguments)) { | 4080 if (!environment()->Lookup(proxy->var())->CheckFlag(HValue::kIsArguments)) { |
3949 return false; | 4081 return false; |
3950 } | 4082 } |
3951 | 4083 |
3952 // Our implementation of arguments (based on this stack frame or an | 4084 // Our implementation of arguments (based on this stack frame or an |
3953 // adapter below it) does not work for inlined functions. | 4085 // 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); | 4159 instr = new(zone()) HLoadNamedFieldPolymorphic(obj, types, name); |
4028 } else { | 4160 } else { |
4029 instr = BuildLoadNamedGeneric(obj, expr); | 4161 instr = BuildLoadNamedGeneric(obj, expr); |
4030 } | 4162 } |
4031 | 4163 |
4032 } else { | 4164 } else { |
4033 CHECK_ALIVE(VisitForValue(expr->key())); | 4165 CHECK_ALIVE(VisitForValue(expr->key())); |
4034 | 4166 |
4035 HValue* key = Pop(); | 4167 HValue* key = Pop(); |
4036 HValue* obj = Pop(); | 4168 HValue* obj = Pop(); |
4037 instr = BuildLoadKeyed(obj, key, expr); | 4169 |
4170 bool has_side_effects = false; | |
4171 HValue* load = HandleKeyedElementAccess( | |
4172 obj, key, NULL, expr, expr->id(), expr->position(), | |
4173 false, // is_store, | |
fschneider
2011/06/16 13:21:28
This comment looks like commented out code. Maybe
Jakob Kummerow
2011/06/17 08:06:09
I see your point. I've removed the comma. Is that
| |
4174 &has_side_effects); | |
4175 if (has_side_effects) { | |
4176 if (ast_context()->IsEffect()) { | |
4177 AddSimulate(expr->id()); | |
4178 } else { | |
4179 Push(load); | |
4180 AddSimulate(expr->id()); | |
4181 Drop(1); | |
4182 } | |
4183 } | |
4184 ast_context()->ReturnValue(load); | |
4185 return; | |
4038 } | 4186 } |
4039 instr->set_position(expr->position()); | 4187 instr->set_position(expr->position()); |
4040 ast_context()->ReturnInstruction(instr, expr->id()); | 4188 ast_context()->ReturnInstruction(instr, expr->id()); |
4041 } | 4189 } |
4042 | 4190 |
4043 | 4191 |
4044 void HGraphBuilder::AddCheckConstantFunction(Call* expr, | 4192 void HGraphBuilder::AddCheckConstantFunction(Call* expr, |
4045 HValue* receiver, | 4193 HValue* receiver, |
4046 Handle<Map> receiver_map, | 4194 Handle<Map> receiver_map, |
4047 bool smi_and_map_check) { | 4195 bool smi_and_map_check) { |
(...skipping 989 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5037 | 5185 |
5038 } else { | 5186 } else { |
5039 // Keyed property. | 5187 // Keyed property. |
5040 if (returns_original_input) Push(graph_->GetConstantUndefined()); | 5188 if (returns_original_input) Push(graph_->GetConstantUndefined()); |
5041 | 5189 |
5042 CHECK_ALIVE(VisitForValue(prop->obj())); | 5190 CHECK_ALIVE(VisitForValue(prop->obj())); |
5043 CHECK_ALIVE(VisitForValue(prop->key())); | 5191 CHECK_ALIVE(VisitForValue(prop->key())); |
5044 HValue* obj = environment()->ExpressionStackAt(1); | 5192 HValue* obj = environment()->ExpressionStackAt(1); |
5045 HValue* key = environment()->ExpressionStackAt(0); | 5193 HValue* key = environment()->ExpressionStackAt(0); |
5046 | 5194 |
5047 HInstruction* load = BuildLoadKeyed(obj, key, prop); | 5195 bool has_side_effects = false; |
5048 PushAndAdd(load); | 5196 HValue* load = HandleKeyedElementAccess( |
5049 if (load->HasSideEffects()) AddSimulate(expr->CountId()); | 5197 obj, key, NULL, prop, expr->CountId(), -1, |
5198 false, // is_store | |
5199 &has_side_effects); | |
5200 Push(load); | |
5201 if (has_side_effects) AddSimulate(expr->CountId()); | |
5050 | 5202 |
5051 after = BuildIncrement(returns_original_input, expr); | 5203 after = BuildIncrement(returns_original_input, expr); |
5052 input = Pop(); | 5204 input = Pop(); |
5053 | 5205 |
5054 expr->RecordTypeFeedback(oracle()); | 5206 expr->RecordTypeFeedback(oracle()); |
5055 HInstruction* store = BuildStoreKeyed(obj, key, after, expr); | 5207 HandleKeyedElementAccess(obj, key, after, expr, expr->AssignmentId(), -1, |
5056 AddInstruction(store); | 5208 true, // is_store |
5209 &has_side_effects); | |
fschneider
2011/06/16 13:21:28
Stores will always have a side effect.
Jakob Kummerow
2011/06/17 08:06:09
Done.
| |
5057 | 5210 |
5058 // Drop the key from the bailout environment. Overwrite the receiver | 5211 // Drop the key from the bailout environment. Overwrite the receiver |
5059 // with the result of the operation, and the placeholder with the | 5212 // with the result of the operation, and the placeholder with the |
5060 // original value if necessary. | 5213 // original value if necessary. |
5061 Drop(1); | 5214 Drop(1); |
5062 environment()->SetExpressionStackAt(0, after); | 5215 environment()->SetExpressionStackAt(0, after); |
5063 if (returns_original_input) environment()->SetExpressionStackAt(1, input); | 5216 if (returns_original_input) environment()->SetExpressionStackAt(1, input); |
5064 if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); | 5217 if (has_side_effects) AddSimulate(expr->AssignmentId()); |
5065 } | 5218 } |
5066 } | 5219 } |
5067 | 5220 |
5068 Drop(returns_original_input ? 2 : 1); | 5221 Drop(returns_original_input ? 2 : 1); |
5069 ast_context()->ReturnValue(expr->is_postfix() ? input : after); | 5222 ast_context()->ReturnValue(expr->is_postfix() ? input : after); |
5070 } | 5223 } |
5071 | 5224 |
5072 | 5225 |
5073 HCompareSymbolEq* HGraphBuilder::BuildSymbolCompare(HValue* left, | 5226 HCompareSymbolEq* HGraphBuilder::BuildSymbolCompare(HValue* left, |
5074 HValue* right, | 5227 HValue* right, |
(...skipping 1332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6407 } | 6560 } |
6408 } | 6561 } |
6409 | 6562 |
6410 #ifdef DEBUG | 6563 #ifdef DEBUG |
6411 if (graph_ != NULL) graph_->Verify(); | 6564 if (graph_ != NULL) graph_->Verify(); |
6412 if (allocator_ != NULL) allocator_->Verify(); | 6565 if (allocator_ != NULL) allocator_->Verify(); |
6413 #endif | 6566 #endif |
6414 } | 6567 } |
6415 | 6568 |
6416 } } // namespace v8::internal | 6569 } } // namespace v8::internal |
OLD | NEW |