blob: 2fc055366100eddeb89eedb0e7b44321e89a84ad [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;
114 class TryCatch;
115 class TryFinally;
116 class Finally;
117 class ForIn;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000118 class TestContext;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000119
120 class NestedStatement BASE_EMBEDDED {
121 public:
122 explicit NestedStatement(FullCodeGenerator* codegen) : codegen_(codegen) {
123 // Link into codegen's nesting stack.
124 previous_ = codegen->nesting_stack_;
125 codegen->nesting_stack_ = this;
126 }
127 virtual ~NestedStatement() {
128 // Unlink from codegen's nesting stack.
129 ASSERT_EQ(this, codegen_->nesting_stack_);
130 codegen_->nesting_stack_ = previous_;
131 }
132
133 virtual Breakable* AsBreakable() { return NULL; }
134 virtual Iteration* AsIteration() { return NULL; }
135 virtual TryCatch* AsTryCatch() { return NULL; }
136 virtual TryFinally* AsTryFinally() { return NULL; }
137 virtual Finally* AsFinally() { return NULL; }
138 virtual ForIn* AsForIn() { return NULL; }
139
140 virtual bool IsContinueTarget(Statement* target) { return false; }
141 virtual bool IsBreakTarget(Statement* target) { return false; }
142
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000143 // Notify the statement that we are exiting it via break, continue, or
144 // return and give it a chance to generate cleanup code. Return the
145 // next outer statement in the nesting stack. We accumulate in
146 // *stack_depth the amount to drop the stack and in *context_length the
147 // number of context chain links to unwind as we traverse the nesting
148 // stack from an exit to its target.
149 virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
150 return previous_;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000151 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000152
153 protected:
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000154 MacroAssembler* masm() { return codegen_->masm(); }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000155
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000156 FullCodeGenerator* codegen_;
157 NestedStatement* previous_;
158 DISALLOW_COPY_AND_ASSIGN(NestedStatement);
159 };
160
161 class Breakable : public NestedStatement {
162 public:
163 Breakable(FullCodeGenerator* codegen,
164 BreakableStatement* break_target)
165 : NestedStatement(codegen),
166 target_(break_target) {}
167 virtual ~Breakable() {}
168 virtual Breakable* AsBreakable() { return this; }
169 virtual bool IsBreakTarget(Statement* statement) {
170 return target_ == statement;
171 }
172 BreakableStatement* statement() { return target_; }
173 Label* break_target() { return &break_target_label_; }
174 private:
175 BreakableStatement* target_;
176 Label break_target_label_;
177 DISALLOW_COPY_AND_ASSIGN(Breakable);
178 };
179
180 class Iteration : public Breakable {
181 public:
182 Iteration(FullCodeGenerator* codegen,
183 IterationStatement* iteration_statement)
184 : Breakable(codegen, iteration_statement) {}
185 virtual ~Iteration() {}
186 virtual Iteration* AsIteration() { return this; }
187 virtual bool IsContinueTarget(Statement* statement) {
188 return this->statement() == statement;
189 }
190 Label* continue_target() { return &continue_target_label_; }
191 private:
192 Label continue_target_label_;
193 DISALLOW_COPY_AND_ASSIGN(Iteration);
194 };
195
196 // The environment inside the try block of a try/catch statement.
197 class TryCatch : public NestedStatement {
198 public:
199 explicit TryCatch(FullCodeGenerator* codegen, Label* catch_entry)
200 : NestedStatement(codegen), catch_entry_(catch_entry) { }
201 virtual ~TryCatch() {}
202 virtual TryCatch* AsTryCatch() { return this; }
203 Label* catch_entry() { return catch_entry_; }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000204 virtual NestedStatement* Exit(int* stack_depth, int* context_length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000205 private:
206 Label* catch_entry_;
207 DISALLOW_COPY_AND_ASSIGN(TryCatch);
208 };
209
210 // The environment inside the try block of a try/finally statement.
211 class TryFinally : public NestedStatement {
212 public:
213 explicit TryFinally(FullCodeGenerator* codegen, Label* finally_entry)
214 : NestedStatement(codegen), finally_entry_(finally_entry) { }
215 virtual ~TryFinally() {}
216 virtual TryFinally* AsTryFinally() { return this; }
217 Label* finally_entry() { return finally_entry_; }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000218 virtual NestedStatement* Exit(int* stack_depth, int* context_length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000219 private:
220 Label* finally_entry_;
221 DISALLOW_COPY_AND_ASSIGN(TryFinally);
222 };
223
224 // A FinallyEnvironment represents being inside a finally block.
225 // Abnormal termination of the finally block needs to clean up
226 // the block's parameters from the stack.
227 class Finally : public NestedStatement {
228 public:
229 explicit Finally(FullCodeGenerator* codegen) : NestedStatement(codegen) { }
230 virtual ~Finally() {}
231 virtual Finally* AsFinally() { return this; }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000232 virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
233 *stack_depth += kFinallyStackElementCount;
234 return previous_;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000235 }
236 private:
237 // Number of extra stack slots occupied during a finally block.
238 static const int kFinallyStackElementCount = 2;
239 DISALLOW_COPY_AND_ASSIGN(Finally);
240 };
241
242 // A ForInEnvironment represents being inside a for-in loop.
243 // Abnormal termination of the for-in block needs to clean up
244 // the block's temporary storage from the stack.
245 class ForIn : public Iteration {
246 public:
247 ForIn(FullCodeGenerator* codegen,
248 ForInStatement* statement)
249 : Iteration(codegen, statement) { }
250 virtual ~ForIn() {}
251 virtual ForIn* AsForIn() { return this; }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000252 virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
253 *stack_depth += kForInStackElementCount;
254 return previous_;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000255 }
256 private:
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000257 static const int kForInStackElementCount = 5;
258 DISALLOW_COPY_AND_ASSIGN(ForIn);
259 };
260
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000261
262 // A WithOrCatch represents being inside the body of a with or catch
263 // statement. Exiting the body needs to remove a link from the context
264 // chain.
265 class WithOrCatch : public NestedStatement {
266 public:
267 explicit WithOrCatch(FullCodeGenerator* codegen)
268 : NestedStatement(codegen) {
269 }
270 virtual ~WithOrCatch() {}
271
272 virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
273 ++(*context_length);
274 return previous_;
275 }
276 };
277
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000278 // The forward bailout stack keeps track of the expressions that can
279 // bail out to just before the control flow is split in a child
280 // node. The stack elements are linked together through the parent
281 // link when visiting expressions in test contexts after requesting
282 // bailout in child forwarding.
283 class ForwardBailoutStack BASE_EMBEDDED {
284 public:
285 ForwardBailoutStack(Expression* expr, ForwardBailoutStack* parent)
286 : expr_(expr), parent_(parent) { }
287
288 Expression* expr() const { return expr_; }
289 ForwardBailoutStack* parent() const { return parent_; }
290
291 private:
292 Expression* const expr_;
293 ForwardBailoutStack* const parent_;
294 };
295
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000296 // Type of a member function that generates inline code for a native function.
297 typedef void (FullCodeGenerator::*InlineFunctionGenerator)
298 (ZoneList<Expression*>*);
299
300 static const InlineFunctionGenerator kInlineFunctionGenerators[];
301
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000302 // A platform-specific utility to overwrite the accumulator register
303 // with a GC-safe value.
304 void ClearAccumulator();
305
ricow@chromium.org65fae842010-08-25 15:26:24 +0000306 // Compute the frame pointer relative offset for a given local or
307 // parameter slot.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000308 int SlotOffset(Slot* slot);
309
ricow@chromium.org65fae842010-08-25 15:26:24 +0000310 // Determine whether or not to inline the smi case for the given
311 // operation.
312 bool ShouldInlineSmiCase(Token::Value op);
313
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000314 // Helper function to convert a pure value into a test context. The value
315 // is expected on the stack or the accumulator, depending on the platform.
316 // See the platform-specific implementation for details.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000317 void DoTest(Expression* condition,
318 Label* if_true,
319 Label* if_false,
320 Label* fall_through);
321 void DoTest(const TestContext* context);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000322
323 // Helper function to split control flow and avoid a branch to the
324 // fall-through label if it is set up.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000325#ifdef V8_TARGET_ARCH_MIPS
326 void Split(Condition cc,
327 Register lhs,
328 const Operand& rhs,
329 Label* if_true,
330 Label* if_false,
331 Label* fall_through);
332#else // All non-mips arch.
ricow@chromium.org65fae842010-08-25 15:26:24 +0000333 void Split(Condition cc,
334 Label* if_true,
335 Label* if_false,
336 Label* fall_through);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000337#endif // V8_TARGET_ARCH_MIPS
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000338
339 void Move(Slot* dst, Register source, Register scratch1, Register scratch2);
340 void Move(Register dst, Slot* source);
341
342 // Return an operand used to read/write to a known (ie, non-LOOKUP) slot.
343 // May emit code to traverse the context chain, destroying the scratch
344 // register.
345 MemOperand EmitSlotSearch(Slot* slot, Register scratch);
346
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000347 // Forward the bailout responsibility for the given expression to
348 // the next child visited (which must be in a test context).
349 void ForwardBailoutToChild(Expression* expr);
350
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000351 void VisitForEffect(Expression* expr) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000352 EffectContext context(this);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000353 VisitInCurrentContext(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000354 }
355
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000356 void VisitForAccumulatorValue(Expression* expr) {
357 AccumulatorValueContext context(this);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000358 VisitInCurrentContext(expr);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000359 }
360
361 void VisitForStackValue(Expression* expr) {
362 StackValueContext context(this);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000363 VisitInCurrentContext(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000364 }
365
ricow@chromium.org65fae842010-08-25 15:26:24 +0000366 void VisitForControl(Expression* expr,
367 Label* if_true,
368 Label* if_false,
369 Label* fall_through) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000370 TestContext context(this, expr, if_true, if_false, fall_through);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000371 VisitInCurrentContext(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000372 }
373
374 void VisitDeclarations(ZoneList<Declaration*>* declarations);
375 void DeclareGlobals(Handle<FixedArray> pairs);
376
ricow@chromium.org65fae842010-08-25 15:26:24 +0000377 // Try to perform a comparison as a fast inlined literal compare if
378 // the operands allow it. Returns true if the compare operations
379 // has been matched and all code generated; false otherwise.
ager@chromium.org04921a82011-06-27 13:21:41 +0000380 bool TryLiteralCompare(CompareOperation* compare,
ricow@chromium.org65fae842010-08-25 15:26:24 +0000381 Label* if_true,
382 Label* if_false,
383 Label* fall_through);
384
ager@chromium.org04921a82011-06-27 13:21:41 +0000385 // Platform-specific code for comparing the type of a value with
386 // a given literal string.
387 void EmitLiteralCompareTypeof(Expression* expr,
388 Handle<String> check,
389 Label* if_true,
390 Label* if_false,
391 Label* fall_through);
392
393 // Platform-specific code for strict equality comparison with
394 // the undefined value.
395 void EmitLiteralCompareUndefined(Expression* expr,
396 Label* if_true,
397 Label* if_false,
398 Label* fall_through);
399
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000400 // Bailout support.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000401 void PrepareForBailout(Expression* node, State state);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000402 void PrepareForBailoutForId(int id, State state);
403
404 // Record a call's return site offset, used to rebuild the frame if the
405 // called function was inlined at the site.
406 void RecordJSReturnSite(Call* call);
407
408 // Prepare for bailout before a test (or compare) and branch. If
409 // should_normalize, then the following comparison will not handle the
410 // canonical JS true value so we will insert a (dead) test against true at
411 // the actual bailout target from the optimized code. If not
412 // should_normalize, the true and false labels are ignored.
413 void PrepareForBailoutBeforeSplit(State state,
414 bool should_normalize,
415 Label* if_true,
416 Label* if_false);
417
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000418 // Platform-specific code for a variable, constant, or function
419 // declaration. Functions have an initial value.
420 void EmitDeclaration(Variable* variable,
421 Variable::Mode mode,
422 FunctionLiteral* function);
423
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000424 // Platform-specific code for checking the stack limit at the back edge of
425 // a loop.
426 void EmitStackCheck(IterationStatement* stmt);
427 // Record the OSR AST id corresponding to a stack check in the code.
428 void RecordStackCheck(int osr_ast_id);
429 // Emit a table of stack check ids and pcs into the code stream. Return
430 // the offset of the start of the table.
431 unsigned EmitStackCheckTable();
432
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000433 // Platform-specific return sequence
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000434 void EmitReturnSequence();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000435
436 // Platform-specific code sequences for calls
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000437 void EmitCallWithStub(Call* expr, CallFunctionFlags flags);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000438 void EmitCallWithIC(Call* expr, Handle<Object> name, RelocInfo::Mode mode);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000439 void EmitKeyedCallWithIC(Call* expr, Expression* key);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000440
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000441 // Platform-specific code for inline runtime calls.
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000442 InlineFunctionGenerator FindInlineFunctionGenerator(Runtime::FunctionId id);
443
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000444 void EmitInlineRuntimeCall(CallRuntime* expr);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000445
446#define EMIT_INLINE_RUNTIME_CALL(name, x, y) \
447 void Emit##name(ZoneList<Expression*>* arguments);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000448 INLINE_FUNCTION_LIST(EMIT_INLINE_RUNTIME_CALL)
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000449 INLINE_RUNTIME_FUNCTION_LIST(EMIT_INLINE_RUNTIME_CALL)
450#undef EMIT_INLINE_RUNTIME_CALL
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000451
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000452 // Platform-specific code for loading variables.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000453 void EmitLoadGlobalSlotCheckExtensions(Slot* slot,
454 TypeofState typeof_state,
455 Label* slow);
456 MemOperand ContextSlotOperandCheckExtensions(Slot* slot, Label* slow);
457 void EmitDynamicLoadFromSlotFastCase(Slot* slot,
458 TypeofState typeof_state,
459 Label* slow,
460 Label* done);
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000461 void EmitVariableLoad(VariableProxy* proxy);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000462
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000463 enum ResolveEvalFlag {
464 SKIP_CONTEXT_LOOKUP,
465 PERFORM_CONTEXT_LOOKUP
466 };
467
468 // Expects the arguments and the function already pushed.
469 void EmitResolvePossiblyDirectEval(ResolveEvalFlag flag, int arg_count);
470
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000471 // Platform-specific support for allocating a new closure based on
472 // the given function info.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000473 void EmitNewClosure(Handle<SharedFunctionInfo> info, bool pretenure);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000474
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000475 // Platform-specific support for compiling assignments.
476
477 // Load a value from a named property.
478 // The receiver is left on the stack by the IC.
479 void EmitNamedPropertyLoad(Property* expr);
480
481 // Load a value from a keyed property.
482 // The receiver and the key is left on the stack by the IC.
483 void EmitKeyedPropertyLoad(Property* expr);
484
485 // Apply the compound assignment operator. Expects the left operand on top
486 // of the stack and the right one in the accumulator.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000487 void EmitBinaryOp(BinaryOperation* expr,
488 Token::Value op,
ricow@chromium.org65fae842010-08-25 15:26:24 +0000489 OverwriteMode mode);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000490
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000491 // Helper functions for generating inlined smi code for certain
492 // binary operations.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000493 void EmitInlineSmiBinaryOp(BinaryOperation* expr,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000494 Token::Value op,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000495 OverwriteMode mode,
496 Expression* left,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000497 Expression* right);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000498
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000499 // Assign to the given expression as if via '='. The right-hand-side value
500 // is expected in the accumulator.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000501 void EmitAssignment(Expression* expr, int bailout_ast_id);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000502
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000503 // Complete a variable assignment. The right-hand-side value is expected
504 // in the accumulator.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000505 void EmitVariableAssignment(Variable* var,
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000506 Token::Value op);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000507
508 // Complete a named property assignment. The receiver is expected on top
509 // of the stack and the right-hand-side value in the accumulator.
510 void EmitNamedPropertyAssignment(Assignment* expr);
511
512 // Complete a keyed property assignment. The receiver and key are
513 // expected on top of the stack and the right-hand-side value in the
514 // accumulator.
515 void EmitKeyedPropertyAssignment(Assignment* expr);
516
517 void SetFunctionPosition(FunctionLiteral* fun);
518 void SetReturnPosition(FunctionLiteral* fun);
519 void SetStatementPosition(Statement* stmt);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000520 void SetExpressionPosition(Expression* expr, int pos);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000521 void SetStatementPosition(int pos);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000522 void SetSourcePosition(int pos);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000523
524 // Non-local control flow support.
525 void EnterFinallyBlock();
526 void ExitFinallyBlock();
527
528 // Loop nesting counter.
529 int loop_depth() { return loop_depth_; }
530 void increment_loop_depth() { loop_depth_++; }
531 void decrement_loop_depth() {
532 ASSERT(loop_depth_ > 0);
533 loop_depth_--;
534 }
535
vegorov@chromium.org7943d462011-08-01 11:41:52 +0000536#if defined(V8_TARGET_ARCH_IA32)
537 int stack_height() { return stack_height_; }
538 void set_stack_height(int depth) { stack_height_ = depth; }
539 void increment_stack_height() { stack_height_++; }
540 void increment_stack_height(int delta) { stack_height_ += delta; }
541 void decrement_stack_height() {
542 if (FLAG_verify_stack_height) {
543 ASSERT(stack_height_ > 0);
544 }
545 stack_height_--;
546 }
547 void decrement_stack_height(int delta) {
548 stack_height_-= delta;
549 if (FLAG_verify_stack_height) {
550 ASSERT(stack_height_ >= 0);
551 }
552 }
553 // Call this function only if FLAG_verify_stack_height is true.
554 void verify_stack_height(); // Generates a runtime check of esp - ebp.
555#else
556 int stack_height() { return 0; }
557 void set_stack_height(int depth) {}
558 void increment_stack_height() {}
559 void increment_stack_height(int delta) {}
560 void decrement_stack_height() {}
561 void decrement_stack_height(int delta) {}
562 void verify_stack_height() {}
563#endif // V8_TARGET_ARCH_IA32
564
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000565 MacroAssembler* masm() { return masm_; }
ager@chromium.org5c838252010-02-19 08:53:10 +0000566
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000567 class ExpressionContext;
568 const ExpressionContext* context() { return context_; }
569 void set_new_context(const ExpressionContext* context) { context_ = context; }
570
ager@chromium.org5c838252010-02-19 08:53:10 +0000571 Handle<Script> script() { return info_->script(); }
572 bool is_eval() { return info_->is_eval(); }
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000573 bool is_strict_mode() { return function()->strict_mode(); }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000574 StrictModeFlag strict_mode_flag() {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000575 return is_strict_mode() ? kStrictMode : kNonStrictMode;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000576 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000577 FunctionLiteral* function() { return info_->function(); }
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000578 Scope* scope() { return scope_; }
ager@chromium.org5c838252010-02-19 08:53:10 +0000579
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000580 static Register result_register();
581 static Register context_register();
582
583 // Set fields in the stack frame. Offsets are the frame pointer relative
584 // offsets defined in, e.g., StandardFrameConstants.
585 void StoreToFrameField(int frame_offset, Register value);
586
587 // Load a value from the current context. Indices are defined as an enum
588 // in v8::internal::Context.
589 void LoadContextField(Register dst, int context_index);
590
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000591 // Push the function argument for the runtime functions PushWithContext
592 // and PushCatchContext.
593 void PushFunctionArgumentForContextAllocation();
594
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000595 // AST node visit functions.
596#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
597 AST_NODE_LIST(DECLARE_VISIT)
598#undef DECLARE_VISIT
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000599
600 void EmitUnaryOperation(UnaryOperation* expr, const char* comment);
601
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000602 void VisitComma(BinaryOperation* expr);
603 void VisitLogicalExpression(BinaryOperation* expr);
604 void VisitArithmeticExpression(BinaryOperation* expr);
605 void VisitInCurrentContext(Expression* expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000606
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000607 void VisitForTypeofValue(Expression* expr);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000608
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000609 struct BailoutEntry {
610 unsigned id;
611 unsigned pc_and_state;
612 };
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000613
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000614
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000615 class ExpressionContext BASE_EMBEDDED {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000616 public:
617 explicit ExpressionContext(FullCodeGenerator* codegen)
618 : masm_(codegen->masm()), old_(codegen->context()), codegen_(codegen) {
619 codegen->set_new_context(this);
620 }
621
622 virtual ~ExpressionContext() {
623 codegen_->set_new_context(old_);
vegorov@chromium.org7943d462011-08-01 11:41:52 +0000624 if (FLAG_verify_stack_height) {
625 ASSERT_EQ(expected_stack_height_, codegen()->stack_height());
626 codegen()->verify_stack_height();
627 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000628 }
629
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000630 Isolate* isolate() const { return codegen_->isolate(); }
631
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000632 // Convert constant control flow (true or false) to the result expected for
633 // this expression context.
634 virtual void Plug(bool flag) const = 0;
635
636 // Emit code to convert a pure value (in a register, slot, as a literal,
637 // or on top of the stack) into the result expected according to this
638 // expression context.
639 virtual void Plug(Register reg) const = 0;
640 virtual void Plug(Slot* slot) const = 0;
641 virtual void Plug(Handle<Object> lit) const = 0;
642 virtual void Plug(Heap::RootListIndex index) const = 0;
643 virtual void PlugTOS() const = 0;
644
645 // Emit code to convert pure control flow to a pair of unbound labels into
646 // the result expected according to this expression context. The
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000647 // implementation will bind both labels unless it's a TestContext, which
648 // won't bind them at this point.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000649 virtual void Plug(Label* materialize_true,
650 Label* materialize_false) const = 0;
651
652 // Emit code to discard count elements from the top of stack, then convert
653 // a pure value into the result expected according to this expression
654 // context.
655 virtual void DropAndPlug(int count, Register reg) const = 0;
656
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000657 // Set up branch labels for a test expression. The three Label** parameters
658 // are output parameters.
659 virtual void PrepareTest(Label* materialize_true,
660 Label* materialize_false,
661 Label** if_true,
662 Label** if_false,
663 Label** fall_through) const = 0;
664
665 // Returns true if we are evaluating only for side effects (ie if the result
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000666 // will be discarded).
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000667 virtual bool IsEffect() const { return false; }
668
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000669 // Returns true if we are evaluating for the value (in accu/on stack).
670 virtual bool IsAccumulatorValue() const { return false; }
671 virtual bool IsStackValue() const { return false; }
672
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000673 // Returns true if we are branching on the value rather than materializing
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000674 // it. Only used for asserts.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000675 virtual bool IsTest() const { return false; }
676
677 protected:
678 FullCodeGenerator* codegen() const { return codegen_; }
679 MacroAssembler* masm() const { return masm_; }
680 MacroAssembler* masm_;
vegorov@chromium.org7943d462011-08-01 11:41:52 +0000681 int expected_stack_height_; // The expected stack height esp - ebp on exit.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000682
683 private:
684 const ExpressionContext* old_;
685 FullCodeGenerator* codegen_;
686 };
687
688 class AccumulatorValueContext : public ExpressionContext {
689 public:
690 explicit AccumulatorValueContext(FullCodeGenerator* codegen)
vegorov@chromium.org7943d462011-08-01 11:41:52 +0000691 : ExpressionContext(codegen) {
692 expected_stack_height_ = codegen->stack_height();
693 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000694
695 virtual void Plug(bool flag) const;
696 virtual void Plug(Register reg) const;
697 virtual void Plug(Label* materialize_true, Label* materialize_false) const;
698 virtual void Plug(Slot* slot) const;
699 virtual void Plug(Handle<Object> lit) const;
700 virtual void Plug(Heap::RootListIndex) const;
701 virtual void PlugTOS() const;
702 virtual void DropAndPlug(int count, Register reg) const;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000703 virtual void PrepareTest(Label* materialize_true,
704 Label* materialize_false,
705 Label** if_true,
706 Label** if_false,
707 Label** fall_through) const;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000708 virtual bool IsAccumulatorValue() const { return true; }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000709 };
710
711 class StackValueContext : public ExpressionContext {
712 public:
713 explicit StackValueContext(FullCodeGenerator* codegen)
vegorov@chromium.org7943d462011-08-01 11:41:52 +0000714 : ExpressionContext(codegen) {
715 expected_stack_height_ = codegen->stack_height() + 1;
716 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000717
718 virtual void Plug(bool flag) const;
719 virtual void Plug(Register reg) const;
720 virtual void Plug(Label* materialize_true, Label* materialize_false) const;
721 virtual void Plug(Slot* slot) const;
722 virtual void Plug(Handle<Object> lit) const;
723 virtual void Plug(Heap::RootListIndex) const;
724 virtual void PlugTOS() const;
725 virtual void DropAndPlug(int count, Register reg) const;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000726 virtual void PrepareTest(Label* materialize_true,
727 Label* materialize_false,
728 Label** if_true,
729 Label** if_false,
730 Label** fall_through) const;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000731 virtual bool IsStackValue() const { return true; }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000732 };
733
734 class TestContext : public ExpressionContext {
735 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000736 TestContext(FullCodeGenerator* codegen,
737 Expression* condition,
738 Label* true_label,
739 Label* false_label,
740 Label* fall_through)
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000741 : ExpressionContext(codegen),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000742 condition_(condition),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000743 true_label_(true_label),
744 false_label_(false_label),
vegorov@chromium.org7943d462011-08-01 11:41:52 +0000745 fall_through_(fall_through) {
746 expected_stack_height_ = codegen->stack_height();
747 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000748
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000749 static const TestContext* cast(const ExpressionContext* context) {
750 ASSERT(context->IsTest());
751 return reinterpret_cast<const TestContext*>(context);
752 }
753
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000754 Expression* condition() const { return condition_; }
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000755 Label* true_label() const { return true_label_; }
756 Label* false_label() const { return false_label_; }
757 Label* fall_through() const { return fall_through_; }
758
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000759 virtual void Plug(bool flag) const;
760 virtual void Plug(Register reg) const;
761 virtual void Plug(Label* materialize_true, Label* materialize_false) const;
762 virtual void Plug(Slot* slot) const;
763 virtual void Plug(Handle<Object> lit) const;
764 virtual void Plug(Heap::RootListIndex) const;
765 virtual void PlugTOS() const;
766 virtual void DropAndPlug(int count, Register reg) const;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000767 virtual void PrepareTest(Label* materialize_true,
768 Label* materialize_false,
769 Label** if_true,
770 Label** if_false,
771 Label** fall_through) const;
772 virtual bool IsTest() const { return true; }
773
774 private:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000775 Expression* condition_;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000776 Label* true_label_;
777 Label* false_label_;
778 Label* fall_through_;
779 };
780
781 class EffectContext : public ExpressionContext {
782 public:
783 explicit EffectContext(FullCodeGenerator* codegen)
vegorov@chromium.org7943d462011-08-01 11:41:52 +0000784 : ExpressionContext(codegen) {
785 expected_stack_height_ = codegen->stack_height();
786 }
787
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000788
789 virtual void Plug(bool flag) const;
790 virtual void Plug(Register reg) const;
791 virtual void Plug(Label* materialize_true, Label* materialize_false) const;
792 virtual void Plug(Slot* slot) const;
793 virtual void Plug(Handle<Object> lit) const;
794 virtual void Plug(Heap::RootListIndex) const;
795 virtual void PlugTOS() const;
796 virtual void DropAndPlug(int count, Register reg) const;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000797 virtual void PrepareTest(Label* materialize_true,
798 Label* materialize_false,
799 Label** if_true,
800 Label** if_false,
801 Label** fall_through) const;
802 virtual bool IsEffect() const { return true; }
803 };
804
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000805 MacroAssembler* masm_;
806 CompilationInfo* info_;
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000807 Scope* scope_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000808 Label return_label_;
809 NestedStatement* nesting_stack_;
810 int loop_depth_;
vegorov@chromium.org7943d462011-08-01 11:41:52 +0000811 int stack_height_;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000812 const ExpressionContext* context_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000813 ZoneList<BailoutEntry> bailout_entries_;
814 ZoneList<BailoutEntry> stack_checks_;
815 ForwardBailoutStack* forward_bailout_stack_;
816 ForwardBailoutStack* forward_bailout_pending_;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000817
818 friend class NestedStatement;
819
820 DISALLOW_COPY_AND_ASSIGN(FullCodeGenerator);
821};
822
823
824} } // namespace v8::internal
825
826#endif // V8_FULL_CODEGEN_H_