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 3 // found in the LICENSE file. 4 5 #include "src/parsing/rewriter.h" 6 7 #include "src/ast/ast.h" 8 #include "src/ast/scopes.h" 9 #include "src/objects-inl.h" 10 #include "src/parsing/parse-info.h" 11 #include "src/parsing/parser.h" 12 13 namespace v8 { 14 namespace internal { 15 16 class Processor final : public AstVisitor<Processor> { 17 public: 18 Processor(uintptr_t stack_limit, DeclarationScope* closure_scope, 19 Variable* result, AstValueFactory* ast_value_factory) 20 : result_(result), 21 result_assigned_(false), 22 replacement_(nullptr), 23 is_set_(false), 24 breakable_(false), 25 zone_(ast_value_factory->zone()), 26 closure_scope_(closure_scope), 27 factory_(ast_value_factory) { 28 DCHECK_EQ(closure_scope, closure_scope->GetClosureScope()); 29 InitializeAstVisitor(stack_limit); 30 } 31 32 Processor(Parser* parser, DeclarationScope* closure_scope, Variable* result, 33 AstValueFactory* ast_value_factory) 34 : result_(result), 35 result_assigned_(false), 36 replacement_(nullptr), 37 is_set_(false), 38 breakable_(false), 39 zone_(ast_value_factory->zone()), 40 closure_scope_(closure_scope), 41 factory_(ast_value_factory) { 42 DCHECK_EQ(closure_scope, closure_scope->GetClosureScope()); 43 InitializeAstVisitor(parser->stack_limit()); 44 } 45 46 void Process(ZoneList<Statement*>* statements); 47 bool result_assigned() const { return result_assigned_; } 48 49 Zone* zone() { return zone_; } 50 DeclarationScope* closure_scope() { return closure_scope_; } 51 AstNodeFactory* factory() { return &factory_; } 52 53 // Returns ".result = value" 54 Expression* SetResult(Expression* value) { 55 result_assigned_ = true; 56 VariableProxy* result_proxy = factory()->NewVariableProxy(result_); 57 return factory()->NewAssignment(Token::ASSIGN, result_proxy, value, 58 kNoSourcePosition); 59 } 60 61 // Inserts '.result = undefined' in front of the given statement. 62 Statement* AssignUndefinedBefore(Statement* s); 63 64 private: 65 Variable* result_; 66 67 // We are not tracking result usage via the result_'s use 68 // counts (we leave the accurate computation to the 69 // usage analyzer). Instead we simple remember if 70 // there was ever an assignment to result_. 71 bool result_assigned_; 72 73 // When visiting a node, we "return" a replacement for that node in 74 // [replacement_]. In many cases this will just be the original node. 75 Statement* replacement_; 76 77 // To avoid storing to .result all the time, we eliminate some of 78 // the stores by keeping track of whether or not we're sure .result 79 // will be overwritten anyway. This is a bit more tricky than what I 80 // was hoping for. 81 bool is_set_; 82 83 bool breakable_; 84 85 class BreakableScope final { 86 public: 87 explicit BreakableScope(Processor* processor, bool breakable = true) 88 : processor_(processor), previous_(processor->breakable_) { 89 processor->breakable_ = processor->breakable_ || breakable; 90 } 91 92 ~BreakableScope() { processor_->breakable_ = previous_; } 93 94 private: 95 Processor* processor_; 96 bool previous_; 97 }; 98 99 Zone* zone_; 100 DeclarationScope* closure_scope_; 101 AstNodeFactory factory_; 102 103 // Node visitors. 104 #define DEF_VISIT(type) void Visit##type(type* node); 105 AST_NODE_LIST(DEF_VISIT) 106 #undef DEF_VISIT 107 108 void VisitIterationStatement(IterationStatement* stmt); 109 110 DEFINE_AST_VISITOR_SUBCLASS_MEMBERS(); 111 }; 112 113 114 Statement* Processor::AssignUndefinedBefore(Statement* s) { 115 Expression* result_proxy = factory()->NewVariableProxy(result_); 116 Expression* undef = factory()->NewUndefinedLiteral(kNoSourcePosition); 117 Expression* assignment = factory()->NewAssignment(Token::ASSIGN, result_proxy, 118 undef, kNoSourcePosition); 119 Block* b = factory()->NewBlock(NULL, 2, false, kNoSourcePosition); 120 b->statements()->Add( 121 factory()->NewExpressionStatement(assignment, kNoSourcePosition), zone()); 122 b->statements()->Add(s, zone()); 123 return b; 124 } 125 126 127 void Processor::Process(ZoneList<Statement*>* statements) { 128 // If we're in a breakable scope (named block, iteration, or switch), we walk 129 // all statements. The last value producing statement before the break needs 130 // to assign to .result. If we're not in a breakable scope, only the last 131 // value producing statement in the block assigns to .result, so we can stop 132 // early. 133 for (int i = statements->length() - 1; i >= 0 && (breakable_ || !is_set_); 134 --i) { 135 Visit(statements->at(i)); 136 statements->Set(i, replacement_); 137 } 138 } 139 140 141 void Processor::VisitBlock(Block* node) { 142 // An initializer block is the rewritten form of a variable declaration 143 // with initialization expressions. The initializer block contains the 144 // list of assignments corresponding to the initialization expressions. 145 // While unclear from the spec (ECMA-262, 3rd., 12.2), the value of 146 // a variable declaration with initialization expression is 'undefined' 147 // with some JS VMs: For instance, using smjs, print(eval('var x = 7')) 148 // returns 'undefined'. To obtain the same behavior with v8, we need 149 // to prevent rewriting in that case. 150 if (!node->ignore_completion_value()) { 151 BreakableScope scope(this, node->labels() != nullptr); 152 Process(node->statements()); 153 } 154 replacement_ = node; 155 } 156 157 158 void Processor::VisitExpressionStatement(ExpressionStatement* node) { 159 // Rewrite : <x>; -> .result = <x>; 160 if (!is_set_) { 161 node->set_expression(SetResult(node->expression())); 162 is_set_ = true; 163 } 164 replacement_ = node; 165 } 166 167 168 void Processor::VisitIfStatement(IfStatement* node) { 169 // Rewrite both branches. 170 bool set_after = is_set_; 171 172 Visit(node->then_statement()); 173 node->set_then_statement(replacement_); 174 bool set_in_then = is_set_; 175 176 is_set_ = set_after; 177 Visit(node->else_statement()); 178 node->set_else_statement(replacement_); 179 180 replacement_ = set_in_then && is_set_ ? node : AssignUndefinedBefore(node); 181 is_set_ = true; 182 } 183 184 185 void Processor::VisitIterationStatement(IterationStatement* node) { 186 // The statement may have to produce a value, so always assign undefined 187 // before. 188 // TODO(verwaest): Omit it if we know that there's no break/continue leaving 189 // it early. 190 DCHECK(breakable_ || !is_set_); 191 BreakableScope scope(this); 192 193 Visit(node->body()); 194 node->set_body(replacement_); 195 196 replacement_ = AssignUndefinedBefore(node); 197 is_set_ = true; 198 } 199 200 201 void Processor::VisitDoWhileStatement(DoWhileStatement* node) { 202 VisitIterationStatement(node); 203 } 204 205 206 void Processor::VisitWhileStatement(WhileStatement* node) { 207 VisitIterationStatement(node); 208 } 209 210 211 void Processor::VisitForStatement(ForStatement* node) { 212 VisitIterationStatement(node); 213 } 214 215 216 void Processor::VisitForInStatement(ForInStatement* node) { 217 VisitIterationStatement(node); 218 } 219 220 221 void Processor::VisitForOfStatement(ForOfStatement* node) { 222 VisitIterationStatement(node); 223 } 224 225 226 void Processor::VisitTryCatchStatement(TryCatchStatement* node) { 227 // Rewrite both try and catch block. 228 bool set_after = is_set_; 229 230 Visit(node->try_block()); 231 node->set_try_block(static_cast<Block*>(replacement_)); 232 bool set_in_try = is_set_; 233 234 is_set_ = set_after; 235 Visit(node->catch_block()); 236 node->set_catch_block(static_cast<Block*>(replacement_)); 237 238 replacement_ = is_set_ && set_in_try ? node : AssignUndefinedBefore(node); 239 is_set_ = true; 240 } 241 242 243 void Processor::VisitTryFinallyStatement(TryFinallyStatement* node) { 244 // Only rewrite finally if it could contain 'break' or 'continue'. Always 245 // rewrite try. 246 if (breakable_) { 247 // Only set result before a 'break' or 'continue'. 248 is_set_ = true; 249 Visit(node->finally_block()); 250 node->set_finally_block(replacement_->AsBlock()); 251 // Save .result value at the beginning of the finally block and restore it 252 // at the end again: ".backup = .result; ...; .result = .backup" 253 // This is necessary because the finally block does not normally contribute 254 // to the completion value. 255 CHECK_NOT_NULL(closure_scope()); 256 Variable* backup = closure_scope()->NewTemporary( 257 factory()->ast_value_factory()->dot_result_string()); 258 Expression* backup_proxy = factory()->NewVariableProxy(backup); 259 Expression* result_proxy = factory()->NewVariableProxy(result_); 260 Expression* save = factory()->NewAssignment( 261 Token::ASSIGN, backup_proxy, result_proxy, kNoSourcePosition); 262 Expression* restore = factory()->NewAssignment( 263 Token::ASSIGN, result_proxy, backup_proxy, kNoSourcePosition); 264 node->finally_block()->statements()->InsertAt( 265 0, factory()->NewExpressionStatement(save, kNoSourcePosition), zone()); 266 node->finally_block()->statements()->Add( 267 factory()->NewExpressionStatement(restore, kNoSourcePosition), zone()); 268 } 269 Visit(node->try_block()); 270 node->set_try_block(replacement_->AsBlock()); 271 272 replacement_ = is_set_ ? node : AssignUndefinedBefore(node); 273 is_set_ = true; 274 } 275 276 277 void Processor::VisitSwitchStatement(SwitchStatement* node) { 278 // The statement may have to produce a value, so always assign undefined 279 // before. 280 // TODO(verwaest): Omit it if we know that there's no break/continue leaving 281 // it early. 282 DCHECK(breakable_ || !is_set_); 283 BreakableScope scope(this); 284 // Rewrite statements in all case clauses. 285 ZoneList<CaseClause*>* clauses = node->cases(); 286 for (int i = clauses->length() - 1; i >= 0; --i) { 287 CaseClause* clause = clauses->at(i); 288 Process(clause->statements()); 289 } 290 291 replacement_ = AssignUndefinedBefore(node); 292 is_set_ = true; 293 } 294 295 296 void Processor::VisitContinueStatement(ContinueStatement* node) { 297 is_set_ = false; 298 replacement_ = node; 299 } 300 301 302 void Processor::VisitBreakStatement(BreakStatement* node) { 303 is_set_ = false; 304 replacement_ = node; 305 } 306 307 308 void Processor::VisitWithStatement(WithStatement* node) { 309 Visit(node->statement()); 310 node->set_statement(replacement_); 311 312 replacement_ = is_set_ ? node : AssignUndefinedBefore(node); 313 is_set_ = true; 314 } 315 316 317 void Processor::VisitSloppyBlockFunctionStatement( 318 SloppyBlockFunctionStatement* node) { 319 Visit(node->statement()); 320 node->set_statement(replacement_); 321 replacement_ = node; 322 } 323 324 325 void Processor::VisitEmptyStatement(EmptyStatement* node) { 326 replacement_ = node; 327 } 328 329 330 void Processor::VisitReturnStatement(ReturnStatement* node) { 331 is_set_ = true; 332 replacement_ = node; 333 } 334 335 336 void Processor::VisitDebuggerStatement(DebuggerStatement* node) { 337 replacement_ = node; 338 } 339 340 341 // Expressions are never visited. 342 #define DEF_VISIT(type) \ 343 void Processor::Visit##type(type* expr) { UNREACHABLE(); } 344 EXPRESSION_NODE_LIST(DEF_VISIT) 345 #undef DEF_VISIT 346 347 348 // Declarations are never visited. 349 #define DEF_VISIT(type) \ 350 void Processor::Visit##type(type* expr) { UNREACHABLE(); } 351 DECLARATION_NODE_LIST(DEF_VISIT) 352 #undef DEF_VISIT 353 354 355 // Assumes code has been parsed. Mutates the AST, so the AST should not 356 // continue to be used in the case of failure. 357 bool Rewriter::Rewrite(ParseInfo* info) { 358 DisallowHeapAllocation no_allocation; 359 DisallowHandleAllocation no_handles; 360 DisallowHandleDereference no_deref; 361 362 RuntimeCallTimerScope runtimeTimer( 363 info->isolate(), &RuntimeCallStats::CompileRewriteReturnResult); 364 365 FunctionLiteral* function = info->literal(); 366 DCHECK_NOT_NULL(function); 367 Scope* scope = function->scope(); 368 DCHECK_NOT_NULL(scope); 369 if (!scope->is_script_scope() && !scope->is_eval_scope()) return true; 370 371 DeclarationScope* closure_scope = scope->GetClosureScope(); 372 373 ZoneList<Statement*>* body = function->body(); 374 if (!body->is_empty()) { 375 Variable* result = closure_scope->NewTemporary( 376 info->ast_value_factory()->dot_result_string()); 377 Processor processor(info->isolate()->stack_guard()->real_climit(), 378 closure_scope, result, info->ast_value_factory()); 379 processor.Process(body); 380 381 // TODO(leszeks): Remove this check and releases once internalization is 382 // moved out of parsing/analysis. 383 DCHECK(ThreadId::Current().Equals(info->isolate()->thread_id())); 384 no_deref.Release(); 385 no_handles.Release(); 386 no_allocation.Release(); 387 388 // Internalize any values created during rewriting. 389 info->ast_value_factory()->Internalize(info->isolate()); 390 if (processor.HasStackOverflow()) return false; 391 392 if (processor.result_assigned()) { 393 int pos = kNoSourcePosition; 394 VariableProxy* result_proxy = 395 processor.factory()->NewVariableProxy(result, pos); 396 Statement* result_statement = 397 processor.factory()->NewReturnStatement(result_proxy, pos); 398 body->Add(result_statement, info->zone()); 399 } 400 } 401 402 return true; 403 } 404 405 bool Rewriter::Rewrite(Parser* parser, DeclarationScope* closure_scope, 406 DoExpression* expr, AstValueFactory* factory) { 407 DisallowHeapAllocation no_allocation; 408 DisallowHandleAllocation no_handles; 409 DisallowHandleDereference no_deref; 410 411 Block* block = expr->block(); 412 DCHECK_EQ(closure_scope, closure_scope->GetClosureScope()); 413 DCHECK(block->scope() == nullptr || 414 block->scope()->GetClosureScope() == closure_scope); 415 ZoneList<Statement*>* body = block->statements(); 416 VariableProxy* result = expr->result(); 417 Variable* result_var = result->var(); 418 419 if (!body->is_empty()) { 420 Processor processor(parser, closure_scope, result_var, factory); 421 processor.Process(body); 422 if (processor.HasStackOverflow()) return false; 423 424 if (!processor.result_assigned()) { 425 AstNodeFactory* node_factory = processor.factory(); 426 Expression* undef = node_factory->NewUndefinedLiteral(kNoSourcePosition); 427 Statement* completion = node_factory->NewExpressionStatement( 428 processor.SetResult(undef), expr->position()); 429 body->Add(completion, factory->zone()); 430 } 431 } 432 return true; 433 } 434 435 436 } // namespace internal 437 } // namespace v8 438