[go: nahoru, domu]

blob: 803c618732a395e1bd2aeb6415cb33f505fd46ef [file] [log] [blame]
Ben Murdoch257744e2011-11-30 15:57:28 +00001// Copyright 2011 the V8 project authors. All rights reserved.
Leon Clarked91b9f72010-01-27 17:25:45 +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
Ben Murdoch257744e2011-11-30 15:57:28 +000033#include "allocation.h"
Leon Clarked91b9f72010-01-27 17:25:45 +000034#include "ast.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010035#include "code-stubs.h"
36#include "codegen.h"
Leon Clarkef7060e22010-06-03 12:02:55 +010037#include "compiler.h"
Leon Clarked91b9f72010-01-27 17:25:45 +000038
39namespace v8 {
40namespace internal {
41
Ben Murdochb0fe1622011-05-05 13:52:32 +010042// Forward declarations.
43class JumpPatchSite;
44
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010045// 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
Leon Clarked91b9f72010-01-27 17:25:45 +000070// -----------------------------------------------------------------------------
71// Full code generator.
72
73class FullCodeGenerator: public AstVisitor {
74 public:
Ben Murdochb0fe1622011-05-05 13:52:32 +010075 enum State {
76 NO_REGISTERS,
77 TOS_REG
78 };
79
Andrei Popescu31002712010-02-23 13:46:05 +000080 explicit FullCodeGenerator(MacroAssembler* masm)
Leon Clarked91b9f72010-01-27 17:25:45 +000081 : masm_(masm),
Andrei Popescu31002712010-02-23 13:46:05 +000082 info_(NULL),
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000083 scope_(NULL),
Leon Clarked91b9f72010-01-27 17:25:45 +000084 nesting_stack_(NULL),
85 loop_depth_(0),
Ben Murdoch69a99ed2011-11-30 16:03:39 +000086 stack_height_(0),
Ben Murdochb0fe1622011-05-05 13:52:32 +010087 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) {
Leon Clarked91b9f72010-01-27 17:25:45 +000092 }
93
Ben Murdochf87a2032010-10-22 12:50:53 +010094 static bool MakeCode(CompilationInfo* info);
Leon Clarked91b9f72010-01-27 17:25:45 +000095
Iain Merrick75681382010-08-19 15:07:18 +010096 void Generate(CompilationInfo* info);
Ben Murdochb0fe1622011-05-05 13:52:32 +010097 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 }
Leon Clarked91b9f72010-01-27 17:25:45 +0000110
111 private:
112 class Breakable;
113 class Iteration;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000114
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000115 class TestContext;
Leon Clarked91b9f72010-01-27 17:25:45 +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; }
Leon Clarked91b9f72010-01-27 17:25:45 +0000132
133 virtual bool IsContinueTarget(Statement* target) { return false; }
134 virtual bool IsBreakTarget(Statement* target) { return false; }
135
Ben Murdoch69a99ed2011-11-30 16:03:39 +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_;
Leon Clarked91b9f72010-01-27 17:25:45 +0000144 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000145
146 protected:
Leon Clarked91b9f72010-01-27 17:25:45 +0000147 MacroAssembler* masm() { return codegen_->masm(); }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000148
Leon Clarked91b9f72010-01-27 17:25:45 +0000149 FullCodeGenerator* codegen_;
150 NestedStatement* previous_;
151 DISALLOW_COPY_AND_ASSIGN(NestedStatement);
152 };
153
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000154 // A breakable statement such as a block.
Leon Clarked91b9f72010-01-27 17:25:45 +0000155 class Breakable : public NestedStatement {
156 public:
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000157 Breakable(FullCodeGenerator* codegen, BreakableStatement* statement)
158 : NestedStatement(codegen), statement_(statement) {
Leon Clarked91b9f72010-01-27 17:25:45 +0000159 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +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
Leon Clarked91b9f72010-01-27 17:25:45 +0000170 private:
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000171 BreakableStatement* statement_;
172 Label break_label_;
Leon Clarked91b9f72010-01-27 17:25:45 +0000173 };
174
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000175 // An iteration statement such as a while, for, or do loop.
Leon Clarked91b9f72010-01-27 17:25:45 +0000176 class Iteration : public Breakable {
177 public:
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000178 Iteration(FullCodeGenerator* codegen, IterationStatement* statement)
179 : Breakable(codegen, statement) {
Leon Clarked91b9f72010-01-27 17:25:45 +0000180 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +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
Leon Clarked91b9f72010-01-27 17:25:45 +0000190 private:
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000191 Label continue_label_;
Leon Clarked91b9f72010-01-27 17:25:45 +0000192 };
193
Ben Murdoch589d6972011-11-30 16:04:58 +0000194 // A nested block statement.
195 class NestedBlock : public Breakable {
196 public:
197 NestedBlock(FullCodeGenerator* codegen, Block* block)
198 : Breakable(codegen, block) {
199 }
200 virtual ~NestedBlock() {}
201
202 virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
203 if (statement()->AsBlock()->block_scope() != NULL) {
204 ++(*context_length);
205 }
206 return previous_;
207 };
208 };
209
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000210 // The try block of a try/catch statement.
Leon Clarked91b9f72010-01-27 17:25:45 +0000211 class TryCatch : public NestedStatement {
212 public:
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000213 explicit TryCatch(FullCodeGenerator* codegen) : NestedStatement(codegen) {
214 }
Leon Clarked91b9f72010-01-27 17:25:45 +0000215 virtual ~TryCatch() {}
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000216
217 virtual NestedStatement* Exit(int* stack_depth, int* context_length);
Leon Clarked91b9f72010-01-27 17:25:45 +0000218 };
219
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000220 // The try block of a try/finally statement.
Leon Clarked91b9f72010-01-27 17:25:45 +0000221 class TryFinally : public NestedStatement {
222 public:
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000223 TryFinally(FullCodeGenerator* codegen, Label* finally_entry)
224 : NestedStatement(codegen), finally_entry_(finally_entry) {
225 }
Leon Clarked91b9f72010-01-27 17:25:45 +0000226 virtual ~TryFinally() {}
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000227
228 virtual NestedStatement* Exit(int* stack_depth, int* context_length);
229
Leon Clarked91b9f72010-01-27 17:25:45 +0000230 private:
231 Label* finally_entry_;
Leon Clarked91b9f72010-01-27 17:25:45 +0000232 };
233
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000234 // The finally block of a try/finally statement.
Leon Clarked91b9f72010-01-27 17:25:45 +0000235 class Finally : public NestedStatement {
236 public:
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000237 static const int kElementCount = 2;
238
Leon Clarked91b9f72010-01-27 17:25:45 +0000239 explicit Finally(FullCodeGenerator* codegen) : NestedStatement(codegen) { }
240 virtual ~Finally() {}
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000241
242 virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
243 *stack_depth += kElementCount;
244 return previous_;
Leon Clarked91b9f72010-01-27 17:25:45 +0000245 }
Leon Clarked91b9f72010-01-27 17:25:45 +0000246 };
247
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000248 // The body of a for/in loop.
Leon Clarked91b9f72010-01-27 17:25:45 +0000249 class ForIn : public Iteration {
250 public:
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000251 static const int kElementCount = 5;
252
253 ForIn(FullCodeGenerator* codegen, ForInStatement* statement)
254 : Iteration(codegen, statement) {
Leon Clarked91b9f72010-01-27 17:25:45 +0000255 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000256 virtual ~ForIn() {}
257
258 virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
259 *stack_depth += kElementCount;
260 return previous_;
261 }
262 };
263
264
265 // The body of a with or catch.
266 class WithOrCatch : public NestedStatement {
267 public:
268 explicit WithOrCatch(FullCodeGenerator* codegen)
269 : NestedStatement(codegen) {
270 }
271 virtual ~WithOrCatch() {}
272
273 virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
274 ++(*context_length);
275 return previous_;
276 }
Leon Clarked91b9f72010-01-27 17:25:45 +0000277 };
278
Ben Murdochb0fe1622011-05-05 13:52:32 +0100279 // The forward bailout stack keeps track of the expressions that can
280 // bail out to just before the control flow is split in a child
281 // node. The stack elements are linked together through the parent
282 // link when visiting expressions in test contexts after requesting
283 // bailout in child forwarding.
284 class ForwardBailoutStack BASE_EMBEDDED {
285 public:
286 ForwardBailoutStack(Expression* expr, ForwardBailoutStack* parent)
287 : expr_(expr), parent_(parent) { }
288
289 Expression* expr() const { return expr_; }
290 ForwardBailoutStack* parent() const { return parent_; }
291
292 private:
293 Expression* const expr_;
294 ForwardBailoutStack* const parent_;
295 };
296
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100297 // Type of a member function that generates inline code for a native function.
298 typedef void (FullCodeGenerator::*InlineFunctionGenerator)
299 (ZoneList<Expression*>*);
300
301 static const InlineFunctionGenerator kInlineFunctionGenerators[];
302
Ben Murdochdb5a90a2011-01-06 18:27:03 +0000303 // A platform-specific utility to overwrite the accumulator register
304 // with a GC-safe value.
305 void ClearAccumulator();
306
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100307 // Determine whether or not to inline the smi case for the given
308 // operation.
309 bool ShouldInlineSmiCase(Token::Value op);
310
Leon Clarked91b9f72010-01-27 17:25:45 +0000311 // Helper function to convert a pure value into a test context. The value
312 // is expected on the stack or the accumulator, depending on the platform.
313 // See the platform-specific implementation for details.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000314 void DoTest(Expression* condition,
315 Label* if_true,
316 Label* if_false,
317 Label* fall_through);
318 void DoTest(const TestContext* context);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100319
320 // Helper function to split control flow and avoid a branch to the
321 // fall-through label if it is set up.
Ben Murdoch257744e2011-11-30 15:57:28 +0000322#ifdef V8_TARGET_ARCH_MIPS
323 void Split(Condition cc,
324 Register lhs,
325 const Operand& rhs,
326 Label* if_true,
327 Label* if_false,
328 Label* fall_through);
329#else // All non-mips arch.
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100330 void Split(Condition cc,
331 Label* if_true,
332 Label* if_false,
333 Label* fall_through);
Ben Murdoch257744e2011-11-30 15:57:28 +0000334#endif // V8_TARGET_ARCH_MIPS
Leon Clarked91b9f72010-01-27 17:25:45 +0000335
Ben Murdoch589d6972011-11-30 16:04:58 +0000336 // Load the value of a known (PARAMETER, LOCAL, or CONTEXT) variable into
337 // a register. Emits a context chain walk if if necessary (so does
338 // SetVar) so avoid calling both on the same variable.
339 void GetVar(Register destination, Variable* var);
Leon Clarked91b9f72010-01-27 17:25:45 +0000340
Ben Murdoch589d6972011-11-30 16:04:58 +0000341 // Assign to a known (PARAMETER, LOCAL, or CONTEXT) variable. If it's in
342 // the context, the write barrier will be emitted and source, scratch0,
343 // scratch1 will be clobbered. Emits a context chain walk if if necessary
344 // (so does GetVar) so avoid calling both on the same variable.
345 void SetVar(Variable* var,
346 Register source,
347 Register scratch0,
348 Register scratch1);
349
350 // An operand used to read/write a stack-allocated (PARAMETER or LOCAL)
351 // variable. Writing does not need the write barrier.
352 MemOperand StackOperand(Variable* var);
353
354 // An operand used to read/write a known (PARAMETER, LOCAL, or CONTEXT)
355 // variable. May emit code to traverse the context chain, loading the
356 // found context into the scratch register. Writing to this operand will
357 // need the write barrier if location is CONTEXT.
358 MemOperand VarOperand(Variable* var, Register scratch);
Leon Clarked91b9f72010-01-27 17:25:45 +0000359
Ben Murdochb0fe1622011-05-05 13:52:32 +0100360 // Forward the bailout responsibility for the given expression to
361 // the next child visited (which must be in a test context).
362 void ForwardBailoutToChild(Expression* expr);
363
Leon Clarked91b9f72010-01-27 17:25:45 +0000364 void VisitForEffect(Expression* expr) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100365 EffectContext context(this);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000366 VisitInCurrentContext(expr);
Leon Clarked91b9f72010-01-27 17:25:45 +0000367 }
368
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100369 void VisitForAccumulatorValue(Expression* expr) {
370 AccumulatorValueContext context(this);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000371 VisitInCurrentContext(expr);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100372 }
373
374 void VisitForStackValue(Expression* expr) {
375 StackValueContext context(this);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000376 VisitInCurrentContext(expr);
Leon Clarked91b9f72010-01-27 17:25:45 +0000377 }
378
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100379 void VisitForControl(Expression* expr,
380 Label* if_true,
381 Label* if_false,
382 Label* fall_through) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000383 TestContext context(this, expr, if_true, if_false, fall_through);
384 VisitInCurrentContext(expr);
Leon Clarked91b9f72010-01-27 17:25:45 +0000385 }
386
387 void VisitDeclarations(ZoneList<Declaration*>* declarations);
388 void DeclareGlobals(Handle<FixedArray> pairs);
Ben Murdoch589d6972011-11-30 16:04:58 +0000389 int DeclareGlobalsFlags();
Leon Clarked91b9f72010-01-27 17:25:45 +0000390
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100391 // Try to perform a comparison as a fast inlined literal compare if
392 // the operands allow it. Returns true if the compare operations
393 // has been matched and all code generated; false otherwise.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000394 bool TryLiteralCompare(CompareOperation* compare,
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100395 Label* if_true,
396 Label* if_false,
397 Label* fall_through);
398
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000399 // Platform-specific code for comparing the type of a value with
400 // a given literal string.
401 void EmitLiteralCompareTypeof(Expression* expr,
402 Handle<String> check,
403 Label* if_true,
404 Label* if_false,
405 Label* fall_through);
406
407 // Platform-specific code for strict equality comparison with
408 // the undefined value.
409 void EmitLiteralCompareUndefined(Expression* expr,
410 Label* if_true,
411 Label* if_false,
412 Label* fall_through);
413
Ben Murdochb0fe1622011-05-05 13:52:32 +0100414 // Bailout support.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000415 void PrepareForBailout(Expression* node, State state);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100416 void PrepareForBailoutForId(int id, State state);
417
418 // Record a call's return site offset, used to rebuild the frame if the
419 // called function was inlined at the site.
420 void RecordJSReturnSite(Call* call);
421
422 // Prepare for bailout before a test (or compare) and branch. If
423 // should_normalize, then the following comparison will not handle the
424 // canonical JS true value so we will insert a (dead) test against true at
425 // the actual bailout target from the optimized code. If not
426 // should_normalize, the true and false labels are ignored.
427 void PrepareForBailoutBeforeSplit(State state,
428 bool should_normalize,
429 Label* if_true,
430 Label* if_false);
431
Leon Clarkef7060e22010-06-03 12:02:55 +0100432 // Platform-specific code for a variable, constant, or function
433 // declaration. Functions have an initial value.
Ben Murdoch589d6972011-11-30 16:04:58 +0000434 void EmitDeclaration(VariableProxy* proxy,
Leon Clarkef7060e22010-06-03 12:02:55 +0100435 Variable::Mode mode,
Ben Murdoch589d6972011-11-30 16:04:58 +0000436 FunctionLiteral* function,
437 int* global_count);
Leon Clarkef7060e22010-06-03 12:02:55 +0100438
Ben Murdochb0fe1622011-05-05 13:52:32 +0100439 // Platform-specific code for checking the stack limit at the back edge of
440 // a loop.
441 void EmitStackCheck(IterationStatement* stmt);
442 // Record the OSR AST id corresponding to a stack check in the code.
443 void RecordStackCheck(int osr_ast_id);
444 // Emit a table of stack check ids and pcs into the code stream. Return
445 // the offset of the start of the table.
446 unsigned EmitStackCheckTable();
447
Leon Clarked91b9f72010-01-27 17:25:45 +0000448 // Platform-specific return sequence
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100449 void EmitReturnSequence();
Leon Clarked91b9f72010-01-27 17:25:45 +0000450
451 // Platform-specific code sequences for calls
Ben Murdoch257744e2011-11-30 15:57:28 +0000452 void EmitCallWithStub(Call* expr, CallFunctionFlags flags);
Leon Clarked91b9f72010-01-27 17:25:45 +0000453 void EmitCallWithIC(Call* expr, Handle<Object> name, RelocInfo::Mode mode);
Ben Murdoch257744e2011-11-30 15:57:28 +0000454 void EmitKeyedCallWithIC(Call* expr, Expression* key);
Leon Clarked91b9f72010-01-27 17:25:45 +0000455
Leon Clarkef7060e22010-06-03 12:02:55 +0100456 // Platform-specific code for inline runtime calls.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100457 InlineFunctionGenerator FindInlineFunctionGenerator(Runtime::FunctionId id);
458
Leon Clarkef7060e22010-06-03 12:02:55 +0100459 void EmitInlineRuntimeCall(CallRuntime* expr);
Steve Block791712a2010-08-27 10:21:07 +0100460
461#define EMIT_INLINE_RUNTIME_CALL(name, x, y) \
462 void Emit##name(ZoneList<Expression*>* arguments);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100463 INLINE_FUNCTION_LIST(EMIT_INLINE_RUNTIME_CALL)
Steve Block791712a2010-08-27 10:21:07 +0100464 INLINE_RUNTIME_FUNCTION_LIST(EMIT_INLINE_RUNTIME_CALL)
465#undef EMIT_INLINE_RUNTIME_CALL
Leon Clarkef7060e22010-06-03 12:02:55 +0100466
Leon Clarked91b9f72010-01-27 17:25:45 +0000467 // Platform-specific code for loading variables.
Ben Murdoch589d6972011-11-30 16:04:58 +0000468 void EmitLoadGlobalCheckExtensions(Variable* var,
469 TypeofState typeof_state,
470 Label* slow);
471 MemOperand ContextSlotOperandCheckExtensions(Variable* var, Label* slow);
472 void EmitDynamicLookupFastCase(Variable* var,
473 TypeofState typeof_state,
474 Label* slow,
475 Label* done);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000476 void EmitVariableLoad(VariableProxy* proxy);
Leon Clarked91b9f72010-01-27 17:25:45 +0000477
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100478 enum ResolveEvalFlag {
479 SKIP_CONTEXT_LOOKUP,
480 PERFORM_CONTEXT_LOOKUP
481 };
482
483 // Expects the arguments and the function already pushed.
484 void EmitResolvePossiblyDirectEval(ResolveEvalFlag flag, int arg_count);
485
Leon Clarkef7060e22010-06-03 12:02:55 +0100486 // Platform-specific support for allocating a new closure based on
487 // the given function info.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800488 void EmitNewClosure(Handle<SharedFunctionInfo> info, bool pretenure);
Leon Clarkef7060e22010-06-03 12:02:55 +0100489
Leon Clarked91b9f72010-01-27 17:25:45 +0000490 // Platform-specific support for compiling assignments.
491
492 // Load a value from a named property.
493 // The receiver is left on the stack by the IC.
494 void EmitNamedPropertyLoad(Property* expr);
495
496 // Load a value from a keyed property.
497 // The receiver and the key is left on the stack by the IC.
498 void EmitKeyedPropertyLoad(Property* expr);
499
500 // Apply the compound assignment operator. Expects the left operand on top
501 // of the stack and the right one in the accumulator.
Ben Murdoch257744e2011-11-30 15:57:28 +0000502 void EmitBinaryOp(BinaryOperation* expr,
503 Token::Value op,
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100504 OverwriteMode mode);
505
506 // Helper functions for generating inlined smi code for certain
507 // binary operations.
Ben Murdoch257744e2011-11-30 15:57:28 +0000508 void EmitInlineSmiBinaryOp(BinaryOperation* expr,
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100509 Token::Value op,
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100510 OverwriteMode mode,
511 Expression* left,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100512 Expression* right);
Leon Clarked91b9f72010-01-27 17:25:45 +0000513
Leon Clarkef7060e22010-06-03 12:02:55 +0100514 // Assign to the given expression as if via '='. The right-hand-side value
515 // is expected in the accumulator.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100516 void EmitAssignment(Expression* expr, int bailout_ast_id);
Leon Clarkef7060e22010-06-03 12:02:55 +0100517
Leon Clarked91b9f72010-01-27 17:25:45 +0000518 // Complete a variable assignment. The right-hand-side value is expected
519 // in the accumulator.
Leon Clarkef7060e22010-06-03 12:02:55 +0100520 void EmitVariableAssignment(Variable* var,
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100521 Token::Value op);
Leon Clarked91b9f72010-01-27 17:25:45 +0000522
523 // Complete a named property assignment. The receiver is expected on top
524 // of the stack and the right-hand-side value in the accumulator.
525 void EmitNamedPropertyAssignment(Assignment* expr);
526
527 // Complete a keyed property assignment. The receiver and key are
528 // expected on top of the stack and the right-hand-side value in the
529 // accumulator.
530 void EmitKeyedPropertyAssignment(Assignment* expr);
531
532 void SetFunctionPosition(FunctionLiteral* fun);
533 void SetReturnPosition(FunctionLiteral* fun);
534 void SetStatementPosition(Statement* stmt);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100535 void SetExpressionPosition(Expression* expr, int pos);
Leon Clarked91b9f72010-01-27 17:25:45 +0000536 void SetStatementPosition(int pos);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100537 void SetSourcePosition(int pos);
Leon Clarked91b9f72010-01-27 17:25:45 +0000538
539 // Non-local control flow support.
540 void EnterFinallyBlock();
541 void ExitFinallyBlock();
542
543 // Loop nesting counter.
544 int loop_depth() { return loop_depth_; }
545 void increment_loop_depth() { loop_depth_++; }
546 void decrement_loop_depth() {
547 ASSERT(loop_depth_ > 0);
548 loop_depth_--;
549 }
550
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000551#if defined(V8_TARGET_ARCH_IA32)
552 int stack_height() { return stack_height_; }
553 void set_stack_height(int depth) { stack_height_ = depth; }
554 void increment_stack_height() { stack_height_++; }
555 void increment_stack_height(int delta) { stack_height_ += delta; }
556 void decrement_stack_height() {
557 if (FLAG_verify_stack_height) {
558 ASSERT(stack_height_ > 0);
559 }
560 stack_height_--;
561 }
562 void decrement_stack_height(int delta) {
563 stack_height_-= delta;
564 if (FLAG_verify_stack_height) {
565 ASSERT(stack_height_ >= 0);
566 }
567 }
568 // Call this function only if FLAG_verify_stack_height is true.
569 void verify_stack_height(); // Generates a runtime check of esp - ebp.
570#else
571 int stack_height() { return 0; }
572 void set_stack_height(int depth) {}
573 void increment_stack_height() {}
574 void increment_stack_height(int delta) {}
575 void decrement_stack_height() {}
576 void decrement_stack_height(int delta) {}
577 void verify_stack_height() {}
578#endif // V8_TARGET_ARCH_IA32
579
Leon Clarked91b9f72010-01-27 17:25:45 +0000580 MacroAssembler* masm() { return masm_; }
Andrei Popescu31002712010-02-23 13:46:05 +0000581
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100582 class ExpressionContext;
583 const ExpressionContext* context() { return context_; }
584 void set_new_context(const ExpressionContext* context) { context_ = context; }
585
Andrei Popescu31002712010-02-23 13:46:05 +0000586 Handle<Script> script() { return info_->script(); }
587 bool is_eval() { return info_->is_eval(); }
Ben Murdoch589d6972011-11-30 16:04:58 +0000588 bool is_native() { return info_->is_native(); }
Steve Block44f0eee2011-05-26 01:26:41 +0100589 bool is_strict_mode() { return function()->strict_mode(); }
Steve Block1e0659c2011-05-24 12:43:12 +0100590 StrictModeFlag strict_mode_flag() {
Steve Block44f0eee2011-05-26 01:26:41 +0100591 return is_strict_mode() ? kStrictMode : kNonStrictMode;
Steve Block1e0659c2011-05-24 12:43:12 +0100592 }
Andrei Popescu31002712010-02-23 13:46:05 +0000593 FunctionLiteral* function() { return info_->function(); }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000594 Scope* scope() { return scope_; }
Andrei Popescu31002712010-02-23 13:46:05 +0000595
Leon Clarked91b9f72010-01-27 17:25:45 +0000596 static Register result_register();
597 static Register context_register();
598
599 // Set fields in the stack frame. Offsets are the frame pointer relative
600 // offsets defined in, e.g., StandardFrameConstants.
601 void StoreToFrameField(int frame_offset, Register value);
602
603 // Load a value from the current context. Indices are defined as an enum
604 // in v8::internal::Context.
605 void LoadContextField(Register dst, int context_index);
606
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000607 // Push the function argument for the runtime functions PushWithContext
608 // and PushCatchContext.
609 void PushFunctionArgumentForContextAllocation();
610
Leon Clarked91b9f72010-01-27 17:25:45 +0000611 // AST node visit functions.
612#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
613 AST_NODE_LIST(DECLARE_VISIT)
614#undef DECLARE_VISIT
Ben Murdoch257744e2011-11-30 15:57:28 +0000615
616 void EmitUnaryOperation(UnaryOperation* expr, const char* comment);
617
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000618 void VisitComma(BinaryOperation* expr);
619 void VisitLogicalExpression(BinaryOperation* expr);
620 void VisitArithmeticExpression(BinaryOperation* expr);
621 void VisitInCurrentContext(Expression* expr);
Leon Clarked91b9f72010-01-27 17:25:45 +0000622
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100623 void VisitForTypeofValue(Expression* expr);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100624
Ben Murdochb0fe1622011-05-05 13:52:32 +0100625 struct BailoutEntry {
626 unsigned id;
627 unsigned pc_and_state;
628 };
Leon Clarke4515c472010-02-03 11:58:03 +0000629
Leon Clarked91b9f72010-01-27 17:25:45 +0000630
Ben Murdochb0fe1622011-05-05 13:52:32 +0100631 class ExpressionContext BASE_EMBEDDED {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100632 public:
633 explicit ExpressionContext(FullCodeGenerator* codegen)
634 : masm_(codegen->masm()), old_(codegen->context()), codegen_(codegen) {
635 codegen->set_new_context(this);
636 }
637
638 virtual ~ExpressionContext() {
639 codegen_->set_new_context(old_);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000640 if (FLAG_verify_stack_height) {
641 ASSERT_EQ(expected_stack_height_, codegen()->stack_height());
642 codegen()->verify_stack_height();
643 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100644 }
645
Steve Block44f0eee2011-05-26 01:26:41 +0100646 Isolate* isolate() const { return codegen_->isolate(); }
647
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100648 // Convert constant control flow (true or false) to the result expected for
649 // this expression context.
650 virtual void Plug(bool flag) const = 0;
651
Ben Murdoch589d6972011-11-30 16:04:58 +0000652 // Emit code to convert a pure value (in a register, known variable
653 // location, as a literal, or on top of the stack) into the result
654 // expected according to this expression context.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100655 virtual void Plug(Register reg) const = 0;
Ben Murdoch589d6972011-11-30 16:04:58 +0000656 virtual void Plug(Variable* var) const = 0;
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100657 virtual void Plug(Handle<Object> lit) const = 0;
658 virtual void Plug(Heap::RootListIndex index) const = 0;
659 virtual void PlugTOS() const = 0;
660
661 // Emit code to convert pure control flow to a pair of unbound labels into
662 // the result expected according to this expression context. The
Ben Murdochb0fe1622011-05-05 13:52:32 +0100663 // implementation will bind both labels unless it's a TestContext, which
664 // won't bind them at this point.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100665 virtual void Plug(Label* materialize_true,
666 Label* materialize_false) const = 0;
667
668 // Emit code to discard count elements from the top of stack, then convert
669 // a pure value into the result expected according to this expression
670 // context.
671 virtual void DropAndPlug(int count, Register reg) const = 0;
672
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100673 // Set up branch labels for a test expression. The three Label** parameters
674 // are output parameters.
675 virtual void PrepareTest(Label* materialize_true,
676 Label* materialize_false,
677 Label** if_true,
678 Label** if_false,
679 Label** fall_through) const = 0;
680
681 // Returns true if we are evaluating only for side effects (ie if the result
Ben Murdochb0fe1622011-05-05 13:52:32 +0100682 // will be discarded).
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100683 virtual bool IsEffect() const { return false; }
684
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000685 // Returns true if we are evaluating for the value (in accu/on stack).
686 virtual bool IsAccumulatorValue() const { return false; }
687 virtual bool IsStackValue() const { return false; }
688
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100689 // Returns true if we are branching on the value rather than materializing
Ben Murdochb0fe1622011-05-05 13:52:32 +0100690 // it. Only used for asserts.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100691 virtual bool IsTest() const { return false; }
692
693 protected:
694 FullCodeGenerator* codegen() const { return codegen_; }
695 MacroAssembler* masm() const { return masm_; }
696 MacroAssembler* masm_;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000697 int expected_stack_height_; // The expected stack height esp - ebp on exit.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100698
699 private:
700 const ExpressionContext* old_;
701 FullCodeGenerator* codegen_;
702 };
703
704 class AccumulatorValueContext : public ExpressionContext {
705 public:
706 explicit AccumulatorValueContext(FullCodeGenerator* codegen)
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000707 : ExpressionContext(codegen) {
708 expected_stack_height_ = codegen->stack_height();
709 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100710
711 virtual void Plug(bool flag) const;
712 virtual void Plug(Register reg) const;
713 virtual void Plug(Label* materialize_true, Label* materialize_false) const;
Ben Murdoch589d6972011-11-30 16:04:58 +0000714 virtual void Plug(Variable* var) const;
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100715 virtual void Plug(Handle<Object> lit) const;
716 virtual void Plug(Heap::RootListIndex) const;
717 virtual void PlugTOS() const;
718 virtual void DropAndPlug(int count, Register reg) const;
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100719 virtual void PrepareTest(Label* materialize_true,
720 Label* materialize_false,
721 Label** if_true,
722 Label** if_false,
723 Label** fall_through) const;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000724 virtual bool IsAccumulatorValue() const { return true; }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100725 };
726
727 class StackValueContext : public ExpressionContext {
728 public:
729 explicit StackValueContext(FullCodeGenerator* codegen)
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000730 : ExpressionContext(codegen) {
731 expected_stack_height_ = codegen->stack_height() + 1;
732 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100733
734 virtual void Plug(bool flag) const;
735 virtual void Plug(Register reg) const;
736 virtual void Plug(Label* materialize_true, Label* materialize_false) const;
Ben Murdoch589d6972011-11-30 16:04:58 +0000737 virtual void Plug(Variable* var) const;
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100738 virtual void Plug(Handle<Object> lit) const;
739 virtual void Plug(Heap::RootListIndex) const;
740 virtual void PlugTOS() const;
741 virtual void DropAndPlug(int count, Register reg) const;
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100742 virtual void PrepareTest(Label* materialize_true,
743 Label* materialize_false,
744 Label** if_true,
745 Label** if_false,
746 Label** fall_through) const;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000747 virtual bool IsStackValue() const { return true; }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100748 };
749
750 class TestContext : public ExpressionContext {
751 public:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000752 TestContext(FullCodeGenerator* codegen,
753 Expression* condition,
754 Label* true_label,
755 Label* false_label,
756 Label* fall_through)
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100757 : ExpressionContext(codegen),
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000758 condition_(condition),
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100759 true_label_(true_label),
760 false_label_(false_label),
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000761 fall_through_(fall_through) {
762 expected_stack_height_ = codegen->stack_height();
763 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100764
Ben Murdochf87a2032010-10-22 12:50:53 +0100765 static const TestContext* cast(const ExpressionContext* context) {
766 ASSERT(context->IsTest());
767 return reinterpret_cast<const TestContext*>(context);
768 }
769
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000770 Expression* condition() const { return condition_; }
Ben Murdochf87a2032010-10-22 12:50:53 +0100771 Label* true_label() const { return true_label_; }
772 Label* false_label() const { return false_label_; }
773 Label* fall_through() const { return fall_through_; }
774
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100775 virtual void Plug(bool flag) const;
776 virtual void Plug(Register reg) const;
777 virtual void Plug(Label* materialize_true, Label* materialize_false) const;
Ben Murdoch589d6972011-11-30 16:04:58 +0000778 virtual void Plug(Variable* var) const;
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100779 virtual void Plug(Handle<Object> lit) const;
780 virtual void Plug(Heap::RootListIndex) const;
781 virtual void PlugTOS() const;
782 virtual void DropAndPlug(int count, Register reg) const;
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100783 virtual void PrepareTest(Label* materialize_true,
784 Label* materialize_false,
785 Label** if_true,
786 Label** if_false,
787 Label** fall_through) const;
788 virtual bool IsTest() const { return true; }
789
790 private:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000791 Expression* condition_;
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100792 Label* true_label_;
793 Label* false_label_;
794 Label* fall_through_;
795 };
796
797 class EffectContext : public ExpressionContext {
798 public:
799 explicit EffectContext(FullCodeGenerator* codegen)
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000800 : ExpressionContext(codegen) {
801 expected_stack_height_ = codegen->stack_height();
802 }
803
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100804
805 virtual void Plug(bool flag) const;
806 virtual void Plug(Register reg) const;
807 virtual void Plug(Label* materialize_true, Label* materialize_false) const;
Ben Murdoch589d6972011-11-30 16:04:58 +0000808 virtual void Plug(Variable* var) const;
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100809 virtual void Plug(Handle<Object> lit) const;
810 virtual void Plug(Heap::RootListIndex) const;
811 virtual void PlugTOS() const;
812 virtual void DropAndPlug(int count, Register reg) const;
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100813 virtual void PrepareTest(Label* materialize_true,
814 Label* materialize_false,
815 Label** if_true,
816 Label** if_false,
817 Label** fall_through) const;
818 virtual bool IsEffect() const { return true; }
819 };
820
Ben Murdochb0fe1622011-05-05 13:52:32 +0100821 MacroAssembler* masm_;
822 CompilationInfo* info_;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000823 Scope* scope_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100824 Label return_label_;
825 NestedStatement* nesting_stack_;
826 int loop_depth_;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000827 int stack_height_;
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100828 const ExpressionContext* context_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100829 ZoneList<BailoutEntry> bailout_entries_;
830 ZoneList<BailoutEntry> stack_checks_;
831 ForwardBailoutStack* forward_bailout_stack_;
832 ForwardBailoutStack* forward_bailout_pending_;
Leon Clarked91b9f72010-01-27 17:25:45 +0000833
834 friend class NestedStatement;
835
836 DISALLOW_COPY_AND_ASSIGN(FullCodeGenerator);
837};
838
839
840} } // namespace v8::internal
841
842#endif // V8_FULL_CODEGEN_H_