| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 1 | // Copyright 2012 the V8 project authors. All rights reserved. | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be | 
|  | 3 | // found in the LICENSE file. | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 4 |  | 
|  | 5 | #ifndef V8_FULL_CODEGEN_H_ | 
|  | 6 | #define V8_FULL_CODEGEN_H_ | 
|  | 7 |  | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 8 | #include "src/v8.h" | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 9 |  | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 10 | #include "src/allocation.h" | 
|  | 11 | #include "src/assert-scope.h" | 
|  | 12 | #include "src/ast.h" | 
| Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 13 | #include "src/bit-vector.h" | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 14 | #include "src/code-stubs.h" | 
|  | 15 | #include "src/codegen.h" | 
|  | 16 | #include "src/compiler.h" | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 17 | #include "src/globals.h" | 
|  | 18 | #include "src/objects.h" | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 19 |  | 
|  | 20 | namespace v8 { | 
|  | 21 | namespace internal { | 
|  | 22 |  | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 23 | // Forward declarations. | 
|  | 24 | class JumpPatchSite; | 
|  | 25 |  | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 26 | // AST node visitor which can tell whether a given statement will be breakable | 
|  | 27 | // when the code is compiled by the full compiler in the debugger. This means | 
|  | 28 | // that there will be an IC (load/store/call) in the code generated for the | 
|  | 29 | // debugger to piggybag on. | 
|  | 30 | class BreakableStatementChecker: public AstVisitor { | 
|  | 31 | public: | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 32 | explicit BreakableStatementChecker(Zone* zone) : is_breakable_(false) { | 
|  | 33 | InitializeAstVisitor(zone); | 
|  | 34 | } | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 35 |  | 
|  | 36 | void Check(Statement* stmt); | 
|  | 37 | void Check(Expression* stmt); | 
|  | 38 |  | 
|  | 39 | bool is_breakable() { return is_breakable_; } | 
|  | 40 |  | 
|  | 41 | private: | 
|  | 42 | // AST node visit functions. | 
| Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 43 | #define DECLARE_VISIT(type) virtual void Visit##type(type* node) OVERRIDE; | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 44 | AST_NODE_LIST(DECLARE_VISIT) | 
|  | 45 | #undef DECLARE_VISIT | 
|  | 46 |  | 
|  | 47 | bool is_breakable_; | 
|  | 48 |  | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 49 | DEFINE_AST_VISITOR_SUBCLASS_MEMBERS(); | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 50 | DISALLOW_COPY_AND_ASSIGN(BreakableStatementChecker); | 
|  | 51 | }; | 
|  | 52 |  | 
|  | 53 |  | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 54 | // ----------------------------------------------------------------------------- | 
|  | 55 | // Full code generator. | 
|  | 56 |  | 
|  | 57 | class FullCodeGenerator: public AstVisitor { | 
|  | 58 | public: | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 59 | enum State { | 
|  | 60 | NO_REGISTERS, | 
|  | 61 | TOS_REG | 
|  | 62 | }; | 
|  | 63 |  | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 64 | FullCodeGenerator(MacroAssembler* masm, CompilationInfo* info) | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 65 | : masm_(masm), | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 66 | info_(info), | 
|  | 67 | scope_(info->scope()), | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 68 | nesting_stack_(NULL), | 
|  | 69 | loop_depth_(0), | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 70 | globals_(NULL), | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 71 | context_(NULL), | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 72 | bailout_entries_(info->HasDeoptimizationSupport() | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 73 | ? info->function()->ast_node_count() : 0, | 
|  | 74 | info->zone()), | 
|  | 75 | back_edges_(2, info->zone()), | 
|  | 76 | ic_total_count_(0) { | 
|  | 77 | DCHECK(!info->IsStub()); | 
|  | 78 | Initialize(); | 
|  | 79 | } | 
|  | 80 |  | 
|  | 81 | void Initialize(); | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 82 |  | 
| Ben Murdoch | f87a203 | 2010-10-22 12:50:53 +0100 | [diff] [blame] | 83 | static bool MakeCode(CompilationInfo* info); | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 84 |  | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 85 | // Encode state and pc-offset as a BitField<type, start, size>. | 
|  | 86 | // Only use 30 bits because we encode the result as a smi. | 
|  | 87 | class StateField : public BitField<State, 0, 1> { }; | 
|  | 88 | class PcField    : public BitField<unsigned, 1, 30-1> { }; | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 89 |  | 
|  | 90 | static const char* State2String(State state) { | 
|  | 91 | switch (state) { | 
|  | 92 | case NO_REGISTERS: return "NO_REGISTERS"; | 
|  | 93 | case TOS_REG: return "TOS_REG"; | 
|  | 94 | } | 
|  | 95 | UNREACHABLE(); | 
|  | 96 | return NULL; | 
|  | 97 | } | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 98 |  | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 99 | static const int kMaxBackEdgeWeight = 127; | 
|  | 100 |  | 
|  | 101 | // Platform-specific code size multiplier. | 
|  | 102 | #if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X87 | 
|  | 103 | static const int kCodeSizeMultiplier = 105; | 
|  | 104 | static const int kBootCodeSizeMultiplier = 100; | 
|  | 105 | #elif V8_TARGET_ARCH_X64 | 
|  | 106 | static const int kCodeSizeMultiplier = 170; | 
|  | 107 | static const int kBootCodeSizeMultiplier = 140; | 
|  | 108 | #elif V8_TARGET_ARCH_ARM | 
|  | 109 | static const int kCodeSizeMultiplier = 149; | 
|  | 110 | static const int kBootCodeSizeMultiplier = 110; | 
|  | 111 | #elif V8_TARGET_ARCH_ARM64 | 
|  | 112 | // TODO(all): Copied ARM value. Check this is sensible for ARM64. | 
|  | 113 | static const int kCodeSizeMultiplier = 149; | 
|  | 114 | static const int kBootCodeSizeMultiplier = 110; | 
|  | 115 | #elif V8_TARGET_ARCH_MIPS | 
|  | 116 | static const int kCodeSizeMultiplier = 149; | 
|  | 117 | static const int kBootCodeSizeMultiplier = 120; | 
|  | 118 | #elif V8_TARGET_ARCH_MIPS64 | 
|  | 119 | static const int kCodeSizeMultiplier = 149; | 
|  | 120 | static const int kBootCodeSizeMultiplier = 120; | 
|  | 121 | #else | 
|  | 122 | #error Unsupported target architecture. | 
|  | 123 | #endif | 
|  | 124 |  | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 125 | private: | 
|  | 126 | class Breakable; | 
|  | 127 | class Iteration; | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 128 |  | 
| Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 129 | class TestContext; | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 130 |  | 
|  | 131 | class NestedStatement BASE_EMBEDDED { | 
|  | 132 | public: | 
|  | 133 | explicit NestedStatement(FullCodeGenerator* codegen) : codegen_(codegen) { | 
|  | 134 | // Link into codegen's nesting stack. | 
|  | 135 | previous_ = codegen->nesting_stack_; | 
|  | 136 | codegen->nesting_stack_ = this; | 
|  | 137 | } | 
|  | 138 | virtual ~NestedStatement() { | 
|  | 139 | // Unlink from codegen's nesting stack. | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 140 | DCHECK_EQ(this, codegen_->nesting_stack_); | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 141 | codegen_->nesting_stack_ = previous_; | 
|  | 142 | } | 
|  | 143 |  | 
|  | 144 | virtual Breakable* AsBreakable() { return NULL; } | 
|  | 145 | virtual Iteration* AsIteration() { return NULL; } | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 146 |  | 
|  | 147 | virtual bool IsContinueTarget(Statement* target) { return false; } | 
|  | 148 | virtual bool IsBreakTarget(Statement* target) { return false; } | 
|  | 149 |  | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 150 | // Notify the statement that we are exiting it via break, continue, or | 
|  | 151 | // return and give it a chance to generate cleanup code.  Return the | 
|  | 152 | // next outer statement in the nesting stack.  We accumulate in | 
|  | 153 | // *stack_depth the amount to drop the stack and in *context_length the | 
|  | 154 | // number of context chain links to unwind as we traverse the nesting | 
|  | 155 | // stack from an exit to its target. | 
|  | 156 | virtual NestedStatement* Exit(int* stack_depth, int* context_length) { | 
|  | 157 | return previous_; | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 158 | } | 
| Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 159 |  | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 160 | protected: | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 161 | MacroAssembler* masm() { return codegen_->masm(); } | 
| Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 162 |  | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 163 | FullCodeGenerator* codegen_; | 
|  | 164 | NestedStatement* previous_; | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 165 |  | 
|  | 166 | private: | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 167 | DISALLOW_COPY_AND_ASSIGN(NestedStatement); | 
|  | 168 | }; | 
|  | 169 |  | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 170 | // A breakable statement such as a block. | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 171 | class Breakable : public NestedStatement { | 
|  | 172 | public: | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 173 | Breakable(FullCodeGenerator* codegen, BreakableStatement* statement) | 
|  | 174 | : NestedStatement(codegen), statement_(statement) { | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 175 | } | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 176 | virtual ~Breakable() {} | 
|  | 177 |  | 
|  | 178 | virtual Breakable* AsBreakable() { return this; } | 
|  | 179 | virtual bool IsBreakTarget(Statement* target) { | 
|  | 180 | return statement() == target; | 
|  | 181 | } | 
|  | 182 |  | 
|  | 183 | BreakableStatement* statement() { return statement_; } | 
|  | 184 | Label* break_label() { return &break_label_; } | 
|  | 185 |  | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 186 | private: | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 187 | BreakableStatement* statement_; | 
|  | 188 | Label break_label_; | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 189 | }; | 
|  | 190 |  | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 191 | // An iteration statement such as a while, for, or do loop. | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 192 | class Iteration : public Breakable { | 
|  | 193 | public: | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 194 | Iteration(FullCodeGenerator* codegen, IterationStatement* statement) | 
|  | 195 | : Breakable(codegen, statement) { | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 196 | } | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 197 | virtual ~Iteration() {} | 
|  | 198 |  | 
|  | 199 | virtual Iteration* AsIteration() { return this; } | 
|  | 200 | virtual bool IsContinueTarget(Statement* target) { | 
|  | 201 | return statement() == target; | 
|  | 202 | } | 
|  | 203 |  | 
|  | 204 | Label* continue_label() { return &continue_label_; } | 
|  | 205 |  | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 206 | private: | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 207 | Label continue_label_; | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 208 | }; | 
|  | 209 |  | 
| Ben Murdoch | 589d697 | 2011-11-30 16:04:58 +0000 | [diff] [blame] | 210 | // A nested block statement. | 
|  | 211 | class NestedBlock : public Breakable { | 
|  | 212 | public: | 
|  | 213 | NestedBlock(FullCodeGenerator* codegen, Block* block) | 
|  | 214 | : Breakable(codegen, block) { | 
|  | 215 | } | 
|  | 216 | virtual ~NestedBlock() {} | 
|  | 217 |  | 
|  | 218 | virtual NestedStatement* Exit(int* stack_depth, int* context_length) { | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 219 | if (statement()->AsBlock()->scope() != NULL) { | 
| Ben Murdoch | 589d697 | 2011-11-30 16:04:58 +0000 | [diff] [blame] | 220 | ++(*context_length); | 
|  | 221 | } | 
|  | 222 | return previous_; | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 223 | } | 
| Ben Murdoch | 589d697 | 2011-11-30 16:04:58 +0000 | [diff] [blame] | 224 | }; | 
|  | 225 |  | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 226 | // The try block of a try/catch statement. | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 227 | class TryCatch : public NestedStatement { | 
|  | 228 | public: | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 229 | explicit TryCatch(FullCodeGenerator* codegen) : NestedStatement(codegen) { | 
|  | 230 | } | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 231 | virtual ~TryCatch() {} | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 232 |  | 
|  | 233 | virtual NestedStatement* Exit(int* stack_depth, int* context_length); | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 234 | }; | 
|  | 235 |  | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 236 | // The try block of a try/finally statement. | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 237 | class TryFinally : public NestedStatement { | 
|  | 238 | public: | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 239 | TryFinally(FullCodeGenerator* codegen, Label* finally_entry) | 
|  | 240 | : NestedStatement(codegen), finally_entry_(finally_entry) { | 
|  | 241 | } | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 242 | virtual ~TryFinally() {} | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 243 |  | 
|  | 244 | virtual NestedStatement* Exit(int* stack_depth, int* context_length); | 
|  | 245 |  | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 246 | private: | 
|  | 247 | Label* finally_entry_; | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 248 | }; | 
|  | 249 |  | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 250 | // The finally block of a try/finally statement. | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 251 | class Finally : public NestedStatement { | 
|  | 252 | public: | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 253 | static const int kElementCount = 5; | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 254 |  | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 255 | explicit Finally(FullCodeGenerator* codegen) : NestedStatement(codegen) { } | 
|  | 256 | virtual ~Finally() {} | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 257 |  | 
|  | 258 | virtual NestedStatement* Exit(int* stack_depth, int* context_length) { | 
|  | 259 | *stack_depth += kElementCount; | 
|  | 260 | return previous_; | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 261 | } | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 262 | }; | 
|  | 263 |  | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 264 | // The body of a for/in loop. | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 265 | class ForIn : public Iteration { | 
|  | 266 | public: | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 267 | static const int kElementCount = 5; | 
|  | 268 |  | 
|  | 269 | ForIn(FullCodeGenerator* codegen, ForInStatement* statement) | 
|  | 270 | : Iteration(codegen, statement) { | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 271 | } | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 272 | virtual ~ForIn() {} | 
|  | 273 |  | 
|  | 274 | virtual NestedStatement* Exit(int* stack_depth, int* context_length) { | 
|  | 275 | *stack_depth += kElementCount; | 
|  | 276 | return previous_; | 
|  | 277 | } | 
|  | 278 | }; | 
|  | 279 |  | 
|  | 280 |  | 
|  | 281 | // The body of a with or catch. | 
|  | 282 | class WithOrCatch : public NestedStatement { | 
|  | 283 | public: | 
|  | 284 | explicit WithOrCatch(FullCodeGenerator* codegen) | 
|  | 285 | : NestedStatement(codegen) { | 
|  | 286 | } | 
|  | 287 | virtual ~WithOrCatch() {} | 
|  | 288 |  | 
|  | 289 | virtual NestedStatement* Exit(int* stack_depth, int* context_length) { | 
|  | 290 | ++(*context_length); | 
|  | 291 | return previous_; | 
|  | 292 | } | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 293 | }; | 
|  | 294 |  | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 295 | // Type of a member function that generates inline code for a native function. | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 296 | typedef void (FullCodeGenerator::*InlineFunctionGenerator)(CallRuntime* expr); | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 297 |  | 
|  | 298 | static const InlineFunctionGenerator kInlineFunctionGenerators[]; | 
|  | 299 |  | 
| Ben Murdoch | db5a90a | 2011-01-06 18:27:03 +0000 | [diff] [blame] | 300 | // A platform-specific utility to overwrite the accumulator register | 
|  | 301 | // with a GC-safe value. | 
|  | 302 | void ClearAccumulator(); | 
|  | 303 |  | 
| Kristian Monsen | 80d68ea | 2010-09-08 11:05:35 +0100 | [diff] [blame] | 304 | // Determine whether or not to inline the smi case for the given | 
|  | 305 | // operation. | 
|  | 306 | bool ShouldInlineSmiCase(Token::Value op); | 
|  | 307 |  | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 308 | // Helper function to convert a pure value into a test context.  The value | 
|  | 309 | // is expected on the stack or the accumulator, depending on the platform. | 
|  | 310 | // See the platform-specific implementation for details. | 
| Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 311 | void DoTest(Expression* condition, | 
|  | 312 | Label* if_true, | 
|  | 313 | Label* if_false, | 
|  | 314 | Label* fall_through); | 
|  | 315 | void DoTest(const TestContext* context); | 
| Kristian Monsen | 80d68ea | 2010-09-08 11:05:35 +0100 | [diff] [blame] | 316 |  | 
|  | 317 | // Helper function to split control flow and avoid a branch to the | 
|  | 318 | // fall-through label if it is set up. | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 319 | #if V8_TARGET_ARCH_MIPS | 
|  | 320 | void Split(Condition cc, | 
|  | 321 | Register lhs, | 
|  | 322 | const Operand&  rhs, | 
|  | 323 | Label* if_true, | 
|  | 324 | Label* if_false, | 
|  | 325 | Label* fall_through); | 
|  | 326 | #elif V8_TARGET_ARCH_MIPS64 | 
| Ben Murdoch | 257744e | 2011-11-30 15:57:28 +0000 | [diff] [blame] | 327 | void Split(Condition cc, | 
|  | 328 | Register lhs, | 
|  | 329 | const Operand&  rhs, | 
|  | 330 | Label* if_true, | 
|  | 331 | Label* if_false, | 
|  | 332 | Label* fall_through); | 
|  | 333 | #else  // All non-mips arch. | 
| Kristian Monsen | 80d68ea | 2010-09-08 11:05:35 +0100 | [diff] [blame] | 334 | void Split(Condition cc, | 
|  | 335 | Label* if_true, | 
|  | 336 | Label* if_false, | 
|  | 337 | Label* fall_through); | 
| Ben Murdoch | 257744e | 2011-11-30 15:57:28 +0000 | [diff] [blame] | 338 | #endif  // V8_TARGET_ARCH_MIPS | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 339 |  | 
| Ben Murdoch | 589d697 | 2011-11-30 16:04:58 +0000 | [diff] [blame] | 340 | // Load the value of a known (PARAMETER, LOCAL, or CONTEXT) variable into | 
|  | 341 | // a register.  Emits a context chain walk if if necessary (so does | 
|  | 342 | // SetVar) so avoid calling both on the same variable. | 
|  | 343 | void GetVar(Register destination, Variable* var); | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 344 |  | 
| Ben Murdoch | 589d697 | 2011-11-30 16:04:58 +0000 | [diff] [blame] | 345 | // Assign to a known (PARAMETER, LOCAL, or CONTEXT) variable.  If it's in | 
|  | 346 | // the context, the write barrier will be emitted and source, scratch0, | 
|  | 347 | // scratch1 will be clobbered.  Emits a context chain walk if if necessary | 
|  | 348 | // (so does GetVar) so avoid calling both on the same variable. | 
|  | 349 | void SetVar(Variable* var, | 
|  | 350 | Register source, | 
|  | 351 | Register scratch0, | 
|  | 352 | Register scratch1); | 
|  | 353 |  | 
|  | 354 | // An operand used to read/write a stack-allocated (PARAMETER or LOCAL) | 
|  | 355 | // variable.  Writing does not need the write barrier. | 
|  | 356 | MemOperand StackOperand(Variable* var); | 
|  | 357 |  | 
|  | 358 | // An operand used to read/write a known (PARAMETER, LOCAL, or CONTEXT) | 
|  | 359 | // variable.  May emit code to traverse the context chain, loading the | 
|  | 360 | // found context into the scratch register.  Writing to this operand will | 
|  | 361 | // need the write barrier if location is CONTEXT. | 
|  | 362 | MemOperand VarOperand(Variable* var, Register scratch); | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 363 |  | 
|  | 364 | void VisitForEffect(Expression* expr) { | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 365 | EffectContext context(this); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 366 | Visit(expr); | 
|  | 367 | PrepareForBailout(expr, NO_REGISTERS); | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 368 | } | 
|  | 369 |  | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 370 | void VisitForAccumulatorValue(Expression* expr) { | 
|  | 371 | AccumulatorValueContext context(this); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 372 | Visit(expr); | 
|  | 373 | PrepareForBailout(expr, TOS_REG); | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 374 | } | 
|  | 375 |  | 
|  | 376 | void VisitForStackValue(Expression* expr) { | 
|  | 377 | StackValueContext context(this); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 378 | Visit(expr); | 
|  | 379 | PrepareForBailout(expr, NO_REGISTERS); | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 380 | } | 
|  | 381 |  | 
| Kristian Monsen | 80d68ea | 2010-09-08 11:05:35 +0100 | [diff] [blame] | 382 | void VisitForControl(Expression* expr, | 
|  | 383 | Label* if_true, | 
|  | 384 | Label* if_false, | 
|  | 385 | Label* fall_through) { | 
| Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 386 | TestContext context(this, expr, if_true, if_false, fall_through); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 387 | Visit(expr); | 
|  | 388 | // For test contexts, we prepare for bailout before branching, not at | 
|  | 389 | // the end of the entire expression.  This happens as part of visiting | 
|  | 390 | // the expression. | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 391 | } | 
|  | 392 |  | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 393 | void VisitInDuplicateContext(Expression* expr); | 
|  | 394 |  | 
| Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 395 | void VisitDeclarations(ZoneList<Declaration*>* declarations) OVERRIDE; | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 396 | void DeclareModules(Handle<FixedArray> descriptions); | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 397 | void DeclareGlobals(Handle<FixedArray> pairs); | 
| Ben Murdoch | 589d697 | 2011-11-30 16:04:58 +0000 | [diff] [blame] | 398 | int DeclareGlobalsFlags(); | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 399 |  | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 400 | // Generate code to allocate all (including nested) modules and contexts. | 
|  | 401 | // Because of recursive linking and the presence of module alias declarations, | 
|  | 402 | // this has to be a separate pass _before_ populating or executing any module. | 
|  | 403 | void AllocateModules(ZoneList<Declaration*>* declarations); | 
|  | 404 |  | 
|  | 405 | // Generate code to create an iterator result object.  The "value" property is | 
|  | 406 | // set to a value popped from the stack, and "done" is set according to the | 
|  | 407 | // argument.  The result object is left in the result register. | 
|  | 408 | void EmitCreateIteratorResult(bool done); | 
|  | 409 |  | 
| Kristian Monsen | 80d68ea | 2010-09-08 11:05:35 +0100 | [diff] [blame] | 410 | // Try to perform a comparison as a fast inlined literal compare if | 
|  | 411 | // the operands allow it.  Returns true if the compare operations | 
|  | 412 | // has been matched and all code generated; false otherwise. | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 413 | bool TryLiteralCompare(CompareOperation* compare); | 
| Kristian Monsen | 80d68ea | 2010-09-08 11:05:35 +0100 | [diff] [blame] | 414 |  | 
| Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 415 | // Platform-specific code for comparing the type of a value with | 
|  | 416 | // a given literal string. | 
|  | 417 | void EmitLiteralCompareTypeof(Expression* expr, | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 418 | Expression* sub_expr, | 
|  | 419 | Handle<String> check); | 
| Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 420 |  | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 421 | // Platform-specific code for equality comparison with a nil-like value. | 
|  | 422 | void EmitLiteralCompareNil(CompareOperation* expr, | 
|  | 423 | Expression* sub_expr, | 
|  | 424 | NilValue nil); | 
| Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 425 |  | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 426 | // Bailout support. | 
| Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 427 | void PrepareForBailout(Expression* node, State state); | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 428 | void PrepareForBailoutForId(BailoutId id, State state); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 429 |  | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 430 | // Feedback slot support. The feedback vector will be cleared during gc and | 
|  | 431 | // collected by the type-feedback oracle. | 
| Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 432 | Handle<TypeFeedbackVector> FeedbackVector() const { | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 433 | return info_->feedback_vector(); | 
|  | 434 | } | 
| Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 435 | void EnsureSlotContainsAllocationSite(FeedbackVectorSlot slot); | 
|  | 436 | void EnsureSlotContainsAllocationSite(FeedbackVectorICSlot slot); | 
|  | 437 |  | 
|  | 438 | // Returns a smi for the index into the FixedArray that backs the feedback | 
|  | 439 | // vector | 
|  | 440 | Smi* SmiFromSlot(FeedbackVectorSlot slot) const { | 
|  | 441 | return Smi::FromInt(FeedbackVector()->GetIndex(slot)); | 
|  | 442 | } | 
|  | 443 |  | 
|  | 444 | Smi* SmiFromSlot(FeedbackVectorICSlot slot) const { | 
|  | 445 | return Smi::FromInt(FeedbackVector()->GetIndex(slot)); | 
|  | 446 | } | 
| Ben Murdoch | 5d4cdbf | 2012-04-11 10:23:59 +0100 | [diff] [blame] | 447 |  | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 448 | // Record a call's return site offset, used to rebuild the frame if the | 
|  | 449 | // called function was inlined at the site. | 
|  | 450 | void RecordJSReturnSite(Call* call); | 
|  | 451 |  | 
|  | 452 | // Prepare for bailout before a test (or compare) and branch.  If | 
|  | 453 | // should_normalize, then the following comparison will not handle the | 
|  | 454 | // canonical JS true value so we will insert a (dead) test against true at | 
|  | 455 | // the actual bailout target from the optimized code. If not | 
|  | 456 | // should_normalize, the true and false labels are ignored. | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 457 | void PrepareForBailoutBeforeSplit(Expression* expr, | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 458 | bool should_normalize, | 
|  | 459 | Label* if_true, | 
|  | 460 | Label* if_false); | 
|  | 461 |  | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 462 | // If enabled, emit debug code for checking that the current context is | 
|  | 463 | // neither a with nor a catch context. | 
|  | 464 | void EmitDebugCheckDeclarationContext(Variable* variable); | 
| Leon Clarke | f7060e2 | 2010-06-03 12:02:55 +0100 | [diff] [blame] | 465 |  | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 466 | // This is meant to be called at loop back edges, |back_edge_target| is | 
|  | 467 | // the jump target of the back edge and is used to approximate the amount | 
|  | 468 | // of code inside the loop. | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 469 | void EmitBackEdgeBookkeeping(IterationStatement* stmt, | 
|  | 470 | Label* back_edge_target); | 
|  | 471 | // Record the OSR AST id corresponding to a back edge in the code. | 
|  | 472 | void RecordBackEdge(BailoutId osr_ast_id); | 
|  | 473 | // Emit a table of back edge ids, pcs and loop depths into the code stream. | 
|  | 474 | // Return the offset of the start of the table. | 
|  | 475 | unsigned EmitBackEdgeTable(); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 476 |  | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 477 | void EmitProfilingCounterDecrement(int delta); | 
|  | 478 | void EmitProfilingCounterReset(); | 
|  | 479 |  | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 480 | // Emit code to pop values from the stack associated with nested statements | 
|  | 481 | // like try/catch, try/finally, etc, running the finallies and unwinding the | 
|  | 482 | // handlers as needed. | 
|  | 483 | void EmitUnwindBeforeReturn(); | 
|  | 484 |  | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 485 | // Platform-specific return sequence | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 486 | void EmitReturnSequence(); | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 487 |  | 
|  | 488 | // Platform-specific code sequences for calls | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 489 | void EmitCall(Call* expr, CallICState::CallType = CallICState::FUNCTION); | 
|  | 490 | void EmitCallWithLoadIC(Call* expr); | 
|  | 491 | void EmitSuperCallWithLoadIC(Call* expr); | 
|  | 492 | void EmitKeyedCallWithLoadIC(Call* expr, Expression* key); | 
| Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 493 | void EmitKeyedSuperCallWithLoadIC(Call* expr); | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 494 |  | 
| Leon Clarke | f7060e2 | 2010-06-03 12:02:55 +0100 | [diff] [blame] | 495 | // Platform-specific code for inline runtime calls. | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 496 | InlineFunctionGenerator FindInlineFunctionGenerator(Runtime::FunctionId id); | 
|  | 497 |  | 
| Leon Clarke | f7060e2 | 2010-06-03 12:02:55 +0100 | [diff] [blame] | 498 | void EmitInlineRuntimeCall(CallRuntime* expr); | 
| Steve Block | 791712a | 2010-08-27 10:21:07 +0100 | [diff] [blame] | 499 |  | 
|  | 500 | #define EMIT_INLINE_RUNTIME_CALL(name, x, y) \ | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 501 | void Emit##name(CallRuntime* expr); | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 502 | INLINE_FUNCTION_LIST(EMIT_INLINE_RUNTIME_CALL) | 
| Steve Block | 791712a | 2010-08-27 10:21:07 +0100 | [diff] [blame] | 503 | #undef EMIT_INLINE_RUNTIME_CALL | 
| Leon Clarke | f7060e2 | 2010-06-03 12:02:55 +0100 | [diff] [blame] | 504 |  | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 505 | // Platform-specific code for resuming generators. | 
|  | 506 | void EmitGeneratorResume(Expression *generator, | 
|  | 507 | Expression *value, | 
|  | 508 | JSGeneratorObject::ResumeMode resume_mode); | 
|  | 509 |  | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 510 | // Platform-specific code for loading variables. | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 511 | void EmitLoadGlobalCheckExtensions(VariableProxy* proxy, | 
| Ben Murdoch | 589d697 | 2011-11-30 16:04:58 +0000 | [diff] [blame] | 512 | TypeofState typeof_state, | 
|  | 513 | Label* slow); | 
|  | 514 | MemOperand ContextSlotOperandCheckExtensions(Variable* var, Label* slow); | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 515 | void EmitDynamicLookupFastCase(VariableProxy* proxy, | 
| Ben Murdoch | 589d697 | 2011-11-30 16:04:58 +0000 | [diff] [blame] | 516 | TypeofState typeof_state, | 
|  | 517 | Label* slow, | 
|  | 518 | Label* done); | 
| Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 519 | void EmitVariableLoad(VariableProxy* proxy); | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 520 |  | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 521 | void EmitAccessor(Expression* expression); | 
| Ben Murdoch | 5d4cdbf | 2012-04-11 10:23:59 +0100 | [diff] [blame] | 522 |  | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 523 | // Expects the arguments and the function already pushed. | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 524 | void EmitResolvePossiblyDirectEval(int arg_count); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 525 |  | 
| Leon Clarke | f7060e2 | 2010-06-03 12:02:55 +0100 | [diff] [blame] | 526 | // Platform-specific support for allocating a new closure based on | 
|  | 527 | // the given function info. | 
| Shimeng (Simon) Wang | 8a31eba | 2010-12-06 19:01:33 -0800 | [diff] [blame] | 528 | void EmitNewClosure(Handle<SharedFunctionInfo> info, bool pretenure); | 
| Leon Clarke | f7060e2 | 2010-06-03 12:02:55 +0100 | [diff] [blame] | 529 |  | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 530 | // Platform-specific support for compiling assignments. | 
|  | 531 |  | 
| Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 532 | // Left-hand side can only be a property, a global or a (parameter or local) | 
|  | 533 | // slot. | 
|  | 534 | enum LhsKind { | 
|  | 535 | VARIABLE, | 
|  | 536 | NAMED_PROPERTY, | 
|  | 537 | KEYED_PROPERTY, | 
|  | 538 | NAMED_SUPER_PROPERTY, | 
|  | 539 | KEYED_SUPER_PROPERTY | 
|  | 540 | }; | 
|  | 541 |  | 
|  | 542 | static LhsKind GetAssignType(Property* property) { | 
|  | 543 | if (property == NULL) return VARIABLE; | 
|  | 544 | bool super_access = property->IsSuperAccess(); | 
|  | 545 | return (property->key()->IsPropertyName()) | 
|  | 546 | ? (super_access ? NAMED_SUPER_PROPERTY : NAMED_PROPERTY) | 
|  | 547 | : (super_access ? KEYED_SUPER_PROPERTY : KEYED_PROPERTY); | 
|  | 548 | } | 
|  | 549 |  | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 550 | // Load a value from a named property. | 
|  | 551 | // The receiver is left on the stack by the IC. | 
|  | 552 | void EmitNamedPropertyLoad(Property* expr); | 
|  | 553 |  | 
| Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 554 | // Load a value from super.named property. | 
|  | 555 | // Expect receiver ('this' value) and home_object on the stack. | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 556 | void EmitNamedSuperPropertyLoad(Property* expr); | 
|  | 557 |  | 
| Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 558 | // Load a value from super[keyed] property. | 
|  | 559 | // Expect receiver ('this' value), home_object and key on the stack. | 
|  | 560 | void EmitKeyedSuperPropertyLoad(Property* expr); | 
|  | 561 |  | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 562 | // Load a value from a keyed property. | 
|  | 563 | // The receiver and the key is left on the stack by the IC. | 
|  | 564 | void EmitKeyedPropertyLoad(Property* expr); | 
|  | 565 |  | 
| Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 566 | // Adds the properties to the class (function) object and to its prototype. | 
|  | 567 | // Expects the class (function) in the accumulator. The class (function) is | 
|  | 568 | // in the accumulator after installing all the properties. | 
|  | 569 | void EmitClassDefineProperties(ClassLiteral* lit); | 
|  | 570 |  | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 571 | // Apply the compound assignment operator. Expects the left operand on top | 
|  | 572 | // of the stack and the right one in the accumulator. | 
| Ben Murdoch | 257744e | 2011-11-30 15:57:28 +0000 | [diff] [blame] | 573 | void EmitBinaryOp(BinaryOperation* expr, | 
|  | 574 | Token::Value op, | 
| Kristian Monsen | 80d68ea | 2010-09-08 11:05:35 +0100 | [diff] [blame] | 575 | OverwriteMode mode); | 
|  | 576 |  | 
|  | 577 | // Helper functions for generating inlined smi code for certain | 
|  | 578 | // binary operations. | 
| Ben Murdoch | 257744e | 2011-11-30 15:57:28 +0000 | [diff] [blame] | 579 | void EmitInlineSmiBinaryOp(BinaryOperation* expr, | 
| Kristian Monsen | 80d68ea | 2010-09-08 11:05:35 +0100 | [diff] [blame] | 580 | Token::Value op, | 
| Kristian Monsen | 80d68ea | 2010-09-08 11:05:35 +0100 | [diff] [blame] | 581 | OverwriteMode mode, | 
|  | 582 | Expression* left, | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 583 | Expression* right); | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 584 |  | 
| Leon Clarke | f7060e2 | 2010-06-03 12:02:55 +0100 | [diff] [blame] | 585 | // Assign to the given expression as if via '='. The right-hand-side value | 
|  | 586 | // is expected in the accumulator. | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 587 | void EmitAssignment(Expression* expr); | 
| Leon Clarke | f7060e2 | 2010-06-03 12:02:55 +0100 | [diff] [blame] | 588 |  | 
| Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 589 | // Shall an error be thrown if assignment with 'op' operation is perfomed | 
|  | 590 | // on this variable in given language mode? | 
|  | 591 | static bool IsSignallingAssignmentToConst(Variable* var, Token::Value op, | 
|  | 592 | StrictMode strict_mode) { | 
|  | 593 | if (var->mode() == CONST) return op != Token::INIT_CONST; | 
|  | 594 |  | 
|  | 595 | if (var->mode() == CONST_LEGACY) { | 
|  | 596 | return strict_mode == STRICT && op != Token::INIT_CONST_LEGACY; | 
|  | 597 | } | 
|  | 598 |  | 
|  | 599 | return false; | 
|  | 600 | } | 
|  | 601 |  | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 602 | // Complete a variable assignment.  The right-hand-side value is expected | 
|  | 603 | // in the accumulator. | 
| Leon Clarke | f7060e2 | 2010-06-03 12:02:55 +0100 | [diff] [blame] | 604 | void EmitVariableAssignment(Variable* var, | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 605 | Token::Value op); | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 606 |  | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 607 | // Helper functions to EmitVariableAssignment | 
|  | 608 | void EmitStoreToStackLocalOrContextSlot(Variable* var, | 
|  | 609 | MemOperand location); | 
|  | 610 |  | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 611 | // Complete a named property assignment.  The receiver is expected on top | 
|  | 612 | // of the stack and the right-hand-side value in the accumulator. | 
|  | 613 | void EmitNamedPropertyAssignment(Assignment* expr); | 
|  | 614 |  | 
| Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 615 | // Complete a super named property assignment. The right-hand-side value | 
|  | 616 | // is expected in accumulator. | 
|  | 617 | void EmitNamedSuperPropertyStore(Property* prop); | 
|  | 618 |  | 
|  | 619 | // Complete a super named property assignment. The right-hand-side value | 
|  | 620 | // is expected in accumulator. | 
|  | 621 | void EmitKeyedSuperPropertyStore(Property* prop); | 
|  | 622 |  | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 623 | // Complete a keyed property assignment.  The receiver and key are | 
|  | 624 | // expected on top of the stack and the right-hand-side value in the | 
|  | 625 | // accumulator. | 
|  | 626 | void EmitKeyedPropertyAssignment(Assignment* expr); | 
|  | 627 |  | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 628 | void EmitLoadHomeObject(SuperReference* expr); | 
|  | 629 |  | 
| Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 630 | static bool NeedsHomeObject(Expression* expr) { | 
|  | 631 | return FunctionLiteral::NeedsHomeObject(expr); | 
|  | 632 | } | 
|  | 633 |  | 
|  | 634 | // Adds the [[HomeObject]] to |initializer| if it is a FunctionLiteral. | 
|  | 635 | // The value of the initializer is expected to be at the top of the stack. | 
|  | 636 | // |offset| is the offset in the stack where the home object can be found. | 
|  | 637 | void EmitSetHomeObjectIfNeeded(Expression* initializer, int offset); | 
|  | 638 |  | 
|  | 639 | void EmitLoadSuperConstructor(SuperReference* expr); | 
|  | 640 |  | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 641 | void CallIC(Handle<Code> code, | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 642 | TypeFeedbackId id = TypeFeedbackId::None()); | 
|  | 643 |  | 
|  | 644 | void CallLoadIC(ContextualMode mode, | 
|  | 645 | TypeFeedbackId id = TypeFeedbackId::None()); | 
|  | 646 | void CallStoreIC(TypeFeedbackId id = TypeFeedbackId::None()); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 647 |  | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 648 | void SetFunctionPosition(FunctionLiteral* fun); | 
|  | 649 | void SetReturnPosition(FunctionLiteral* fun); | 
|  | 650 | void SetStatementPosition(Statement* stmt); | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 651 | void SetExpressionPosition(Expression* expr); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 652 | void SetSourcePosition(int pos); | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 653 |  | 
|  | 654 | // Non-local control flow support. | 
|  | 655 | void EnterFinallyBlock(); | 
|  | 656 | void ExitFinallyBlock(); | 
|  | 657 |  | 
|  | 658 | // Loop nesting counter. | 
|  | 659 | int loop_depth() { return loop_depth_; } | 
|  | 660 | void increment_loop_depth() { loop_depth_++; } | 
|  | 661 | void decrement_loop_depth() { | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 662 | DCHECK(loop_depth_ > 0); | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 663 | loop_depth_--; | 
|  | 664 | } | 
|  | 665 |  | 
|  | 666 | MacroAssembler* masm() { return masm_; } | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 667 |  | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 668 | class ExpressionContext; | 
|  | 669 | const ExpressionContext* context() { return context_; } | 
|  | 670 | void set_new_context(const ExpressionContext* context) { context_ = context; } | 
|  | 671 |  | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 672 | Handle<Script> script() { return info_->script(); } | 
|  | 673 | bool is_eval() { return info_->is_eval(); } | 
| Ben Murdoch | 589d697 | 2011-11-30 16:04:58 +0000 | [diff] [blame] | 674 | bool is_native() { return info_->is_native(); } | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 675 | StrictMode strict_mode() { return function()->strict_mode(); } | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 676 | FunctionLiteral* function() { return info_->function(); } | 
| Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 677 | Scope* scope() { return scope_; } | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 678 |  | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 679 | static Register result_register(); | 
|  | 680 | static Register context_register(); | 
|  | 681 |  | 
|  | 682 | // Set fields in the stack frame. Offsets are the frame pointer relative | 
|  | 683 | // offsets defined in, e.g., StandardFrameConstants. | 
|  | 684 | void StoreToFrameField(int frame_offset, Register value); | 
|  | 685 |  | 
|  | 686 | // Load a value from the current context. Indices are defined as an enum | 
|  | 687 | // in v8::internal::Context. | 
|  | 688 | void LoadContextField(Register dst, int context_index); | 
|  | 689 |  | 
| Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 690 | // Push the function argument for the runtime functions PushWithContext | 
|  | 691 | // and PushCatchContext. | 
|  | 692 | void PushFunctionArgumentForContextAllocation(); | 
|  | 693 |  | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 694 | // AST node visit functions. | 
| Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 695 | #define DECLARE_VISIT(type) virtual void Visit##type(type* node) OVERRIDE; | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 696 | AST_NODE_LIST(DECLARE_VISIT) | 
|  | 697 | #undef DECLARE_VISIT | 
| Ben Murdoch | 257744e | 2011-11-30 15:57:28 +0000 | [diff] [blame] | 698 |  | 
| Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 699 | void VisitComma(BinaryOperation* expr); | 
|  | 700 | void VisitLogicalExpression(BinaryOperation* expr); | 
|  | 701 | void VisitArithmeticExpression(BinaryOperation* expr); | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 702 |  | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 703 | void VisitForTypeofValue(Expression* expr); | 
| Kristian Monsen | 80d68ea | 2010-09-08 11:05:35 +0100 | [diff] [blame] | 704 |  | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 705 | void Generate(); | 
|  | 706 | void PopulateDeoptimizationData(Handle<Code> code); | 
|  | 707 | void PopulateTypeFeedbackInfo(Handle<Code> code); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 708 |  | 
|  | 709 | Handle<FixedArray> handler_table() { return handler_table_; } | 
|  | 710 |  | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 711 | struct BailoutEntry { | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 712 | BailoutId id; | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 713 | unsigned pc_and_state; | 
|  | 714 | }; | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 715 |  | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 716 | struct BackEdgeEntry { | 
|  | 717 | BailoutId id; | 
|  | 718 | unsigned pc; | 
|  | 719 | uint32_t loop_depth; | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 720 | }; | 
|  | 721 |  | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 722 | class ExpressionContext BASE_EMBEDDED { | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 723 | public: | 
|  | 724 | explicit ExpressionContext(FullCodeGenerator* codegen) | 
|  | 725 | : masm_(codegen->masm()), old_(codegen->context()), codegen_(codegen) { | 
|  | 726 | codegen->set_new_context(this); | 
|  | 727 | } | 
|  | 728 |  | 
|  | 729 | virtual ~ExpressionContext() { | 
|  | 730 | codegen_->set_new_context(old_); | 
|  | 731 | } | 
|  | 732 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 733 | Isolate* isolate() const { return codegen_->isolate(); } | 
|  | 734 |  | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 735 | // Convert constant control flow (true or false) to the result expected for | 
|  | 736 | // this expression context. | 
|  | 737 | virtual void Plug(bool flag) const = 0; | 
|  | 738 |  | 
| Ben Murdoch | 589d697 | 2011-11-30 16:04:58 +0000 | [diff] [blame] | 739 | // Emit code to convert a pure value (in a register, known variable | 
|  | 740 | // location, as a literal, or on top of the stack) into the result | 
|  | 741 | // expected according to this expression context. | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 742 | virtual void Plug(Register reg) const = 0; | 
| Ben Murdoch | 589d697 | 2011-11-30 16:04:58 +0000 | [diff] [blame] | 743 | virtual void Plug(Variable* var) const = 0; | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 744 | virtual void Plug(Handle<Object> lit) const = 0; | 
|  | 745 | virtual void Plug(Heap::RootListIndex index) const = 0; | 
|  | 746 | virtual void PlugTOS() const = 0; | 
|  | 747 |  | 
|  | 748 | // Emit code to convert pure control flow to a pair of unbound labels into | 
|  | 749 | // the result expected according to this expression context.  The | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 750 | // implementation will bind both labels unless it's a TestContext, which | 
|  | 751 | // won't bind them at this point. | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 752 | virtual void Plug(Label* materialize_true, | 
|  | 753 | Label* materialize_false) const = 0; | 
|  | 754 |  | 
|  | 755 | // Emit code to discard count elements from the top of stack, then convert | 
|  | 756 | // a pure value into the result expected according to this expression | 
|  | 757 | // context. | 
|  | 758 | virtual void DropAndPlug(int count, Register reg) const = 0; | 
|  | 759 |  | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 760 | // Set up branch labels for a test expression.  The three Label** parameters | 
|  | 761 | // are output parameters. | 
|  | 762 | virtual void PrepareTest(Label* materialize_true, | 
|  | 763 | Label* materialize_false, | 
|  | 764 | Label** if_true, | 
|  | 765 | Label** if_false, | 
|  | 766 | Label** fall_through) const = 0; | 
|  | 767 |  | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 768 | // Returns true if we are evaluating only for side effects (i.e. if the | 
|  | 769 | // result will be discarded). | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 770 | virtual bool IsEffect() const { return false; } | 
|  | 771 |  | 
| Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 772 | // Returns true if we are evaluating for the value (in accu/on stack). | 
|  | 773 | virtual bool IsAccumulatorValue() const { return false; } | 
|  | 774 | virtual bool IsStackValue() const { return false; } | 
|  | 775 |  | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 776 | // Returns true if we are branching on the value rather than materializing | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 777 | // it.  Only used for asserts. | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 778 | virtual bool IsTest() const { return false; } | 
|  | 779 |  | 
|  | 780 | protected: | 
|  | 781 | FullCodeGenerator* codegen() const { return codegen_; } | 
|  | 782 | MacroAssembler* masm() const { return masm_; } | 
|  | 783 | MacroAssembler* masm_; | 
|  | 784 |  | 
|  | 785 | private: | 
|  | 786 | const ExpressionContext* old_; | 
|  | 787 | FullCodeGenerator* codegen_; | 
|  | 788 | }; | 
|  | 789 |  | 
|  | 790 | class AccumulatorValueContext : public ExpressionContext { | 
|  | 791 | public: | 
|  | 792 | explicit AccumulatorValueContext(FullCodeGenerator* codegen) | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 793 | : ExpressionContext(codegen) { } | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 794 |  | 
|  | 795 | virtual void Plug(bool flag) const; | 
|  | 796 | virtual void Plug(Register reg) const; | 
|  | 797 | virtual void Plug(Label* materialize_true, Label* materialize_false) const; | 
| Ben Murdoch | 589d697 | 2011-11-30 16:04:58 +0000 | [diff] [blame] | 798 | virtual void Plug(Variable* var) const; | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 799 | virtual void Plug(Handle<Object> lit) const; | 
|  | 800 | virtual void Plug(Heap::RootListIndex) const; | 
|  | 801 | virtual void PlugTOS() const; | 
|  | 802 | virtual void DropAndPlug(int count, Register reg) const; | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 803 | virtual void PrepareTest(Label* materialize_true, | 
|  | 804 | Label* materialize_false, | 
|  | 805 | Label** if_true, | 
|  | 806 | Label** if_false, | 
|  | 807 | Label** fall_through) const; | 
| Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 808 | virtual bool IsAccumulatorValue() const { return true; } | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 809 | }; | 
|  | 810 |  | 
|  | 811 | class StackValueContext : public ExpressionContext { | 
|  | 812 | public: | 
|  | 813 | explicit StackValueContext(FullCodeGenerator* codegen) | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 814 | : ExpressionContext(codegen) { } | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 815 |  | 
|  | 816 | virtual void Plug(bool flag) const; | 
|  | 817 | virtual void Plug(Register reg) const; | 
|  | 818 | virtual void Plug(Label* materialize_true, Label* materialize_false) const; | 
| Ben Murdoch | 589d697 | 2011-11-30 16:04:58 +0000 | [diff] [blame] | 819 | virtual void Plug(Variable* var) const; | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 820 | virtual void Plug(Handle<Object> lit) const; | 
|  | 821 | virtual void Plug(Heap::RootListIndex) const; | 
|  | 822 | virtual void PlugTOS() const; | 
|  | 823 | virtual void DropAndPlug(int count, Register reg) const; | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 824 | virtual void PrepareTest(Label* materialize_true, | 
|  | 825 | Label* materialize_false, | 
|  | 826 | Label** if_true, | 
|  | 827 | Label** if_false, | 
|  | 828 | Label** fall_through) const; | 
| Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 829 | virtual bool IsStackValue() const { return true; } | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 830 | }; | 
|  | 831 |  | 
|  | 832 | class TestContext : public ExpressionContext { | 
|  | 833 | public: | 
| Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 834 | TestContext(FullCodeGenerator* codegen, | 
|  | 835 | Expression* condition, | 
|  | 836 | Label* true_label, | 
|  | 837 | Label* false_label, | 
|  | 838 | Label* fall_through) | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 839 | : ExpressionContext(codegen), | 
| Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 840 | condition_(condition), | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 841 | true_label_(true_label), | 
|  | 842 | false_label_(false_label), | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 843 | fall_through_(fall_through) { } | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 844 |  | 
| Ben Murdoch | f87a203 | 2010-10-22 12:50:53 +0100 | [diff] [blame] | 845 | static const TestContext* cast(const ExpressionContext* context) { | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 846 | DCHECK(context->IsTest()); | 
| Ben Murdoch | f87a203 | 2010-10-22 12:50:53 +0100 | [diff] [blame] | 847 | return reinterpret_cast<const TestContext*>(context); | 
|  | 848 | } | 
|  | 849 |  | 
| Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 850 | Expression* condition() const { return condition_; } | 
| Ben Murdoch | f87a203 | 2010-10-22 12:50:53 +0100 | [diff] [blame] | 851 | Label* true_label() const { return true_label_; } | 
|  | 852 | Label* false_label() const { return false_label_; } | 
|  | 853 | Label* fall_through() const { return fall_through_; } | 
|  | 854 |  | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 855 | virtual void Plug(bool flag) const; | 
|  | 856 | virtual void Plug(Register reg) const; | 
|  | 857 | virtual void Plug(Label* materialize_true, Label* materialize_false) const; | 
| Ben Murdoch | 589d697 | 2011-11-30 16:04:58 +0000 | [diff] [blame] | 858 | virtual void Plug(Variable* var) const; | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 859 | virtual void Plug(Handle<Object> lit) const; | 
|  | 860 | virtual void Plug(Heap::RootListIndex) const; | 
|  | 861 | virtual void PlugTOS() const; | 
|  | 862 | virtual void DropAndPlug(int count, Register reg) const; | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 863 | virtual void PrepareTest(Label* materialize_true, | 
|  | 864 | Label* materialize_false, | 
|  | 865 | Label** if_true, | 
|  | 866 | Label** if_false, | 
|  | 867 | Label** fall_through) const; | 
|  | 868 | virtual bool IsTest() const { return true; } | 
|  | 869 |  | 
|  | 870 | private: | 
| Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 871 | Expression* condition_; | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 872 | Label* true_label_; | 
|  | 873 | Label* false_label_; | 
|  | 874 | Label* fall_through_; | 
|  | 875 | }; | 
|  | 876 |  | 
|  | 877 | class EffectContext : public ExpressionContext { | 
|  | 878 | public: | 
|  | 879 | explicit EffectContext(FullCodeGenerator* codegen) | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 880 | : ExpressionContext(codegen) { } | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 881 |  | 
|  | 882 | virtual void Plug(bool flag) const; | 
|  | 883 | virtual void Plug(Register reg) const; | 
|  | 884 | virtual void Plug(Label* materialize_true, Label* materialize_false) const; | 
| Ben Murdoch | 589d697 | 2011-11-30 16:04:58 +0000 | [diff] [blame] | 885 | virtual void Plug(Variable* var) const; | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 886 | virtual void Plug(Handle<Object> lit) const; | 
|  | 887 | virtual void Plug(Heap::RootListIndex) const; | 
|  | 888 | virtual void PlugTOS() const; | 
|  | 889 | virtual void DropAndPlug(int count, Register reg) const; | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 890 | virtual void PrepareTest(Label* materialize_true, | 
|  | 891 | Label* materialize_false, | 
|  | 892 | Label** if_true, | 
|  | 893 | Label** if_false, | 
|  | 894 | Label** fall_through) const; | 
|  | 895 | virtual bool IsEffect() const { return true; } | 
|  | 896 | }; | 
|  | 897 |  | 
| Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 898 | class EnterBlockScopeIfNeeded { | 
|  | 899 | public: | 
|  | 900 | EnterBlockScopeIfNeeded(FullCodeGenerator* codegen, Scope* scope, | 
|  | 901 | BailoutId entry_id, BailoutId declarations_id, | 
|  | 902 | BailoutId exit_id); | 
|  | 903 | ~EnterBlockScopeIfNeeded(); | 
|  | 904 |  | 
|  | 905 | private: | 
|  | 906 | MacroAssembler* masm() const { return codegen_->masm(); } | 
|  | 907 |  | 
|  | 908 | FullCodeGenerator* codegen_; | 
|  | 909 | Scope* scope_; | 
|  | 910 | Scope* saved_scope_; | 
|  | 911 | BailoutId exit_id_; | 
|  | 912 | }; | 
|  | 913 |  | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 914 | MacroAssembler* masm_; | 
|  | 915 | CompilationInfo* info_; | 
| Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 916 | Scope* scope_; | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 917 | Label return_label_; | 
|  | 918 | NestedStatement* nesting_stack_; | 
|  | 919 | int loop_depth_; | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 920 | ZoneList<Handle<Object> >* globals_; | 
|  | 921 | Handle<FixedArray> modules_; | 
|  | 922 | int module_index_; | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 923 | const ExpressionContext* context_; | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 924 | ZoneList<BailoutEntry> bailout_entries_; | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 925 | ZoneList<BackEdgeEntry> back_edges_; | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 926 | int ic_total_count_; | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 927 | Handle<FixedArray> handler_table_; | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 928 | Handle<Cell> profiling_counter_; | 
|  | 929 | bool generate_debug_code_; | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 930 |  | 
|  | 931 | friend class NestedStatement; | 
|  | 932 |  | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 933 | DEFINE_AST_VISITOR_SUBCLASS_MEMBERS(); | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 934 | DISALLOW_COPY_AND_ASSIGN(FullCodeGenerator); | 
|  | 935 | }; | 
|  | 936 |  | 
|  | 937 |  | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 938 | // A map from property names to getter/setter pairs allocated in the zone. | 
|  | 939 | class AccessorTable: public TemplateHashMap<Literal, | 
|  | 940 | ObjectLiteral::Accessors, | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 941 | ZoneAllocationPolicy> { | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 942 | public: | 
|  | 943 | explicit AccessorTable(Zone* zone) : | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 944 | TemplateHashMap<Literal, ObjectLiteral::Accessors, | 
|  | 945 | ZoneAllocationPolicy>(Literal::Match, | 
|  | 946 | ZoneAllocationPolicy(zone)), | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 947 | zone_(zone) { } | 
|  | 948 |  | 
|  | 949 | Iterator lookup(Literal* literal) { | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 950 | Iterator it = find(literal, true, ZoneAllocationPolicy(zone_)); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 951 | if (it->second == NULL) it->second = new(zone_) ObjectLiteral::Accessors(); | 
|  | 952 | return it; | 
|  | 953 | } | 
|  | 954 |  | 
|  | 955 | private: | 
|  | 956 | Zone* zone_; | 
|  | 957 | }; | 
|  | 958 |  | 
|  | 959 |  | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 960 | class BackEdgeTable { | 
|  | 961 | public: | 
|  | 962 | BackEdgeTable(Code* code, DisallowHeapAllocation* required) { | 
|  | 963 | DCHECK(code->kind() == Code::FUNCTION); | 
|  | 964 | instruction_start_ = code->instruction_start(); | 
|  | 965 | Address table_address = instruction_start_ + code->back_edge_table_offset(); | 
|  | 966 | length_ = Memory::uint32_at(table_address); | 
|  | 967 | start_ = table_address + kTableLengthSize; | 
|  | 968 | } | 
|  | 969 |  | 
|  | 970 | uint32_t length() { return length_; } | 
|  | 971 |  | 
|  | 972 | BailoutId ast_id(uint32_t index) { | 
|  | 973 | return BailoutId(static_cast<int>( | 
|  | 974 | Memory::uint32_at(entry_at(index) + kAstIdOffset))); | 
|  | 975 | } | 
|  | 976 |  | 
|  | 977 | uint32_t loop_depth(uint32_t index) { | 
|  | 978 | return Memory::uint32_at(entry_at(index) + kLoopDepthOffset); | 
|  | 979 | } | 
|  | 980 |  | 
|  | 981 | uint32_t pc_offset(uint32_t index) { | 
|  | 982 | return Memory::uint32_at(entry_at(index) + kPcOffsetOffset); | 
|  | 983 | } | 
|  | 984 |  | 
|  | 985 | Address pc(uint32_t index) { | 
|  | 986 | return instruction_start_ + pc_offset(index); | 
|  | 987 | } | 
|  | 988 |  | 
|  | 989 | enum BackEdgeState { | 
|  | 990 | INTERRUPT, | 
|  | 991 | ON_STACK_REPLACEMENT, | 
|  | 992 | OSR_AFTER_STACK_CHECK | 
|  | 993 | }; | 
|  | 994 |  | 
|  | 995 | // Increase allowed loop nesting level by one and patch those matching loops. | 
|  | 996 | static void Patch(Isolate* isolate, Code* unoptimized_code); | 
|  | 997 |  | 
|  | 998 | // Patch the back edge to the target state, provided the correct callee. | 
|  | 999 | static void PatchAt(Code* unoptimized_code, | 
|  | 1000 | Address pc, | 
|  | 1001 | BackEdgeState target_state, | 
|  | 1002 | Code* replacement_code); | 
|  | 1003 |  | 
|  | 1004 | // Change all patched back edges back to normal interrupts. | 
|  | 1005 | static void Revert(Isolate* isolate, | 
|  | 1006 | Code* unoptimized_code); | 
|  | 1007 |  | 
|  | 1008 | // Change a back edge patched for on-stack replacement to perform a | 
|  | 1009 | // stack check first. | 
|  | 1010 | static void AddStackCheck(Handle<Code> code, uint32_t pc_offset); | 
|  | 1011 |  | 
|  | 1012 | // Revert the patch by AddStackCheck. | 
|  | 1013 | static void RemoveStackCheck(Handle<Code> code, uint32_t pc_offset); | 
|  | 1014 |  | 
|  | 1015 | // Return the current patch state of the back edge. | 
|  | 1016 | static BackEdgeState GetBackEdgeState(Isolate* isolate, | 
|  | 1017 | Code* unoptimized_code, | 
|  | 1018 | Address pc_after); | 
|  | 1019 |  | 
|  | 1020 | #ifdef DEBUG | 
|  | 1021 | // Verify that all back edges of a certain loop depth are patched. | 
|  | 1022 | static bool Verify(Isolate* isolate, Code* unoptimized_code); | 
|  | 1023 | #endif  // DEBUG | 
|  | 1024 |  | 
|  | 1025 | private: | 
|  | 1026 | Address entry_at(uint32_t index) { | 
|  | 1027 | DCHECK(index < length_); | 
|  | 1028 | return start_ + index * kEntrySize; | 
|  | 1029 | } | 
|  | 1030 |  | 
|  | 1031 | static const int kTableLengthSize = kIntSize; | 
|  | 1032 | static const int kAstIdOffset = 0 * kIntSize; | 
|  | 1033 | static const int kPcOffsetOffset = 1 * kIntSize; | 
|  | 1034 | static const int kLoopDepthOffset = 2 * kIntSize; | 
|  | 1035 | static const int kEntrySize = 3 * kIntSize; | 
|  | 1036 |  | 
|  | 1037 | Address start_; | 
|  | 1038 | Address instruction_start_; | 
|  | 1039 | uint32_t length_; | 
|  | 1040 | }; | 
|  | 1041 |  | 
|  | 1042 |  | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 1043 | } }  // namespace v8::internal | 
|  | 1044 |  | 
|  | 1045 | #endif  // V8_FULL_CODEGEN_H_ |