| Index: src/full-codegen.cc
|
| ===================================================================
|
| --- src/full-codegen.cc (revision 4816)
|
| +++ src/full-codegen.cc (working copy)
|
| @@ -439,6 +439,231 @@
|
| #undef CHECK_BAILOUT
|
|
|
|
|
| +void BreakableStatementChecker::Check(Statement* stmt) {
|
| + Visit(stmt);
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::Check(Expression* expr) {
|
| + Visit(expr);
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitDeclaration(Declaration* decl) {
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitBlock(Block* stmt) {
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitExpressionStatement(
|
| + ExpressionStatement* stmt) {
|
| + // Check if expression is breakable.
|
| + Visit(stmt->expression());
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitEmptyStatement(EmptyStatement* stmt) {
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitIfStatement(IfStatement* stmt) {
|
| + // If the condition is breakable the if statement is breakable.
|
| + Visit(stmt->condition());
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitContinueStatement(
|
| + ContinueStatement* stmt) {
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitBreakStatement(BreakStatement* stmt) {
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitReturnStatement(ReturnStatement* stmt) {
|
| + // Return is breakable if the expression is.
|
| + Visit(stmt->expression());
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitWithEnterStatement(
|
| + WithEnterStatement* stmt) {
|
| + Visit(stmt->expression());
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitWithExitStatement(
|
| + WithExitStatement* stmt) {
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitSwitchStatement(SwitchStatement* stmt) {
|
| + // Switch statements breakable if the tag expression is.
|
| + Visit(stmt->tag());
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitDoWhileStatement(DoWhileStatement* stmt) {
|
| + // Mark do while as breakable to avoid adding a break slot in front of it.
|
| + is_breakable_ = true;
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitWhileStatement(WhileStatement* stmt) {
|
| + // Mark while statements breakable if the condition expression is.
|
| + Visit(stmt->cond());
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitForStatement(ForStatement* stmt) {
|
| + // Mark for statements breakable if the condition expression is.
|
| + if (stmt->cond() != NULL) {
|
| + Visit(stmt->cond());
|
| + }
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitForInStatement(ForInStatement* stmt) {
|
| + // Mark for in statements breakable if the enumerable expression is.
|
| + Visit(stmt->enumerable());
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitTryCatchStatement(
|
| + TryCatchStatement* stmt) {
|
| + // Mark try catch as breakable to avoid adding a break slot in front of it.
|
| + is_breakable_ = true;
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitTryFinallyStatement(
|
| + TryFinallyStatement* stmt) {
|
| + // Mark try finally as breakable to avoid adding a break slot in front of it.
|
| + is_breakable_ = true;
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitDebuggerStatement(
|
| + DebuggerStatement* stmt) {
|
| + // The debugger statement is breakable.
|
| + is_breakable_ = true;
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitFunctionLiteral(FunctionLiteral* expr) {
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitSharedFunctionInfoLiteral(
|
| + SharedFunctionInfoLiteral* expr) {
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitConditional(Conditional* expr) {
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitSlot(Slot* expr) {
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitVariableProxy(VariableProxy* expr) {
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitLiteral(Literal* expr) {
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitRegExpLiteral(RegExpLiteral* expr) {
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitObjectLiteral(ObjectLiteral* expr) {
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitArrayLiteral(ArrayLiteral* expr) {
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitCatchExtensionObject(
|
| + CatchExtensionObject* expr) {
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitAssignment(Assignment* expr) {
|
| + // If assigning to a property (including a global property) the assignment is
|
| + // breakable.
|
| + Variable* var = expr->target()->AsVariableProxy()->AsVariable();
|
| + Property* prop = expr->target()->AsProperty();
|
| + if (prop != NULL || (var != NULL && var->is_global())) {
|
| + is_breakable_ = true;
|
| + return;
|
| + }
|
| +
|
| + // Otherwise the assignment is breakable if the assigned value is.
|
| + Visit(expr->value());
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitThrow(Throw* expr) {
|
| + // Throw is breakable if the expression is.
|
| + Visit(expr->exception());
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitProperty(Property* expr) {
|
| + // Property load is breakable.
|
| + is_breakable_ = true;
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitCall(Call* expr) {
|
| + // Function calls both through IC and call stub are breakable.
|
| + is_breakable_ = true;
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitCallNew(CallNew* expr) {
|
| + // Function calls through new are breakable.
|
| + is_breakable_ = true;
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitCallRuntime(CallRuntime* expr) {
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitUnaryOperation(UnaryOperation* expr) {
|
| + Visit(expr->expression());
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitCountOperation(CountOperation* expr) {
|
| + Visit(expr->expression());
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitBinaryOperation(BinaryOperation* expr) {
|
| + Visit(expr->left());
|
| + Visit(expr->right());
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitCompareOperation(CompareOperation* expr) {
|
| + Visit(expr->left());
|
| + Visit(expr->right());
|
| +}
|
| +
|
| +
|
| +void BreakableStatementChecker::VisitThisFunction(ThisFunction* expr) {
|
| +}
|
| +
|
| +
|
| #define __ ACCESS_MASM(masm())
|
|
|
| Handle<Code> FullCodeGenerator::MakeCode(CompilationInfo* info) {
|
| @@ -552,11 +777,64 @@
|
|
|
| void FullCodeGenerator::SetStatementPosition(Statement* stmt) {
|
| if (FLAG_debug_info) {
|
| +#ifdef ENABLE_DEBUGGER_SUPPORT
|
| + if (!Debugger::IsDebuggerActive()) {
|
| + CodeGenerator::RecordPositions(masm_, stmt->statement_pos());
|
| + } else {
|
| + // Check if the statement will be breakable without adding a debug break
|
| + // slot.
|
| + BreakableStatementChecker checker;
|
| + checker.Check(stmt);
|
| + // Record the statement position right here if the statement is not
|
| + // breakable. For breakable statements the actual recording of the
|
| + // position will be postponed to the breakable code (typically an IC).
|
| + bool position_recorded = CodeGenerator::RecordPositions(
|
| + masm_, stmt->statement_pos(), !checker.is_breakable());
|
| + // If the position recording did record a new position generate a debug
|
| + // break slot to make the statement breakable.
|
| + if (position_recorded) {
|
| + Debug::GenerateSlot(masm_);
|
| + }
|
| + }
|
| +#else
|
| CodeGenerator::RecordPositions(masm_, stmt->statement_pos());
|
| +#endif
|
| }
|
| }
|
|
|
|
|
| +void FullCodeGenerator::SetExpressionPosition(Expression* expr, int pos) {
|
| + if (FLAG_debug_info) {
|
| +#ifdef ENABLE_DEBUGGER_SUPPORT
|
| + if (!Debugger::IsDebuggerActive()) {
|
| + CodeGenerator::RecordPositions(masm_, pos);
|
| + } else {
|
| + // Check if the expression will be breakable without adding a debug break
|
| + // slot.
|
| + BreakableStatementChecker checker;
|
| + checker.Check(expr);
|
| + // Record a statement position right here if the expression is not
|
| + // breakable. For breakable expressions the actual recording of the
|
| + // position will be postponed to the breakable code (typically an IC).
|
| + // NOTE this will record a statement position for something which might
|
| + // not be a statement. As stepping in the debugger will only stop at
|
| + // statement positions this is used for e.g. the condition expression of
|
| + // a do while loop.
|
| + bool position_recorded = CodeGenerator::RecordPositions(
|
| + masm_, pos, !checker.is_breakable());
|
| + // If the position recording did record a new position generate a debug
|
| + // break slot to make the statement breakable.
|
| + if (position_recorded) {
|
| + Debug::GenerateSlot(masm_);
|
| + }
|
| + }
|
| +#else
|
| + CodeGenerator::RecordPositions(masm_, pos);
|
| +#endif
|
| + }
|
| +}
|
| +
|
| +
|
| void FullCodeGenerator::SetStatementPosition(int pos) {
|
| if (FLAG_debug_info) {
|
| CodeGenerator::RecordPositions(masm_, pos);
|
| @@ -848,7 +1126,11 @@
|
| __ bind(&stack_check_success);
|
|
|
| __ bind(loop_statement.continue_target());
|
| - SetStatementPosition(stmt->condition_position());
|
| +
|
| + // Record the position of the do while condition and make sure it is possible
|
| + // to break on the condition.
|
| + SetExpressionPosition(stmt->cond(), stmt->condition_position());
|
| +
|
| VisitForControl(stmt->cond(), &body, loop_statement.break_target());
|
|
|
| __ bind(&stack_limit_hit);
|
| @@ -864,7 +1146,6 @@
|
|
|
| void FullCodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
|
| Comment cmnt(masm_, "[ WhileStatement");
|
| - SetStatementPosition(stmt);
|
| Label body, stack_limit_hit, stack_check_success;
|
|
|
| Iteration loop_statement(this, stmt);
|
| @@ -877,6 +1158,9 @@
|
| Visit(stmt->body());
|
|
|
| __ bind(loop_statement.continue_target());
|
| + // Emit the statement position here as this is where the while statement code
|
| + // starts.
|
| + SetStatementPosition(stmt);
|
|
|
| // Check stack before looping.
|
| __ StackLimitCheck(&stack_limit_hit);
|
| @@ -896,7 +1180,6 @@
|
|
|
| void FullCodeGenerator::VisitForStatement(ForStatement* stmt) {
|
| Comment cmnt(masm_, "[ ForStatement");
|
| - SetStatementPosition(stmt);
|
| Label test, body, stack_limit_hit, stack_check_success;
|
|
|
| Iteration loop_statement(this, stmt);
|
| @@ -919,6 +1202,9 @@
|
| }
|
|
|
| __ bind(&test);
|
| + // Emit the statement position here as this is where the for statement code
|
| + // starts.
|
| + SetStatementPosition(stmt);
|
|
|
| // Check stack before looping.
|
| __ StackLimitCheck(&stack_limit_hit);
|
| @@ -1064,6 +1350,8 @@
|
| VisitForControl(expr->condition(), &true_case, &false_case);
|
|
|
| __ bind(&true_case);
|
| + SetExpressionPosition(expr->then_expression(),
|
| + expr->then_expression_position());
|
| Visit(expr->then_expression());
|
| // If control flow falls through Visit, jump to done.
|
| if (context_ == Expression::kEffect || context_ == Expression::kValue) {
|
| @@ -1071,6 +1359,8 @@
|
| }
|
|
|
| __ bind(&false_case);
|
| + SetExpressionPosition(expr->else_expression(),
|
| + expr->else_expression_position());
|
| Visit(expr->else_expression());
|
| // If control flow falls through Visit, merge it with true case here.
|
| if (context_ == Expression::kEffect || context_ == Expression::kValue) {
|
|
|