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