| Index: src/full-codegen.cc
|
| diff --git a/src/full-codegen.cc b/src/full-codegen.cc
|
| index 6ae927c9018a16a5462f2448f5ae79bdc3e997a1..1409f90629b8e2e2fed0380955bc0abd19735d42 100644
|
| --- a/src/full-codegen.cc
|
| +++ b/src/full-codegen.cc
|
| @@ -381,6 +381,9 @@ void FullCodeGenerator::PopulateDeoptimizationData(Handle<Code> code) {
|
| for (int i = 0; i < length; i++) {
|
| data->SetAstId(i, bailout_entries_[i].id);
|
| data->SetPcAndState(i, Smi::FromInt(bailout_entries_[i].pc_and_state));
|
| +#if defined(COMPARE_OPT_STACK_HEIGHT)
|
| + data->SetStackHeight(i, Smi::FromInt(bailout_entries_[i].stack_height));
|
| +#endif
|
| }
|
| code->set_deoptimization_data(*data);
|
| }
|
| @@ -448,7 +451,12 @@ void FullCodeGenerator::RecordJSReturnSite(Call* call) {
|
| void FullCodeGenerator::PrepareForBailoutForId(BailoutId id, State state) {
|
| // There's no need to prepare this code for bailouts from already optimized
|
| // code or code that can't be optimized.
|
| - if (!info_->HasDeoptimizationSupport()) return;
|
| + if (!info_->HasDeoptimizationSupport()) {
|
| + // We still need to insert the check to make sure that we generate exactly
|
| + // the same code
|
| + CheckStackHeight();
|
| + return;
|
| + }
|
| unsigned pc_and_state =
|
| StateField::encode(state) | PcField::encode(masm_->pc_offset());
|
| ASSERT(Smi::IsValid(pc_and_state));
|
| @@ -457,8 +465,11 @@ void FullCodeGenerator::PrepareForBailoutForId(BailoutId id, State state) {
|
| ASSERT(bailout_entries_[i].id != id);
|
| }
|
| #endif
|
| - BailoutEntry entry = { id, pc_and_state };
|
| + // If the we store the top of the stack register, pretend it is on the stack
|
| + int stack_height = stack_height_.get() + (state == TOS_REG ? 1 : 0);
|
| + BailoutEntry entry = { id, pc_and_state, stack_height };
|
| bailout_entries_.Add(entry, zone());
|
| + CheckStackHeight();
|
| }
|
|
|
|
|
| @@ -492,7 +503,7 @@ void FullCodeGenerator::AccumulatorValueContext::Plug(Register reg) const {
|
|
|
|
|
| void FullCodeGenerator::StackValueContext::Plug(Register reg) const {
|
| - __ Push(reg);
|
| + codegen()->AsmPush(reg);
|
| }
|
|
|
|
|
| @@ -505,12 +516,12 @@ void FullCodeGenerator::TestContext::Plug(Register reg) const {
|
|
|
|
|
| void FullCodeGenerator::EffectContext::PlugTOS() const {
|
| - __ Drop(1);
|
| + codegen()->AsmDrop(1);
|
| }
|
|
|
|
|
| void FullCodeGenerator::AccumulatorValueContext::PlugTOS() const {
|
| - __ Pop(result_register());
|
| + codegen()->AsmPop(result_register());
|
| }
|
|
|
|
|
| @@ -520,7 +531,7 @@ void FullCodeGenerator::StackValueContext::PlugTOS() const {
|
|
|
| void FullCodeGenerator::TestContext::PlugTOS() const {
|
| // For simplicity we always test the accumulator register.
|
| - __ Pop(result_register());
|
| + codegen()->AsmPop(result_register());
|
| codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
|
| codegen()->DoTest(this);
|
| }
|
| @@ -597,9 +608,9 @@ void FullCodeGenerator::AllocateModules(ZoneList<Declaration*>* declarations) {
|
|
|
| // Set up module context.
|
| ASSERT(scope->interface()->Index() >= 0);
|
| - __ Push(Smi::FromInt(scope->interface()->Index()));
|
| - __ Push(scope->GetScopeInfo());
|
| - __ CallRuntime(Runtime::kHiddenPushModuleContext, 2);
|
| + AsmPushSmi(Smi::FromInt(scope->interface()->Index()));
|
| + AsmPushHandle(scope->GetScopeInfo());
|
| + AsmCallRuntime(Runtime::kHiddenPushModuleContext, 2);
|
| StoreToFrameField(StandardFrameConstants::kContextOffset,
|
| context_register());
|
|
|
| @@ -688,6 +699,7 @@ void FullCodeGenerator::VisitDeclarations(
|
| // This is a scope hosting modules. Allocate a descriptor array to pass
|
| // to the runtime for initialization.
|
| Comment cmnt(masm_, "[ Allocate modules");
|
| +
|
| ASSERT(scope_->is_global_scope());
|
| modules_ =
|
| isolate()->factory()->NewFixedArray(scope_->num_modules(), TENURED);
|
| @@ -737,9 +749,9 @@ void FullCodeGenerator::VisitModuleLiteral(ModuleLiteral* module) {
|
|
|
| // Set up module context.
|
| ASSERT(interface->Index() >= 0);
|
| - __ Push(Smi::FromInt(interface->Index()));
|
| - __ Push(Smi::FromInt(0));
|
| - __ CallRuntime(Runtime::kHiddenPushModuleContext, 2);
|
| + AsmPushSmi(Smi::FromInt(interface->Index()));
|
| + AsmPushSmi(Smi::FromInt(0));
|
| + AsmCallRuntime(Runtime::kHiddenPushModuleContext, 2);
|
| StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
|
|
|
| {
|
| @@ -970,32 +982,32 @@ void FullCodeGenerator::VisitLogicalExpression(BinaryOperation* expr) {
|
| } else {
|
| VisitForControl(left, test->true_label(), &eval_right, &eval_right);
|
| }
|
| - PrepareForBailoutForId(right_id, NO_REGISTERS);
|
| __ bind(&eval_right);
|
| -
|
| + PrepareForBailoutForId(right_id, NO_REGISTERS);
|
| } else if (context()->IsAccumulatorValue()) {
|
| VisitForAccumulatorValue(left);
|
| // We want the value in the accumulator for the test, and on the stack in
|
| // case we need it.
|
| - __ Push(result_register());
|
| + AsmPush(result_register());
|
| Label discard, restore;
|
| if (is_logical_and) {
|
| DoTest(left, &discard, &restore, &restore);
|
| } else {
|
| DoTest(left, &restore, &discard, &restore);
|
| }
|
| + StackHeightWrapper branch_stack_height = CurrentStackHeight();
|
| __ bind(&restore);
|
| - __ Pop(result_register());
|
| + AsmPop(result_register());
|
| __ jmp(&done);
|
| __ bind(&discard);
|
| - __ Drop(1);
|
| + SetStackHeight(branch_stack_height);
|
| + AsmDrop(1);
|
| PrepareForBailoutForId(right_id, NO_REGISTERS);
|
| -
|
| } else if (context()->IsStackValue()) {
|
| VisitForAccumulatorValue(left);
|
| // We want the value in the accumulator for the test, and on the stack in
|
| // case we need it.
|
| - __ Push(result_register());
|
| + AsmPush(result_register());
|
| Label discard;
|
| if (is_logical_and) {
|
| DoTest(left, &discard, &done, &discard);
|
| @@ -1003,9 +1015,8 @@ void FullCodeGenerator::VisitLogicalExpression(BinaryOperation* expr) {
|
| DoTest(left, &done, &discard, &discard);
|
| }
|
| __ bind(&discard);
|
| - __ Drop(1);
|
| + AsmDrop(1);
|
| PrepareForBailoutForId(right_id, NO_REGISTERS);
|
| -
|
| } else {
|
| ASSERT(context()->IsEffect());
|
| Label eval_right;
|
| @@ -1014,8 +1025,8 @@ void FullCodeGenerator::VisitLogicalExpression(BinaryOperation* expr) {
|
| } else {
|
| VisitForControl(left, &done, &eval_right, &eval_right);
|
| }
|
| - PrepareForBailoutForId(right_id, NO_REGISTERS);
|
| __ bind(&eval_right);
|
| + PrepareForBailoutForId(right_id, NO_REGISTERS);
|
| }
|
|
|
| VisitInDuplicateContext(right);
|
| @@ -1056,9 +1067,9 @@ void FullCodeGenerator::VisitBlock(Block* stmt) {
|
| scope_ = stmt->scope();
|
| ASSERT(!scope_->is_module_scope());
|
| { Comment cmnt(masm_, "[ Extend block context");
|
| - __ Push(scope_->GetScopeInfo());
|
| + AsmPushHandle(scope_->GetScopeInfo());
|
| PushFunctionArgumentForContextAllocation();
|
| - __ CallRuntime(Runtime::kHiddenPushBlockContext, 2);
|
| + AsmCallRuntime(Runtime::kHiddenPushBlockContext, 2);
|
|
|
| // Replace the context stored in the frame.
|
| StoreToFrameField(StandardFrameConstants::kContextOffset,
|
| @@ -1088,9 +1099,9 @@ void FullCodeGenerator::VisitBlock(Block* stmt) {
|
| void FullCodeGenerator::VisitModuleStatement(ModuleStatement* stmt) {
|
| Comment cmnt(masm_, "[ Module context");
|
|
|
| - __ Push(Smi::FromInt(stmt->proxy()->interface()->Index()));
|
| - __ Push(Smi::FromInt(0));
|
| - __ CallRuntime(Runtime::kHiddenPushModuleContext, 2);
|
| + AsmPushSmi(Smi::FromInt(stmt->proxy()->interface()->Index()));
|
| + AsmPushSmi(Smi::FromInt(0));
|
| + AsmCallRuntime(Runtime::kHiddenPushModuleContext, 2);
|
| StoreToFrameField(
|
| StandardFrameConstants::kContextOffset, context_register());
|
|
|
| @@ -1125,18 +1136,20 @@ void FullCodeGenerator::VisitIfStatement(IfStatement* stmt) {
|
|
|
| if (stmt->HasElseStatement()) {
|
| VisitForControl(stmt->condition(), &then_part, &else_part, &then_part);
|
| - PrepareForBailoutForId(stmt->ThenId(), NO_REGISTERS);
|
| + StackHeightWrapper if_stack_height = CurrentStackHeight();
|
| __ bind(&then_part);
|
| + PrepareForBailoutForId(stmt->ThenId(), NO_REGISTERS);
|
| Visit(stmt->then_statement());
|
| __ jmp(&done);
|
|
|
| - PrepareForBailoutForId(stmt->ElseId(), NO_REGISTERS);
|
| __ bind(&else_part);
|
| + SetStackHeight(if_stack_height);
|
| + PrepareForBailoutForId(stmt->ElseId(), NO_REGISTERS);
|
| Visit(stmt->else_statement());
|
| } else {
|
| VisitForControl(stmt->condition(), &then_part, &done, &then_part);
|
| - PrepareForBailoutForId(stmt->ThenId(), NO_REGISTERS);
|
| __ bind(&then_part);
|
| + PrepareForBailoutForId(stmt->ThenId(), NO_REGISTERS);
|
| Visit(stmt->then_statement());
|
|
|
| PrepareForBailoutForId(stmt->ElseId(), NO_REGISTERS);
|
| @@ -1150,6 +1163,7 @@ void FullCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) {
|
| Comment cmnt(masm_, "[ ContinueStatement");
|
| SetStatementPosition(stmt);
|
| NestedStatement* current = nesting_stack_;
|
| + StackHeightWrapper original_stack_height = CurrentStackHeight();
|
| int stack_depth = 0;
|
| int context_length = 0;
|
| // When continuing, we clobber the unpredictable value in the accumulator
|
| @@ -1160,7 +1174,7 @@ void FullCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) {
|
| while (!current->IsContinueTarget(stmt->target())) {
|
| current = current->Exit(&stack_depth, &context_length);
|
| }
|
| - __ Drop(stack_depth);
|
| + AsmDrop(stack_depth);
|
| if (context_length > 0) {
|
| while (context_length > 0) {
|
| LoadContextField(context_register(), Context::PREVIOUS_INDEX);
|
| @@ -1171,6 +1185,7 @@ void FullCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) {
|
| }
|
|
|
| __ jmp(current->AsIteration()->continue_label());
|
| + SetStackHeight(original_stack_height);
|
| }
|
|
|
|
|
| @@ -1178,6 +1193,7 @@ void FullCodeGenerator::VisitBreakStatement(BreakStatement* stmt) {
|
| Comment cmnt(masm_, "[ BreakStatement");
|
| SetStatementPosition(stmt);
|
| NestedStatement* current = nesting_stack_;
|
| + StackHeightWrapper original_stack_height = CurrentStackHeight();
|
| int stack_depth = 0;
|
| int context_length = 0;
|
| // When breaking, we clobber the unpredictable value in the accumulator
|
| @@ -1188,7 +1204,7 @@ void FullCodeGenerator::VisitBreakStatement(BreakStatement* stmt) {
|
| while (!current->IsBreakTarget(stmt->target())) {
|
| current = current->Exit(&stack_depth, &context_length);
|
| }
|
| - __ Drop(stack_depth);
|
| + AsmDrop(stack_depth);
|
| if (context_length > 0) {
|
| while (context_length > 0) {
|
| LoadContextField(context_register(), Context::PREVIOUS_INDEX);
|
| @@ -1199,6 +1215,7 @@ void FullCodeGenerator::VisitBreakStatement(BreakStatement* stmt) {
|
| }
|
|
|
| __ jmp(current->AsBreakable()->break_label());
|
| + SetStackHeight(original_stack_height);
|
| }
|
|
|
|
|
| @@ -1209,7 +1226,7 @@ void FullCodeGenerator::EmitUnwindBeforeReturn() {
|
| while (current != NULL) {
|
| current = current->Exit(&stack_depth, &context_length);
|
| }
|
| - __ Drop(stack_depth);
|
| + AsmDrop(stack_depth);
|
| }
|
|
|
|
|
| @@ -1218,8 +1235,11 @@ void FullCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
|
| SetStatementPosition(stmt);
|
| Expression* expr = stmt->expression();
|
| VisitForAccumulatorValue(expr);
|
| + StackHeightWrapper previous_stack_height = CurrentStackHeight();
|
| EmitUnwindBeforeReturn();
|
| EmitReturnSequence();
|
| + // Reset the expected stack height
|
| + SetStackHeight(previous_stack_height);
|
| }
|
|
|
|
|
| @@ -1229,7 +1249,7 @@ void FullCodeGenerator::VisitWithStatement(WithStatement* stmt) {
|
|
|
| VisitForStackValue(stmt->expression());
|
| PushFunctionArgumentForContextAllocation();
|
| - __ CallRuntime(Runtime::kHiddenPushWithContext, 2);
|
| + AsmCallRuntime(Runtime::kHiddenPushWithContext, 2);
|
| StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
|
|
|
| Scope* saved_scope = scope();
|
| @@ -1268,13 +1288,13 @@ void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
|
| &book_keeping);
|
|
|
| // Check stack before looping.
|
| - PrepareForBailoutForId(stmt->BackEdgeId(), NO_REGISTERS);
|
| __ bind(&book_keeping);
|
| + PrepareForBailoutForId(stmt->BackEdgeId(), NO_REGISTERS);
|
| EmitBackEdgeBookkeeping(stmt, &body);
|
| __ jmp(&body);
|
|
|
| - PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
|
| __ bind(loop_statement.break_label());
|
| + PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
|
| decrement_loop_depth();
|
| }
|
|
|
| @@ -1289,8 +1309,8 @@ void FullCodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
|
| // Emit the test at the bottom of the loop.
|
| __ jmp(&test);
|
|
|
| - PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
|
| __ bind(&body);
|
| + PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
|
| Visit(stmt->body());
|
|
|
| // Emit the statement position here as this is where the while
|
| @@ -1307,8 +1327,8 @@ void FullCodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
|
| loop_statement.break_label(),
|
| loop_statement.break_label());
|
|
|
| - PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
|
| __ bind(loop_statement.break_label());
|
| + PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
|
| decrement_loop_depth();
|
| }
|
|
|
| @@ -1330,12 +1350,12 @@ void FullCodeGenerator::VisitForStatement(ForStatement* stmt) {
|
| // Emit the test at the bottom of the loop (even if empty).
|
| __ jmp(&test);
|
|
|
| - PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
|
| __ bind(&body);
|
| + PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
|
| Visit(stmt->body());
|
|
|
| - PrepareForBailoutForId(stmt->ContinueId(), NO_REGISTERS);
|
| __ bind(loop_statement.continue_label());
|
| + PrepareForBailoutForId(stmt->ContinueId(), NO_REGISTERS);
|
| if (stmt->next() != NULL) {
|
| Visit(stmt->next());
|
| }
|
| @@ -1357,8 +1377,8 @@ void FullCodeGenerator::VisitForStatement(ForStatement* stmt) {
|
| __ jmp(&body);
|
| }
|
|
|
| - PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
|
| __ bind(loop_statement.break_label());
|
| + PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
|
| decrement_loop_depth();
|
| }
|
|
|
| @@ -1379,10 +1399,10 @@ void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
|
| // Exception handler code, the exception is in the result register.
|
| // Extend the context before executing the catch block.
|
| { Comment cmnt(masm_, "[ Extend catch context");
|
| - __ Push(stmt->variable()->name());
|
| - __ Push(result_register());
|
| + AsmPushHandle(stmt->variable()->name());
|
| + AsmPush(result_register());
|
| PushFunctionArgumentForContextAllocation();
|
| - __ CallRuntime(Runtime::kHiddenPushCatchContext, 3);
|
| + AsmCallRuntime(Runtime::kHiddenPushCatchContext, 3);
|
| StoreToFrameField(StandardFrameConstants::kContextOffset,
|
| context_register());
|
| }
|
| @@ -1401,11 +1421,11 @@ void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
|
|
|
| // Try block code. Sets up the exception handler chain.
|
| __ bind(&try_entry);
|
| - __ PushTryHandler(StackHandler::CATCH, stmt->index());
|
| + AsmPushTryHandler(StackHandler::CATCH, stmt->index());
|
| { TryCatch try_body(this);
|
| Visit(stmt->try_block());
|
| }
|
| - __ PopTryHandler();
|
| + AsmPopTryHandler();
|
| __ bind(&exit);
|
| }
|
|
|
| @@ -1445,11 +1465,13 @@ void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
|
| // preserved by the finally block. Call the finally block and then
|
| // rethrow the exception if it returns.
|
| __ Call(&finally_entry);
|
| - __ Push(result_register());
|
| - __ CallRuntime(Runtime::kHiddenReThrow, 1);
|
| + AsmPush(result_register());
|
| + AsmCallRuntime(Runtime::kHiddenReThrow, 1);
|
|
|
| // Finally block implementation.
|
| __ bind(&finally_entry);
|
| + // The return address is on the stack -> update the height
|
| + UpdateStackHeight(1);
|
| EnterFinallyBlock();
|
| { Finally finally_body(this);
|
| Visit(stmt->finally_block());
|
| @@ -1458,11 +1480,11 @@ void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
|
|
|
| // Set up try handler.
|
| __ bind(&try_entry);
|
| - __ PushTryHandler(StackHandler::FINALLY, stmt->index());
|
| + AsmPushTryHandler(StackHandler::FINALLY, stmt->index());
|
| { TryFinally try_body(this, &finally_entry);
|
| Visit(stmt->try_block());
|
| }
|
| - __ PopTryHandler();
|
| + AsmPopTryHandler();
|
| // Execute the finally block on the way out. Clobber the unpredictable
|
| // value in the result register with one that's safe for GC because the
|
| // finally block will unconditionally preserve the result register on the
|
| @@ -1490,9 +1512,10 @@ void FullCodeGenerator::VisitConditional(Conditional* expr) {
|
| Comment cmnt(masm_, "[ Conditional");
|
| Label true_case, false_case, done;
|
| VisitForControl(expr->condition(), &true_case, &false_case, &true_case);
|
| + StackHeightWrapper if_stack_height = CurrentStackHeight();
|
|
|
| - PrepareForBailoutForId(expr->ThenId(), NO_REGISTERS);
|
| __ bind(&true_case);
|
| + PrepareForBailoutForId(expr->ThenId(), NO_REGISTERS);
|
| SetExpressionPosition(expr->then_expression());
|
| if (context()->IsTest()) {
|
| const TestContext* for_test = TestContext::cast(context());
|
| @@ -1505,8 +1528,9 @@ void FullCodeGenerator::VisitConditional(Conditional* expr) {
|
| __ jmp(&done);
|
| }
|
|
|
| - PrepareForBailoutForId(expr->ElseId(), NO_REGISTERS);
|
| __ bind(&false_case);
|
| + SetStackHeight(if_stack_height);
|
| + PrepareForBailoutForId(expr->ElseId(), NO_REGISTERS);
|
| SetExpressionPosition(expr->else_expression());
|
| VisitInDuplicateContext(expr->else_expression());
|
| // If control flow falls through Visit, merge it with true case here.
|
| @@ -1572,8 +1596,12 @@ void FullCodeGenerator::VisitNativeFunctionLiteral(
|
| void FullCodeGenerator::VisitThrow(Throw* expr) {
|
| Comment cmnt(masm_, "[ Throw");
|
| VisitForStackValue(expr->exception());
|
| - __ CallRuntime(Runtime::kHiddenThrow, 1);
|
| - // Never returns here.
|
| + AsmCallRuntime(Runtime::kHiddenThrow, 1);
|
| + // Never returns here. Update stack height so that we do not confuse the
|
| + // stack height checker.
|
| + if (context() != NULL && !context()->IsEffect()) {
|
| + UpdateStackHeight(1);
|
| + }
|
| }
|
|
|
|
|
| @@ -1581,8 +1609,8 @@ FullCodeGenerator::NestedStatement* FullCodeGenerator::TryCatch::Exit(
|
| int* stack_depth,
|
| int* context_length) {
|
| // The macros used here must preserve the result register.
|
| - __ Drop(*stack_depth);
|
| - __ PopTryHandler();
|
| + codegen()->AsmDrop(*stack_depth);
|
| + codegen()->AsmPopTryHandler();
|
| *stack_depth = 0;
|
| return previous_;
|
| }
|
|
|