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 3110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3121 context = context_instruction; | 3121 context = context_instruction; |
3122 } | 3122 } |
3123 return context; | 3123 return context; |
3124 } | 3124 } |
3125 | 3125 |
3126 | 3126 |
3127 void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { | 3127 void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { |
3128 ASSERT(!HasStackOverflow()); | 3128 ASSERT(!HasStackOverflow()); |
3129 ASSERT(current_block() != NULL); | 3129 ASSERT(current_block() != NULL); |
3130 ASSERT(current_block()->HasPredecessor()); | 3130 ASSERT(current_block()->HasPredecessor()); |
3131 Variable* variable = expr->AsVariable(); | 3131 Variable* variable = expr->var(); |
3132 if (variable == NULL) { | 3132 if (variable->mode() == Variable::LET) { |
3133 return Bailout("reference to rewritten variable"); | |
3134 } else if (variable->mode() == Variable::LET) { | |
3135 return Bailout("reference to let variable"); | 3133 return Bailout("reference to let variable"); |
3136 } else if (variable->IsStackAllocated()) { | 3134 } |
3137 HValue* value = environment()->Lookup(variable); | 3135 switch (variable->location()) { |
3138 if (variable->mode() == Variable::CONST && | 3136 case Variable::UNALLOCATED: { |
3139 value == graph()->GetConstantHole()) { | 3137 LookupResult lookup; |
3140 return Bailout("reference to uninitialized const variable"); | 3138 GlobalPropertyAccess type = LookupGlobalProperty(variable, &lookup, false) ; |
fschneider
2011/09/06 09:34:22
Long line.
| |
3141 } | |
3142 return ast_context()->ReturnValue(value); | |
3143 } else if (variable->IsContextSlot()) { | |
3144 if (variable->mode() == Variable::CONST) { | |
3145 return Bailout("reference to const context slot"); | |
3146 } | |
3147 HValue* context = BuildContextChainWalk(variable); | |
3148 int index = variable->AsSlot()->index(); | |
3149 HLoadContextSlot* instr = new(zone()) HLoadContextSlot(context, index); | |
3150 return ast_context()->ReturnInstruction(instr, expr->id()); | |
3151 } else if (variable->is_global()) { | |
3152 LookupResult lookup; | |
3153 GlobalPropertyAccess type = LookupGlobalProperty(variable, &lookup, false); | |
3154 | 3139 |
3155 if (type == kUseCell && | 3140 if (type == kUseCell && |
3156 info()->global_object()->IsAccessCheckNeeded()) { | 3141 info()->global_object()->IsAccessCheckNeeded()) { |
3157 type = kUseGeneric; | 3142 type = kUseGeneric; |
3143 } | |
3144 | |
3145 if (type == kUseCell) { | |
3146 Handle<GlobalObject> global(info()->global_object()); | |
3147 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); | |
3148 bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); | |
3149 HLoadGlobalCell* instr = new(zone()) HLoadGlobalCell(cell, check_hole); | |
3150 return ast_context()->ReturnInstruction(instr, expr->id()); | |
3151 } else { | |
3152 HValue* context = environment()->LookupContext(); | |
3153 HGlobalObject* global_object = new(zone()) HGlobalObject(context); | |
3154 AddInstruction(global_object); | |
3155 HLoadGlobalGeneric* instr = | |
3156 new(zone()) HLoadGlobalGeneric(context, | |
3157 global_object, | |
3158 variable->name(), | |
3159 ast_context()->is_for_typeof()); | |
3160 instr->set_position(expr->position()); | |
3161 return ast_context()->ReturnInstruction(instr, expr->id()); | |
3162 } | |
3158 } | 3163 } |
3159 | 3164 |
3160 if (type == kUseCell) { | 3165 case Variable::PARAMETER: |
3161 Handle<GlobalObject> global(info()->global_object()); | 3166 case Variable::LOCAL: { |
3162 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); | 3167 HValue* value = environment()->Lookup(variable); |
3163 bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); | 3168 if (variable->mode() == Variable::CONST && |
3164 HLoadGlobalCell* instr = new(zone()) HLoadGlobalCell(cell, check_hole); | 3169 value == graph()->GetConstantHole()) { |
3165 return ast_context()->ReturnInstruction(instr, expr->id()); | 3170 return Bailout("reference to uninitialized const variable"); |
3166 } else { | 3171 } |
3167 HValue* context = environment()->LookupContext(); | 3172 return ast_context()->ReturnValue(value); |
3168 HGlobalObject* global_object = new(zone()) HGlobalObject(context); | 3173 } |
3169 AddInstruction(global_object); | 3174 |
3170 HLoadGlobalGeneric* instr = | 3175 case Variable::CONTEXT:{ |
3171 new(zone()) HLoadGlobalGeneric(context, | 3176 if (variable->mode() == Variable::CONST) { |
3172 global_object, | 3177 return Bailout("reference to const context slot"); |
3173 variable->name(), | 3178 } |
3174 ast_context()->is_for_typeof()); | 3179 HValue* context = BuildContextChainWalk(variable); |
3175 instr->set_position(expr->position()); | 3180 HLoadContextSlot* instr = |
3176 ASSERT(instr->HasSideEffects()); | 3181 new(zone()) HLoadContextSlot(context, variable->index()); |
3177 return ast_context()->ReturnInstruction(instr, expr->id()); | 3182 return ast_context()->ReturnInstruction(instr, expr->id()); |
3178 } | 3183 } |
3179 } else { | 3184 |
3180 return Bailout("reference to a variable which requires dynamic lookup"); | 3185 case Variable::LOOKUP: |
3186 return Bailout("reference to a variable which requires dynamic lookup"); | |
3181 } | 3187 } |
3182 } | 3188 } |
3183 | 3189 |
3184 | 3190 |
3185 void HGraphBuilder::VisitLiteral(Literal* expr) { | 3191 void HGraphBuilder::VisitLiteral(Literal* expr) { |
3186 ASSERT(!HasStackOverflow()); | 3192 ASSERT(!HasStackOverflow()); |
3187 ASSERT(current_block() != NULL); | 3193 ASSERT(current_block() != NULL); |
3188 ASSERT(current_block()->HasPredecessor()); | 3194 ASSERT(current_block()->HasPredecessor()); |
3189 HConstant* instr = | 3195 HConstant* instr = |
3190 new(zone()) HConstant(expr->handle(), Representation::Tagged()); | 3196 new(zone()) HConstant(expr->handle(), Representation::Tagged()); |
(...skipping 391 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3582 AddInstruction(instr); | 3588 AddInstruction(instr); |
3583 ASSERT(instr->HasSideEffects()); | 3589 ASSERT(instr->HasSideEffects()); |
3584 if (instr->HasSideEffects()) AddSimulate(ast_id); | 3590 if (instr->HasSideEffects()) AddSimulate(ast_id); |
3585 } | 3591 } |
3586 } | 3592 } |
3587 | 3593 |
3588 | 3594 |
3589 void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { | 3595 void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { |
3590 Expression* target = expr->target(); | 3596 Expression* target = expr->target(); |
3591 VariableProxy* proxy = target->AsVariableProxy(); | 3597 VariableProxy* proxy = target->AsVariableProxy(); |
3592 Variable* var = proxy->AsVariable(); | |
3593 Property* prop = target->AsProperty(); | 3598 Property* prop = target->AsProperty(); |
3594 ASSERT(var == NULL || prop == NULL); | 3599 ASSERT(proxy == NULL || prop == NULL); |
3595 | 3600 |
3596 // We have a second position recorded in the FullCodeGenerator to have | 3601 // We have a second position recorded in the FullCodeGenerator to have |
3597 // type feedback for the binary operation. | 3602 // type feedback for the binary operation. |
3598 BinaryOperation* operation = expr->binary_operation(); | 3603 BinaryOperation* operation = expr->binary_operation(); |
3599 | 3604 |
3600 if (var != NULL) { | 3605 if (proxy != NULL) { |
3601 if (var->mode() == Variable::CONST || | 3606 Variable* var = proxy->var(); |
3602 var->mode() == Variable::LET) { | 3607 if (var->mode() == Variable::CONST || var->mode() == Variable::LET) { |
3603 return Bailout("unsupported let or const compound assignment"); | 3608 return Bailout("unsupported let or const compound assignment"); |
3604 } | 3609 } |
3605 | 3610 |
3606 CHECK_ALIVE(VisitForValue(operation)); | 3611 CHECK_ALIVE(VisitForValue(operation)); |
3607 | 3612 |
3608 if (var->is_global()) { | 3613 switch (var->location()) { |
3609 HandleGlobalVariableAssignment(var, | 3614 case Variable::UNALLOCATED: |
3610 Top(), | 3615 HandleGlobalVariableAssignment(var, |
3611 expr->position(), | 3616 Top(), |
3612 expr->AssignmentId()); | 3617 expr->position(), |
3613 } else if (var->IsStackAllocated()) { | 3618 expr->AssignmentId()); |
3614 Bind(var, Top()); | 3619 break; |
3615 } else if (var->IsContextSlot()) { | 3620 |
3616 // Bail out if we try to mutate a parameter value in a function using | 3621 case Variable::PARAMETER: |
3617 // the arguments object. We do not (yet) correctly handle the | 3622 case Variable::LOCAL: |
3618 // arguments property of the function. | 3623 Bind(var, Top()); |
3619 if (info()->scope()->arguments() != NULL) { | 3624 break; |
3620 // Parameters will rewrite to context slots. We have no direct way | 3625 |
3621 // to detect that the variable is a parameter. | 3626 case Variable::CONTEXT: { |
3622 int count = info()->scope()->num_parameters(); | 3627 // Bail out if we try to mutate a parameter value in a function |
3623 for (int i = 0; i < count; ++i) { | 3628 // using the arguments object. We do not (yet) correctly handle the |
3624 if (var == info()->scope()->parameter(i)) { | 3629 // arguments property of the function. |
3625 Bailout("assignment to parameter, function uses arguments object"); | 3630 if (info()->scope()->arguments() != NULL) { |
3631 // Parameters will be allocated to context slots. We have no | |
3632 // direct way to detect that the variable is a parameter so we do | |
3633 // a linear search of the parameter variables. | |
3634 int count = info()->scope()->num_parameters(); | |
3635 for (int i = 0; i < count; ++i) { | |
3636 if (var == info()->scope()->parameter(i)) { | |
3637 Bailout("assignment to parameter, function uses arguments object") ; | |
fschneider
2011/09/06 09:34:22
Long line.
| |
3638 } | |
3626 } | 3639 } |
3627 } | 3640 } |
3641 | |
3642 HValue* context = BuildContextChainWalk(var); | |
3643 HStoreContextSlot* instr = | |
3644 new(zone()) HStoreContextSlot(context, var->index(), Top()); | |
3645 AddInstruction(instr); | |
3646 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); | |
3647 break; | |
3628 } | 3648 } |
3629 | 3649 |
3630 HValue* context = BuildContextChainWalk(var); | 3650 case Variable::LOOKUP: |
3631 int index = var->AsSlot()->index(); | 3651 return Bailout("compound assignment to lookup slot"); |
3632 HStoreContextSlot* instr = | |
3633 new(zone()) HStoreContextSlot(context, index, Top()); | |
3634 AddInstruction(instr); | |
3635 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); | |
3636 } else { | |
3637 return Bailout("compound assignment to lookup slot"); | |
3638 } | 3652 } |
3639 return ast_context()->ReturnValue(Pop()); | 3653 return ast_context()->ReturnValue(Pop()); |
3640 | 3654 |
3641 } else if (prop != NULL) { | 3655 } else if (prop != NULL) { |
3642 prop->RecordTypeFeedback(oracle()); | 3656 prop->RecordTypeFeedback(oracle()); |
3643 | 3657 |
3644 if (prop->key()->IsPropertyName()) { | 3658 if (prop->key()->IsPropertyName()) { |
3645 // Named property. | 3659 // Named property. |
3646 CHECK_ALIVE(VisitForValue(prop->obj())); | 3660 CHECK_ALIVE(VisitForValue(prop->obj())); |
3647 HValue* obj = Top(); | 3661 HValue* obj = Top(); |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3715 return Bailout("invalid lhs in compound assignment"); | 3729 return Bailout("invalid lhs in compound assignment"); |
3716 } | 3730 } |
3717 } | 3731 } |
3718 | 3732 |
3719 | 3733 |
3720 void HGraphBuilder::VisitAssignment(Assignment* expr) { | 3734 void HGraphBuilder::VisitAssignment(Assignment* expr) { |
3721 ASSERT(!HasStackOverflow()); | 3735 ASSERT(!HasStackOverflow()); |
3722 ASSERT(current_block() != NULL); | 3736 ASSERT(current_block() != NULL); |
3723 ASSERT(current_block()->HasPredecessor()); | 3737 ASSERT(current_block()->HasPredecessor()); |
3724 VariableProxy* proxy = expr->target()->AsVariableProxy(); | 3738 VariableProxy* proxy = expr->target()->AsVariableProxy(); |
3725 Variable* var = proxy->AsVariable(); | |
3726 Property* prop = expr->target()->AsProperty(); | 3739 Property* prop = expr->target()->AsProperty(); |
3727 ASSERT(var == NULL || prop == NULL); | 3740 ASSERT(proxy == NULL || prop == NULL); |
3728 | 3741 |
3729 if (expr->is_compound()) { | 3742 if (expr->is_compound()) { |
3730 HandleCompoundAssignment(expr); | 3743 HandleCompoundAssignment(expr); |
3731 return; | 3744 return; |
3732 } | 3745 } |
3733 | 3746 |
3734 if (var != NULL) { | 3747 if (prop != NULL) { |
3748 HandlePropertyAssignment(expr); | |
3749 } else if (proxy != NULL) { | |
3750 Variable* var = proxy->var(); | |
3735 if (var->mode() == Variable::CONST) { | 3751 if (var->mode() == Variable::CONST) { |
3736 if (expr->op() != Token::INIT_CONST) { | 3752 if (expr->op() != Token::INIT_CONST) { |
3737 return Bailout("non-initializer assignment to const"); | 3753 return Bailout("non-initializer assignment to const"); |
3738 } | 3754 } |
3739 if (!var->IsStackAllocated()) { | 3755 if (!var->IsStackAllocated()) { |
3740 return Bailout("assignment to const context slot"); | 3756 return Bailout("assignment to const context slot"); |
3741 } | 3757 } |
3742 // We insert a use of the old value to detect unsupported uses of const | 3758 // We insert a use of the old value to detect unsupported uses of const |
3743 // variables (e.g. initialization inside a loop). | 3759 // variables (e.g. initialization inside a loop). |
3744 HValue* old_value = environment()->Lookup(var); | 3760 HValue* old_value = environment()->Lookup(var); |
3745 AddInstruction(new HUseConst(old_value)); | 3761 AddInstruction(new HUseConst(old_value)); |
3746 } else if (var->mode() == Variable::LET) { | 3762 } else if (var->mode() == Variable::LET) { |
3747 return Bailout("unsupported assignment to let"); | 3763 return Bailout("unsupported assignment to let"); |
3748 } | 3764 } |
3749 | 3765 |
3750 if (proxy->IsArguments()) return Bailout("assignment to arguments"); | 3766 if (proxy->IsArguments()) return Bailout("assignment to arguments"); |
3751 | 3767 |
3752 // Handle the assignment. | 3768 // Handle the assignment. |
3753 if (var->IsStackAllocated()) { | 3769 switch (var->location()) { |
3754 // We do not allow the arguments object to occur in a context where it | 3770 case Variable::UNALLOCATED: |
3755 // may escape, but assignments to stack-allocated locals are | 3771 CHECK_ALIVE(VisitForValue(expr->value())); |
3756 // permitted. | 3772 HandleGlobalVariableAssignment(var, |
3757 CHECK_ALIVE(VisitForValue(expr->value(), ARGUMENTS_ALLOWED)); | 3773 Top(), |
3758 HValue* value = Pop(); | 3774 expr->position(), |
3759 Bind(var, value); | 3775 expr->AssignmentId()); |
3760 return ast_context()->ReturnValue(value); | 3776 return ast_context()->ReturnValue(Pop()); |
3761 | 3777 |
3762 } else if (var->IsContextSlot()) { | 3778 case Variable::PARAMETER: |
3763 ASSERT(var->mode() != Variable::CONST); | 3779 case Variable::LOCAL: { |
3764 // Bail out if we try to mutate a parameter value in a function using | 3780 // We do not allow the arguments object to occur in a context where it |
3765 // the arguments object. We do not (yet) correctly handle the | 3781 // may escape, but assignments to stack-allocated locals are |
3766 // arguments property of the function. | 3782 // permitted. |
3767 if (info()->scope()->arguments() != NULL) { | 3783 CHECK_ALIVE(VisitForValue(expr->value(), ARGUMENTS_ALLOWED)); |
3768 // Parameters will rewrite to context slots. We have no direct way | 3784 HValue* value = Pop(); |
3769 // to detect that the variable is a parameter. | 3785 Bind(var, value); |
3770 int count = info()->scope()->num_parameters(); | 3786 return ast_context()->ReturnValue(value); |
3771 for (int i = 0; i < count; ++i) { | 3787 } |
3772 if (var == info()->scope()->parameter(i)) { | 3788 |
3773 Bailout("assignment to parameter, function uses arguments object"); | 3789 case Variable::CONTEXT: { |
3790 ASSERT(var->mode() != Variable::CONST); | |
3791 // Bail out if we try to mutate a parameter value in a function using | |
3792 // the arguments object. We do not (yet) correctly handle the | |
3793 // arguments property of the function. | |
3794 if (info()->scope()->arguments() != NULL) { | |
3795 // Parameters will rewrite to context slots. We have no direct way | |
3796 // to detect that the variable is a parameter. | |
3797 int count = info()->scope()->num_parameters(); | |
3798 for (int i = 0; i < count; ++i) { | |
3799 if (var == info()->scope()->parameter(i)) { | |
3800 return Bailout("assignment to parameter in arguments object"); | |
3801 } | |
3774 } | 3802 } |
3775 } | 3803 } |
3804 | |
3805 CHECK_ALIVE(VisitForValue(expr->value())); | |
3806 HValue* context = BuildContextChainWalk(var); | |
3807 HStoreContextSlot* instr = | |
3808 new(zone()) HStoreContextSlot(context, var->index(), Top()); | |
3809 AddInstruction(instr); | |
3810 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); | |
3811 return ast_context()->ReturnValue(Pop()); | |
3776 } | 3812 } |
3777 | 3813 |
3778 CHECK_ALIVE(VisitForValue(expr->value())); | 3814 case Variable::LOOKUP: |
3779 HValue* context = BuildContextChainWalk(var); | 3815 return Bailout("assignment to LOOKUP variable"); |
3780 int index = var->AsSlot()->index(); | |
3781 HStoreContextSlot* instr = | |
3782 new(zone()) HStoreContextSlot(context, index, Top()); | |
3783 AddInstruction(instr); | |
3784 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); | |
3785 return ast_context()->ReturnValue(Pop()); | |
3786 | |
3787 } else if (var->is_global()) { | |
3788 CHECK_ALIVE(VisitForValue(expr->value())); | |
3789 HandleGlobalVariableAssignment(var, | |
3790 Top(), | |
3791 expr->position(), | |
3792 expr->AssignmentId()); | |
3793 return ast_context()->ReturnValue(Pop()); | |
3794 | |
3795 } else { | |
3796 return Bailout("assignment to LOOKUP or const CONTEXT variable"); | |
3797 } | 3816 } |
3798 | |
3799 } else if (prop != NULL) { | |
3800 HandlePropertyAssignment(expr); | |
3801 } else { | 3817 } else { |
3802 return Bailout("invalid left-hand side in assignment"); | 3818 return Bailout("invalid left-hand side in assignment"); |
3803 } | 3819 } |
3804 } | 3820 } |
3805 | 3821 |
3806 | 3822 |
3807 void HGraphBuilder::VisitThrow(Throw* expr) { | 3823 void HGraphBuilder::VisitThrow(Throw* expr) { |
3808 ASSERT(!HasStackOverflow()); | 3824 ASSERT(!HasStackOverflow()); |
3809 ASSERT(current_block() != NULL); | 3825 ASSERT(current_block() != NULL); |
3810 ASSERT(current_block()->HasPredecessor()); | 3826 ASSERT(current_block()->HasPredecessor()); |
(...skipping 1091 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4902 HandlePolymorphicCallNamed(expr, receiver, types, name); | 4918 HandlePolymorphicCallNamed(expr, receiver, types, name); |
4903 return; | 4919 return; |
4904 | 4920 |
4905 } else { | 4921 } else { |
4906 HValue* context = environment()->LookupContext(); | 4922 HValue* context = environment()->LookupContext(); |
4907 call = PreProcessCall( | 4923 call = PreProcessCall( |
4908 new(zone()) HCallNamed(context, name, argument_count)); | 4924 new(zone()) HCallNamed(context, name, argument_count)); |
4909 } | 4925 } |
4910 | 4926 |
4911 } else { | 4927 } else { |
4912 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); | 4928 VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
4913 bool global_call = (var != NULL) && var->is_global() && !var->is_this(); | 4929 // FIXME. |
fschneider
2011/09/06 09:34:22
Is this a TODO?
Kevin Millikin (Chromium)
2011/09/06 10:44:06
Oops. It was a TODO, but it's been fixed and I di
| |
4930 bool global_call = proxy != NULL && proxy->var()->IsUnallocated(); | |
4914 | 4931 |
4915 if (global_call) { | 4932 if (global_call) { |
4933 Variable* var = proxy->var(); | |
4916 bool known_global_function = false; | 4934 bool known_global_function = false; |
4917 // If there is a global property cell for the name at compile time and | 4935 // If there is a global property cell for the name at compile time and |
4918 // access check is not enabled we assume that the function will not change | 4936 // access check is not enabled we assume that the function will not change |
4919 // and generate optimized code for calling the function. | 4937 // and generate optimized code for calling the function. |
4920 LookupResult lookup; | 4938 LookupResult lookup; |
4921 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, false); | 4939 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, false); |
4922 if (type == kUseCell && | 4940 if (type == kUseCell && |
4923 !info()->global_object()->IsAccessCheckNeeded()) { | 4941 !info()->global_object()->IsAccessCheckNeeded()) { |
4924 Handle<GlobalObject> global(info()->global_object()); | 4942 Handle<GlobalObject> global(info()->global_object()); |
4925 known_global_function = expr->ComputeGlobalTarget(global, &lookup); | 4943 known_global_function = expr->ComputeGlobalTarget(global, &lookup); |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5069 case Token::ADD: return VisitAdd(expr); | 5087 case Token::ADD: return VisitAdd(expr); |
5070 case Token::SUB: return VisitSub(expr); | 5088 case Token::SUB: return VisitSub(expr); |
5071 case Token::BIT_NOT: return VisitBitNot(expr); | 5089 case Token::BIT_NOT: return VisitBitNot(expr); |
5072 case Token::NOT: return VisitNot(expr); | 5090 case Token::NOT: return VisitNot(expr); |
5073 default: UNREACHABLE(); | 5091 default: UNREACHABLE(); |
5074 } | 5092 } |
5075 } | 5093 } |
5076 | 5094 |
5077 void HGraphBuilder::VisitDelete(UnaryOperation* expr) { | 5095 void HGraphBuilder::VisitDelete(UnaryOperation* expr) { |
5078 Property* prop = expr->expression()->AsProperty(); | 5096 Property* prop = expr->expression()->AsProperty(); |
5079 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); | 5097 VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
5080 if (prop == NULL && var == NULL) { | 5098 if (prop != NULL) { |
5081 // Result of deleting non-property, non-variable reference is true. | |
5082 // Evaluate the subexpression for side effects. | |
5083 CHECK_ALIVE(VisitForEffect(expr->expression())); | |
5084 return ast_context()->ReturnValue(graph()->GetConstantTrue()); | |
5085 } else if (var != NULL && | |
5086 !var->is_global() && | |
5087 var->AsSlot() != NULL && | |
5088 var->AsSlot()->type() != Slot::LOOKUP) { | |
5089 // Result of deleting non-global, non-dynamic variables is false. | |
5090 // The subexpression does not have side effects. | |
5091 return ast_context()->ReturnValue(graph()->GetConstantFalse()); | |
5092 } else if (prop != NULL) { | |
5093 CHECK_ALIVE(VisitForValue(prop->obj())); | 5099 CHECK_ALIVE(VisitForValue(prop->obj())); |
5094 CHECK_ALIVE(VisitForValue(prop->key())); | 5100 CHECK_ALIVE(VisitForValue(prop->key())); |
5095 HValue* key = Pop(); | 5101 HValue* key = Pop(); |
5096 HValue* obj = Pop(); | 5102 HValue* obj = Pop(); |
5097 HValue* context = environment()->LookupContext(); | 5103 HValue* context = environment()->LookupContext(); |
5098 HDeleteProperty* instr = new(zone()) HDeleteProperty(context, obj, key); | 5104 HDeleteProperty* instr = new(zone()) HDeleteProperty(context, obj, key); |
5099 return ast_context()->ReturnInstruction(instr, expr->id()); | 5105 return ast_context()->ReturnInstruction(instr, expr->id()); |
5100 } else if (var->is_global()) { | 5106 } else if (proxy != NULL) { |
5101 Bailout("delete with global variable"); | 5107 Variable* var = proxy->var(); |
5108 if (var->IsUnallocated()) { | |
5109 Bailout("delete with global variable"); | |
5110 } else if (var->IsStackAllocated() || var->IsContextSlot()) { | |
5111 // Result of deleting non-global variables is false. 'this' is not | |
5112 // really a variable, though we implement it as one. The | |
5113 // subexpression does not have side effects. | |
5114 HValue* value = var->is_this() | |
5115 ? graph()->GetConstantTrue() | |
5116 : graph()->GetConstantFalse(); | |
5117 return ast_context()->ReturnValue(value); | |
5118 } else { | |
5119 Bailout("delete with non-global variable"); | |
5120 } | |
5102 } else { | 5121 } else { |
5103 Bailout("delete with non-global variable"); | 5122 // Result of deleting non-property, non-variable reference is true. |
5123 // Evaluate the subexpression for side effects. | |
5124 CHECK_ALIVE(VisitForEffect(expr->expression())); | |
5125 return ast_context()->ReturnValue(graph()->GetConstantTrue()); | |
5104 } | 5126 } |
5105 } | 5127 } |
5106 | 5128 |
5107 | 5129 |
5108 void HGraphBuilder::VisitVoid(UnaryOperation* expr) { | 5130 void HGraphBuilder::VisitVoid(UnaryOperation* expr) { |
5109 CHECK_ALIVE(VisitForEffect(expr->expression())); | 5131 CHECK_ALIVE(VisitForEffect(expr->expression())); |
5110 return ast_context()->ReturnValue(graph()->GetConstantUndefined()); | 5132 return ast_context()->ReturnValue(graph()->GetConstantUndefined()); |
5111 } | 5133 } |
5112 | 5134 |
5113 | 5135 |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5240 return instr; | 5262 return instr; |
5241 } | 5263 } |
5242 | 5264 |
5243 | 5265 |
5244 void HGraphBuilder::VisitCountOperation(CountOperation* expr) { | 5266 void HGraphBuilder::VisitCountOperation(CountOperation* expr) { |
5245 ASSERT(!HasStackOverflow()); | 5267 ASSERT(!HasStackOverflow()); |
5246 ASSERT(current_block() != NULL); | 5268 ASSERT(current_block() != NULL); |
5247 ASSERT(current_block()->HasPredecessor()); | 5269 ASSERT(current_block()->HasPredecessor()); |
5248 Expression* target = expr->expression(); | 5270 Expression* target = expr->expression(); |
5249 VariableProxy* proxy = target->AsVariableProxy(); | 5271 VariableProxy* proxy = target->AsVariableProxy(); |
5250 Variable* var = proxy->AsVariable(); | |
5251 Property* prop = target->AsProperty(); | 5272 Property* prop = target->AsProperty(); |
5252 if (var == NULL && prop == NULL) { | 5273 if (proxy == NULL && prop == NULL) { |
5253 return Bailout("invalid lhs in count operation"); | 5274 return Bailout("invalid lhs in count operation"); |
5254 } | 5275 } |
5255 | 5276 |
5256 // Match the full code generator stack by simulating an extra stack | 5277 // Match the full code generator stack by simulating an extra stack |
5257 // element for postfix operations in a non-effect context. The return | 5278 // element for postfix operations in a non-effect context. The return |
5258 // value is ToNumber(input). | 5279 // value is ToNumber(input). |
5259 bool returns_original_input = | 5280 bool returns_original_input = |
5260 expr->is_postfix() && !ast_context()->IsEffect(); | 5281 expr->is_postfix() && !ast_context()->IsEffect(); |
5261 HValue* input = NULL; // ToNumber(original_input). | 5282 HValue* input = NULL; // ToNumber(original_input). |
5262 HValue* after = NULL; // The result after incrementing or decrementing. | 5283 HValue* after = NULL; // The result after incrementing or decrementing. |
5263 | 5284 |
5264 if (var != NULL) { | 5285 if (proxy != NULL) { |
5286 Variable* var = proxy->var(); | |
5265 if (var->mode() == Variable::CONST) { | 5287 if (var->mode() == Variable::CONST) { |
5266 return Bailout("unsupported count operation with const"); | 5288 return Bailout("unsupported count operation with const"); |
5267 } | 5289 } |
5268 // Argument of the count operation is a variable, not a property. | 5290 // Argument of the count operation is a variable, not a property. |
5269 ASSERT(prop == NULL); | 5291 ASSERT(prop == NULL); |
5270 CHECK_ALIVE(VisitForValue(target)); | 5292 CHECK_ALIVE(VisitForValue(target)); |
5271 | 5293 |
5272 after = BuildIncrement(returns_original_input, expr); | 5294 after = BuildIncrement(returns_original_input, expr); |
5273 input = returns_original_input ? Top() : Pop(); | 5295 input = returns_original_input ? Top() : Pop(); |
5274 Push(after); | 5296 Push(after); |
5275 | 5297 |
5276 if (var->is_global()) { | 5298 switch (var->location()) { |
5277 HandleGlobalVariableAssignment(var, | 5299 case Variable::UNALLOCATED: |
5278 after, | 5300 HandleGlobalVariableAssignment(var, |
5279 expr->position(), | 5301 after, |
5280 expr->AssignmentId()); | 5302 expr->position(), |
5281 } else if (var->IsStackAllocated()) { | 5303 expr->AssignmentId()); |
5282 Bind(var, after); | 5304 break; |
5283 } else if (var->IsContextSlot()) { | 5305 |
5284 // Bail out if we try to mutate a parameter value in a function using | 5306 case Variable::PARAMETER: |
5285 // the arguments object. We do not (yet) correctly handle the | 5307 case Variable::LOCAL: |
5286 // arguments property of the function. | 5308 Bind(var, after); |
5287 if (info()->scope()->arguments() != NULL) { | 5309 break; |
5288 // Parameters will rewrite to context slots. We have no direct way | 5310 |
5289 // to detect that the variable is a parameter. | 5311 case Variable::CONTEXT: { |
5290 int count = info()->scope()->num_parameters(); | 5312 // Bail out if we try to mutate a parameter value in a function |
5291 for (int i = 0; i < count; ++i) { | 5313 // using the arguments object. We do not (yet) correctly handle the |
5292 if (var == info()->scope()->parameter(i)) { | 5314 // arguments property of the function. |
5293 Bailout("assignment to parameter, function uses arguments object"); | 5315 if (info()->scope()->arguments() != NULL) { |
5316 // Parameters will rewrite to context slots. We have no direct | |
5317 // way to detect that the variable is a parameter so we use a | |
5318 // linear search of the parameter list. | |
5319 int count = info()->scope()->num_parameters(); | |
5320 for (int i = 0; i < count; ++i) { | |
5321 if (var == info()->scope()->parameter(i)) { | |
5322 return Bailout("assignment to parameter in arguments object"); | |
5323 } | |
5294 } | 5324 } |
5295 } | 5325 } |
5326 | |
5327 HValue* context = BuildContextChainWalk(var); | |
5328 HStoreContextSlot* instr = | |
5329 new(zone()) HStoreContextSlot(context, var->index(), after); | |
5330 AddInstruction(instr); | |
5331 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); | |
5332 break; | |
5296 } | 5333 } |
5297 | 5334 |
5298 HValue* context = BuildContextChainWalk(var); | 5335 case Variable::LOOKUP: |
5299 int index = var->AsSlot()->index(); | 5336 return Bailout("lookup variable in count operation"); |
5300 HStoreContextSlot* instr = | |
5301 new(zone()) HStoreContextSlot(context, index, after); | |
5302 AddInstruction(instr); | |
5303 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); | |
5304 } else { | |
5305 return Bailout("lookup variable in count operation"); | |
5306 } | 5337 } |
5307 | 5338 |
5308 } else { | 5339 } else { |
5309 // Argument of the count operation is a property. | 5340 // Argument of the count operation is a property. |
5310 ASSERT(prop != NULL); | 5341 ASSERT(prop != NULL); |
5311 prop->RecordTypeFeedback(oracle()); | 5342 prop->RecordTypeFeedback(oracle()); |
5312 | 5343 |
5313 if (prop->key()->IsPropertyName()) { | 5344 if (prop->key()->IsPropertyName()) { |
5314 // Named property. | 5345 // Named property. |
5315 if (returns_original_input) Push(graph_->GetConstantUndefined()); | 5346 if (returns_original_input) Push(graph_->GetConstantUndefined()); |
(...skipping 391 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5707 HValue* context = environment()->LookupContext(); | 5738 HValue* context = environment()->LookupContext(); |
5708 HValue* right = Pop(); | 5739 HValue* right = Pop(); |
5709 HValue* left = Pop(); | 5740 HValue* left = Pop(); |
5710 Token::Value op = expr->op(); | 5741 Token::Value op = expr->op(); |
5711 | 5742 |
5712 if (op == Token::INSTANCEOF) { | 5743 if (op == Token::INSTANCEOF) { |
5713 // Check to see if the rhs of the instanceof is a global function not | 5744 // Check to see if the rhs of the instanceof is a global function not |
5714 // residing in new space. If it is we assume that the function will stay the | 5745 // residing in new space. If it is we assume that the function will stay the |
5715 // same. | 5746 // same. |
5716 Handle<JSFunction> target = Handle<JSFunction>::null(); | 5747 Handle<JSFunction> target = Handle<JSFunction>::null(); |
5717 Variable* var = expr->right()->AsVariableProxy()->AsVariable(); | 5748 VariableProxy* proxy = expr->right()->AsVariableProxy(); |
5718 bool global_function = (var != NULL) && var->is_global() && !var->is_this(); | 5749 bool global_function = (proxy != NULL) && proxy->var()->IsUnallocated(); |
5719 if (global_function && | 5750 if (global_function && |
5720 info()->has_global_object() && | 5751 info()->has_global_object() && |
5721 !info()->global_object()->IsAccessCheckNeeded()) { | 5752 !info()->global_object()->IsAccessCheckNeeded()) { |
5722 Handle<String> name = var->name(); | 5753 Handle<String> name = proxy->name(); |
5723 Handle<GlobalObject> global(info()->global_object()); | 5754 Handle<GlobalObject> global(info()->global_object()); |
5724 LookupResult lookup; | 5755 LookupResult lookup; |
5725 global->Lookup(*name, &lookup); | 5756 global->Lookup(*name, &lookup); |
5726 if (lookup.IsProperty() && | 5757 if (lookup.IsProperty() && |
5727 lookup.type() == NORMAL && | 5758 lookup.type() == NORMAL && |
5728 lookup.GetValue()->IsJSFunction()) { | 5759 lookup.GetValue()->IsJSFunction()) { |
5729 Handle<JSFunction> candidate(JSFunction::cast(lookup.GetValue())); | 5760 Handle<JSFunction> candidate(JSFunction::cast(lookup.GetValue())); |
5730 // If the function is in new space we assume it's more likely to | 5761 // If the function is in new space we assume it's more likely to |
5731 // change and thus prefer the general IC code. | 5762 // change and thus prefer the general IC code. |
5732 if (!isolate()->heap()->InNewSpace(*candidate)) { | 5763 if (!isolate()->heap()->InNewSpace(*candidate)) { |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5816 return ast_context()->ReturnInstruction(self, expr->id()); | 5847 return ast_context()->ReturnInstruction(self, expr->id()); |
5817 } | 5848 } |
5818 | 5849 |
5819 | 5850 |
5820 void HGraphBuilder::VisitDeclaration(Declaration* decl) { | 5851 void HGraphBuilder::VisitDeclaration(Declaration* decl) { |
5821 HandleDeclaration(decl->proxy(), decl->mode(), decl->fun()); | 5852 HandleDeclaration(decl->proxy(), decl->mode(), decl->fun()); |
5822 } | 5853 } |
5823 | 5854 |
5824 | 5855 |
5825 void HGraphBuilder::HandleDeclaration(VariableProxy* proxy, | 5856 void HGraphBuilder::HandleDeclaration(VariableProxy* proxy, |
5826 Variable::Mode mode, | 5857 Variable::Mode mode, |
5827 FunctionLiteral* function) { | 5858 FunctionLiteral* function) { |
5828 if (mode == Variable::LET) return Bailout("unsupported let declaration"); | 5859 if (mode == Variable::LET) return Bailout("unsupported let declaration"); |
5829 Variable* var = proxy->var(); | 5860 Variable* var = proxy->var(); |
5830 Slot* slot = var->AsSlot(); | 5861 switch (var->location()) { |
5831 ASSERT(slot != NULL); | 5862 case Variable::UNALLOCATED: |
5832 switch (slot->type()) { | 5863 return Bailout("unsupported global declaration"); |
5833 case Slot::PARAMETER: | 5864 case Variable::PARAMETER: |
5834 case Slot::LOCAL: | 5865 case Variable::LOCAL: |
5835 if (mode == Variable::CONST) { | 5866 case Variable::CONTEXT: |
5836 environment()->Bind(var, graph()->GetConstantHole()); | 5867 if (mode == Variable::CONST || function != NULL) { |
5837 } else if (function != NULL) { | 5868 HValue* value = NULL; |
5838 VisitForValue(function); | 5869 if (mode == Variable::CONST) { |
5839 HValue* function_value = Pop(); | 5870 value = graph()->GetConstantHole(); |
5840 environment()->Bind(var, function_value); | 5871 } else { |
5872 VisitForValue(function); | |
5873 value = Pop(); | |
5874 } | |
5875 if (var->IsContextSlot()) { | |
5876 HValue* context = environment()->LookupContext(); | |
5877 HStoreContextSlot* store = | |
5878 new HStoreContextSlot(context, var->index(), value); | |
5879 AddInstruction(store); | |
5880 if (store->HasSideEffects()) AddSimulate(proxy->id()); | |
5881 } else { | |
5882 environment()->Bind(var, value); | |
5883 } | |
5841 } | 5884 } |
5842 break; | 5885 break; |
5843 case Slot::CONTEXT: { | 5886 case Variable::LOOKUP: |
5844 HValue* context = environment()->LookupContext(); | |
5845 if (mode == Variable::CONST) { | |
5846 HStoreContextSlot* store = | |
5847 new HStoreContextSlot(context, | |
5848 slot->index(), | |
5849 graph()->GetConstantHole()); | |
5850 AddInstruction(store); | |
5851 if (store->HasSideEffects()) AddSimulate(proxy->id()); | |
5852 } else if (function != NULL) { | |
5853 VisitForValue(function); | |
5854 HValue* function_value = Pop(); | |
5855 HStoreContextSlot* store = | |
5856 new HStoreContextSlot(context, | |
5857 slot->index(), | |
5858 function_value); | |
5859 AddInstruction(store); | |
5860 if (store->HasSideEffects()) AddSimulate(proxy->id()); | |
5861 } | |
5862 break; | |
5863 } | |
5864 case Slot::LOOKUP: | |
5865 return Bailout("unsupported lookup slot in declaration"); | 5887 return Bailout("unsupported lookup slot in declaration"); |
5866 } | 5888 } |
5867 } | 5889 } |
5868 | 5890 |
5869 | 5891 |
5870 // Generators for inline runtime functions. | 5892 // Generators for inline runtime functions. |
5871 // Support for types. | 5893 // Support for types. |
5872 void HGraphBuilder::GenerateIsSmi(CallRuntime* call) { | 5894 void HGraphBuilder::GenerateIsSmi(CallRuntime* call) { |
5873 ASSERT(call->arguments()->length() == 1); | 5895 ASSERT(call->arguments()->length() == 1); |
5874 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 5896 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
(...skipping 917 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6792 } | 6814 } |
6793 } | 6815 } |
6794 | 6816 |
6795 #ifdef DEBUG | 6817 #ifdef DEBUG |
6796 if (graph_ != NULL) graph_->Verify(); | 6818 if (graph_ != NULL) graph_->Verify(); |
6797 if (allocator_ != NULL) allocator_->Verify(); | 6819 if (allocator_ != NULL) allocator_->Verify(); |
6798 #endif | 6820 #endif |
6799 } | 6821 } |
6800 | 6822 |
6801 } } // namespace v8::internal | 6823 } } // namespace v8::internal |
OLD | NEW |