1 // Copyright 2009 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 #ifndef V8_FULL_CODEGEN_H_ 29 #define V8_FULL_CODEGEN_H_ 30 31 #include "v8.h" 32 33 #include "ast.h" 34 35 namespace v8 { 36 namespace internal { 37 38 class FullCodeGenSyntaxChecker: public AstVisitor { 39 public: FullCodeGenSyntaxChecker()40 FullCodeGenSyntaxChecker() : has_supported_syntax_(true) {} 41 42 void Check(FunctionLiteral* fun); 43 has_supported_syntax()44 bool has_supported_syntax() { return has_supported_syntax_; } 45 46 private: 47 void VisitDeclarations(ZoneList<Declaration*>* decls); 48 void VisitStatements(ZoneList<Statement*>* stmts); 49 50 // AST node visit functions. 51 #define DECLARE_VISIT(type) virtual void Visit##type(type* node); 52 AST_NODE_LIST(DECLARE_VISIT) 53 #undef DECLARE_VISIT 54 55 bool has_supported_syntax_; 56 57 DISALLOW_COPY_AND_ASSIGN(FullCodeGenSyntaxChecker); 58 }; 59 60 61 // ----------------------------------------------------------------------------- 62 // Full code generator. 63 64 class FullCodeGenerator: public AstVisitor { 65 public: 66 enum Mode { 67 PRIMARY, 68 SECONDARY 69 }; 70 FullCodeGenerator(MacroAssembler * masm)71 explicit FullCodeGenerator(MacroAssembler* masm) 72 : masm_(masm), 73 info_(NULL), 74 nesting_stack_(NULL), 75 loop_depth_(0), 76 location_(kStack), 77 true_label_(NULL), 78 false_label_(NULL) { 79 } 80 81 static Handle<Code> MakeCode(CompilationInfo* info); 82 83 void Generate(CompilationInfo* info, Mode mode); 84 85 private: 86 class Breakable; 87 class Iteration; 88 class TryCatch; 89 class TryFinally; 90 class Finally; 91 class ForIn; 92 93 class NestedStatement BASE_EMBEDDED { 94 public: NestedStatement(FullCodeGenerator * codegen)95 explicit NestedStatement(FullCodeGenerator* codegen) : codegen_(codegen) { 96 // Link into codegen's nesting stack. 97 previous_ = codegen->nesting_stack_; 98 codegen->nesting_stack_ = this; 99 } ~NestedStatement()100 virtual ~NestedStatement() { 101 // Unlink from codegen's nesting stack. 102 ASSERT_EQ(this, codegen_->nesting_stack_); 103 codegen_->nesting_stack_ = previous_; 104 } 105 AsBreakable()106 virtual Breakable* AsBreakable() { return NULL; } AsIteration()107 virtual Iteration* AsIteration() { return NULL; } AsTryCatch()108 virtual TryCatch* AsTryCatch() { return NULL; } AsTryFinally()109 virtual TryFinally* AsTryFinally() { return NULL; } AsFinally()110 virtual Finally* AsFinally() { return NULL; } AsForIn()111 virtual ForIn* AsForIn() { return NULL; } 112 IsContinueTarget(Statement * target)113 virtual bool IsContinueTarget(Statement* target) { return false; } IsBreakTarget(Statement * target)114 virtual bool IsBreakTarget(Statement* target) { return false; } 115 116 // Generate code to leave the nested statement. This includes 117 // cleaning up any stack elements in use and restoring the 118 // stack to the expectations of the surrounding statements. 119 // Takes a number of stack elements currently on top of the 120 // nested statement's stack, and returns a number of stack 121 // elements left on top of the surrounding statement's stack. 122 // The generated code must preserve the result register (which 123 // contains the value in case of a return). Exit(int stack_depth)124 virtual int Exit(int stack_depth) { 125 // Default implementation for the case where there is 126 // nothing to clean up. 127 return stack_depth; 128 } outer()129 NestedStatement* outer() { return previous_; } 130 protected: masm()131 MacroAssembler* masm() { return codegen_->masm(); } 132 private: 133 FullCodeGenerator* codegen_; 134 NestedStatement* previous_; 135 DISALLOW_COPY_AND_ASSIGN(NestedStatement); 136 }; 137 138 class Breakable : public NestedStatement { 139 public: Breakable(FullCodeGenerator * codegen,BreakableStatement * break_target)140 Breakable(FullCodeGenerator* codegen, 141 BreakableStatement* break_target) 142 : NestedStatement(codegen), 143 target_(break_target) {} ~Breakable()144 virtual ~Breakable() {} AsBreakable()145 virtual Breakable* AsBreakable() { return this; } IsBreakTarget(Statement * statement)146 virtual bool IsBreakTarget(Statement* statement) { 147 return target_ == statement; 148 } statement()149 BreakableStatement* statement() { return target_; } break_target()150 Label* break_target() { return &break_target_label_; } 151 private: 152 BreakableStatement* target_; 153 Label break_target_label_; 154 DISALLOW_COPY_AND_ASSIGN(Breakable); 155 }; 156 157 class Iteration : public Breakable { 158 public: Iteration(FullCodeGenerator * codegen,IterationStatement * iteration_statement)159 Iteration(FullCodeGenerator* codegen, 160 IterationStatement* iteration_statement) 161 : Breakable(codegen, iteration_statement) {} ~Iteration()162 virtual ~Iteration() {} AsIteration()163 virtual Iteration* AsIteration() { return this; } IsContinueTarget(Statement * statement)164 virtual bool IsContinueTarget(Statement* statement) { 165 return this->statement() == statement; 166 } continue_target()167 Label* continue_target() { return &continue_target_label_; } 168 private: 169 Label continue_target_label_; 170 DISALLOW_COPY_AND_ASSIGN(Iteration); 171 }; 172 173 // The environment inside the try block of a try/catch statement. 174 class TryCatch : public NestedStatement { 175 public: TryCatch(FullCodeGenerator * codegen,Label * catch_entry)176 explicit TryCatch(FullCodeGenerator* codegen, Label* catch_entry) 177 : NestedStatement(codegen), catch_entry_(catch_entry) { } ~TryCatch()178 virtual ~TryCatch() {} AsTryCatch()179 virtual TryCatch* AsTryCatch() { return this; } catch_entry()180 Label* catch_entry() { return catch_entry_; } 181 virtual int Exit(int stack_depth); 182 private: 183 Label* catch_entry_; 184 DISALLOW_COPY_AND_ASSIGN(TryCatch); 185 }; 186 187 // The environment inside the try block of a try/finally statement. 188 class TryFinally : public NestedStatement { 189 public: TryFinally(FullCodeGenerator * codegen,Label * finally_entry)190 explicit TryFinally(FullCodeGenerator* codegen, Label* finally_entry) 191 : NestedStatement(codegen), finally_entry_(finally_entry) { } ~TryFinally()192 virtual ~TryFinally() {} AsTryFinally()193 virtual TryFinally* AsTryFinally() { return this; } finally_entry()194 Label* finally_entry() { return finally_entry_; } 195 virtual int Exit(int stack_depth); 196 private: 197 Label* finally_entry_; 198 DISALLOW_COPY_AND_ASSIGN(TryFinally); 199 }; 200 201 // A FinallyEnvironment represents being inside a finally block. 202 // Abnormal termination of the finally block needs to clean up 203 // the block's parameters from the stack. 204 class Finally : public NestedStatement { 205 public: Finally(FullCodeGenerator * codegen)206 explicit Finally(FullCodeGenerator* codegen) : NestedStatement(codegen) { } ~Finally()207 virtual ~Finally() {} AsFinally()208 virtual Finally* AsFinally() { return this; } Exit(int stack_depth)209 virtual int Exit(int stack_depth) { 210 return stack_depth + kFinallyStackElementCount; 211 } 212 private: 213 // Number of extra stack slots occupied during a finally block. 214 static const int kFinallyStackElementCount = 2; 215 DISALLOW_COPY_AND_ASSIGN(Finally); 216 }; 217 218 // A ForInEnvironment represents being inside a for-in loop. 219 // Abnormal termination of the for-in block needs to clean up 220 // the block's temporary storage from the stack. 221 class ForIn : public Iteration { 222 public: ForIn(FullCodeGenerator * codegen,ForInStatement * statement)223 ForIn(FullCodeGenerator* codegen, 224 ForInStatement* statement) 225 : Iteration(codegen, statement) { } ~ForIn()226 virtual ~ForIn() {} AsForIn()227 virtual ForIn* AsForIn() { return this; } Exit(int stack_depth)228 virtual int Exit(int stack_depth) { 229 return stack_depth + kForInStackElementCount; 230 } 231 private: 232 // TODO(lrn): Check that this value is correct when implementing 233 // for-in. 234 static const int kForInStackElementCount = 5; 235 DISALLOW_COPY_AND_ASSIGN(ForIn); 236 }; 237 238 enum Location { 239 kAccumulator, 240 kStack 241 }; 242 243 int SlotOffset(Slot* slot); 244 245 // Emit code to convert a pure value (in a register, slot, as a literal, 246 // or on top of the stack) into the result expected according to an 247 // expression context. 248 void Apply(Expression::Context context, Register reg); 249 250 // Slot cannot have type Slot::LOOKUP. 251 void Apply(Expression::Context context, Slot* slot); 252 253 void Apply(Expression::Context context, Literal* lit); 254 void ApplyTOS(Expression::Context context); 255 256 // Emit code to discard count elements from the top of stack, then convert 257 // a pure value into the result expected according to an expression 258 // context. 259 void DropAndApply(int count, Expression::Context context, Register reg); 260 261 // Emit code to convert pure control flow to a pair of labels into the 262 // result expected according to an expression context. 263 void Apply(Expression::Context context, 264 Label* materialize_true, 265 Label* materialize_false); 266 267 // Helper function to convert a pure value into a test context. The value 268 // is expected on the stack or the accumulator, depending on the platform. 269 // See the platform-specific implementation for details. 270 void DoTest(Expression::Context context); 271 272 void Move(Slot* dst, Register source, Register scratch1, Register scratch2); 273 void Move(Register dst, Slot* source); 274 275 // Return an operand used to read/write to a known (ie, non-LOOKUP) slot. 276 // May emit code to traverse the context chain, destroying the scratch 277 // register. 278 MemOperand EmitSlotSearch(Slot* slot, Register scratch); 279 VisitForEffect(Expression * expr)280 void VisitForEffect(Expression* expr) { 281 Expression::Context saved_context = context_; 282 context_ = Expression::kEffect; 283 Visit(expr); 284 context_ = saved_context; 285 } 286 VisitForValue(Expression * expr,Location where)287 void VisitForValue(Expression* expr, Location where) { 288 Expression::Context saved_context = context_; 289 Location saved_location = location_; 290 context_ = Expression::kValue; 291 location_ = where; 292 Visit(expr); 293 context_ = saved_context; 294 location_ = saved_location; 295 } 296 VisitForControl(Expression * expr,Label * if_true,Label * if_false)297 void VisitForControl(Expression* expr, Label* if_true, Label* if_false) { 298 Expression::Context saved_context = context_; 299 Label* saved_true = true_label_; 300 Label* saved_false = false_label_; 301 context_ = Expression::kTest; 302 true_label_ = if_true; 303 false_label_ = if_false; 304 Visit(expr); 305 context_ = saved_context; 306 true_label_ = saved_true; 307 false_label_ = saved_false; 308 } 309 VisitForValueControl(Expression * expr,Location where,Label * if_true,Label * if_false)310 void VisitForValueControl(Expression* expr, 311 Location where, 312 Label* if_true, 313 Label* if_false) { 314 Expression::Context saved_context = context_; 315 Location saved_location = location_; 316 Label* saved_true = true_label_; 317 Label* saved_false = false_label_; 318 context_ = Expression::kValueTest; 319 location_ = where; 320 true_label_ = if_true; 321 false_label_ = if_false; 322 Visit(expr); 323 context_ = saved_context; 324 location_ = saved_location; 325 true_label_ = saved_true; 326 false_label_ = saved_false; 327 } 328 VisitForControlValue(Expression * expr,Location where,Label * if_true,Label * if_false)329 void VisitForControlValue(Expression* expr, 330 Location where, 331 Label* if_true, 332 Label* if_false) { 333 Expression::Context saved_context = context_; 334 Location saved_location = location_; 335 Label* saved_true = true_label_; 336 Label* saved_false = false_label_; 337 context_ = Expression::kTestValue; 338 location_ = where; 339 true_label_ = if_true; 340 false_label_ = if_false; 341 Visit(expr); 342 context_ = saved_context; 343 location_ = saved_location; 344 true_label_ = saved_true; 345 false_label_ = saved_false; 346 } 347 348 void VisitDeclarations(ZoneList<Declaration*>* declarations); 349 void DeclareGlobals(Handle<FixedArray> pairs); 350 351 // Platform-specific return sequence 352 void EmitReturnSequence(int position); 353 354 // Platform-specific code sequences for calls 355 void EmitCallWithStub(Call* expr); 356 void EmitCallWithIC(Call* expr, Handle<Object> name, RelocInfo::Mode mode); 357 358 // Platform-specific code for loading variables. 359 void EmitVariableLoad(Variable* expr, Expression::Context context); 360 361 // Platform-specific support for compiling assignments. 362 363 // Load a value from a named property. 364 // The receiver is left on the stack by the IC. 365 void EmitNamedPropertyLoad(Property* expr); 366 367 // Load a value from a keyed property. 368 // The receiver and the key is left on the stack by the IC. 369 void EmitKeyedPropertyLoad(Property* expr); 370 371 // Apply the compound assignment operator. Expects the left operand on top 372 // of the stack and the right one in the accumulator. 373 void EmitBinaryOp(Token::Value op, Expression::Context context); 374 375 // Complete a variable assignment. The right-hand-side value is expected 376 // in the accumulator. 377 void EmitVariableAssignment(Variable* var, Expression::Context context); 378 379 // Complete a named property assignment. The receiver is expected on top 380 // of the stack and the right-hand-side value in the accumulator. 381 void EmitNamedPropertyAssignment(Assignment* expr); 382 383 // Complete a keyed property assignment. The receiver and key are 384 // expected on top of the stack and the right-hand-side value in the 385 // accumulator. 386 void EmitKeyedPropertyAssignment(Assignment* expr); 387 388 void SetFunctionPosition(FunctionLiteral* fun); 389 void SetReturnPosition(FunctionLiteral* fun); 390 void SetStatementPosition(Statement* stmt); 391 void SetStatementPosition(int pos); 392 void SetSourcePosition(int pos); 393 394 // Non-local control flow support. 395 void EnterFinallyBlock(); 396 void ExitFinallyBlock(); 397 398 // Loop nesting counter. loop_depth()399 int loop_depth() { return loop_depth_; } increment_loop_depth()400 void increment_loop_depth() { loop_depth_++; } decrement_loop_depth()401 void decrement_loop_depth() { 402 ASSERT(loop_depth_ > 0); 403 loop_depth_--; 404 } 405 masm()406 MacroAssembler* masm() { return masm_; } 407 script()408 Handle<Script> script() { return info_->script(); } is_eval()409 bool is_eval() { return info_->is_eval(); } function()410 FunctionLiteral* function() { return info_->function(); } scope()411 Scope* scope() { return info_->scope(); } 412 413 static Register result_register(); 414 static Register context_register(); 415 416 // Set fields in the stack frame. Offsets are the frame pointer relative 417 // offsets defined in, e.g., StandardFrameConstants. 418 void StoreToFrameField(int frame_offset, Register value); 419 420 // Load a value from the current context. Indices are defined as an enum 421 // in v8::internal::Context. 422 void LoadContextField(Register dst, int context_index); 423 424 // AST node visit functions. 425 #define DECLARE_VISIT(type) virtual void Visit##type(type* node); 426 AST_NODE_LIST(DECLARE_VISIT) 427 #undef DECLARE_VISIT 428 // Handles the shortcutted logical binary operations in VisitBinaryOperation. 429 void EmitLogicalOperation(BinaryOperation* expr); 430 431 MacroAssembler* masm_; 432 CompilationInfo* info_; 433 434 Label return_label_; 435 NestedStatement* nesting_stack_; 436 int loop_depth_; 437 438 Expression::Context context_; 439 Location location_; 440 Label* true_label_; 441 Label* false_label_; 442 443 friend class NestedStatement; 444 445 DISALLOW_COPY_AND_ASSIGN(FullCodeGenerator); 446 }; 447 448 449 } } // namespace v8::internal 450 451 #endif // V8_FULL_CODEGEN_H_ 452