Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(350)

Side by Side Diff: src/parser.cc

Issue 720863002: Fix desugaring of let bindings in for loops to handle continue properly (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Ready for review Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/v8.h" 5 #include "src/v8.h"
6 6
7 #include "src/api.h" 7 #include "src/api.h"
8 #include "src/ast.h" 8 #include "src/ast.h"
9 #include "src/bailout-reason.h" 9 #include "src/bailout-reason.h"
10 #include "src/base/platform/platform.h" 10 #include "src/base/platform/platform.h"
(...skipping 2968 matching lines...) Expand 10 before | Expand all | Expand 10 after
2979 Scope* inner_scope, ZoneList<const AstRawString*>* names, 2979 Scope* inner_scope, ZoneList<const AstRawString*>* names,
2980 ForStatement* loop, Statement* init, Expression* cond, Statement* next, 2980 ForStatement* loop, Statement* init, Expression* cond, Statement* next,
2981 Statement* body, bool* ok) { 2981 Statement* body, bool* ok) {
2982 // ES6 13.6.3.4 specifies that on each loop iteration the let variables are 2982 // ES6 13.6.3.4 specifies that on each loop iteration the let variables are
2983 // copied into a new environment. After copying, the "next" statement of the 2983 // copied into a new environment. After copying, the "next" statement of the
2984 // loop is executed to update the loop variables. The loop condition is 2984 // loop is executed to update the loop variables. The loop condition is
2985 // checked and the loop body is executed. 2985 // checked and the loop body is executed.
2986 // 2986 //
2987 // We rewrite a for statement of the form 2987 // We rewrite a for statement of the form
2988 // 2988 //
2989 // for (let x = i; cond; next) body 2989 // labels: for (let x = i; cond; next) body
2990 // 2990 //
2991 // into 2991 // into
2992 // 2992 //
2993 // { 2993 // {
2994 // let x = i; 2994 // let x = i;
2995 // temp_x = x; 2995 // temp_x = x;
2996 // flag = 1; 2996 // first = 1;
2997 // for (;;) { 2997 // outer: for (;;) {
2998 // let x = temp_x; 2998 // let x = temp_x;
2999 // if (flag == 1) { 2999 // if (first == 1) {
3000 // flag = 0; 3000 // first = 0;
3001 // } else {
3002 // next;
3003 // }
3004 // flag = 1;
3005 // labels: for (; flag == 1; flag = 0, temp_x = x) {
3006 // if (cond) {
3007 // body
3001 // } else { 3008 // } else {
3002 // next; 3009 // break outer;
3003 // } 3010 // }
3004 // if (cond) { 3011 // }
3005 // <empty> 3012 // if (flag == 1) {
3006 // } else { 3013 // break;
3007 // break; 3014 // }
3008 // } 3015 // }
3009 // b
3010 // temp_x = x;
3011 // }
3012 // } 3016 // }
3013 3017
3014 DCHECK(names->length() > 0); 3018 DCHECK(names->length() > 0);
3015 Scope* for_scope = scope_; 3019 Scope* for_scope = scope_;
3016 ZoneList<Variable*> temps(names->length(), zone()); 3020 ZoneList<Variable*> temps(names->length(), zone());
3017 3021
3018 Block* outer_block = factory()->NewBlock(NULL, names->length() + 3, false, 3022 Block* outer_block = factory()->NewBlock(NULL, names->length() + 3, false,
3019 RelocInfo::kNoPosition); 3023 RelocInfo::kNoPosition);
3024
3025 // Add statement: let x = i.
3020 outer_block->AddStatement(init, zone()); 3026 outer_block->AddStatement(init, zone());
3021 3027
3022 const AstRawString* temp_name = ast_value_factory()->dot_for_string(); 3028 const AstRawString* temp_name = ast_value_factory()->dot_for_string();
3023 3029
3024 // For each let variable x: 3030 // For each let variable x:
3025 // make statement: temp_x = x. 3031 // make statement: temp_x = x.
3026 for (int i = 0; i < names->length(); i++) { 3032 for (int i = 0; i < names->length(); i++) {
3027 VariableProxy* proxy = 3033 VariableProxy* proxy =
3028 NewUnresolved(names->at(i), LET, Interface::NewValue()); 3034 NewUnresolved(names->at(i), LET, Interface::NewValue());
3029 Variable* temp = scope_->DeclarationScope()->NewTemporary(temp_name); 3035 Variable* temp = scope_->DeclarationScope()->NewTemporary(temp_name);
3030 VariableProxy* temp_proxy = factory()->NewVariableProxy(temp); 3036 VariableProxy* temp_proxy = factory()->NewVariableProxy(temp);
3031 Assignment* assignment = factory()->NewAssignment( 3037 Assignment* assignment = factory()->NewAssignment(
3032 Token::ASSIGN, temp_proxy, proxy, RelocInfo::kNoPosition); 3038 Token::ASSIGN, temp_proxy, proxy, RelocInfo::kNoPosition);
3033 Statement* assignment_statement = factory()->NewExpressionStatement( 3039 Statement* assignment_statement = factory()->NewExpressionStatement(
3034 assignment, RelocInfo::kNoPosition); 3040 assignment, RelocInfo::kNoPosition);
3035 outer_block->AddStatement(assignment_statement, zone()); 3041 outer_block->AddStatement(assignment_statement, zone());
3036 temps.Add(temp, zone()); 3042 temps.Add(temp, zone());
3037 } 3043 }
3038 3044
3039 Variable* flag = scope_->DeclarationScope()->NewTemporary(temp_name); 3045 Variable* first = NULL;
3040 // Make statement: flag = 1. 3046 // Make statement: first = 1.
3041 { 3047 if (next) {
3042 VariableProxy* flag_proxy = factory()->NewVariableProxy(flag); 3048 first = scope_->DeclarationScope()->NewTemporary(temp_name);
3049 VariableProxy* first_proxy = factory()->NewVariableProxy(first);
3043 Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition); 3050 Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
3044 Assignment* assignment = factory()->NewAssignment( 3051 Assignment* assignment = factory()->NewAssignment(
3045 Token::ASSIGN, flag_proxy, const1, RelocInfo::kNoPosition); 3052 Token::ASSIGN, first_proxy, const1, RelocInfo::kNoPosition);
3046 Statement* assignment_statement = factory()->NewExpressionStatement( 3053 Statement* assignment_statement =
3047 assignment, RelocInfo::kNoPosition); 3054 factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition);
3048 outer_block->AddStatement(assignment_statement, zone()); 3055 outer_block->AddStatement(assignment_statement, zone());
3049 } 3056 }
3050 3057
3051 outer_block->AddStatement(loop, zone()); 3058 // Make statement: outer: for (;;)
3059 // Note that we don't actually create the label, or set this loop up as an
3060 // explicit break target, instead handing it directly to those nodes that
3061 // need to know about it. This should be safe because we don't run any code
3062 // in this function that looks up break targets.
3063 ForStatement* outer_loop =
3064 factory()->NewForStatement(NULL, RelocInfo::kNoPosition);
3065 outer_block->AddStatement(outer_loop, zone());
3066
3052 outer_block->set_scope(for_scope); 3067 outer_block->set_scope(for_scope);
3053 scope_ = inner_scope; 3068 scope_ = inner_scope;
3054 3069
3055 Block* inner_block = factory()->NewBlock(NULL, 2 * names->length() + 3, 3070 Block* inner_block = factory()->NewBlock(NULL, names->length() + 4, false,
3056 false, RelocInfo::kNoPosition); 3071 RelocInfo::kNoPosition);
3057 int pos = scanner()->location().beg_pos; 3072 int pos = scanner()->location().beg_pos;
3058 ZoneList<Variable*> inner_vars(names->length(), zone()); 3073 ZoneList<Variable*> inner_vars(names->length(), zone());
3059 3074
3060 // For each let variable x: 3075 // For each let variable x:
3061 // make statement: let x = temp_x. 3076 // make statement: let x = temp_x.
3062 for (int i = 0; i < names->length(); i++) { 3077 for (int i = 0; i < names->length(); i++) {
3063 VariableProxy* proxy = 3078 VariableProxy* proxy =
3064 NewUnresolved(names->at(i), LET, Interface::NewValue()); 3079 NewUnresolved(names->at(i), LET, Interface::NewValue());
3065 Declaration* declaration = 3080 Declaration* declaration =
3066 factory()->NewVariableDeclaration(proxy, LET, scope_, pos); 3081 factory()->NewVariableDeclaration(proxy, LET, scope_, pos);
3067 Declare(declaration, true, CHECK_OK); 3082 Declare(declaration, true, CHECK_OK);
3068 inner_vars.Add(declaration->proxy()->var(), zone()); 3083 inner_vars.Add(declaration->proxy()->var(), zone());
3069 VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i)); 3084 VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i));
3070 Assignment* assignment = factory()->NewAssignment( 3085 Assignment* assignment = factory()->NewAssignment(
3071 Token::INIT_LET, proxy, temp_proxy, pos); 3086 Token::INIT_LET, proxy, temp_proxy, pos);
3072 Statement* assignment_statement = factory()->NewExpressionStatement( 3087 Statement* assignment_statement = factory()->NewExpressionStatement(
3073 assignment, pos); 3088 assignment, pos);
3074 proxy->var()->set_initializer_position(pos); 3089 proxy->var()->set_initializer_position(pos);
3075 inner_block->AddStatement(assignment_statement, zone()); 3090 inner_block->AddStatement(assignment_statement, zone());
3076 } 3091 }
3077 3092
3078 // Make statement: if (flag == 1) { flag = 0; } else { next; }. 3093 // Make statement: if (first == 1) { first = 0; } else { next; }
3079 if (next) { 3094 if (next) {
3095 DCHECK(first);
3096 Expression* compare = NULL;
3097 // Make compare expression: first == 1.
3098 {
3099 Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
3100 VariableProxy* first_proxy = factory()->NewVariableProxy(first);
3101 compare =
3102 factory()->NewCompareOperation(Token::EQ, first_proxy, const1, pos);
3103 }
3104 Statement* clear_first = NULL;
3105 // Make statement: first = 0.
3106 {
3107 VariableProxy* first_proxy = factory()->NewVariableProxy(first);
3108 Expression* const0 = factory()->NewSmiLiteral(0, RelocInfo::kNoPosition);
3109 Assignment* assignment = factory()->NewAssignment(
3110 Token::ASSIGN, first_proxy, const0, RelocInfo::kNoPosition);
3111 clear_first =
3112 factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition);
3113 }
3114 Statement* clear_first_or_next = factory()->NewIfStatement(
3115 compare, clear_first, next, RelocInfo::kNoPosition);
3116 inner_block->AddStatement(clear_first_or_next, zone());
3117 }
3118
3119 Variable* flag = scope_->DeclarationScope()->NewTemporary(temp_name);
3120 // Make statement: flag = 1.
3121 {
3122 VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
3123 Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
3124 Assignment* assignment = factory()->NewAssignment(
3125 Token::ASSIGN, flag_proxy, const1, RelocInfo::kNoPosition);
3126 Statement* assignment_statement =
3127 factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition);
3128 inner_block->AddStatement(assignment_statement, zone());
3129 }
3130
3131 // Make cond expression for main loop: flag == 1.
3132 Expression* flag_cond = NULL;
3133 {
3134 Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
3135 VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
3136 flag_cond =
3137 factory()->NewCompareOperation(Token::EQ, flag_proxy, const1, pos);
3138 }
3139
3140 // Create chain of expressions "flag = 0, temp_x = x, ..."
3141 Statement* compound_next_statement = NULL;
3142 {
3143 Expression* compound_next = NULL;
3144 // Make expression: flag = 0.
3145 {
3146 VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
3147 Expression* const0 = factory()->NewSmiLiteral(0, RelocInfo::kNoPosition);
3148 compound_next = factory()->NewAssignment(Token::ASSIGN, flag_proxy,
3149 const0, RelocInfo::kNoPosition);
3150 }
3151
3152 // Make the comma-separated list of temp_x = x assignments.
3153 for (int i = 0; i < names->length(); i++) {
3154 VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i));
3155 VariableProxy* proxy = factory()->NewVariableProxy(inner_vars.at(i), pos);
3156 Assignment* assignment = factory()->NewAssignment(
3157 Token::ASSIGN, temp_proxy, proxy, RelocInfo::kNoPosition);
3158 compound_next = factory()->NewBinaryOperation(
3159 Token::COMMA, compound_next, assignment, RelocInfo::kNoPosition);
3160 }
3161
3162 compound_next_statement = factory()->NewExpressionStatement(
3163 compound_next, RelocInfo::kNoPosition);
3164 }
3165
3166 // Make statement: if (cond) { body; } else { break outer; }
3167 Statement* body_or_stop = body;
3168 if (cond) {
3169 Statement* stop =
3170 factory()->NewBreakStatement(outer_loop, RelocInfo::kNoPosition);
3171 body_or_stop =
3172 factory()->NewIfStatement(cond, body, stop, cond->position());
3173 }
3174
3175 loop->Initialize(NULL, flag_cond, compound_next_statement, body_or_stop);
rossberg 2014/11/14 10:58:01 Perhaps add a comment explaining that this reuses
adamk 2014/11/14 19:03:36 Added a comment and explained why we re-use.
3176 inner_block->AddStatement(loop, zone());
3177
3178 // Make statement: if (flag == 1) { break; }
3179 {
3080 Expression* compare = NULL; 3180 Expression* compare = NULL;
3081 // Make compare expresion: flag == 1. 3181 // Make compare expresion: flag == 1.
3082 { 3182 {
3083 Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition); 3183 Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
3084 VariableProxy* flag_proxy = factory()->NewVariableProxy(flag); 3184 VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
3085 compare = factory()->NewCompareOperation( 3185 compare =
3086 Token::EQ, flag_proxy, const1, pos); 3186 factory()->NewCompareOperation(Token::EQ, flag_proxy, const1, pos);
3087 } 3187 }
3088 Statement* clear_flag = NULL; 3188 Statement* stop =
3089 // Make statement: flag = 0. 3189 factory()->NewBreakStatement(outer_loop, RelocInfo::kNoPosition);
3090 {
3091 VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
3092 Expression* const0 = factory()->NewSmiLiteral(0, RelocInfo::kNoPosition);
3093 Assignment* assignment = factory()->NewAssignment(
3094 Token::ASSIGN, flag_proxy, const0, RelocInfo::kNoPosition);
3095 clear_flag = factory()->NewExpressionStatement(assignment, pos);
3096 }
3097 Statement* clear_flag_or_next = factory()->NewIfStatement(
3098 compare, clear_flag, next, RelocInfo::kNoPosition);
3099 inner_block->AddStatement(clear_flag_or_next, zone());
3100 }
3101
3102
3103 // Make statement: if (cond) { } else { break; }.
3104 if (cond) {
3105 Statement* empty = factory()->NewEmptyStatement(RelocInfo::kNoPosition); 3190 Statement* empty = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
3106 BreakableStatement* t = LookupBreakTarget(NULL, CHECK_OK); 3191 Statement* if_flag_break =
3107 Statement* stop = factory()->NewBreakStatement(t, RelocInfo::kNoPosition); 3192 factory()->NewIfStatement(compare, stop, empty, RelocInfo::kNoPosition);
3108 Statement* if_not_cond_break = factory()->NewIfStatement( 3193 inner_block->AddStatement(if_flag_break, zone());
3109 cond, empty, stop, cond->position());
3110 inner_block->AddStatement(if_not_cond_break, zone());
3111 }
3112
3113 inner_block->AddStatement(body, zone());
3114
3115 // For each let variable x:
3116 // make statement: temp_x = x;
3117 for (int i = 0; i < names->length(); i++) {
3118 VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i));
3119 int pos = scanner()->location().end_pos;
3120 VariableProxy* proxy = factory()->NewVariableProxy(inner_vars.at(i), pos);
3121 Assignment* assignment = factory()->NewAssignment(
3122 Token::ASSIGN, temp_proxy, proxy, RelocInfo::kNoPosition);
3123 Statement* assignment_statement = factory()->NewExpressionStatement(
3124 assignment, RelocInfo::kNoPosition);
3125 inner_block->AddStatement(assignment_statement, zone());
3126 } 3194 }
3127 3195
3128 inner_scope->set_end_position(scanner()->location().end_pos); 3196 inner_scope->set_end_position(scanner()->location().end_pos);
3129 inner_block->set_scope(inner_scope); 3197 inner_block->set_scope(inner_scope);
3130 scope_ = for_scope; 3198 scope_ = for_scope;
3131 3199
3132 loop->Initialize(NULL, NULL, NULL, inner_block); 3200 outer_loop->Initialize(NULL, NULL, NULL, inner_block);
3133 return outer_block; 3201 return outer_block;
3134 } 3202 }
3135 3203
3136 3204
3137 Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, 3205 Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
3138 bool* ok) { 3206 bool* ok) {
3139 // ForStatement :: 3207 // ForStatement ::
3140 // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement 3208 // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
3141 3209
3142 int stmt_pos = peek_position(); 3210 int stmt_pos = peek_position();
(...skipping 1867 matching lines...) Expand 10 before | Expand all | Expand 10 after
5010 5078
5011 // We cannot internalize on a background thread; a foreground task will take 5079 // We cannot internalize on a background thread; a foreground task will take
5012 // care of calling Parser::Internalize just before compilation. 5080 // care of calling Parser::Internalize just before compilation.
5013 5081
5014 if (compile_options() == ScriptCompiler::kProduceParserCache) { 5082 if (compile_options() == ScriptCompiler::kProduceParserCache) {
5015 if (result != NULL) *info_->cached_data() = recorder.GetScriptData(); 5083 if (result != NULL) *info_->cached_data() = recorder.GetScriptData();
5016 log_ = NULL; 5084 log_ = NULL;
5017 } 5085 }
5018 } 5086 }
5019 } } // namespace v8::internal 5087 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « no previous file | test/mjsunit/harmony/regress/regress-3683.js » ('j') | test/mjsunit/harmony/regress/regress-3683.js » ('J')

Powered by Google App Engine
This is Rietveld 408576698