}
-void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
- Comment cmnt(masm_, "[ ReturnStatement");
- Expression* expr = stmt->expression();
- // Complete the statement based on the type of the subexpression.
- if (expr->AsLiteral() != NULL) {
- __ mov(r0, Operand(expr->AsLiteral()->handle()));
- } else {
- ASSERT_EQ(Expression::kValue, expr->context());
- Visit(expr);
- __ pop(r0);
- }
- EmitReturnSequence(stmt->statement_pos());
-}
-
-
void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
Comment cmnt(masm_, "[ FunctionLiteral");
}
+Register FastCodeGenerator::result_register() { return r0; }
+
#undef __
}
+void MacroAssembler::Drop(int stack_elements, Condition cond) {
+ if (stack_elements > 0) {
+ add(sp, sp, Operand(stack_elements * kPointerSize), LeaveCC, cond);
+ }
+}
+
+
+void MacroAssembler::Call(Label* target) {
+ bl(target);
+}
+
+
+void MacroAssembler::Move(Register dst, Handle<Object> value) {
+ mov(dst, Operand(value));
+}
void MacroAssembler::SmiJumpTable(Register index, Vector<Label*> targets) {
}
+void MacroAssembler::PopTryHandler() {
+ ASSERT_EQ(0, StackHandlerConstants::kNextOffset);
+ pop(r1);
+ mov(ip, Operand(ExternalReference(Top::k_handler_address)));
+ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
+ str(r1, MemOperand(ip));
+}
+
+
Register MacroAssembler::CheckMaps(JSObject* object, Register object_reg,
JSObject* holder, Register holder_reg,
Register scratch,
void Call(byte* target, RelocInfo::Mode rmode, Condition cond = al);
void Call(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al);
void Ret(Condition cond = al);
+ void Drop(int stack_elements, Condition cond = al);
+ void Call(Label* target);
+ void Move(Register dst, Handle<Object> value);
// Jumps to the label at the index given by the Smi in "index".
void SmiJumpTable(Register index, Vector<Label*> targets);
// Load an object from the root table.
// On exit, r0 contains TOS (code slot).
void PushTryHandler(CodeLocation try_location, HandlerType type);
+ // Unlink the stack handler on top of the stack from the try handler chain.
+ // Must preserve the result register.
+ void PopTryHandler();
// ---------------------------------------------------------------------------
// Inline caching support
void CodeGenSelector::VisitContinueStatement(ContinueStatement* stmt) {
- BAILOUT("ContinueStatement");
}
void CodeGenSelector::VisitBreakStatement(BreakStatement* stmt) {
- BAILOUT("BreakStatement");
}
namespace v8 {
namespace internal {
-#define __ ACCESS_MASM(masm_)
+#define __ ACCESS_MASM(masm())
Handle<Code> FastCodeGenerator::MakeCode(FunctionLiteral* fun,
Handle<Script> script,
void FastCodeGenerator::VisitBlock(Block* stmt) {
Comment cmnt(masm_, "[ Block");
+ Breakable nested_statement(this, stmt);
SetStatementPosition(stmt);
VisitStatements(stmt->statements());
+ __ bind(nested_statement.break_target());
}
void FastCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) {
- UNREACHABLE();
+ Comment cmnt(masm_, "[ ContinueStatement");
+ NestedStatement* current = nesting_stack_;
+ int stack_depth = 0;
+ while (!current->IsContinueTarget(stmt->target())) {
+ stack_depth = current->Exit(stack_depth);
+ current = current->outer();
+ }
+ __ Drop(stack_depth);
+
+ Iteration* loop = current->AsIteration();
+ __ jmp(loop->continue_target());
}
void FastCodeGenerator::VisitBreakStatement(BreakStatement* stmt) {
- UNREACHABLE();
+ Comment cmnt(masm_, "[ BreakStatement");
+ NestedStatement* current = nesting_stack_;
+ int stack_depth = 0;
+ while (!current->IsBreakTarget(stmt->target())) {
+ stack_depth = current->Exit(stack_depth);
+ current = current->outer();
+ }
+ __ Drop(stack_depth);
+
+ Breakable* target = current->AsBreakable();
+ __ jmp(target->break_target());
}
+void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
+ Comment cmnt(masm_, "[ ReturnStatement");
+ Expression* expr = stmt->expression();
+ // Complete the statement based on the type of the subexpression.
+ if (expr->AsLiteral() != NULL) {
+ __ Move(result_register(), expr->AsLiteral()->handle());
+ } else {
+ ASSERT_EQ(Expression::kValue, expr->context());
+ Visit(expr);
+ __ pop(result_register());
+ }
+
+ // Exit all nested statements.
+ NestedStatement* current = nesting_stack_;
+ int stack_depth = 0;
+ while (current != NULL) {
+ stack_depth = current->Exit(stack_depth);
+ current = current->outer();
+ }
+ __ Drop(stack_depth);
+
+ EmitReturnSequence(stmt->statement_pos());
+}
+
+
+
+
void FastCodeGenerator::VisitWithEnterStatement(WithEnterStatement* stmt) {
UNREACHABLE();
}
void FastCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
Comment cmnt(masm_, "[ DoWhileStatement");
+ Label body, stack_limit_hit, stack_check_success;
+
+ Iteration loop_statement(this, stmt);
increment_loop_depth();
- Label body, exit, stack_limit_hit, stack_check_success;
__ bind(&body);
Visit(stmt->body());
// We are not in an expression context because we have been compiling
// statements. Set up a test expression context for the condition.
+ __ bind(loop_statement.continue_target());
ASSERT_EQ(NULL, true_label_);
ASSERT_EQ(NULL, false_label_);
true_label_ = &body;
- false_label_ = &exit;
+ false_label_ = loop_statement.break_target();
ASSERT(stmt->cond()->context() == Expression::kTest);
Visit(stmt->cond());
true_label_ = NULL;
__ CallStub(&stack_stub);
__ jmp(&stack_check_success);
- __ bind(&exit);
+ __ bind(loop_statement.break_target());
decrement_loop_depth();
}
void FastCodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
Comment cmnt(masm_, "[ WhileStatement");
+ Label body, stack_limit_hit, stack_check_success;
+
+ Iteration loop_statement(this, stmt);
increment_loop_depth();
- Label test, body, exit, stack_limit_hit, stack_check_success;
// Emit the test at the bottom of the loop.
- __ jmp(&test);
+ __ jmp(loop_statement.continue_target());
__ bind(&body);
Visit(stmt->body());
- __ bind(&test);
+ __ bind(loop_statement.continue_target());
// Check stack before looping.
__ StackLimitCheck(&stack_limit_hit);
__ bind(&stack_check_success);
ASSERT_EQ(NULL, true_label_);
ASSERT_EQ(NULL, false_label_);
true_label_ = &body;
- false_label_ = &exit;
+ false_label_ = loop_statement.break_target();
ASSERT(stmt->cond()->context() == Expression::kTest);
Visit(stmt->cond());
true_label_ = NULL;
__ CallStub(&stack_stub);
__ jmp(&stack_check_success);
- __ bind(&exit);
-
+ __ bind(loop_statement.break_target());
decrement_loop_depth();
}
}
+int FastCodeGenerator::TryFinally::Exit(int stack_depth) {
+ // The macros used here must preserve the result register.
+ __ Drop(stack_depth);
+ __ PopTryHandler();
+ __ Call(finally_entry_);
+ return 0;
+}
+
+
+int FastCodeGenerator::TryCatch::Exit(int stack_depth) {
+ // The macros used here must preserve the result register.
+ __ Drop(stack_depth);
+ __ PopTryHandler();
+ return 0;
+}
+
+
#undef __
namespace v8 {
namespace internal {
+// -----------------------------------------------------------------------------
+// Fast code generator.
class FastCodeGenerator: public AstVisitor {
public:
function_(NULL),
script_(script),
is_eval_(is_eval),
+ nesting_stack_(NULL),
loop_depth_(0),
true_label_(NULL),
false_label_(NULL) {
void Generate(FunctionLiteral* fun);
private:
+ class Breakable;
+ class Iteration;
+ class TryCatch;
+ class TryFinally;
+ class Finally;
+ class ForIn;
+
+ class NestedStatement BASE_EMBEDDED {
+ public:
+ explicit NestedStatement(FastCodeGenerator* codegen) : codegen_(codegen) {
+ // Link into codegen's nesting stack.
+ previous_ = codegen->nesting_stack_;
+ codegen->nesting_stack_ = this;
+ }
+ virtual ~NestedStatement() {
+ // Unlink from codegen's nesting stack.
+ ASSERT_EQ(this, codegen_->nesting_stack_);
+ codegen_->nesting_stack_ = previous_;
+ }
+
+ virtual Breakable* AsBreakable() { return NULL; }
+ virtual Iteration* AsIteration() { return NULL; }
+ virtual TryCatch* AsTryCatch() { return NULL; }
+ virtual TryFinally* AsTryFinally() { return NULL; }
+ virtual Finally* AsFinally() { return NULL; }
+ virtual ForIn* AsForIn() { return NULL; }
+
+ virtual bool IsContinueTarget(Statement* target) { return false; }
+ virtual bool IsBreakTarget(Statement* target) { return false; }
+
+ // Generate code to leave the nested statement. This includes
+ // cleaning up any stack elements in use and restoring the
+ // stack to the expectations of the surrounding statements.
+ // Takes a number of stack elements currently on top of the
+ // nested statement's stack, and returns a number of stack
+ // elements left on top of the surrounding statement's stack.
+ // The generated code must preserve the result register (which
+ // contains the value in case of a return).
+ virtual int Exit(int stack_depth) {
+ // Default implementation for the case where there is
+ // nothing to clean up.
+ return stack_depth;
+ }
+ NestedStatement* outer() { return previous_; }
+ protected:
+ MacroAssembler* masm() { return codegen_->masm(); }
+ private:
+ FastCodeGenerator* codegen_;
+ NestedStatement* previous_;
+ DISALLOW_COPY_AND_ASSIGN(NestedStatement);
+ };
+
+ class Breakable : public NestedStatement {
+ public:
+ Breakable(FastCodeGenerator* codegen,
+ BreakableStatement* break_target)
+ : NestedStatement(codegen),
+ target_(break_target) {}
+ virtual ~Breakable() {}
+ virtual Breakable* AsBreakable() { return this; }
+ virtual bool IsBreakTarget(Statement* statement) {
+ return target_ == statement;
+ }
+ BreakableStatement* statement() { return target_; }
+ Label* break_target() { return &break_target_label_; }
+ private:
+ BreakableStatement* target_;
+ Label break_target_label_;
+ DISALLOW_COPY_AND_ASSIGN(Breakable);
+ };
+
+ class Iteration : public Breakable {
+ public:
+ Iteration(FastCodeGenerator* codegen,
+ IterationStatement* iteration_statement)
+ : Breakable(codegen, iteration_statement) {}
+ virtual ~Iteration() {}
+ virtual Iteration* AsIteration() { return this; }
+ virtual bool IsContinueTarget(Statement* statement) {
+ return this->statement() == statement;
+ }
+ Label* continue_target() { return &continue_target_label_; }
+ private:
+ Label continue_target_label_;
+ DISALLOW_COPY_AND_ASSIGN(Iteration);
+ };
+
+ // The environment inside the try block of a try/catch statement.
+ class TryCatch : public NestedStatement {
+ public:
+ explicit TryCatch(FastCodeGenerator* codegen, Label* catch_entry)
+ : NestedStatement(codegen), catch_entry_(catch_entry) { }
+ virtual ~TryCatch() {}
+ virtual TryCatch* AsTryCatch() { return this; }
+ Label* catch_entry() { return catch_entry_; }
+ virtual int Exit(int stack_depth);
+ private:
+ Label* catch_entry_;
+ DISALLOW_COPY_AND_ASSIGN(TryCatch);
+ };
+
+ // The environment inside the try block of a try/finally statement.
+ class TryFinally : public NestedStatement {
+ public:
+ explicit TryFinally(FastCodeGenerator* codegen, Label* finally_entry)
+ : NestedStatement(codegen), finally_entry_(finally_entry) { }
+ virtual ~TryFinally() {}
+ virtual TryFinally* AsTryFinally() { return this; }
+ Label* finally_entry() { return finally_entry_; }
+ virtual int Exit(int stack_depth);
+ private:
+ Label* finally_entry_;
+ DISALLOW_COPY_AND_ASSIGN(TryFinally);
+ };
+
+ // A FinallyEnvironment represents being inside a finally block.
+ // Abnormal termination of the finally block needs to clean up
+ // the block's parameters from the stack.
+ class Finally : public NestedStatement {
+ public:
+ explicit Finally(FastCodeGenerator* codegen) : NestedStatement(codegen) { }
+ virtual ~Finally() {}
+ virtual Finally* AsFinally() { return this; }
+ virtual int Exit(int stack_depth) {
+ return stack_depth + kFinallyStackElementCount;
+ }
+ private:
+ // Number of extra stack slots occupied during a finally block.
+ static const int kFinallyStackElementCount = 2;
+ DISALLOW_COPY_AND_ASSIGN(Finally);
+ };
+
+ // A ForInEnvironment represents being inside a for-in loop.
+ // Abnormal termination of the for-in block needs to clean up
+ // the block's temporary storage from the stack.
+ class ForIn : public Iteration {
+ public:
+ ForIn(FastCodeGenerator* codegen,
+ ForInStatement* statement)
+ : Iteration(codegen, statement) { }
+ virtual ~ForIn() {}
+ virtual ForIn* AsForIn() { return this; }
+ virtual int Exit(int stack_depth) {
+ return stack_depth + kForInStackElementCount;
+ }
+ private:
+ // TODO(lrn): Check that this value is correct when implementing
+ // for-in.
+ static const int kForInStackElementCount = 5;
+ DISALLOW_COPY_AND_ASSIGN(ForIn);
+ };
+
+
int SlotOffset(Slot* slot);
void Move(Expression::Context destination, Register source);
void Move(Expression::Context destination, Slot* source, Register scratch);
loop_depth_--;
}
+ MacroAssembler* masm() { return masm_; }
+ static Register result_register();
+
// AST node visit functions.
#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
AST_NODE_LIST(DECLARE_VISIT)
#undef DECLARE_VISIT
-
// Handles the shortcutted logical binary operations in VisitBinaryOperation.
void EmitLogicalOperation(BinaryOperation* expr);
Handle<Script> script_;
bool is_eval_;
Label return_label_;
+ NestedStatement* nesting_stack_;
int loop_depth_;
Label* true_label_;
Label* false_label_;
+ friend class NestedStatement;
+
DISALLOW_COPY_AND_ASSIGN(FastCodeGenerator);
};
}
-void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
- Comment cmnt(masm_, "[ ReturnStatement");
- Expression* expr = stmt->expression();
- if (expr->AsLiteral() != NULL) {
- __ mov(eax, expr->AsLiteral()->handle());
- } else {
- ASSERT_EQ(Expression::kValue, expr->context());
- Visit(expr);
- __ pop(eax);
- }
- EmitReturnSequence(stmt->statement_pos());
-}
-
-
void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
Comment cmnt(masm_, "[ FunctionLiteral");
// Convert current context to test context: End post-test code.
}
+Register FastCodeGenerator::result_register() { return eax; }
void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) {
__ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
}
+void MacroAssembler::PopTryHandler() {
+ ASSERT_EQ(0, StackHandlerConstants::kNextOffset);
+ pop(Operand::StaticVariable(ExternalReference(Top::k_handler_address)));
+ add(Operand(esp), Immediate(StackHandlerConstants::kSize - kPointerSize));
+}
+
+
Register MacroAssembler::CheckMaps(JSObject* object, Register object_reg,
JSObject* holder, Register holder_reg,
Register scratch,
}
+void MacroAssembler::Drop(int stack_elements) {
+ if (stack_elements > 0) {
+ add(Operand(esp), Immediate(stack_elements * kPointerSize));
+ }
+}
+
+
+void MacroAssembler::Move(Register dst, Handle<Object> value) {
+ mov(dst, value);
+}
+
+
void MacroAssembler::SetCounter(StatsCounter* counter, int value) {
if (FLAG_native_code_counters && counter->Enabled()) {
mov(Operand::StaticVariable(ExternalReference(counter)), Immediate(value));
// address must be pushed before calling this helper.
void PushTryHandler(CodeLocation try_location, HandlerType type);
+ // Unlink the stack handler on top of the stack from the try handler chain.
+ void PopTryHandler();
+
// ---------------------------------------------------------------------------
// Inline caching support
void Ret();
+ void Drop(int element_count);
+
+ void Call(Label* target) { call(target); }
+
+ void Move(Register target, Handle<Object> value);
+
struct Unresolved {
int pc;
uint32_t flags; // see Bootstrapper::FixupFlags decoders/encoders.
}
-void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
- Comment cmnt(masm_, "[ ReturnStatement");
- Expression* expr = stmt->expression();
- if (expr->AsLiteral() != NULL) {
- __ Move(rax, expr->AsLiteral()->handle());
- } else {
- Visit(expr);
- ASSERT_EQ(Expression::kValue, expr->context());
- __ pop(rax);
- }
- EmitReturnSequence(stmt->statement_pos());
-}
-
-
void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
Comment cmnt(masm_, "[ FunctionLiteral");
}
+Register FastCodeGenerator::result_register() { return rax; }
+
#undef __
}
+void MacroAssembler::Drop(int stack_elements) {
+ if (stack_elements > 0) {
+ addq(rsp, Immediate(stack_elements * kPointerSize));
+ }
+}
+
+
void MacroAssembler::Test(const Operand& src, Smi* source) {
intptr_t smi = reinterpret_cast<intptr_t>(source);
if (is_int32(smi)) {
}
+void MacroAssembler::PopTryHandler() {
+ ASSERT_EQ(0, StackHandlerConstants::kNextOffset);
+ movq(kScratchRegister, ExternalReference(Top::k_handler_address));
+ pop(Operand(kScratchRegister, 0));
+ addq(rsp, Immediate(StackHandlerConstants::kSize - kPointerSize));
+}
+
+
void MacroAssembler::Ret() {
ret(0);
}
void Test(const Operand& dst, Smi* source);
// ---------------------------------------------------------------------------
- // Macro instructions
+ // Macro instructions.
// Load a register with a long value as efficiently as possible.
void Set(Register dst, int64_t x);
void Cmp(Register dst, Handle<Object> source);
void Cmp(const Operand& dst, Handle<Object> source);
void Push(Handle<Object> source);
+ void Drop(int stack_elements);
+ void Call(Label* target) { call(target); }
// Control Flow
void Jump(Address destination, RelocInfo::Mode rmode);
// address must be pushed before calling this helper.
void PushTryHandler(CodeLocation try_location, HandlerType type);
+ // Unlink the stack handler on top of the stack from the try handler chain.
+ void PopTryHandler();
// ---------------------------------------------------------------------------
// Inline caching support