1 // Copyright 2012 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 "allocation.h" 34 #include "ast.h" 35 #include "code-stubs.h" 36 #include "codegen.h" 37 #include "compiler.h" 38 39 namespace v8 { 40 namespace internal { 41 42 // Forward declarations. 43 class JumpPatchSite; 44 45 // AST node visitor which can tell whether a given statement will be breakable 46 // when the code is compiled by the full compiler in the debugger. This means 47 // that there will be an IC (load/store/call) in the code generated for the 48 // debugger to piggybag on. 49 class BreakableStatementChecker: public AstVisitor { 50 public: BreakableStatementChecker()51 BreakableStatementChecker() : is_breakable_(false) {} 52 53 void Check(Statement* stmt); 54 void Check(Expression* stmt); 55 is_breakable()56 bool is_breakable() { return is_breakable_; } 57 58 private: 59 // AST node visit functions. 60 #define DECLARE_VISIT(type) virtual void Visit##type(type* node); 61 AST_NODE_LIST(DECLARE_VISIT) 62 #undef DECLARE_VISIT 63 64 bool is_breakable_; 65 66 DISALLOW_COPY_AND_ASSIGN(BreakableStatementChecker); 67 }; 68 69 70 // ----------------------------------------------------------------------------- 71 // Full code generator. 72 73 class FullCodeGenerator: public AstVisitor { 74 public: 75 enum State { 76 NO_REGISTERS, 77 TOS_REG 78 }; 79 FullCodeGenerator(MacroAssembler * masm,CompilationInfo * info)80 FullCodeGenerator(MacroAssembler* masm, CompilationInfo* info) 81 : masm_(masm), 82 info_(info), 83 scope_(info->scope()), 84 nesting_stack_(NULL), 85 loop_depth_(0), 86 global_count_(0), 87 context_(NULL), 88 bailout_entries_(info->HasDeoptimizationSupport() 89 ? info->function()->ast_node_count() : 0), 90 stack_checks_(2), // There's always at least one. 91 type_feedback_cells_(info->HasDeoptimizationSupport() 92 ? info->function()->ast_node_count() : 0), 93 ic_total_count_(0), 94 has_self_optimization_header_(false) { } 95 96 static bool MakeCode(CompilationInfo* info); 97 98 // Returns the platform-specific size in bytes of the self-optimization 99 // header. 100 static int self_optimization_header_size(); 101 102 // Encode state and pc-offset as a BitField<type, start, size>. 103 // Only use 30 bits because we encode the result as a smi. 104 class StateField : public BitField<State, 0, 1> { }; 105 class PcField : public BitField<unsigned, 1, 30-1> { }; 106 State2String(State state)107 static const char* State2String(State state) { 108 switch (state) { 109 case NO_REGISTERS: return "NO_REGISTERS"; 110 case TOS_REG: return "TOS_REG"; 111 } 112 UNREACHABLE(); 113 return NULL; 114 } 115 116 private: 117 class Breakable; 118 class Iteration; 119 120 class TestContext; 121 122 class NestedStatement BASE_EMBEDDED { 123 public: NestedStatement(FullCodeGenerator * codegen)124 explicit NestedStatement(FullCodeGenerator* codegen) : codegen_(codegen) { 125 // Link into codegen's nesting stack. 126 previous_ = codegen->nesting_stack_; 127 codegen->nesting_stack_ = this; 128 } ~NestedStatement()129 virtual ~NestedStatement() { 130 // Unlink from codegen's nesting stack. 131 ASSERT_EQ(this, codegen_->nesting_stack_); 132 codegen_->nesting_stack_ = previous_; 133 } 134 AsBreakable()135 virtual Breakable* AsBreakable() { return NULL; } AsIteration()136 virtual Iteration* AsIteration() { return NULL; } 137 IsContinueTarget(Statement * target)138 virtual bool IsContinueTarget(Statement* target) { return false; } IsBreakTarget(Statement * target)139 virtual bool IsBreakTarget(Statement* target) { return false; } 140 141 // Notify the statement that we are exiting it via break, continue, or 142 // return and give it a chance to generate cleanup code. Return the 143 // next outer statement in the nesting stack. We accumulate in 144 // *stack_depth the amount to drop the stack and in *context_length the 145 // number of context chain links to unwind as we traverse the nesting 146 // stack from an exit to its target. Exit(int * stack_depth,int * context_length)147 virtual NestedStatement* Exit(int* stack_depth, int* context_length) { 148 return previous_; 149 } 150 151 protected: masm()152 MacroAssembler* masm() { return codegen_->masm(); } 153 154 FullCodeGenerator* codegen_; 155 NestedStatement* previous_; 156 157 private: 158 DISALLOW_COPY_AND_ASSIGN(NestedStatement); 159 }; 160 161 // A breakable statement such as a block. 162 class Breakable : public NestedStatement { 163 public: Breakable(FullCodeGenerator * codegen,BreakableStatement * statement)164 Breakable(FullCodeGenerator* codegen, BreakableStatement* statement) 165 : NestedStatement(codegen), statement_(statement) { 166 } ~Breakable()167 virtual ~Breakable() {} 168 AsBreakable()169 virtual Breakable* AsBreakable() { return this; } IsBreakTarget(Statement * target)170 virtual bool IsBreakTarget(Statement* target) { 171 return statement() == target; 172 } 173 statement()174 BreakableStatement* statement() { return statement_; } break_label()175 Label* break_label() { return &break_label_; } 176 177 private: 178 BreakableStatement* statement_; 179 Label break_label_; 180 }; 181 182 // An iteration statement such as a while, for, or do loop. 183 class Iteration : public Breakable { 184 public: Iteration(FullCodeGenerator * codegen,IterationStatement * statement)185 Iteration(FullCodeGenerator* codegen, IterationStatement* statement) 186 : Breakable(codegen, statement) { 187 } ~Iteration()188 virtual ~Iteration() {} 189 AsIteration()190 virtual Iteration* AsIteration() { return this; } IsContinueTarget(Statement * target)191 virtual bool IsContinueTarget(Statement* target) { 192 return statement() == target; 193 } 194 continue_label()195 Label* continue_label() { return &continue_label_; } 196 197 private: 198 Label continue_label_; 199 }; 200 201 // A nested block statement. 202 class NestedBlock : public Breakable { 203 public: NestedBlock(FullCodeGenerator * codegen,Block * block)204 NestedBlock(FullCodeGenerator* codegen, Block* block) 205 : Breakable(codegen, block) { 206 } ~NestedBlock()207 virtual ~NestedBlock() {} 208 Exit(int * stack_depth,int * context_length)209 virtual NestedStatement* Exit(int* stack_depth, int* context_length) { 210 if (statement()->AsBlock()->block_scope() != NULL) { 211 ++(*context_length); 212 } 213 return previous_; 214 }; 215 }; 216 217 // The try block of a try/catch statement. 218 class TryCatch : public NestedStatement { 219 public: TryCatch(FullCodeGenerator * codegen)220 explicit TryCatch(FullCodeGenerator* codegen) : NestedStatement(codegen) { 221 } ~TryCatch()222 virtual ~TryCatch() {} 223 224 virtual NestedStatement* Exit(int* stack_depth, int* context_length); 225 }; 226 227 // The try block of a try/finally statement. 228 class TryFinally : public NestedStatement { 229 public: TryFinally(FullCodeGenerator * codegen,Label * finally_entry)230 TryFinally(FullCodeGenerator* codegen, Label* finally_entry) 231 : NestedStatement(codegen), finally_entry_(finally_entry) { 232 } ~TryFinally()233 virtual ~TryFinally() {} 234 235 virtual NestedStatement* Exit(int* stack_depth, int* context_length); 236 237 private: 238 Label* finally_entry_; 239 }; 240 241 // The finally block of a try/finally statement. 242 class Finally : public NestedStatement { 243 public: 244 static const int kElementCount = 2; 245 Finally(FullCodeGenerator * codegen)246 explicit Finally(FullCodeGenerator* codegen) : NestedStatement(codegen) { } ~Finally()247 virtual ~Finally() {} 248 Exit(int * stack_depth,int * context_length)249 virtual NestedStatement* Exit(int* stack_depth, int* context_length) { 250 *stack_depth += kElementCount; 251 return previous_; 252 } 253 }; 254 255 // The body of a for/in loop. 256 class ForIn : public Iteration { 257 public: 258 static const int kElementCount = 5; 259 ForIn(FullCodeGenerator * codegen,ForInStatement * statement)260 ForIn(FullCodeGenerator* codegen, ForInStatement* statement) 261 : Iteration(codegen, statement) { 262 } ~ForIn()263 virtual ~ForIn() {} 264 Exit(int * stack_depth,int * context_length)265 virtual NestedStatement* Exit(int* stack_depth, int* context_length) { 266 *stack_depth += kElementCount; 267 return previous_; 268 } 269 }; 270 271 272 // The body of a with or catch. 273 class WithOrCatch : public NestedStatement { 274 public: WithOrCatch(FullCodeGenerator * codegen)275 explicit WithOrCatch(FullCodeGenerator* codegen) 276 : NestedStatement(codegen) { 277 } ~WithOrCatch()278 virtual ~WithOrCatch() {} 279 Exit(int * stack_depth,int * context_length)280 virtual NestedStatement* Exit(int* stack_depth, int* context_length) { 281 ++(*context_length); 282 return previous_; 283 } 284 }; 285 286 // Type of a member function that generates inline code for a native function. 287 typedef void (FullCodeGenerator::*InlineFunctionGenerator)(CallRuntime* expr); 288 289 static const InlineFunctionGenerator kInlineFunctionGenerators[]; 290 291 // A platform-specific utility to overwrite the accumulator register 292 // with a GC-safe value. 293 void ClearAccumulator(); 294 295 // Determine whether or not to inline the smi case for the given 296 // operation. 297 bool ShouldInlineSmiCase(Token::Value op); 298 299 // Helper function to convert a pure value into a test context. The value 300 // is expected on the stack or the accumulator, depending on the platform. 301 // See the platform-specific implementation for details. 302 void DoTest(Expression* condition, 303 Label* if_true, 304 Label* if_false, 305 Label* fall_through); 306 void DoTest(const TestContext* context); 307 308 // Helper function to split control flow and avoid a branch to the 309 // fall-through label if it is set up. 310 #ifdef V8_TARGET_ARCH_MIPS 311 void Split(Condition cc, 312 Register lhs, 313 const Operand& rhs, 314 Label* if_true, 315 Label* if_false, 316 Label* fall_through); 317 #else // All non-mips arch. 318 void Split(Condition cc, 319 Label* if_true, 320 Label* if_false, 321 Label* fall_through); 322 #endif // V8_TARGET_ARCH_MIPS 323 324 // Load the value of a known (PARAMETER, LOCAL, or CONTEXT) variable into 325 // a register. Emits a context chain walk if if necessary (so does 326 // SetVar) so avoid calling both on the same variable. 327 void GetVar(Register destination, Variable* var); 328 329 // Assign to a known (PARAMETER, LOCAL, or CONTEXT) variable. If it's in 330 // the context, the write barrier will be emitted and source, scratch0, 331 // scratch1 will be clobbered. Emits a context chain walk if if necessary 332 // (so does GetVar) so avoid calling both on the same variable. 333 void SetVar(Variable* var, 334 Register source, 335 Register scratch0, 336 Register scratch1); 337 338 // An operand used to read/write a stack-allocated (PARAMETER or LOCAL) 339 // variable. Writing does not need the write barrier. 340 MemOperand StackOperand(Variable* var); 341 342 // An operand used to read/write a known (PARAMETER, LOCAL, or CONTEXT) 343 // variable. May emit code to traverse the context chain, loading the 344 // found context into the scratch register. Writing to this operand will 345 // need the write barrier if location is CONTEXT. 346 MemOperand VarOperand(Variable* var, Register scratch); 347 VisitForEffect(Expression * expr)348 void VisitForEffect(Expression* expr) { 349 EffectContext context(this); 350 Visit(expr); 351 PrepareForBailout(expr, NO_REGISTERS); 352 } 353 VisitForAccumulatorValue(Expression * expr)354 void VisitForAccumulatorValue(Expression* expr) { 355 AccumulatorValueContext context(this); 356 Visit(expr); 357 PrepareForBailout(expr, TOS_REG); 358 } 359 VisitForStackValue(Expression * expr)360 void VisitForStackValue(Expression* expr) { 361 StackValueContext context(this); 362 Visit(expr); 363 PrepareForBailout(expr, NO_REGISTERS); 364 } 365 VisitForControl(Expression * expr,Label * if_true,Label * if_false,Label * fall_through)366 void VisitForControl(Expression* expr, 367 Label* if_true, 368 Label* if_false, 369 Label* fall_through) { 370 TestContext context(this, expr, if_true, if_false, fall_through); 371 Visit(expr); 372 // For test contexts, we prepare for bailout before branching, not at 373 // the end of the entire expression. This happens as part of visiting 374 // the expression. 375 } 376 377 void VisitInDuplicateContext(Expression* expr); 378 379 void VisitDeclarations(ZoneList<Declaration*>* declarations); 380 void DeclareGlobals(Handle<FixedArray> pairs); 381 int DeclareGlobalsFlags(); 382 383 // Try to perform a comparison as a fast inlined literal compare if 384 // the operands allow it. Returns true if the compare operations 385 // has been matched and all code generated; false otherwise. 386 bool TryLiteralCompare(CompareOperation* compare); 387 388 // Platform-specific code for comparing the type of a value with 389 // a given literal string. 390 void EmitLiteralCompareTypeof(Expression* expr, 391 Expression* sub_expr, 392 Handle<String> check); 393 394 // Platform-specific code for equality comparison with a nil-like value. 395 void EmitLiteralCompareNil(CompareOperation* expr, 396 Expression* sub_expr, 397 NilValue nil); 398 399 // Bailout support. 400 void PrepareForBailout(Expression* node, State state); 401 void PrepareForBailoutForId(unsigned id, State state); 402 403 // Cache cell support. This associates AST ids with global property cells 404 // that will be cleared during GC and collected by the type-feedback oracle. 405 void RecordTypeFeedbackCell(unsigned id, Handle<JSGlobalPropertyCell> cell); 406 407 // Record a call's return site offset, used to rebuild the frame if the 408 // called function was inlined at the site. 409 void RecordJSReturnSite(Call* call); 410 411 // Prepare for bailout before a test (or compare) and branch. If 412 // should_normalize, then the following comparison will not handle the 413 // canonical JS true value so we will insert a (dead) test against true at 414 // the actual bailout target from the optimized code. If not 415 // should_normalize, the true and false labels are ignored. 416 void PrepareForBailoutBeforeSplit(Expression* expr, 417 bool should_normalize, 418 Label* if_true, 419 Label* if_false); 420 421 // Platform-specific code for a variable, constant, or function 422 // declaration. Functions have an initial value. 423 // Increments global_count_ for unallocated variables. 424 void EmitDeclaration(VariableProxy* proxy, 425 VariableMode mode, 426 FunctionLiteral* function); 427 428 // Platform-specific code for checking the stack limit at the back edge of 429 // a loop. 430 // This is meant to be called at loop back edges, |back_edge_target| is 431 // the jump target of the back edge and is used to approximate the amount 432 // of code inside the loop. 433 void EmitStackCheck(IterationStatement* stmt, Label* back_edge_target); 434 // Record the OSR AST id corresponding to a stack check in the code. 435 void RecordStackCheck(unsigned osr_ast_id); 436 // Emit a table of stack check ids and pcs into the code stream. Return 437 // the offset of the start of the table. 438 unsigned EmitStackCheckTable(); 439 440 void EmitProfilingCounterDecrement(int delta); 441 void EmitProfilingCounterReset(); 442 443 // Platform-specific return sequence 444 void EmitReturnSequence(); 445 446 // Platform-specific code sequences for calls 447 void EmitCallWithStub(Call* expr, CallFunctionFlags flags); 448 void EmitCallWithIC(Call* expr, Handle<Object> name, RelocInfo::Mode mode); 449 void EmitKeyedCallWithIC(Call* expr, Expression* key); 450 451 // Platform-specific code for inline runtime calls. 452 InlineFunctionGenerator FindInlineFunctionGenerator(Runtime::FunctionId id); 453 454 void EmitInlineRuntimeCall(CallRuntime* expr); 455 456 #define EMIT_INLINE_RUNTIME_CALL(name, x, y) \ 457 void Emit##name(CallRuntime* expr); 458 INLINE_FUNCTION_LIST(EMIT_INLINE_RUNTIME_CALL) 459 INLINE_RUNTIME_FUNCTION_LIST(EMIT_INLINE_RUNTIME_CALL) 460 #undef EMIT_INLINE_RUNTIME_CALL 461 462 // Platform-specific code for loading variables. 463 void EmitLoadGlobalCheckExtensions(Variable* var, 464 TypeofState typeof_state, 465 Label* slow); 466 MemOperand ContextSlotOperandCheckExtensions(Variable* var, Label* slow); 467 void EmitDynamicLookupFastCase(Variable* var, 468 TypeofState typeof_state, 469 Label* slow, 470 Label* done); 471 void EmitVariableLoad(VariableProxy* proxy); 472 473 void EmitAccessor(Expression* expression); 474 475 // Expects the arguments and the function already pushed. 476 void EmitResolvePossiblyDirectEval(int arg_count); 477 478 // Platform-specific support for allocating a new closure based on 479 // the given function info. 480 void EmitNewClosure(Handle<SharedFunctionInfo> info, bool pretenure); 481 482 // Platform-specific support for compiling assignments. 483 484 // Load a value from a named property. 485 // The receiver is left on the stack by the IC. 486 void EmitNamedPropertyLoad(Property* expr); 487 488 // Load a value from a keyed property. 489 // The receiver and the key is left on the stack by the IC. 490 void EmitKeyedPropertyLoad(Property* expr); 491 492 // Apply the compound assignment operator. Expects the left operand on top 493 // of the stack and the right one in the accumulator. 494 void EmitBinaryOp(BinaryOperation* expr, 495 Token::Value op, 496 OverwriteMode mode); 497 498 // Helper functions for generating inlined smi code for certain 499 // binary operations. 500 void EmitInlineSmiBinaryOp(BinaryOperation* expr, 501 Token::Value op, 502 OverwriteMode mode, 503 Expression* left, 504 Expression* right); 505 506 // Assign to the given expression as if via '='. The right-hand-side value 507 // is expected in the accumulator. 508 void EmitAssignment(Expression* expr); 509 510 // Complete a variable assignment. The right-hand-side value is expected 511 // in the accumulator. 512 void EmitVariableAssignment(Variable* var, 513 Token::Value op); 514 515 // Complete a named property assignment. The receiver is expected on top 516 // of the stack and the right-hand-side value in the accumulator. 517 void EmitNamedPropertyAssignment(Assignment* expr); 518 519 // Complete a keyed property assignment. The receiver and key are 520 // expected on top of the stack and the right-hand-side value in the 521 // accumulator. 522 void EmitKeyedPropertyAssignment(Assignment* expr); 523 524 void CallIC(Handle<Code> code, 525 RelocInfo::Mode rmode = RelocInfo::CODE_TARGET, 526 unsigned ast_id = kNoASTId); 527 528 void SetFunctionPosition(FunctionLiteral* fun); 529 void SetReturnPosition(FunctionLiteral* fun); 530 void SetStatementPosition(Statement* stmt); 531 void SetExpressionPosition(Expression* expr, int pos); 532 void SetStatementPosition(int pos); 533 void SetSourcePosition(int pos); 534 535 // Non-local control flow support. 536 void EnterFinallyBlock(); 537 void ExitFinallyBlock(); 538 539 // Loop nesting counter. loop_depth()540 int loop_depth() { return loop_depth_; } increment_loop_depth()541 void increment_loop_depth() { loop_depth_++; } decrement_loop_depth()542 void decrement_loop_depth() { 543 ASSERT(loop_depth_ > 0); 544 loop_depth_--; 545 } 546 masm()547 MacroAssembler* masm() { return masm_; } 548 549 class ExpressionContext; context()550 const ExpressionContext* context() { return context_; } set_new_context(const ExpressionContext * context)551 void set_new_context(const ExpressionContext* context) { context_ = context; } 552 script()553 Handle<Script> script() { return info_->script(); } is_eval()554 bool is_eval() { return info_->is_eval(); } is_native()555 bool is_native() { return info_->is_native(); } is_classic_mode()556 bool is_classic_mode() { 557 return language_mode() == CLASSIC_MODE; 558 } language_mode()559 LanguageMode language_mode() { 560 return function()->language_mode(); 561 } function()562 FunctionLiteral* function() { return info_->function(); } scope()563 Scope* scope() { return scope_; } 564 565 static Register result_register(); 566 static Register context_register(); 567 568 // Set fields in the stack frame. Offsets are the frame pointer relative 569 // offsets defined in, e.g., StandardFrameConstants. 570 void StoreToFrameField(int frame_offset, Register value); 571 572 // Load a value from the current context. Indices are defined as an enum 573 // in v8::internal::Context. 574 void LoadContextField(Register dst, int context_index); 575 576 // Push the function argument for the runtime functions PushWithContext 577 // and PushCatchContext. 578 void PushFunctionArgumentForContextAllocation(); 579 580 // AST node visit functions. 581 #define DECLARE_VISIT(type) virtual void Visit##type(type* node); 582 AST_NODE_LIST(DECLARE_VISIT) 583 #undef DECLARE_VISIT 584 585 void EmitUnaryOperation(UnaryOperation* expr, const char* comment); 586 587 void VisitComma(BinaryOperation* expr); 588 void VisitLogicalExpression(BinaryOperation* expr); 589 void VisitArithmeticExpression(BinaryOperation* expr); 590 591 void VisitForTypeofValue(Expression* expr); 592 593 void Generate(); 594 void PopulateDeoptimizationData(Handle<Code> code); 595 void PopulateTypeFeedbackInfo(Handle<Code> code); 596 void PopulateTypeFeedbackCells(Handle<Code> code); 597 handler_table()598 Handle<FixedArray> handler_table() { return handler_table_; } 599 600 struct BailoutEntry { 601 unsigned id; 602 unsigned pc_and_state; 603 }; 604 605 struct TypeFeedbackCellEntry { 606 unsigned ast_id; 607 Handle<JSGlobalPropertyCell> cell; 608 }; 609 610 611 class ExpressionContext BASE_EMBEDDED { 612 public: ExpressionContext(FullCodeGenerator * codegen)613 explicit ExpressionContext(FullCodeGenerator* codegen) 614 : masm_(codegen->masm()), old_(codegen->context()), codegen_(codegen) { 615 codegen->set_new_context(this); 616 } 617 ~ExpressionContext()618 virtual ~ExpressionContext() { 619 codegen_->set_new_context(old_); 620 } 621 isolate()622 Isolate* isolate() const { return codegen_->isolate(); } 623 624 // Convert constant control flow (true or false) to the result expected for 625 // this expression context. 626 virtual void Plug(bool flag) const = 0; 627 628 // Emit code to convert a pure value (in a register, known variable 629 // location, as a literal, or on top of the stack) into the result 630 // expected according to this expression context. 631 virtual void Plug(Register reg) const = 0; 632 virtual void Plug(Variable* var) const = 0; 633 virtual void Plug(Handle<Object> lit) const = 0; 634 virtual void Plug(Heap::RootListIndex index) const = 0; 635 virtual void PlugTOS() const = 0; 636 637 // Emit code to convert pure control flow to a pair of unbound labels into 638 // the result expected according to this expression context. The 639 // implementation will bind both labels unless it's a TestContext, which 640 // won't bind them at this point. 641 virtual void Plug(Label* materialize_true, 642 Label* materialize_false) const = 0; 643 644 // Emit code to discard count elements from the top of stack, then convert 645 // a pure value into the result expected according to this expression 646 // context. 647 virtual void DropAndPlug(int count, Register reg) const = 0; 648 649 // Set up branch labels for a test expression. The three Label** parameters 650 // are output parameters. 651 virtual void PrepareTest(Label* materialize_true, 652 Label* materialize_false, 653 Label** if_true, 654 Label** if_false, 655 Label** fall_through) const = 0; 656 657 // Returns true if we are evaluating only for side effects (i.e. if the 658 // result will be discarded). IsEffect()659 virtual bool IsEffect() const { return false; } 660 661 // Returns true if we are evaluating for the value (in accu/on stack). IsAccumulatorValue()662 virtual bool IsAccumulatorValue() const { return false; } IsStackValue()663 virtual bool IsStackValue() const { return false; } 664 665 // Returns true if we are branching on the value rather than materializing 666 // it. Only used for asserts. IsTest()667 virtual bool IsTest() const { return false; } 668 669 protected: codegen()670 FullCodeGenerator* codegen() const { return codegen_; } masm()671 MacroAssembler* masm() const { return masm_; } 672 MacroAssembler* masm_; 673 674 private: 675 const ExpressionContext* old_; 676 FullCodeGenerator* codegen_; 677 }; 678 679 class AccumulatorValueContext : public ExpressionContext { 680 public: AccumulatorValueContext(FullCodeGenerator * codegen)681 explicit AccumulatorValueContext(FullCodeGenerator* codegen) 682 : ExpressionContext(codegen) { } 683 684 virtual void Plug(bool flag) const; 685 virtual void Plug(Register reg) const; 686 virtual void Plug(Label* materialize_true, Label* materialize_false) const; 687 virtual void Plug(Variable* var) const; 688 virtual void Plug(Handle<Object> lit) const; 689 virtual void Plug(Heap::RootListIndex) const; 690 virtual void PlugTOS() const; 691 virtual void DropAndPlug(int count, Register reg) const; 692 virtual void PrepareTest(Label* materialize_true, 693 Label* materialize_false, 694 Label** if_true, 695 Label** if_false, 696 Label** fall_through) const; IsAccumulatorValue()697 virtual bool IsAccumulatorValue() const { return true; } 698 }; 699 700 class StackValueContext : public ExpressionContext { 701 public: StackValueContext(FullCodeGenerator * codegen)702 explicit StackValueContext(FullCodeGenerator* codegen) 703 : ExpressionContext(codegen) { } 704 705 virtual void Plug(bool flag) const; 706 virtual void Plug(Register reg) const; 707 virtual void Plug(Label* materialize_true, Label* materialize_false) const; 708 virtual void Plug(Variable* var) const; 709 virtual void Plug(Handle<Object> lit) const; 710 virtual void Plug(Heap::RootListIndex) const; 711 virtual void PlugTOS() const; 712 virtual void DropAndPlug(int count, Register reg) const; 713 virtual void PrepareTest(Label* materialize_true, 714 Label* materialize_false, 715 Label** if_true, 716 Label** if_false, 717 Label** fall_through) const; IsStackValue()718 virtual bool IsStackValue() const { return true; } 719 }; 720 721 class TestContext : public ExpressionContext { 722 public: TestContext(FullCodeGenerator * codegen,Expression * condition,Label * true_label,Label * false_label,Label * fall_through)723 TestContext(FullCodeGenerator* codegen, 724 Expression* condition, 725 Label* true_label, 726 Label* false_label, 727 Label* fall_through) 728 : ExpressionContext(codegen), 729 condition_(condition), 730 true_label_(true_label), 731 false_label_(false_label), 732 fall_through_(fall_through) { } 733 cast(const ExpressionContext * context)734 static const TestContext* cast(const ExpressionContext* context) { 735 ASSERT(context->IsTest()); 736 return reinterpret_cast<const TestContext*>(context); 737 } 738 condition()739 Expression* condition() const { return condition_; } true_label()740 Label* true_label() const { return true_label_; } false_label()741 Label* false_label() const { return false_label_; } fall_through()742 Label* fall_through() const { return fall_through_; } 743 744 virtual void Plug(bool flag) const; 745 virtual void Plug(Register reg) const; 746 virtual void Plug(Label* materialize_true, Label* materialize_false) const; 747 virtual void Plug(Variable* var) const; 748 virtual void Plug(Handle<Object> lit) const; 749 virtual void Plug(Heap::RootListIndex) const; 750 virtual void PlugTOS() const; 751 virtual void DropAndPlug(int count, Register reg) const; 752 virtual void PrepareTest(Label* materialize_true, 753 Label* materialize_false, 754 Label** if_true, 755 Label** if_false, 756 Label** fall_through) const; IsTest()757 virtual bool IsTest() const { return true; } 758 759 private: 760 Expression* condition_; 761 Label* true_label_; 762 Label* false_label_; 763 Label* fall_through_; 764 }; 765 766 class EffectContext : public ExpressionContext { 767 public: EffectContext(FullCodeGenerator * codegen)768 explicit EffectContext(FullCodeGenerator* codegen) 769 : ExpressionContext(codegen) { } 770 771 virtual void Plug(bool flag) const; 772 virtual void Plug(Register reg) const; 773 virtual void Plug(Label* materialize_true, Label* materialize_false) const; 774 virtual void Plug(Variable* var) const; 775 virtual void Plug(Handle<Object> lit) const; 776 virtual void Plug(Heap::RootListIndex) const; 777 virtual void PlugTOS() const; 778 virtual void DropAndPlug(int count, Register reg) const; 779 virtual void PrepareTest(Label* materialize_true, 780 Label* materialize_false, 781 Label** if_true, 782 Label** if_false, 783 Label** fall_through) const; IsEffect()784 virtual bool IsEffect() const { return true; } 785 }; 786 787 MacroAssembler* masm_; 788 CompilationInfo* info_; 789 Scope* scope_; 790 Label return_label_; 791 NestedStatement* nesting_stack_; 792 int loop_depth_; 793 int global_count_; 794 const ExpressionContext* context_; 795 ZoneList<BailoutEntry> bailout_entries_; 796 ZoneList<BailoutEntry> stack_checks_; 797 ZoneList<TypeFeedbackCellEntry> type_feedback_cells_; 798 int ic_total_count_; 799 bool has_self_optimization_header_; 800 Handle<FixedArray> handler_table_; 801 Handle<JSGlobalPropertyCell> profiling_counter_; 802 803 friend class NestedStatement; 804 805 DISALLOW_COPY_AND_ASSIGN(FullCodeGenerator); 806 }; 807 808 809 // A map from property names to getter/setter pairs allocated in the zone. 810 class AccessorTable: public TemplateHashMap<Literal, 811 ObjectLiteral::Accessors, 812 ZoneListAllocationPolicy> { 813 public: AccessorTable(Zone * zone)814 explicit AccessorTable(Zone* zone) : 815 TemplateHashMap<Literal, 816 ObjectLiteral::Accessors, 817 ZoneListAllocationPolicy>(Literal::Match), 818 zone_(zone) { } 819 lookup(Literal * literal)820 Iterator lookup(Literal* literal) { 821 Iterator it = find(literal, true); 822 if (it->second == NULL) it->second = new(zone_) ObjectLiteral::Accessors(); 823 return it; 824 } 825 826 private: 827 Zone* zone_; 828 }; 829 830 831 } } // namespace v8::internal 832 833 #endif // V8_FULL_CODEGEN_H_ 834