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/v8.h" 6 7 #include "src/rewriter.h" 8 9 #include "src/ast.h" 10 #include "src/compiler.h" 11 #include "src/scopes.h" 12 13 namespace v8 { 14 namespace internal { 15 16 class Processor: public AstVisitor { 17 public: 18 Processor(Variable* result, Zone* zone, AstNode::IdGen* ast_node_id_gen) 19 : result_(result), 20 result_assigned_(false), 21 is_set_(false), 22 in_try_(false), 23 // Passing a null AstValueFactory is fine, because Processor doesn't 24 // need to create strings or literals. 25 factory_(zone, NULL, ast_node_id_gen) { 26 InitializeAstVisitor(zone); 27 } 28 29 virtual ~Processor() { } 30 31 void Process(ZoneList<Statement*>* statements); 32 bool result_assigned() const { return result_assigned_; } 33 34 AstNodeFactory<AstNullVisitor>* factory() { 35 return &factory_; 36 } 37 38 private: 39 Variable* result_; 40 41 // We are not tracking result usage via the result_'s use 42 // counts (we leave the accurate computation to the 43 // usage analyzer). Instead we simple remember if 44 // there was ever an assignment to result_. 45 bool result_assigned_; 46 47 // To avoid storing to .result all the time, we eliminate some of 48 // the stores by keeping track of whether or not we're sure .result 49 // will be overwritten anyway. This is a bit more tricky than what I 50 // was hoping for 51 bool is_set_; 52 bool in_try_; 53 54 AstNodeFactory<AstNullVisitor> factory_; 55 56 Expression* SetResult(Expression* value) { 57 result_assigned_ = true; 58 VariableProxy* result_proxy = factory()->NewVariableProxy(result_); 59 return factory()->NewAssignment( 60 Token::ASSIGN, result_proxy, value, RelocInfo::kNoPosition); 61 } 62 63 // Node visitors. 64 #define DEF_VISIT(type) \ 65 virtual void Visit##type(type* node); 66 AST_NODE_LIST(DEF_VISIT) 67 #undef DEF_VISIT 68 69 void VisitIterationStatement(IterationStatement* stmt); 70 71 DEFINE_AST_VISITOR_SUBCLASS_MEMBERS(); 72 }; 73 74 75 void Processor::Process(ZoneList<Statement*>* statements) { 76 for (int i = statements->length() - 1; i >= 0; --i) { 77 Visit(statements->at(i)); 78 } 79 } 80 81 82 void Processor::VisitBlock(Block* node) { 83 // An initializer block is the rewritten form of a variable declaration 84 // with initialization expressions. The initializer block contains the 85 // list of assignments corresponding to the initialization expressions. 86 // While unclear from the spec (ECMA-262, 3rd., 12.2), the value of 87 // a variable declaration with initialization expression is 'undefined' 88 // with some JS VMs: For instance, using smjs, print(eval('var x = 7')) 89 // returns 'undefined'. To obtain the same behavior with v8, we need 90 // to prevent rewriting in that case. 91 if (!node->is_initializer_block()) Process(node->statements()); 92 } 93 94 95 void Processor::VisitModuleStatement(ModuleStatement* node) { 96 bool set_after_body = is_set_; 97 Visit(node->body()); 98 is_set_ = is_set_ && set_after_body; 99 } 100 101 102 void Processor::VisitExpressionStatement(ExpressionStatement* node) { 103 // Rewrite : <x>; -> .result = <x>; 104 if (!is_set_ && !node->expression()->IsThrow()) { 105 node->set_expression(SetResult(node->expression())); 106 if (!in_try_) is_set_ = true; 107 } 108 } 109 110 111 void Processor::VisitIfStatement(IfStatement* node) { 112 // Rewrite both then and else parts (reversed). 113 bool save = is_set_; 114 Visit(node->else_statement()); 115 bool set_after_then = is_set_; 116 is_set_ = save; 117 Visit(node->then_statement()); 118 is_set_ = is_set_ && set_after_then; 119 } 120 121 122 void Processor::VisitIterationStatement(IterationStatement* node) { 123 // Rewrite the body. 124 bool set_after_loop = is_set_; 125 Visit(node->body()); 126 is_set_ = is_set_ && set_after_loop; 127 } 128 129 130 void Processor::VisitDoWhileStatement(DoWhileStatement* node) { 131 VisitIterationStatement(node); 132 } 133 134 135 void Processor::VisitWhileStatement(WhileStatement* node) { 136 VisitIterationStatement(node); 137 } 138 139 140 void Processor::VisitForStatement(ForStatement* node) { 141 VisitIterationStatement(node); 142 } 143 144 145 void Processor::VisitForInStatement(ForInStatement* node) { 146 VisitIterationStatement(node); 147 } 148 149 150 void Processor::VisitForOfStatement(ForOfStatement* node) { 151 VisitIterationStatement(node); 152 } 153 154 155 void Processor::VisitTryCatchStatement(TryCatchStatement* node) { 156 // Rewrite both try and catch blocks (reversed order). 157 bool set_after_catch = is_set_; 158 Visit(node->catch_block()); 159 is_set_ = is_set_ && set_after_catch; 160 bool save = in_try_; 161 in_try_ = true; 162 Visit(node->try_block()); 163 in_try_ = save; 164 } 165 166 167 void Processor::VisitTryFinallyStatement(TryFinallyStatement* node) { 168 // Rewrite both try and finally block (reversed order). 169 Visit(node->finally_block()); 170 bool save = in_try_; 171 in_try_ = true; 172 Visit(node->try_block()); 173 in_try_ = save; 174 } 175 176 177 void Processor::VisitSwitchStatement(SwitchStatement* node) { 178 // Rewrite statements in all case clauses in reversed order. 179 ZoneList<CaseClause*>* clauses = node->cases(); 180 bool set_after_switch = is_set_; 181 for (int i = clauses->length() - 1; i >= 0; --i) { 182 CaseClause* clause = clauses->at(i); 183 Process(clause->statements()); 184 } 185 is_set_ = is_set_ && set_after_switch; 186 } 187 188 189 void Processor::VisitContinueStatement(ContinueStatement* node) { 190 is_set_ = false; 191 } 192 193 194 void Processor::VisitBreakStatement(BreakStatement* node) { 195 is_set_ = false; 196 } 197 198 199 void Processor::VisitWithStatement(WithStatement* node) { 200 bool set_after_body = is_set_; 201 Visit(node->statement()); 202 is_set_ = is_set_ && set_after_body; 203 } 204 205 206 // Do nothing: 207 void Processor::VisitVariableDeclaration(VariableDeclaration* node) {} 208 void Processor::VisitFunctionDeclaration(FunctionDeclaration* node) {} 209 void Processor::VisitModuleDeclaration(ModuleDeclaration* node) {} 210 void Processor::VisitImportDeclaration(ImportDeclaration* node) {} 211 void Processor::VisitExportDeclaration(ExportDeclaration* node) {} 212 void Processor::VisitModuleLiteral(ModuleLiteral* node) {} 213 void Processor::VisitModuleVariable(ModuleVariable* node) {} 214 void Processor::VisitModulePath(ModulePath* node) {} 215 void Processor::VisitModuleUrl(ModuleUrl* node) {} 216 void Processor::VisitEmptyStatement(EmptyStatement* node) {} 217 void Processor::VisitReturnStatement(ReturnStatement* node) {} 218 void Processor::VisitDebuggerStatement(DebuggerStatement* node) {} 219 220 221 // Expressions are never visited yet. 222 #define DEF_VISIT(type) \ 223 void Processor::Visit##type(type* expr) { UNREACHABLE(); } 224 EXPRESSION_NODE_LIST(DEF_VISIT) 225 #undef DEF_VISIT 226 227 228 // Assumes code has been parsed. Mutates the AST, so the AST should not 229 // continue to be used in the case of failure. 230 bool Rewriter::Rewrite(CompilationInfo* info) { 231 FunctionLiteral* function = info->function(); 232 DCHECK(function != NULL); 233 Scope* scope = function->scope(); 234 DCHECK(scope != NULL); 235 if (!scope->is_global_scope() && !scope->is_eval_scope()) return true; 236 237 ZoneList<Statement*>* body = function->body(); 238 if (!body->is_empty()) { 239 Variable* result = 240 scope->NewTemporary(info->ast_value_factory()->dot_result_string()); 241 // The name string must be internalized at this point. 242 DCHECK(!result->name().is_null()); 243 Processor processor(result, info->zone(), info->ast_node_id_gen()); 244 processor.Process(body); 245 if (processor.HasStackOverflow()) return false; 246 247 if (processor.result_assigned()) { 248 DCHECK(function->end_position() != RelocInfo::kNoPosition); 249 // Set the position of the assignment statement one character past the 250 // source code, such that it definitely is not in the source code range 251 // of an immediate inner scope. For example in 252 // eval('with ({x:1}) x = 1'); 253 // the end position of the function generated for executing the eval code 254 // coincides with the end of the with scope which is the position of '1'. 255 int pos = function->end_position(); 256 VariableProxy* result_proxy = processor.factory()->NewVariableProxy( 257 result->raw_name(), false, result->interface(), pos); 258 result_proxy->BindTo(result); 259 Statement* result_statement = 260 processor.factory()->NewReturnStatement(result_proxy, pos); 261 body->Add(result_statement, info->zone()); 262 } 263 } 264 265 return true; 266 } 267 268 269 } } // namespace v8::internal 270