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 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 |