blob: 0ed26a149e8da8d04cd968411daf0217ef7c7270 [file] [log] [blame]
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001// Copyright 2011 the V8 project authors. All rights reserved.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002// 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
lrn@chromium.org1c092762011-05-09 09:42:16 +000033#include "allocation.h"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000034#include "ast.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000035#include "code-stubs.h"
36#include "codegen.h"
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000037#include "compiler.h"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000038
39namespace v8 {
40namespace internal {
41
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000042// Forward declarations.
43class JumpPatchSite;
44
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000045// 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.
49class BreakableStatementChecker: public AstVisitor {
50 public:
51 BreakableStatementChecker() : is_breakable_(false) {}
52
53 void Check(Statement* stmt);
54 void Check(Expression* stmt);
55
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
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000070// -----------------------------------------------------------------------------
71// Full code generator.
72
73class FullCodeGenerator: public AstVisitor {
74 public:
kasperl@chromium.orga5551262010-12-07 12:49:48 +000075 enum State {
76 NO_REGISTERS,
77 TOS_REG
78 };
79
ager@chromium.org5c838252010-02-19 08:53:10 +000080 explicit FullCodeGenerator(MacroAssembler* masm)
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000081 : masm_(masm),
ager@chromium.org5c838252010-02-19 08:53:10 +000082 info_(NULL),
ricow@chromium.org4f693d62011-07-04 14:01:31 +000083 scope_(NULL),
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000084 nesting_stack_(NULL),
85 loop_depth_(0),
vegorov@chromium.org7943d462011-08-01 11:41:52 +000086 stack_height_(0),
kasperl@chromium.orga5551262010-12-07 12:49:48 +000087 context_(NULL),
88 bailout_entries_(0),
89 stack_checks_(2), // There's always at least one.
90 forward_bailout_stack_(NULL),
91 forward_bailout_pending_(NULL) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000092 }
93
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000094 static bool MakeCode(CompilationInfo* info);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000095
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000096 void Generate(CompilationInfo* info);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000097 void PopulateDeoptimizationData(Handle<Code> code);
98
99 class StateField : public BitField<State, 0, 8> { };
100 class PcField : public BitField<unsigned, 8, 32-8> { };
101
102 static const char* State2String(State state) {
103 switch (state) {
104 case NO_REGISTERS: return "NO_REGISTERS";
105 case TOS_REG: return "TOS_REG";
106 }
107 UNREACHABLE();
108 return NULL;
109 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000110
111 private:
112 class Breakable;
113 class Iteration;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000114
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000115 class TestContext;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000116
117 class NestedStatement BASE_EMBEDDED {
118 public:
119 explicit NestedStatement(FullCodeGenerator* codegen) : codegen_(codegen) {
120 // Link into codegen's nesting stack.
121 previous_ = codegen->nesting_stack_;
122 codegen->nesting_stack_ = this;
123 }
124 virtual ~NestedStatement() {
125 // Unlink from codegen's nesting stack.
126 ASSERT_EQ(this, codegen_->nesting_stack_);
127 codegen_->nesting_stack_ = previous_;
128 }
129
130 virtual Breakable* AsBreakable() { return NULL; }
131 virtual Iteration* AsIteration() { return NULL; }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000132
133 virtual bool IsContinueTarget(Statement* target) { return false; }
134 virtual bool IsBreakTarget(Statement* target) { return false; }
135
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000136 // Notify the statement that we are exiting it via break, continue, or
137 // return and give it a chance to generate cleanup code. Return the
138 // next outer statement in the nesting stack. We accumulate in
139 // *stack_depth the amount to drop the stack and in *context_length the
140 // number of context chain links to unwind as we traverse the nesting
141 // stack from an exit to its target.
142 virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
143 return previous_;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000144 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000145
146 protected:
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000147 MacroAssembler* masm() { return codegen_->masm(); }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000148
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000149 FullCodeGenerator* codegen_;
150 NestedStatement* previous_;
151 DISALLOW_COPY_AND_ASSIGN(NestedStatement);
152 };
153
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000154 // A breakable statement such as a block.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000155 class Breakable : public NestedStatement {
156 public:
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000157 Breakable(FullCodeGenerator* codegen, BreakableStatement* statement)
158 : NestedStatement(codegen), statement_(statement) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000159 }
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000160 virtual ~Breakable() {}
161
162 virtual Breakable* AsBreakable() { return this; }
163 virtual bool IsBreakTarget(Statement* target) {
164 return statement() == target;
165 }
166
167 BreakableStatement* statement() { return statement_; }
168 Label* break_label() { return &break_label_; }
169
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000170 private:
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000171 BreakableStatement* statement_;
172 Label break_label_;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000173 };
174
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000175 // An iteration statement such as a while, for, or do loop.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000176 class Iteration : public Breakable {
177 public:
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000178 Iteration(FullCodeGenerator* codegen, IterationStatement* statement)
179 : Breakable(codegen, statement) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000180 }
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000181 virtual ~Iteration() {}
182
183 virtual Iteration* AsIteration() { return this; }
184 virtual bool IsContinueTarget(Statement* target) {
185 return statement() == target;
186 }
187
188 Label* continue_label() { return &continue_label_; }
189
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000190 private:
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000191 Label continue_label_;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000192 };
193
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000194 // The try block of a try/catch statement.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000195 class TryCatch : public NestedStatement {
196 public:
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000197 explicit TryCatch(FullCodeGenerator* codegen) : NestedStatement(codegen) {
198 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000199 virtual ~TryCatch() {}
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000200
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000201 virtual NestedStatement* Exit(int* stack_depth, int* context_length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000202 };
203
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000204 // The try block of a try/finally statement.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000205 class TryFinally : public NestedStatement {
206 public:
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000207 TryFinally(FullCodeGenerator* codegen, Label* finally_entry)
208 : NestedStatement(codegen), finally_entry_(finally_entry) {
209 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000210 virtual ~TryFinally() {}
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000211
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000212 virtual NestedStatement* Exit(int* stack_depth, int* context_length);
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000213
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000214 private:
215 Label* finally_entry_;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000216 };
217
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000218 // The finally block of a try/finally statement.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000219 class Finally : public NestedStatement {
220 public:
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000221 static const int kElementCount = 2;
222
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000223 explicit Finally(FullCodeGenerator* codegen) : NestedStatement(codegen) { }
224 virtual ~Finally() {}
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000225
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000226 virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000227 *stack_depth += kElementCount;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000228 return previous_;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000229 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000230 };
231
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000232 // The body of a for/in loop.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000233 class ForIn : public Iteration {
234 public:
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000235 static const int kElementCount = 5;
236
237 ForIn(FullCodeGenerator* codegen, ForInStatement* statement)
238 : Iteration(codegen, statement) {
239 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000240 virtual ~ForIn() {}
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000241
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000242 virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000243 *stack_depth += kElementCount;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000244 return previous_;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000245 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000246 };
247
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000248
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000249 // The body of a with or catch.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000250 class WithOrCatch : public NestedStatement {
251 public:
252 explicit WithOrCatch(FullCodeGenerator* codegen)
253 : NestedStatement(codegen) {
254 }
255 virtual ~WithOrCatch() {}
256
257 virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
258 ++(*context_length);
259 return previous_;
260 }
261 };
262
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000263 // The forward bailout stack keeps track of the expressions that can
264 // bail out to just before the control flow is split in a child
265 // node. The stack elements are linked together through the parent
266 // link when visiting expressions in test contexts after requesting
267 // bailout in child forwarding.
268 class ForwardBailoutStack BASE_EMBEDDED {
269 public:
270 ForwardBailoutStack(Expression* expr, ForwardBailoutStack* parent)
271 : expr_(expr), parent_(parent) { }
272
273 Expression* expr() const { return expr_; }
274 ForwardBailoutStack* parent() const { return parent_; }
275
276 private:
277 Expression* const expr_;
278 ForwardBailoutStack* const parent_;
279 };
280
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000281 // Type of a member function that generates inline code for a native function.
282 typedef void (FullCodeGenerator::*InlineFunctionGenerator)
283 (ZoneList<Expression*>*);
284
285 static const InlineFunctionGenerator kInlineFunctionGenerators[];
286
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000287 // A platform-specific utility to overwrite the accumulator register
288 // with a GC-safe value.
289 void ClearAccumulator();
290
ricow@chromium.org65fae842010-08-25 15:26:24 +0000291 // Compute the frame pointer relative offset for a given local or
292 // parameter slot.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000293 int SlotOffset(Slot* slot);
294
ricow@chromium.org65fae842010-08-25 15:26:24 +0000295 // Determine whether or not to inline the smi case for the given
296 // operation.
297 bool ShouldInlineSmiCase(Token::Value op);
298
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000299 // 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.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000302 void DoTest(Expression* condition,
303 Label* if_true,
304 Label* if_false,
305 Label* fall_through);
306 void DoTest(const TestContext* context);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000307
308 // Helper function to split control flow and avoid a branch to the
309 // fall-through label if it is set up.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000310#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.
ricow@chromium.org65fae842010-08-25 15:26:24 +0000318 void Split(Condition cc,
319 Label* if_true,
320 Label* if_false,
321 Label* fall_through);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000322#endif // V8_TARGET_ARCH_MIPS
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000323
324 void Move(Slot* dst, Register source, Register scratch1, Register scratch2);
325 void Move(Register dst, Slot* source);
326
327 // Return an operand used to read/write to a known (ie, non-LOOKUP) slot.
328 // May emit code to traverse the context chain, destroying the scratch
329 // register.
330 MemOperand EmitSlotSearch(Slot* slot, Register scratch);
331
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000332 // Forward the bailout responsibility for the given expression to
333 // the next child visited (which must be in a test context).
334 void ForwardBailoutToChild(Expression* expr);
335
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000336 void VisitForEffect(Expression* expr) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000337 EffectContext context(this);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000338 VisitInCurrentContext(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000339 }
340
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000341 void VisitForAccumulatorValue(Expression* expr) {
342 AccumulatorValueContext context(this);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000343 VisitInCurrentContext(expr);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000344 }
345
346 void VisitForStackValue(Expression* expr) {
347 StackValueContext context(this);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000348 VisitInCurrentContext(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000349 }
350
ricow@chromium.org65fae842010-08-25 15:26:24 +0000351 void VisitForControl(Expression* expr,
352 Label* if_true,
353 Label* if_false,
354 Label* fall_through) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000355 TestContext context(this, expr, if_true, if_false, fall_through);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000356 VisitInCurrentContext(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000357 }
358
359 void VisitDeclarations(ZoneList<Declaration*>* declarations);
360 void DeclareGlobals(Handle<FixedArray> pairs);
361
ricow@chromium.org65fae842010-08-25 15:26:24 +0000362 // Try to perform a comparison as a fast inlined literal compare if
363 // the operands allow it. Returns true if the compare operations
364 // has been matched and all code generated; false otherwise.
ager@chromium.org04921a82011-06-27 13:21:41 +0000365 bool TryLiteralCompare(CompareOperation* compare,
ricow@chromium.org65fae842010-08-25 15:26:24 +0000366 Label* if_true,
367 Label* if_false,
368 Label* fall_through);
369
ager@chromium.org04921a82011-06-27 13:21:41 +0000370 // Platform-specific code for comparing the type of a value with
371 // a given literal string.
372 void EmitLiteralCompareTypeof(Expression* expr,
373 Handle<String> check,
374 Label* if_true,
375 Label* if_false,
376 Label* fall_through);
377
378 // Platform-specific code for strict equality comparison with
379 // the undefined value.
380 void EmitLiteralCompareUndefined(Expression* expr,
381 Label* if_true,
382 Label* if_false,
383 Label* fall_through);
384
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000385 // Bailout support.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000386 void PrepareForBailout(Expression* node, State state);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000387 void PrepareForBailoutForId(int id, State state);
388
389 // Record a call's return site offset, used to rebuild the frame if the
390 // called function was inlined at the site.
391 void RecordJSReturnSite(Call* call);
392
393 // Prepare for bailout before a test (or compare) and branch. If
394 // should_normalize, then the following comparison will not handle the
395 // canonical JS true value so we will insert a (dead) test against true at
396 // the actual bailout target from the optimized code. If not
397 // should_normalize, the true and false labels are ignored.
398 void PrepareForBailoutBeforeSplit(State state,
399 bool should_normalize,
400 Label* if_true,
401 Label* if_false);
402
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000403 // Platform-specific code for a variable, constant, or function
404 // declaration. Functions have an initial value.
405 void EmitDeclaration(Variable* variable,
406 Variable::Mode mode,
407 FunctionLiteral* function);
408
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000409 // Platform-specific code for checking the stack limit at the back edge of
410 // a loop.
411 void EmitStackCheck(IterationStatement* stmt);
412 // Record the OSR AST id corresponding to a stack check in the code.
413 void RecordStackCheck(int osr_ast_id);
414 // Emit a table of stack check ids and pcs into the code stream. Return
415 // the offset of the start of the table.
416 unsigned EmitStackCheckTable();
417
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000418 // Platform-specific return sequence
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000419 void EmitReturnSequence();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000420
421 // Platform-specific code sequences for calls
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000422 void EmitCallWithStub(Call* expr, CallFunctionFlags flags);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000423 void EmitCallWithIC(Call* expr, Handle<Object> name, RelocInfo::Mode mode);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000424 void EmitKeyedCallWithIC(Call* expr, Expression* key);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000425
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000426 // Platform-specific code for inline runtime calls.
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000427 InlineFunctionGenerator FindInlineFunctionGenerator(Runtime::FunctionId id);
428
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000429 void EmitInlineRuntimeCall(CallRuntime* expr);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000430
431#define EMIT_INLINE_RUNTIME_CALL(name, x, y) \
432 void Emit##name(ZoneList<Expression*>* arguments);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000433 INLINE_FUNCTION_LIST(EMIT_INLINE_RUNTIME_CALL)
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000434 INLINE_RUNTIME_FUNCTION_LIST(EMIT_INLINE_RUNTIME_CALL)
435#undef EMIT_INLINE_RUNTIME_CALL
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000436
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000437 // Platform-specific code for loading variables.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000438 void EmitLoadGlobalSlotCheckExtensions(Slot* slot,
439 TypeofState typeof_state,
440 Label* slow);
441 MemOperand ContextSlotOperandCheckExtensions(Slot* slot, Label* slow);
442 void EmitDynamicLoadFromSlotFastCase(Slot* slot,
443 TypeofState typeof_state,
444 Label* slow,
445 Label* done);
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000446 void EmitVariableLoad(VariableProxy* proxy);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000447
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000448 enum ResolveEvalFlag {
449 SKIP_CONTEXT_LOOKUP,
450 PERFORM_CONTEXT_LOOKUP
451 };
452
453 // Expects the arguments and the function already pushed.
454 void EmitResolvePossiblyDirectEval(ResolveEvalFlag flag, int arg_count);
455
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000456 // Platform-specific support for allocating a new closure based on
457 // the given function info.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000458 void EmitNewClosure(Handle<SharedFunctionInfo> info, bool pretenure);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000459
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000460 // Platform-specific support for compiling assignments.
461
462 // Load a value from a named property.
463 // The receiver is left on the stack by the IC.
464 void EmitNamedPropertyLoad(Property* expr);
465
466 // Load a value from a keyed property.
467 // The receiver and the key is left on the stack by the IC.
468 void EmitKeyedPropertyLoad(Property* expr);
469
470 // Apply the compound assignment operator. Expects the left operand on top
471 // of the stack and the right one in the accumulator.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000472 void EmitBinaryOp(BinaryOperation* expr,
473 Token::Value op,
ricow@chromium.org65fae842010-08-25 15:26:24 +0000474 OverwriteMode mode);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000475
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000476 // Helper functions for generating inlined smi code for certain
477 // binary operations.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000478 void EmitInlineSmiBinaryOp(BinaryOperation* expr,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000479 Token::Value op,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000480 OverwriteMode mode,
481 Expression* left,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000482 Expression* right);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000483
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000484 // Assign to the given expression as if via '='. The right-hand-side value
485 // is expected in the accumulator.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000486 void EmitAssignment(Expression* expr, int bailout_ast_id);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000487
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000488 // Complete a variable assignment. The right-hand-side value is expected
489 // in the accumulator.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000490 void EmitVariableAssignment(Variable* var,
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000491 Token::Value op);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000492
493 // Complete a named property assignment. The receiver is expected on top
494 // of the stack and the right-hand-side value in the accumulator.
495 void EmitNamedPropertyAssignment(Assignment* expr);
496
497 // Complete a keyed property assignment. The receiver and key are
498 // expected on top of the stack and the right-hand-side value in the
499 // accumulator.
500 void EmitKeyedPropertyAssignment(Assignment* expr);
501
502 void SetFunctionPosition(FunctionLiteral* fun);
503 void SetReturnPosition(FunctionLiteral* fun);
504 void SetStatementPosition(Statement* stmt);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000505 void SetExpressionPosition(Expression* expr, int pos);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000506 void SetStatementPosition(int pos);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000507 void SetSourcePosition(int pos);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000508
509 // Non-local control flow support.
510 void EnterFinallyBlock();
511 void ExitFinallyBlock();
512
513 // Loop nesting counter.
514 int loop_depth() { return loop_depth_; }
515 void increment_loop_depth() { loop_depth_++; }
516 void decrement_loop_depth() {
517 ASSERT(loop_depth_ > 0);
518 loop_depth_--;
519 }
520
vegorov@chromium.org7943d462011-08-01 11:41:52 +0000521#if defined(V8_TARGET_ARCH_IA32)
522 int stack_height() { return stack_height_; }
523 void set_stack_height(int depth) { stack_height_ = depth; }
524 void increment_stack_height() { stack_height_++; }
525 void increment_stack_height(int delta) { stack_height_ += delta; }
526 void decrement_stack_height() {
527 if (FLAG_verify_stack_height) {
528 ASSERT(stack_height_ > 0);
529 }
530 stack_height_--;
531 }
532 void decrement_stack_height(int delta) {
533 stack_height_-= delta;
534 if (FLAG_verify_stack_height) {
535 ASSERT(stack_height_ >= 0);
536 }
537 }
538 // Call this function only if FLAG_verify_stack_height is true.
539 void verify_stack_height(); // Generates a runtime check of esp - ebp.
540#else
541 int stack_height() { return 0; }
542 void set_stack_height(int depth) {}
543 void increment_stack_height() {}
544 void increment_stack_height(int delta) {}
545 void decrement_stack_height() {}
546 void decrement_stack_height(int delta) {}
547 void verify_stack_height() {}
548#endif // V8_TARGET_ARCH_IA32
549
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000550 MacroAssembler* masm() { return masm_; }
ager@chromium.org5c838252010-02-19 08:53:10 +0000551
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000552 class ExpressionContext;
553 const ExpressionContext* context() { return context_; }
554 void set_new_context(const ExpressionContext* context) { context_ = context; }
555
ager@chromium.org5c838252010-02-19 08:53:10 +0000556 Handle<Script> script() { return info_->script(); }
557 bool is_eval() { return info_->is_eval(); }
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000558 bool is_strict_mode() { return function()->strict_mode(); }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000559 StrictModeFlag strict_mode_flag() {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000560 return is_strict_mode() ? kStrictMode : kNonStrictMode;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000561 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000562 FunctionLiteral* function() { return info_->function(); }
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000563 Scope* scope() { return scope_; }
ager@chromium.org5c838252010-02-19 08:53:10 +0000564
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000565 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
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000576 // Push the function argument for the runtime functions PushWithContext
577 // and PushCatchContext.
578 void PushFunctionArgumentForContextAllocation();
579
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000580 // 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
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000584
585 void EmitUnaryOperation(UnaryOperation* expr, const char* comment);
586
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000587 void VisitComma(BinaryOperation* expr);
588 void VisitLogicalExpression(BinaryOperation* expr);
589 void VisitArithmeticExpression(BinaryOperation* expr);
590 void VisitInCurrentContext(Expression* expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000591
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000592 void VisitForTypeofValue(Expression* expr);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000593
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000594 struct BailoutEntry {
595 unsigned id;
596 unsigned pc_and_state;
597 };
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000598
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000599
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000600 class ExpressionContext BASE_EMBEDDED {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000601 public:
602 explicit ExpressionContext(FullCodeGenerator* codegen)
603 : masm_(codegen->masm()), old_(codegen->context()), codegen_(codegen) {
604 codegen->set_new_context(this);
605 }
606
607 virtual ~ExpressionContext() {
608 codegen_->set_new_context(old_);
vegorov@chromium.org7943d462011-08-01 11:41:52 +0000609 if (FLAG_verify_stack_height) {
610 ASSERT_EQ(expected_stack_height_, codegen()->stack_height());
611 codegen()->verify_stack_height();
612 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000613 }
614
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000615 Isolate* isolate() const { return codegen_->isolate(); }
616
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000617 // Convert constant control flow (true or false) to the result expected for
618 // this expression context.
619 virtual void Plug(bool flag) const = 0;
620
621 // Emit code to convert a pure value (in a register, slot, as a literal,
622 // or on top of the stack) into the result expected according to this
623 // expression context.
624 virtual void Plug(Register reg) const = 0;
625 virtual void Plug(Slot* slot) const = 0;
626 virtual void Plug(Handle<Object> lit) const = 0;
627 virtual void Plug(Heap::RootListIndex index) const = 0;
628 virtual void PlugTOS() const = 0;
629
630 // Emit code to convert pure control flow to a pair of unbound labels into
631 // the result expected according to this expression context. The
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000632 // implementation will bind both labels unless it's a TestContext, which
633 // won't bind them at this point.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000634 virtual void Plug(Label* materialize_true,
635 Label* materialize_false) const = 0;
636
637 // Emit code to discard count elements from the top of stack, then convert
638 // a pure value into the result expected according to this expression
639 // context.
640 virtual void DropAndPlug(int count, Register reg) const = 0;
641
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000642 // Set up branch labels for a test expression. The three Label** parameters
643 // are output parameters.
644 virtual void PrepareTest(Label* materialize_true,
645 Label* materialize_false,
646 Label** if_true,
647 Label** if_false,
648 Label** fall_through) const = 0;
649
650 // Returns true if we are evaluating only for side effects (ie if the result
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000651 // will be discarded).
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000652 virtual bool IsEffect() const { return false; }
653
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000654 // Returns true if we are evaluating for the value (in accu/on stack).
655 virtual bool IsAccumulatorValue() const { return false; }
656 virtual bool IsStackValue() const { return false; }
657
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000658 // Returns true if we are branching on the value rather than materializing
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000659 // it. Only used for asserts.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000660 virtual bool IsTest() const { return false; }
661
662 protected:
663 FullCodeGenerator* codegen() const { return codegen_; }
664 MacroAssembler* masm() const { return masm_; }
665 MacroAssembler* masm_;
vegorov@chromium.org7943d462011-08-01 11:41:52 +0000666 int expected_stack_height_; // The expected stack height esp - ebp on exit.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000667
668 private:
669 const ExpressionContext* old_;
670 FullCodeGenerator* codegen_;
671 };
672
673 class AccumulatorValueContext : public ExpressionContext {
674 public:
675 explicit AccumulatorValueContext(FullCodeGenerator* codegen)
vegorov@chromium.org7943d462011-08-01 11:41:52 +0000676 : ExpressionContext(codegen) {
677 expected_stack_height_ = codegen->stack_height();
678 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000679
680 virtual void Plug(bool flag) const;
681 virtual void Plug(Register reg) const;
682 virtual void Plug(Label* materialize_true, Label* materialize_false) const;
683 virtual void Plug(Slot* slot) const;
684 virtual void Plug(Handle<Object> lit) const;
685 virtual void Plug(Heap::RootListIndex) const;
686 virtual void PlugTOS() const;
687 virtual void DropAndPlug(int count, Register reg) const;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000688 virtual void PrepareTest(Label* materialize_true,
689 Label* materialize_false,
690 Label** if_true,
691 Label** if_false,
692 Label** fall_through) const;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000693 virtual bool IsAccumulatorValue() const { return true; }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000694 };
695
696 class StackValueContext : public ExpressionContext {
697 public:
698 explicit StackValueContext(FullCodeGenerator* codegen)
vegorov@chromium.org7943d462011-08-01 11:41:52 +0000699 : ExpressionContext(codegen) {
700 expected_stack_height_ = codegen->stack_height() + 1;
701 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000702
703 virtual void Plug(bool flag) const;
704 virtual void Plug(Register reg) const;
705 virtual void Plug(Label* materialize_true, Label* materialize_false) const;
706 virtual void Plug(Slot* slot) const;
707 virtual void Plug(Handle<Object> lit) const;
708 virtual void Plug(Heap::RootListIndex) const;
709 virtual void PlugTOS() const;
710 virtual void DropAndPlug(int count, Register reg) const;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000711 virtual void PrepareTest(Label* materialize_true,
712 Label* materialize_false,
713 Label** if_true,
714 Label** if_false,
715 Label** fall_through) const;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000716 virtual bool IsStackValue() const { return true; }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000717 };
718
719 class TestContext : public ExpressionContext {
720 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000721 TestContext(FullCodeGenerator* codegen,
722 Expression* condition,
723 Label* true_label,
724 Label* false_label,
725 Label* fall_through)
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000726 : ExpressionContext(codegen),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000727 condition_(condition),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000728 true_label_(true_label),
729 false_label_(false_label),
vegorov@chromium.org7943d462011-08-01 11:41:52 +0000730 fall_through_(fall_through) {
731 expected_stack_height_ = codegen->stack_height();
732 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000733
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000734 static const TestContext* cast(const ExpressionContext* context) {
735 ASSERT(context->IsTest());
736 return reinterpret_cast<const TestContext*>(context);
737 }
738
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000739 Expression* condition() const { return condition_; }
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000740 Label* true_label() const { return true_label_; }
741 Label* false_label() const { return false_label_; }
742 Label* fall_through() const { return fall_through_; }
743
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000744 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(Slot* slot) 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;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000752 virtual void PrepareTest(Label* materialize_true,
753 Label* materialize_false,
754 Label** if_true,
755 Label** if_false,
756 Label** fall_through) const;
757 virtual bool IsTest() const { return true; }
758
759 private:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000760 Expression* condition_;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000761 Label* true_label_;
762 Label* false_label_;
763 Label* fall_through_;
764 };
765
766 class EffectContext : public ExpressionContext {
767 public:
768 explicit EffectContext(FullCodeGenerator* codegen)
vegorov@chromium.org7943d462011-08-01 11:41:52 +0000769 : ExpressionContext(codegen) {
770 expected_stack_height_ = codegen->stack_height();
771 }
772
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000773
774 virtual void Plug(bool flag) const;
775 virtual void Plug(Register reg) const;
776 virtual void Plug(Label* materialize_true, Label* materialize_false) const;
777 virtual void Plug(Slot* slot) const;
778 virtual void Plug(Handle<Object> lit) const;
779 virtual void Plug(Heap::RootListIndex) const;
780 virtual void PlugTOS() const;
781 virtual void DropAndPlug(int count, Register reg) const;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000782 virtual void PrepareTest(Label* materialize_true,
783 Label* materialize_false,
784 Label** if_true,
785 Label** if_false,
786 Label** fall_through) const;
787 virtual bool IsEffect() const { return true; }
788 };
789
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000790 MacroAssembler* masm_;
791 CompilationInfo* info_;
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000792 Scope* scope_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000793 Label return_label_;
794 NestedStatement* nesting_stack_;
795 int loop_depth_;
vegorov@chromium.org7943d462011-08-01 11:41:52 +0000796 int stack_height_;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000797 const ExpressionContext* context_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000798 ZoneList<BailoutEntry> bailout_entries_;
799 ZoneList<BailoutEntry> stack_checks_;
800 ForwardBailoutStack* forward_bailout_stack_;
801 ForwardBailoutStack* forward_bailout_pending_;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000802
803 friend class NestedStatement;
804
805 DISALLOW_COPY_AND_ASSIGN(FullCodeGenerator);
806};
807
808
809} } // namespace v8::internal
810
811#endif // V8_FULL_CODEGEN_H_