1// Copyright 2011 the V8 project authors. All rights reserved. 2// Redistribution and use in source and binary forms, with or without 3// modification, are permitted provided that the following conditions are 4// met: 5// 6// * Redistributions of source code must retain the above copyright 7// notice, this list of conditions and the following disclaimer. 8// * Redistributions in binary form must reproduce the above 9// copyright notice, this list of conditions and the following 10// disclaimer in the documentation and/or other materials provided 11// with the distribution. 12// * Neither the name of Google Inc. nor the names of its 13// contributors may be used to endorse or promote products derived 14// from this software without specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28#include "v8.h" 29 30#include "rewriter.h" 31 32#include "ast.h" 33#include "compiler.h" 34#include "scopes.h" 35 36namespace v8 { 37namespace internal { 38 39class Processor: public AstVisitor { 40 public: 41 explicit Processor(Variable* result) 42 : result_(result), 43 result_assigned_(false), 44 is_set_(false), 45 in_try_(false) { 46 } 47 48 void Process(ZoneList<Statement*>* statements); 49 bool result_assigned() const { return result_assigned_; } 50 51 private: 52 Variable* result_; 53 54 // We are not tracking result usage via the result_'s use 55 // counts (we leave the accurate computation to the 56 // usage analyzer). Instead we simple remember if 57 // there was ever an assignment to result_. 58 bool result_assigned_; 59 60 // To avoid storing to .result all the time, we eliminate some of 61 // the stores by keeping track of whether or not we're sure .result 62 // will be overwritten anyway. This is a bit more tricky than what I 63 // was hoping for 64 bool is_set_; 65 bool in_try_; 66 67 Expression* SetResult(Expression* value) { 68 result_assigned_ = true; 69 VariableProxy* result_proxy = new VariableProxy(result_); 70 return new Assignment(Token::ASSIGN, result_proxy, value, 71 RelocInfo::kNoPosition); 72 } 73 74 // Node visitors. 75#define DEF_VISIT(type) \ 76 virtual void Visit##type(type* node); 77 AST_NODE_LIST(DEF_VISIT) 78#undef DEF_VISIT 79 80 void VisitIterationStatement(IterationStatement* stmt); 81}; 82 83 84void Processor::Process(ZoneList<Statement*>* statements) { 85 for (int i = statements->length() - 1; i >= 0; --i) { 86 Visit(statements->at(i)); 87 } 88} 89 90 91void Processor::VisitBlock(Block* node) { 92 // An initializer block is the rewritten form of a variable declaration 93 // with initialization expressions. The initializer block contains the 94 // list of assignments corresponding to the initialization expressions. 95 // While unclear from the spec (ECMA-262, 3rd., 12.2), the value of 96 // a variable declaration with initialization expression is 'undefined' 97 // with some JS VMs: For instance, using smjs, print(eval('var x = 7')) 98 // returns 'undefined'. To obtain the same behavior with v8, we need 99 // to prevent rewriting in that case. 100 if (!node->is_initializer_block()) Process(node->statements()); 101} 102 103 104void Processor::VisitExpressionStatement(ExpressionStatement* node) { 105 // Rewrite : <x>; -> .result = <x>; 106 if (!is_set_) { 107 node->set_expression(SetResult(node->expression())); 108 if (!in_try_) is_set_ = true; 109 } 110} 111 112 113void Processor::VisitIfStatement(IfStatement* node) { 114 // Rewrite both then and else parts (reversed). 115 bool save = is_set_; 116 Visit(node->else_statement()); 117 bool set_after_then = is_set_; 118 is_set_ = save; 119 Visit(node->then_statement()); 120 is_set_ = is_set_ && set_after_then; 121} 122 123 124void Processor::VisitIterationStatement(IterationStatement* node) { 125 // Rewrite the body. 126 bool set_after_loop = is_set_; 127 Visit(node->body()); 128 is_set_ = is_set_ && set_after_loop; 129} 130 131 132void Processor::VisitDoWhileStatement(DoWhileStatement* node) { 133 VisitIterationStatement(node); 134} 135 136 137void Processor::VisitWhileStatement(WhileStatement* node) { 138 VisitIterationStatement(node); 139} 140 141 142void Processor::VisitForStatement(ForStatement* node) { 143 VisitIterationStatement(node); 144} 145 146 147void Processor::VisitForInStatement(ForInStatement* node) { 148 VisitIterationStatement(node); 149} 150 151 152void Processor::VisitTryCatchStatement(TryCatchStatement* node) { 153 // Rewrite both try and catch blocks (reversed order). 154 bool set_after_catch = is_set_; 155 Visit(node->catch_block()); 156 is_set_ = is_set_ && set_after_catch; 157 bool save = in_try_; 158 in_try_ = true; 159 Visit(node->try_block()); 160 in_try_ = save; 161} 162 163 164void Processor::VisitTryFinallyStatement(TryFinallyStatement* node) { 165 // Rewrite both try and finally block (reversed order). 166 Visit(node->finally_block()); 167 bool save = in_try_; 168 in_try_ = true; 169 Visit(node->try_block()); 170 in_try_ = save; 171} 172 173 174void Processor::VisitSwitchStatement(SwitchStatement* node) { 175 // Rewrite statements in all case clauses in reversed order. 176 ZoneList<CaseClause*>* clauses = node->cases(); 177 bool set_after_switch = is_set_; 178 for (int i = clauses->length() - 1; i >= 0; --i) { 179 CaseClause* clause = clauses->at(i); 180 Process(clause->statements()); 181 } 182 is_set_ = is_set_ && set_after_switch; 183} 184 185 186void Processor::VisitContinueStatement(ContinueStatement* node) { 187 is_set_ = false; 188} 189 190 191void Processor::VisitBreakStatement(BreakStatement* node) { 192 is_set_ = false; 193} 194 195 196// Do nothing: 197void Processor::VisitDeclaration(Declaration* node) {} 198void Processor::VisitEmptyStatement(EmptyStatement* node) {} 199void Processor::VisitReturnStatement(ReturnStatement* node) {} 200void Processor::VisitWithEnterStatement(WithEnterStatement* node) {} 201void Processor::VisitWithExitStatement(WithExitStatement* node) {} 202void Processor::VisitDebuggerStatement(DebuggerStatement* node) {} 203 204 205// Expressions are never visited yet. 206void Processor::VisitFunctionLiteral(FunctionLiteral* node) { 207 USE(node); 208 UNREACHABLE(); 209} 210 211 212void Processor::VisitSharedFunctionInfoLiteral( 213 SharedFunctionInfoLiteral* node) { 214 USE(node); 215 UNREACHABLE(); 216} 217 218 219void Processor::VisitConditional(Conditional* node) { 220 USE(node); 221 UNREACHABLE(); 222} 223 224 225void Processor::VisitVariableProxy(VariableProxy* node) { 226 USE(node); 227 UNREACHABLE(); 228} 229 230 231void Processor::VisitLiteral(Literal* node) { 232 USE(node); 233 UNREACHABLE(); 234} 235 236 237void Processor::VisitRegExpLiteral(RegExpLiteral* node) { 238 USE(node); 239 UNREACHABLE(); 240} 241 242 243void Processor::VisitArrayLiteral(ArrayLiteral* node) { 244 USE(node); 245 UNREACHABLE(); 246} 247 248 249void Processor::VisitObjectLiteral(ObjectLiteral* node) { 250 USE(node); 251 UNREACHABLE(); 252} 253 254 255void Processor::VisitCatchExtensionObject(CatchExtensionObject* node) { 256 USE(node); 257 UNREACHABLE(); 258} 259 260 261void Processor::VisitAssignment(Assignment* node) { 262 USE(node); 263 UNREACHABLE(); 264} 265 266 267void Processor::VisitThrow(Throw* node) { 268 USE(node); 269 UNREACHABLE(); 270} 271 272 273void Processor::VisitProperty(Property* node) { 274 USE(node); 275 UNREACHABLE(); 276} 277 278 279void Processor::VisitCall(Call* node) { 280 USE(node); 281 UNREACHABLE(); 282} 283 284 285void Processor::VisitCallNew(CallNew* node) { 286 USE(node); 287 UNREACHABLE(); 288} 289 290 291void Processor::VisitCallRuntime(CallRuntime* node) { 292 USE(node); 293 UNREACHABLE(); 294} 295 296 297void Processor::VisitUnaryOperation(UnaryOperation* node) { 298 USE(node); 299 UNREACHABLE(); 300} 301 302 303void Processor::VisitCountOperation(CountOperation* node) { 304 USE(node); 305 UNREACHABLE(); 306} 307 308 309void Processor::VisitBinaryOperation(BinaryOperation* node) { 310 USE(node); 311 UNREACHABLE(); 312} 313 314 315void Processor::VisitCompareOperation(CompareOperation* node) { 316 USE(node); 317 UNREACHABLE(); 318} 319 320 321void Processor::VisitCompareToNull(CompareToNull* node) { 322 USE(node); 323 UNREACHABLE(); 324} 325 326 327void Processor::VisitThisFunction(ThisFunction* node) { 328 USE(node); 329 UNREACHABLE(); 330} 331 332 333// Assumes code has been parsed and scopes have been analyzed. Mutates the 334// AST, so the AST should not continue to be used in the case of failure. 335bool Rewriter::Rewrite(CompilationInfo* info) { 336 FunctionLiteral* function = info->function(); 337 ASSERT(function != NULL); 338 Scope* scope = function->scope(); 339 ASSERT(scope != NULL); 340 if (scope->is_function_scope()) return true; 341 342 ZoneList<Statement*>* body = function->body(); 343 if (!body->is_empty()) { 344 Variable* result = scope->NewTemporary( 345 info->isolate()->factory()->result_symbol()); 346 Processor processor(result); 347 processor.Process(body); 348 if (processor.HasStackOverflow()) return false; 349 350 if (processor.result_assigned()) { 351 VariableProxy* result_proxy = new VariableProxy(result); 352 body->Add(new ReturnStatement(result_proxy)); 353 } 354 } 355 356 return true; 357} 358 359 360} } // namespace v8::internal 361