Chromium Code Reviews| 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 |