blob: 0482ee8d947b30a112d18a5453082b2d891c1487 [file] [log] [blame]
Leon Clarkef7060e22010-06-03 12:02:55 +01001// Copyright 2010 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
33#include "ast.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010034#include "code-stubs.h"
35#include "codegen.h"
Leon Clarkef7060e22010-06-03 12:02:55 +010036#include "compiler.h"
Leon Clarked91b9f72010-01-27 17:25:45 +000037
38namespace v8 {
39namespace internal {
40
Ben Murdochb0fe1622011-05-05 13:52:32 +010041// Forward declarations.
42class JumpPatchSite;
43
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010044// AST node visitor which can tell whether a given statement will be breakable
45// when the code is compiled by the full compiler in the debugger. This means
46// that there will be an IC (load/store/call) in the code generated for the
47// debugger to piggybag on.
48class BreakableStatementChecker: public AstVisitor {
49 public:
50 BreakableStatementChecker() : is_breakable_(false) {}
51
52 void Check(Statement* stmt);
53 void Check(Expression* stmt);
54
55 bool is_breakable() { return is_breakable_; }
56
57 private:
58 // AST node visit functions.
59#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
60 AST_NODE_LIST(DECLARE_VISIT)
61#undef DECLARE_VISIT
62
63 bool is_breakable_;
64
65 DISALLOW_COPY_AND_ASSIGN(BreakableStatementChecker);
66};
67
68
Leon Clarked91b9f72010-01-27 17:25:45 +000069// -----------------------------------------------------------------------------
70// Full code generator.
71
72class FullCodeGenerator: public AstVisitor {
73 public:
Ben Murdochb0fe1622011-05-05 13:52:32 +010074 enum State {
75 NO_REGISTERS,
76 TOS_REG
77 };
78
Andrei Popescu31002712010-02-23 13:46:05 +000079 explicit FullCodeGenerator(MacroAssembler* masm)
Leon Clarked91b9f72010-01-27 17:25:45 +000080 : masm_(masm),
Andrei Popescu31002712010-02-23 13:46:05 +000081 info_(NULL),
Leon Clarked91b9f72010-01-27 17:25:45 +000082 nesting_stack_(NULL),
83 loop_depth_(0),
Ben Murdochb0fe1622011-05-05 13:52:32 +010084 context_(NULL),
85 bailout_entries_(0),
86 stack_checks_(2), // There's always at least one.
87 forward_bailout_stack_(NULL),
88 forward_bailout_pending_(NULL) {
Leon Clarked91b9f72010-01-27 17:25:45 +000089 }
90
Ben Murdochf87a2032010-10-22 12:50:53 +010091 static bool MakeCode(CompilationInfo* info);
Leon Clarked91b9f72010-01-27 17:25:45 +000092
Iain Merrick75681382010-08-19 15:07:18 +010093 void Generate(CompilationInfo* info);
Ben Murdochb0fe1622011-05-05 13:52:32 +010094 void PopulateDeoptimizationData(Handle<Code> code);
95
96 class StateField : public BitField<State, 0, 8> { };
97 class PcField : public BitField<unsigned, 8, 32-8> { };
98
99 static const char* State2String(State state) {
100 switch (state) {
101 case NO_REGISTERS: return "NO_REGISTERS";
102 case TOS_REG: return "TOS_REG";
103 }
104 UNREACHABLE();
105 return NULL;
106 }
Leon Clarked91b9f72010-01-27 17:25:45 +0000107
108 private:
109 class Breakable;
110 class Iteration;
111 class TryCatch;
112 class TryFinally;
113 class Finally;
114 class ForIn;
115
116 class NestedStatement BASE_EMBEDDED {
117 public:
118 explicit NestedStatement(FullCodeGenerator* codegen) : codegen_(codegen) {
119 // Link into codegen's nesting stack.
120 previous_ = codegen->nesting_stack_;
121 codegen->nesting_stack_ = this;
122 }
123 virtual ~NestedStatement() {
124 // Unlink from codegen's nesting stack.
125 ASSERT_EQ(this, codegen_->nesting_stack_);
126 codegen_->nesting_stack_ = previous_;
127 }
128
129 virtual Breakable* AsBreakable() { return NULL; }
130 virtual Iteration* AsIteration() { return NULL; }
131 virtual TryCatch* AsTryCatch() { return NULL; }
132 virtual TryFinally* AsTryFinally() { return NULL; }
133 virtual Finally* AsFinally() { return NULL; }
134 virtual ForIn* AsForIn() { return NULL; }
135
136 virtual bool IsContinueTarget(Statement* target) { return false; }
137 virtual bool IsBreakTarget(Statement* target) { return false; }
138
139 // Generate code to leave the nested statement. This includes
140 // cleaning up any stack elements in use and restoring the
141 // stack to the expectations of the surrounding statements.
142 // Takes a number of stack elements currently on top of the
143 // nested statement's stack, and returns a number of stack
144 // elements left on top of the surrounding statement's stack.
145 // The generated code must preserve the result register (which
146 // contains the value in case of a return).
147 virtual int Exit(int stack_depth) {
148 // Default implementation for the case where there is
149 // nothing to clean up.
150 return stack_depth;
151 }
152 NestedStatement* outer() { return previous_; }
153 protected:
154 MacroAssembler* masm() { return codegen_->masm(); }
155 private:
156 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_; }
204 virtual int Exit(int stack_depth);
205 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_; }
218 virtual int Exit(int stack_depth);
219 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; }
232 virtual int Exit(int stack_depth) {
233 return stack_depth + kFinallyStackElementCount;
234 }
235 private:
236 // Number of extra stack slots occupied during a finally block.
237 static const int kFinallyStackElementCount = 2;
238 DISALLOW_COPY_AND_ASSIGN(Finally);
239 };
240
241 // A ForInEnvironment represents being inside a for-in loop.
242 // Abnormal termination of the for-in block needs to clean up
243 // the block's temporary storage from the stack.
244 class ForIn : public Iteration {
245 public:
246 ForIn(FullCodeGenerator* codegen,
247 ForInStatement* statement)
248 : Iteration(codegen, statement) { }
249 virtual ~ForIn() {}
250 virtual ForIn* AsForIn() { return this; }
251 virtual int Exit(int stack_depth) {
252 return stack_depth + kForInStackElementCount;
253 }
254 private:
Leon Clarked91b9f72010-01-27 17:25:45 +0000255 static const int kForInStackElementCount = 5;
256 DISALLOW_COPY_AND_ASSIGN(ForIn);
257 };
258
Ben Murdochb0fe1622011-05-05 13:52:32 +0100259 // The forward bailout stack keeps track of the expressions that can
260 // bail out to just before the control flow is split in a child
261 // node. The stack elements are linked together through the parent
262 // link when visiting expressions in test contexts after requesting
263 // bailout in child forwarding.
264 class ForwardBailoutStack BASE_EMBEDDED {
265 public:
266 ForwardBailoutStack(Expression* expr, ForwardBailoutStack* parent)
267 : expr_(expr), parent_(parent) { }
268
269 Expression* expr() const { return expr_; }
270 ForwardBailoutStack* parent() const { return parent_; }
271
272 private:
273 Expression* const expr_;
274 ForwardBailoutStack* const parent_;
275 };
276
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100277 enum ConstantOperand {
278 kNoConstants,
279 kLeftConstant,
280 kRightConstant
281 };
282
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100283 // Type of a member function that generates inline code for a native function.
284 typedef void (FullCodeGenerator::*InlineFunctionGenerator)
285 (ZoneList<Expression*>*);
286
287 static const InlineFunctionGenerator kInlineFunctionGenerators[];
288
Ben Murdochdb5a90a2011-01-06 18:27:03 +0000289 // A platform-specific utility to overwrite the accumulator register
290 // with a GC-safe value.
291 void ClearAccumulator();
292
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100293 // Compute the frame pointer relative offset for a given local or
294 // parameter slot.
Leon Clarked91b9f72010-01-27 17:25:45 +0000295 int SlotOffset(Slot* slot);
296
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100297 // Determine whether or not to inline the smi case for the given
298 // operation.
299 bool ShouldInlineSmiCase(Token::Value op);
300
301 // Compute which (if any) of the operands is a compile-time constant.
302 ConstantOperand GetConstantOperand(Token::Value op,
303 Expression* left,
304 Expression* right);
305
Leon Clarked91b9f72010-01-27 17:25:45 +0000306 // Helper function to convert a pure value into a test context. The value
307 // is expected on the stack or the accumulator, depending on the platform.
308 // See the platform-specific implementation for details.
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100309 void DoTest(Label* if_true, Label* if_false, Label* fall_through);
310
311 // Helper function to split control flow and avoid a branch to the
312 // fall-through label if it is set up.
313 void Split(Condition cc,
314 Label* if_true,
315 Label* if_false,
316 Label* fall_through);
Leon Clarked91b9f72010-01-27 17:25:45 +0000317
318 void Move(Slot* dst, Register source, Register scratch1, Register scratch2);
319 void Move(Register dst, Slot* source);
320
321 // Return an operand used to read/write to a known (ie, non-LOOKUP) slot.
322 // May emit code to traverse the context chain, destroying the scratch
323 // register.
324 MemOperand EmitSlotSearch(Slot* slot, Register scratch);
325
Ben Murdochb0fe1622011-05-05 13:52:32 +0100326 // Forward the bailout responsibility for the given expression to
327 // the next child visited (which must be in a test context).
328 void ForwardBailoutToChild(Expression* expr);
329
Leon Clarked91b9f72010-01-27 17:25:45 +0000330 void VisitForEffect(Expression* expr) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100331 EffectContext context(this);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100332 HandleInNonTestContext(expr, NO_REGISTERS);
Leon Clarked91b9f72010-01-27 17:25:45 +0000333 }
334
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100335 void VisitForAccumulatorValue(Expression* expr) {
336 AccumulatorValueContext context(this);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100337 HandleInNonTestContext(expr, TOS_REG);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100338 }
339
340 void VisitForStackValue(Expression* expr) {
341 StackValueContext context(this);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100342 HandleInNonTestContext(expr, NO_REGISTERS);
Leon Clarked91b9f72010-01-27 17:25:45 +0000343 }
344
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100345 void VisitForControl(Expression* expr,
346 Label* if_true,
347 Label* if_false,
348 Label* fall_through) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100349 TestContext context(this, if_true, if_false, fall_through);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100350 VisitInTestContext(expr);
351 // Forwarding bailouts to children is a one shot operation. It
352 // should have been processed at this point.
353 ASSERT(forward_bailout_pending_ == NULL);
Leon Clarked91b9f72010-01-27 17:25:45 +0000354 }
355
Ben Murdochb0fe1622011-05-05 13:52:32 +0100356 void HandleInNonTestContext(Expression* expr, State state);
357 void VisitInTestContext(Expression* expr);
358
Leon Clarked91b9f72010-01-27 17:25:45 +0000359 void VisitDeclarations(ZoneList<Declaration*>* declarations);
360 void DeclareGlobals(Handle<FixedArray> pairs);
361
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100362 // 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.
365 bool TryLiteralCompare(Token::Value op,
366 Expression* left,
367 Expression* right,
368 Label* if_true,
369 Label* if_false,
370 Label* fall_through);
371
Ben Murdochb0fe1622011-05-05 13:52:32 +0100372 // Bailout support.
373 void PrepareForBailout(AstNode* node, State state);
374 void PrepareForBailoutForId(int id, State state);
375
376 // Record a call's return site offset, used to rebuild the frame if the
377 // called function was inlined at the site.
378 void RecordJSReturnSite(Call* call);
379
380 // Prepare for bailout before a test (or compare) and branch. If
381 // should_normalize, then the following comparison will not handle the
382 // canonical JS true value so we will insert a (dead) test against true at
383 // the actual bailout target from the optimized code. If not
384 // should_normalize, the true and false labels are ignored.
385 void PrepareForBailoutBeforeSplit(State state,
386 bool should_normalize,
387 Label* if_true,
388 Label* if_false);
389
Leon Clarkef7060e22010-06-03 12:02:55 +0100390 // Platform-specific code for a variable, constant, or function
391 // declaration. Functions have an initial value.
392 void EmitDeclaration(Variable* variable,
393 Variable::Mode mode,
394 FunctionLiteral* function);
395
Ben Murdochb0fe1622011-05-05 13:52:32 +0100396 // Platform-specific code for checking the stack limit at the back edge of
397 // a loop.
398 void EmitStackCheck(IterationStatement* stmt);
399 // Record the OSR AST id corresponding to a stack check in the code.
400 void RecordStackCheck(int osr_ast_id);
401 // Emit a table of stack check ids and pcs into the code stream. Return
402 // the offset of the start of the table.
403 unsigned EmitStackCheckTable();
404
Leon Clarked91b9f72010-01-27 17:25:45 +0000405 // Platform-specific return sequence
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100406 void EmitReturnSequence();
Leon Clarked91b9f72010-01-27 17:25:45 +0000407
408 // Platform-specific code sequences for calls
409 void EmitCallWithStub(Call* expr);
410 void EmitCallWithIC(Call* expr, Handle<Object> name, RelocInfo::Mode mode);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100411 void EmitKeyedCallWithIC(Call* expr, Expression* key, RelocInfo::Mode mode);
Leon Clarked91b9f72010-01-27 17:25:45 +0000412
Leon Clarkef7060e22010-06-03 12:02:55 +0100413 // Platform-specific code for inline runtime calls.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100414 InlineFunctionGenerator FindInlineFunctionGenerator(Runtime::FunctionId id);
415
Leon Clarkef7060e22010-06-03 12:02:55 +0100416 void EmitInlineRuntimeCall(CallRuntime* expr);
Steve Block791712a2010-08-27 10:21:07 +0100417
418#define EMIT_INLINE_RUNTIME_CALL(name, x, y) \
419 void Emit##name(ZoneList<Expression*>* arguments);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100420 INLINE_FUNCTION_LIST(EMIT_INLINE_RUNTIME_CALL)
Steve Block791712a2010-08-27 10:21:07 +0100421 INLINE_RUNTIME_FUNCTION_LIST(EMIT_INLINE_RUNTIME_CALL)
422#undef EMIT_INLINE_RUNTIME_CALL
Leon Clarkef7060e22010-06-03 12:02:55 +0100423
Leon Clarked91b9f72010-01-27 17:25:45 +0000424 // Platform-specific code for loading variables.
Steve Block59151502010-09-22 15:07:15 +0100425 void EmitLoadGlobalSlotCheckExtensions(Slot* slot,
426 TypeofState typeof_state,
427 Label* slow);
428 MemOperand ContextSlotOperandCheckExtensions(Slot* slot, Label* slow);
429 void EmitDynamicLoadFromSlotFastCase(Slot* slot,
430 TypeofState typeof_state,
431 Label* slow,
432 Label* done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100433 void EmitVariableLoad(Variable* expr);
Leon Clarked91b9f72010-01-27 17:25:45 +0000434
Leon Clarkef7060e22010-06-03 12:02:55 +0100435 // Platform-specific support for allocating a new closure based on
436 // the given function info.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800437 void EmitNewClosure(Handle<SharedFunctionInfo> info, bool pretenure);
Leon Clarkef7060e22010-06-03 12:02:55 +0100438
Leon Clarked91b9f72010-01-27 17:25:45 +0000439 // Platform-specific support for compiling assignments.
440
441 // Load a value from a named property.
442 // The receiver is left on the stack by the IC.
443 void EmitNamedPropertyLoad(Property* expr);
444
445 // Load a value from a keyed property.
446 // The receiver and the key is left on the stack by the IC.
447 void EmitKeyedPropertyLoad(Property* expr);
448
449 // Apply the compound assignment operator. Expects the left operand on top
450 // of the stack and the right one in the accumulator.
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100451 void EmitBinaryOp(Token::Value op,
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100452 OverwriteMode mode);
453
454 // Helper functions for generating inlined smi code for certain
455 // binary operations.
456 void EmitInlineSmiBinaryOp(Expression* expr,
457 Token::Value op,
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100458 OverwriteMode mode,
459 Expression* left,
460 Expression* right,
461 ConstantOperand constant);
462
463 void EmitConstantSmiBinaryOp(Expression* expr,
464 Token::Value op,
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100465 OverwriteMode mode,
466 bool left_is_constant_smi,
467 Smi* value);
468
469 void EmitConstantSmiBitOp(Expression* expr,
470 Token::Value op,
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100471 OverwriteMode mode,
472 Smi* value);
473
474 void EmitConstantSmiShiftOp(Expression* expr,
475 Token::Value op,
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100476 OverwriteMode mode,
477 Smi* value);
478
479 void EmitConstantSmiAdd(Expression* expr,
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100480 OverwriteMode mode,
481 bool left_is_constant_smi,
482 Smi* value);
483
484 void EmitConstantSmiSub(Expression* expr,
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100485 OverwriteMode mode,
486 bool left_is_constant_smi,
487 Smi* value);
Leon Clarked91b9f72010-01-27 17:25:45 +0000488
Leon Clarkef7060e22010-06-03 12:02:55 +0100489 // Assign to the given expression as if via '='. The right-hand-side value
490 // is expected in the accumulator.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100491 void EmitAssignment(Expression* expr, int bailout_ast_id);
Leon Clarkef7060e22010-06-03 12:02:55 +0100492
Leon Clarked91b9f72010-01-27 17:25:45 +0000493 // Complete a variable assignment. The right-hand-side value is expected
494 // in the accumulator.
Leon Clarkef7060e22010-06-03 12:02:55 +0100495 void EmitVariableAssignment(Variable* var,
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100496 Token::Value op);
Leon Clarked91b9f72010-01-27 17:25:45 +0000497
498 // Complete a named property assignment. The receiver is expected on top
499 // of the stack and the right-hand-side value in the accumulator.
500 void EmitNamedPropertyAssignment(Assignment* expr);
501
502 // Complete a keyed property assignment. The receiver and key are
503 // expected on top of the stack and the right-hand-side value in the
504 // accumulator.
505 void EmitKeyedPropertyAssignment(Assignment* expr);
506
507 void SetFunctionPosition(FunctionLiteral* fun);
508 void SetReturnPosition(FunctionLiteral* fun);
509 void SetStatementPosition(Statement* stmt);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100510 void SetExpressionPosition(Expression* expr, int pos);
Leon Clarked91b9f72010-01-27 17:25:45 +0000511 void SetStatementPosition(int pos);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100512 void SetSourcePosition(int pos);
Leon Clarked91b9f72010-01-27 17:25:45 +0000513
514 // Non-local control flow support.
515 void EnterFinallyBlock();
516 void ExitFinallyBlock();
517
518 // Loop nesting counter.
519 int loop_depth() { return loop_depth_; }
520 void increment_loop_depth() { loop_depth_++; }
521 void decrement_loop_depth() {
522 ASSERT(loop_depth_ > 0);
523 loop_depth_--;
524 }
525
526 MacroAssembler* masm() { return masm_; }
Andrei Popescu31002712010-02-23 13:46:05 +0000527
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100528 class ExpressionContext;
529 const ExpressionContext* context() { return context_; }
530 void set_new_context(const ExpressionContext* context) { context_ = context; }
531
Andrei Popescu31002712010-02-23 13:46:05 +0000532 Handle<Script> script() { return info_->script(); }
533 bool is_eval() { return info_->is_eval(); }
534 FunctionLiteral* function() { return info_->function(); }
535 Scope* scope() { return info_->scope(); }
536
Leon Clarked91b9f72010-01-27 17:25:45 +0000537 static Register result_register();
538 static Register context_register();
539
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100540 // Helper for calling an IC stub.
541 void EmitCallIC(Handle<Code> ic, RelocInfo::Mode mode);
542
Ben Murdochb0fe1622011-05-05 13:52:32 +0100543 // Calling an IC stub with a patch site. Passing NULL for patch_site
544 // indicates no inlined smi code and emits a nop after the IC call.
545 void EmitCallIC(Handle<Code> ic, JumpPatchSite* patch_site);
546
Leon Clarked91b9f72010-01-27 17:25:45 +0000547 // Set fields in the stack frame. Offsets are the frame pointer relative
548 // offsets defined in, e.g., StandardFrameConstants.
549 void StoreToFrameField(int frame_offset, Register value);
550
551 // Load a value from the current context. Indices are defined as an enum
552 // in v8::internal::Context.
553 void LoadContextField(Register dst, int context_index);
554
555 // AST node visit functions.
556#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
557 AST_NODE_LIST(DECLARE_VISIT)
558#undef DECLARE_VISIT
559 // Handles the shortcutted logical binary operations in VisitBinaryOperation.
560 void EmitLogicalOperation(BinaryOperation* expr);
561
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100562 void VisitForTypeofValue(Expression* expr);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100563
Ben Murdochb0fe1622011-05-05 13:52:32 +0100564 struct BailoutEntry {
565 unsigned id;
566 unsigned pc_and_state;
567 };
Leon Clarke4515c472010-02-03 11:58:03 +0000568
Leon Clarked91b9f72010-01-27 17:25:45 +0000569
Ben Murdochb0fe1622011-05-05 13:52:32 +0100570 class ExpressionContext BASE_EMBEDDED {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100571 public:
572 explicit ExpressionContext(FullCodeGenerator* codegen)
573 : masm_(codegen->masm()), old_(codegen->context()), codegen_(codegen) {
574 codegen->set_new_context(this);
575 }
576
577 virtual ~ExpressionContext() {
578 codegen_->set_new_context(old_);
579 }
580
581 // Convert constant control flow (true or false) to the result expected for
582 // this expression context.
583 virtual void Plug(bool flag) const = 0;
584
585 // Emit code to convert a pure value (in a register, slot, as a literal,
586 // or on top of the stack) into the result expected according to this
587 // expression context.
588 virtual void Plug(Register reg) const = 0;
589 virtual void Plug(Slot* slot) const = 0;
590 virtual void Plug(Handle<Object> lit) const = 0;
591 virtual void Plug(Heap::RootListIndex index) const = 0;
592 virtual void PlugTOS() const = 0;
593
594 // Emit code to convert pure control flow to a pair of unbound labels into
595 // the result expected according to this expression context. The
Ben Murdochb0fe1622011-05-05 13:52:32 +0100596 // implementation will bind both labels unless it's a TestContext, which
597 // won't bind them at this point.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100598 virtual void Plug(Label* materialize_true,
599 Label* materialize_false) const = 0;
600
601 // Emit code to discard count elements from the top of stack, then convert
602 // a pure value into the result expected according to this expression
603 // context.
604 virtual void DropAndPlug(int count, Register reg) const = 0;
605
606 // For shortcutting operations || and &&.
607 virtual void EmitLogicalLeft(BinaryOperation* expr,
608 Label* eval_right,
609 Label* done) const = 0;
610
611 // Set up branch labels for a test expression. The three Label** parameters
612 // are output parameters.
613 virtual void PrepareTest(Label* materialize_true,
614 Label* materialize_false,
615 Label** if_true,
616 Label** if_false,
617 Label** fall_through) const = 0;
618
Ben Murdochb0fe1622011-05-05 13:52:32 +0100619 virtual void HandleExpression(Expression* expr) const = 0;
620
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100621 // Returns true if we are evaluating only for side effects (ie if the result
Ben Murdochb0fe1622011-05-05 13:52:32 +0100622 // will be discarded).
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100623 virtual bool IsEffect() const { return false; }
624
625 // Returns true if we are branching on the value rather than materializing
Ben Murdochb0fe1622011-05-05 13:52:32 +0100626 // it. Only used for asserts.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100627 virtual bool IsTest() const { return false; }
628
629 protected:
630 FullCodeGenerator* codegen() const { return codegen_; }
631 MacroAssembler* masm() const { return masm_; }
632 MacroAssembler* masm_;
633
634 private:
635 const ExpressionContext* old_;
636 FullCodeGenerator* codegen_;
637 };
638
639 class AccumulatorValueContext : public ExpressionContext {
640 public:
641 explicit AccumulatorValueContext(FullCodeGenerator* codegen)
642 : ExpressionContext(codegen) { }
643
644 virtual void Plug(bool flag) const;
645 virtual void Plug(Register reg) const;
646 virtual void Plug(Label* materialize_true, Label* materialize_false) const;
647 virtual void Plug(Slot* slot) const;
648 virtual void Plug(Handle<Object> lit) const;
649 virtual void Plug(Heap::RootListIndex) const;
650 virtual void PlugTOS() const;
651 virtual void DropAndPlug(int count, Register reg) const;
652 virtual void EmitLogicalLeft(BinaryOperation* expr,
653 Label* eval_right,
654 Label* done) const;
655 virtual void PrepareTest(Label* materialize_true,
656 Label* materialize_false,
657 Label** if_true,
658 Label** if_false,
659 Label** fall_through) const;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100660 virtual void HandleExpression(Expression* expr) const;
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100661 };
662
663 class StackValueContext : public ExpressionContext {
664 public:
665 explicit StackValueContext(FullCodeGenerator* codegen)
666 : ExpressionContext(codegen) { }
667
668 virtual void Plug(bool flag) const;
669 virtual void Plug(Register reg) const;
670 virtual void Plug(Label* materialize_true, Label* materialize_false) const;
671 virtual void Plug(Slot* slot) const;
672 virtual void Plug(Handle<Object> lit) const;
673 virtual void Plug(Heap::RootListIndex) const;
674 virtual void PlugTOS() const;
675 virtual void DropAndPlug(int count, Register reg) const;
676 virtual void EmitLogicalLeft(BinaryOperation* expr,
677 Label* eval_right,
678 Label* done) const;
679 virtual void PrepareTest(Label* materialize_true,
680 Label* materialize_false,
681 Label** if_true,
682 Label** if_false,
683 Label** fall_through) const;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100684 virtual void HandleExpression(Expression* expr) const;
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100685 };
686
687 class TestContext : public ExpressionContext {
688 public:
689 explicit TestContext(FullCodeGenerator* codegen,
690 Label* true_label,
691 Label* false_label,
692 Label* fall_through)
693 : ExpressionContext(codegen),
694 true_label_(true_label),
695 false_label_(false_label),
696 fall_through_(fall_through) { }
697
Ben Murdochf87a2032010-10-22 12:50:53 +0100698 static const TestContext* cast(const ExpressionContext* context) {
699 ASSERT(context->IsTest());
700 return reinterpret_cast<const TestContext*>(context);
701 }
702
703 Label* true_label() const { return true_label_; }
704 Label* false_label() const { return false_label_; }
705 Label* fall_through() const { return fall_through_; }
706
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100707 virtual void Plug(bool flag) const;
708 virtual void Plug(Register reg) const;
709 virtual void Plug(Label* materialize_true, Label* materialize_false) const;
710 virtual void Plug(Slot* slot) const;
711 virtual void Plug(Handle<Object> lit) const;
712 virtual void Plug(Heap::RootListIndex) const;
713 virtual void PlugTOS() const;
714 virtual void DropAndPlug(int count, Register reg) const;
715 virtual void EmitLogicalLeft(BinaryOperation* expr,
716 Label* eval_right,
717 Label* done) const;
718 virtual void PrepareTest(Label* materialize_true,
719 Label* materialize_false,
720 Label** if_true,
721 Label** if_false,
722 Label** fall_through) const;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100723 virtual void HandleExpression(Expression* expr) const;
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100724 virtual bool IsTest() const { return true; }
725
726 private:
727 Label* true_label_;
728 Label* false_label_;
729 Label* fall_through_;
730 };
731
732 class EffectContext : public ExpressionContext {
733 public:
734 explicit EffectContext(FullCodeGenerator* codegen)
735 : ExpressionContext(codegen) { }
736
737 virtual void Plug(bool flag) const;
738 virtual void Plug(Register reg) const;
739 virtual void Plug(Label* materialize_true, Label* materialize_false) const;
740 virtual void Plug(Slot* slot) const;
741 virtual void Plug(Handle<Object> lit) const;
742 virtual void Plug(Heap::RootListIndex) const;
743 virtual void PlugTOS() const;
744 virtual void DropAndPlug(int count, Register reg) const;
745 virtual void EmitLogicalLeft(BinaryOperation* expr,
746 Label* eval_right,
747 Label* done) const;
748 virtual void PrepareTest(Label* materialize_true,
749 Label* materialize_false,
750 Label** if_true,
751 Label** if_false,
752 Label** fall_through) const;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100753 virtual void HandleExpression(Expression* expr) const;
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100754 virtual bool IsEffect() const { return true; }
755 };
756
Ben Murdochb0fe1622011-05-05 13:52:32 +0100757 MacroAssembler* masm_;
758 CompilationInfo* info_;
759 Label return_label_;
760 NestedStatement* nesting_stack_;
761 int loop_depth_;
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100762 const ExpressionContext* context_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100763 ZoneList<BailoutEntry> bailout_entries_;
764 ZoneList<BailoutEntry> stack_checks_;
765 ForwardBailoutStack* forward_bailout_stack_;
766 ForwardBailoutStack* forward_bailout_pending_;
Leon Clarked91b9f72010-01-27 17:25:45 +0000767
768 friend class NestedStatement;
769
770 DISALLOW_COPY_AND_ASSIGN(FullCodeGenerator);
771};
772
773
774} } // namespace v8::internal
775
776#endif // V8_FULL_CODEGEN_H_