| Index: src/full-codegen.cc
|
| ===================================================================
|
| --- src/full-codegen.cc (revision 8618)
|
| +++ src/full-codegen.cc (working copy)
|
| @@ -90,14 +90,14 @@
|
| }
|
|
|
|
|
| -void BreakableStatementChecker::VisitWithEnterStatement(
|
| - WithEnterStatement* stmt) {
|
| +void BreakableStatementChecker::VisitEnterWithContextStatement(
|
| + EnterWithContextStatement* stmt) {
|
| Visit(stmt->expression());
|
| }
|
|
|
|
|
| -void BreakableStatementChecker::VisitWithExitStatement(
|
| - WithExitStatement* stmt) {
|
| +void BreakableStatementChecker::VisitExitContextStatement(
|
| + ExitContextStatement* stmt) {
|
| }
|
|
|
|
|
| @@ -187,11 +187,6 @@
|
| }
|
|
|
|
|
| -void BreakableStatementChecker::VisitCatchExtensionObject(
|
| - CatchExtensionObject* expr) {
|
| -}
|
| -
|
| -
|
| void BreakableStatementChecker::VisitAssignment(Assignment* expr) {
|
| // If assigning to a property (including a global property) the assignment is
|
| // breakable.
|
| @@ -247,7 +242,10 @@
|
|
|
| void BreakableStatementChecker::VisitBinaryOperation(BinaryOperation* expr) {
|
| Visit(expr->left());
|
| - Visit(expr->right());
|
| + if (expr->op() != Token::AND &&
|
| + expr->op() != Token::OR) {
|
| + Visit(expr->right());
|
| + }
|
| }
|
|
|
|
|
| @@ -348,7 +346,7 @@
|
| }
|
|
|
|
|
| -void FullCodeGenerator::PrepareForBailout(AstNode* node, State state) {
|
| +void FullCodeGenerator::PrepareForBailout(Expression* node, State state) {
|
| PrepareForBailoutForId(node->id(), state);
|
| }
|
|
|
| @@ -406,7 +404,7 @@
|
| // Adjust by a (parameter or local) base offset.
|
| switch (slot->type()) {
|
| case Slot::PARAMETER:
|
| - offset += (scope()->num_parameters() + 1) * kPointerSize;
|
| + offset += (info_->scope()->num_parameters() + 1) * kPointerSize;
|
| break;
|
| case Slot::LOCAL:
|
| offset += JavaScriptFrameConstants::kLocal0Offset;
|
| @@ -446,7 +444,7 @@
|
| // For simplicity we always test the accumulator register.
|
| __ Move(result_register(), reg);
|
| codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
|
| - codegen()->DoTest(true_label_, false_label_, fall_through_);
|
| + codegen()->DoTest(this);
|
| }
|
|
|
|
|
| @@ -468,7 +466,7 @@
|
| // For simplicity we always test the accumulator register.
|
| __ pop(result_register());
|
| codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
|
| - codegen()->DoTest(true_label_, false_label_, fall_through_);
|
| + codegen()->DoTest(this);
|
| }
|
|
|
|
|
| @@ -518,6 +516,14 @@
|
| }
|
|
|
|
|
| +void FullCodeGenerator::DoTest(const TestContext* context) {
|
| + DoTest(context->condition(),
|
| + context->true_label(),
|
| + context->false_label(),
|
| + context->fall_through());
|
| +}
|
| +
|
| +
|
| void FullCodeGenerator::VisitDeclarations(
|
| ZoneList<Declaration*>* declarations) {
|
| int length = declarations->length();
|
| @@ -577,88 +583,78 @@
|
|
|
|
|
| void FullCodeGenerator::SetFunctionPosition(FunctionLiteral* fun) {
|
| - if (FLAG_debug_info) {
|
| - CodeGenerator::RecordPositions(masm_, fun->start_position());
|
| - }
|
| + CodeGenerator::RecordPositions(masm_, fun->start_position());
|
| }
|
|
|
|
|
| void FullCodeGenerator::SetReturnPosition(FunctionLiteral* fun) {
|
| - if (FLAG_debug_info) {
|
| - CodeGenerator::RecordPositions(masm_, fun->end_position() - 1);
|
| - }
|
| + CodeGenerator::RecordPositions(masm_, fun->end_position() - 1);
|
| }
|
|
|
|
|
| void FullCodeGenerator::SetStatementPosition(Statement* stmt) {
|
| - if (FLAG_debug_info) {
|
| #ifdef ENABLE_DEBUGGER_SUPPORT
|
| - if (!isolate()->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_);
|
| - }
|
| + if (!isolate()->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());
|
| + CodeGenerator::RecordPositions(masm_, stmt->statement_pos());
|
| #endif
|
| - }
|
| }
|
|
|
|
|
| void FullCodeGenerator::SetExpressionPosition(Expression* expr, int pos) {
|
| - if (FLAG_debug_info) {
|
| #ifdef ENABLE_DEBUGGER_SUPPORT
|
| - if (!isolate()->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_);
|
| - }
|
| + if (!isolate()->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);
|
| + CodeGenerator::RecordPositions(masm_, pos);
|
| #endif
|
| - }
|
| }
|
|
|
|
|
| void FullCodeGenerator::SetStatementPosition(int pos) {
|
| - if (FLAG_debug_info) {
|
| - CodeGenerator::RecordPositions(masm_, pos);
|
| - }
|
| + CodeGenerator::RecordPositions(masm_, pos);
|
| }
|
|
|
|
|
| void FullCodeGenerator::SetSourcePosition(int pos) {
|
| - if (FLAG_debug_info && pos != RelocInfo::kNoPosition) {
|
| + if (pos != RelocInfo::kNoPosition) {
|
| masm_->positions_recorder()->RecordPosition(pos);
|
| }
|
| }
|
| @@ -701,143 +697,116 @@
|
|
|
|
|
| void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
|
| - Comment cmnt(masm_, "[ BinaryOperation");
|
| - Token::Value op = expr->op();
|
| - Expression* left = expr->left();
|
| - Expression* right = expr->right();
|
| -
|
| - OverwriteMode mode = NO_OVERWRITE;
|
| - if (left->ResultOverwriteAllowed()) {
|
| - mode = OVERWRITE_LEFT;
|
| - } else if (right->ResultOverwriteAllowed()) {
|
| - mode = OVERWRITE_RIGHT;
|
| - }
|
| -
|
| - switch (op) {
|
| + switch (expr->op()) {
|
| case Token::COMMA:
|
| - VisitForEffect(left);
|
| - if (context()->IsTest()) ForwardBailoutToChild(expr);
|
| - context()->HandleExpression(right);
|
| - break;
|
| -
|
| + return VisitComma(expr);
|
| case Token::OR:
|
| case Token::AND:
|
| - EmitLogicalOperation(expr);
|
| - break;
|
| -
|
| - case Token::ADD:
|
| - case Token::SUB:
|
| - case Token::DIV:
|
| - case Token::MOD:
|
| - case Token::MUL:
|
| - case Token::BIT_OR:
|
| - case Token::BIT_AND:
|
| - case Token::BIT_XOR:
|
| - case Token::SHL:
|
| - case Token::SHR:
|
| - case Token::SAR: {
|
| - // Load both operands.
|
| - VisitForStackValue(left);
|
| - VisitForAccumulatorValue(right);
|
| -
|
| - SetSourcePosition(expr->position());
|
| - if (ShouldInlineSmiCase(op)) {
|
| - EmitInlineSmiBinaryOp(expr, op, mode, left, right);
|
| - } else {
|
| - EmitBinaryOp(expr, op, mode);
|
| - }
|
| - break;
|
| - }
|
| -
|
| + return VisitLogicalExpression(expr);
|
| default:
|
| - UNREACHABLE();
|
| + return VisitArithmeticExpression(expr);
|
| }
|
| }
|
|
|
|
|
| -void FullCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) {
|
| - Label eval_right, done;
|
| -
|
| - context()->EmitLogicalLeft(expr, &eval_right, &done);
|
| -
|
| - PrepareForBailoutForId(expr->RightId(), NO_REGISTERS);
|
| - __ bind(&eval_right);
|
| +void FullCodeGenerator::VisitComma(BinaryOperation* expr) {
|
| + Comment cmnt(masm_, "[ Comma");
|
| + VisitForEffect(expr->left());
|
| if (context()->IsTest()) ForwardBailoutToChild(expr);
|
| - context()->HandleExpression(expr->right());
|
| -
|
| - __ bind(&done);
|
| + VisitInCurrentContext(expr->right());
|
| }
|
|
|
|
|
| -void FullCodeGenerator::EffectContext::EmitLogicalLeft(BinaryOperation* expr,
|
| - Label* eval_right,
|
| - Label* done) const {
|
| - if (expr->op() == Token::OR) {
|
| - codegen()->VisitForControl(expr->left(), done, eval_right, eval_right);
|
| - } else {
|
| - ASSERT(expr->op() == Token::AND);
|
| - codegen()->VisitForControl(expr->left(), eval_right, done, eval_right);
|
| - }
|
| -}
|
| +void FullCodeGenerator::VisitLogicalExpression(BinaryOperation* expr) {
|
| + bool is_logical_and = expr->op() == Token::AND;
|
| + Comment cmnt(masm_, is_logical_and ? "[ Logical AND" : "[ Logical OR");
|
| + Expression* left = expr->left();
|
| + Expression* right = expr->right();
|
| + int right_id = expr->RightId();
|
| + Label done;
|
|
|
| + if (context()->IsTest()) {
|
| + Label eval_right;
|
| + const TestContext* test = TestContext::cast(context());
|
| + if (is_logical_and) {
|
| + VisitForControl(left, &eval_right, test->false_label(), &eval_right);
|
| + } else {
|
| + VisitForControl(left, test->true_label(), &eval_right, &eval_right);
|
| + }
|
| + PrepareForBailoutForId(right_id, NO_REGISTERS);
|
| + __ bind(&eval_right);
|
| + ForwardBailoutToChild(expr);
|
|
|
| -void FullCodeGenerator::AccumulatorValueContext::EmitLogicalLeft(
|
| - BinaryOperation* expr,
|
| - Label* eval_right,
|
| - Label* done) const {
|
| - HandleExpression(expr->left());
|
| - // We want the value in the accumulator for the test, and on the stack in case
|
| - // we need it.
|
| - __ push(result_register());
|
| - Label discard, restore;
|
| - if (expr->op() == Token::OR) {
|
| - codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
|
| - codegen()->DoTest(&restore, &discard, &restore);
|
| - } else {
|
| - ASSERT(expr->op() == Token::AND);
|
| - codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
|
| - codegen()->DoTest(&discard, &restore, &restore);
|
| - }
|
| - __ bind(&restore);
|
| - __ pop(result_register());
|
| - __ jmp(done);
|
| - __ bind(&discard);
|
| - __ Drop(1);
|
| -}
|
| + } 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());
|
| + Label discard, restore;
|
| + PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
|
| + if (is_logical_and) {
|
| + DoTest(left, &discard, &restore, &restore);
|
| + } else {
|
| + DoTest(left, &restore, &discard, &restore);
|
| + }
|
| + __ bind(&restore);
|
| + __ pop(result_register());
|
| + __ jmp(&done);
|
| + __ bind(&discard);
|
| + __ Drop(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());
|
| + Label discard;
|
| + PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
|
| + if (is_logical_and) {
|
| + DoTest(left, &discard, &done, &discard);
|
| + } else {
|
| + DoTest(left, &done, &discard, &discard);
|
| + }
|
| + __ bind(&discard);
|
| + __ Drop(1);
|
| + PrepareForBailoutForId(right_id, NO_REGISTERS);
|
|
|
| -void FullCodeGenerator::StackValueContext::EmitLogicalLeft(
|
| - BinaryOperation* expr,
|
| - Label* eval_right,
|
| - Label* done) const {
|
| - codegen()->VisitForAccumulatorValue(expr->left());
|
| - // We want the value in the accumulator for the test, and on the stack in case
|
| - // we need it.
|
| - __ push(result_register());
|
| - Label discard;
|
| - if (expr->op() == Token::OR) {
|
| - codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
|
| - codegen()->DoTest(done, &discard, &discard);
|
| } else {
|
| - ASSERT(expr->op() == Token::AND);
|
| - codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
|
| - codegen()->DoTest(&discard, done, &discard);
|
| + ASSERT(context()->IsEffect());
|
| + Label eval_right;
|
| + if (is_logical_and) {
|
| + VisitForControl(left, &eval_right, &done, &eval_right);
|
| + } else {
|
| + VisitForControl(left, &done, &eval_right, &eval_right);
|
| + }
|
| + PrepareForBailoutForId(right_id, NO_REGISTERS);
|
| + __ bind(&eval_right);
|
| }
|
| - __ bind(&discard);
|
| - __ Drop(1);
|
| +
|
| + VisitInCurrentContext(right);
|
| + __ bind(&done);
|
| }
|
|
|
|
|
| -void FullCodeGenerator::TestContext::EmitLogicalLeft(BinaryOperation* expr,
|
| - Label* eval_right,
|
| - Label* done) const {
|
| - if (expr->op() == Token::OR) {
|
| - codegen()->VisitForControl(expr->left(),
|
| - true_label_, eval_right, eval_right);
|
| +void FullCodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) {
|
| + Token::Value op = expr->op();
|
| + Comment cmnt(masm_, "[ ArithmeticExpression");
|
| + Expression* left = expr->left();
|
| + Expression* right = expr->right();
|
| + OverwriteMode mode =
|
| + left->ResultOverwriteAllowed()
|
| + ? OVERWRITE_LEFT
|
| + : (right->ResultOverwriteAllowed() ? OVERWRITE_RIGHT : NO_OVERWRITE);
|
| +
|
| + VisitForStackValue(left);
|
| + VisitForAccumulatorValue(right);
|
| +
|
| + SetSourcePosition(expr->position());
|
| + if (ShouldInlineSmiCase(op)) {
|
| + EmitInlineSmiBinaryOp(expr, op, mode, left, right);
|
| } else {
|
| - ASSERT(expr->op() == Token::AND);
|
| - codegen()->VisitForControl(expr->left(),
|
| - eval_right, false_label_, eval_right);
|
| + EmitBinaryOp(expr, op, mode);
|
| }
|
| }
|
|
|
| @@ -850,49 +819,26 @@
|
| }
|
|
|
|
|
| -void FullCodeGenerator::EffectContext::HandleExpression(
|
| - Expression* expr) const {
|
| - codegen()->HandleInNonTestContext(expr, NO_REGISTERS);
|
| +void FullCodeGenerator::VisitInCurrentContext(Expression* expr) {
|
| + if (context()->IsTest()) {
|
| + ForwardBailoutStack stack(expr, forward_bailout_pending_);
|
| + ForwardBailoutStack* saved = forward_bailout_stack_;
|
| + forward_bailout_pending_ = NULL;
|
| + forward_bailout_stack_ = &stack;
|
| + Visit(expr);
|
| + forward_bailout_stack_ = saved;
|
| + } else {
|
| + ASSERT(forward_bailout_pending_ == NULL);
|
| + Visit(expr);
|
| + State state = context()->IsAccumulatorValue() ? TOS_REG : NO_REGISTERS;
|
| + PrepareForBailout(expr, state);
|
| + // Forwarding bailouts to children is a one shot operation. It should have
|
| + // been processed at this point.
|
| + ASSERT(forward_bailout_pending_ == NULL);
|
| + }
|
| }
|
|
|
|
|
| -void FullCodeGenerator::AccumulatorValueContext::HandleExpression(
|
| - Expression* expr) const {
|
| - codegen()->HandleInNonTestContext(expr, TOS_REG);
|
| -}
|
| -
|
| -
|
| -void FullCodeGenerator::StackValueContext::HandleExpression(
|
| - Expression* expr) const {
|
| - codegen()->HandleInNonTestContext(expr, NO_REGISTERS);
|
| -}
|
| -
|
| -
|
| -void FullCodeGenerator::TestContext::HandleExpression(Expression* expr) const {
|
| - codegen()->VisitInTestContext(expr);
|
| -}
|
| -
|
| -
|
| -void FullCodeGenerator::HandleInNonTestContext(Expression* expr, State state) {
|
| - ASSERT(forward_bailout_pending_ == NULL);
|
| - AstVisitor::Visit(expr);
|
| - PrepareForBailout(expr, state);
|
| - // Forwarding bailouts to children is a one shot operation. It
|
| - // should have been processed at this point.
|
| - ASSERT(forward_bailout_pending_ == NULL);
|
| -}
|
| -
|
| -
|
| -void FullCodeGenerator::VisitInTestContext(Expression* expr) {
|
| - ForwardBailoutStack stack(expr, forward_bailout_pending_);
|
| - ForwardBailoutStack* saved = forward_bailout_stack_;
|
| - forward_bailout_pending_ = NULL;
|
| - forward_bailout_stack_ = &stack;
|
| - AstVisitor::Visit(expr);
|
| - forward_bailout_stack_ = saved;
|
| -}
|
| -
|
| -
|
| void FullCodeGenerator::VisitBlock(Block* stmt) {
|
| Comment cmnt(masm_, "[ Block");
|
| Breakable nested_statement(this, stmt);
|
| @@ -942,7 +888,7 @@
|
| PrepareForBailoutForId(stmt->ElseId(), NO_REGISTERS);
|
| }
|
| __ bind(&done);
|
| - PrepareForBailoutForId(stmt->id(), NO_REGISTERS);
|
| + PrepareForBailoutForId(stmt->IfId(), NO_REGISTERS);
|
| }
|
|
|
|
|
| @@ -1007,26 +953,20 @@
|
| }
|
|
|
|
|
| -void FullCodeGenerator::VisitWithEnterStatement(WithEnterStatement* stmt) {
|
| - Comment cmnt(masm_, "[ WithEnterStatement");
|
| +void FullCodeGenerator::VisitEnterWithContextStatement(
|
| + EnterWithContextStatement* stmt) {
|
| + Comment cmnt(masm_, "[ EnterWithContextStatement");
|
| SetStatementPosition(stmt);
|
|
|
| VisitForStackValue(stmt->expression());
|
| - if (stmt->is_catch_block()) {
|
| - __ CallRuntime(Runtime::kPushCatchContext, 1);
|
| - } else {
|
| - __ CallRuntime(Runtime::kPushContext, 1);
|
| - }
|
| - // Both runtime calls return the new context in both the context and the
|
| - // result registers.
|
| -
|
| - // Update local stack frame context field.
|
| + PushFunctionArgumentForContextAllocation();
|
| + __ CallRuntime(Runtime::kPushWithContext, 2);
|
| StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
|
| }
|
|
|
|
|
| -void FullCodeGenerator::VisitWithExitStatement(WithExitStatement* stmt) {
|
| - Comment cmnt(masm_, "[ WithExitStatement");
|
| +void FullCodeGenerator::VisitExitContextStatement(ExitContextStatement* stmt) {
|
| + Comment cmnt(masm_, "[ ExitContextStatement");
|
| SetStatementPosition(stmt);
|
|
|
| // Pop context.
|
| @@ -1167,18 +1107,21 @@
|
| __ Call(&try_handler_setup);
|
| // Try handler code, exception in result register.
|
|
|
| - // Store exception in local .catch variable before executing catch block.
|
| - {
|
| - // The catch variable is *always* a variable proxy for a local variable.
|
| - Variable* catch_var = stmt->catch_var()->AsVariableProxy()->AsVariable();
|
| - ASSERT_NOT_NULL(catch_var);
|
| - Slot* variable_slot = catch_var->AsSlot();
|
| - ASSERT_NOT_NULL(variable_slot);
|
| - ASSERT_EQ(Slot::LOCAL, variable_slot->type());
|
| - StoreToFrameField(SlotOffset(variable_slot), result_register());
|
| + // Extend the context before executing the catch block.
|
| + { Comment cmnt(masm_, "[ Extend catch context");
|
| + __ Push(stmt->variable()->name());
|
| + __ push(result_register());
|
| + PushFunctionArgumentForContextAllocation();
|
| + __ CallRuntime(Runtime::kPushCatchContext, 3);
|
| + StoreToFrameField(StandardFrameConstants::kContextOffset,
|
| + context_register());
|
| }
|
|
|
| + Scope* saved_scope = scope();
|
| + scope_ = stmt->scope();
|
| + ASSERT(scope_->declarations()->is_empty());
|
| Visit(stmt->catch_block());
|
| + scope_ = saved_scope;
|
| __ jmp(&done);
|
|
|
| // Try block code. Sets up the exception handler chain.
|
| @@ -1287,7 +1230,7 @@
|
| for_test->false_label(),
|
| NULL);
|
| } else {
|
| - context()->HandleExpression(expr->then_expression());
|
| + VisitInCurrentContext(expr->then_expression());
|
| __ jmp(&done);
|
| }
|
|
|
| @@ -1296,7 +1239,7 @@
|
| if (context()->IsTest()) ForwardBailoutToChild(expr);
|
| SetExpressionPosition(expr->else_expression(),
|
| expr->else_expression_position());
|
| - context()->HandleExpression(expr->else_expression());
|
| + VisitInCurrentContext(expr->else_expression());
|
| // If control flow falls through Visit, merge it with true case here.
|
| if (!context()->IsTest()) {
|
| __ bind(&done);
|
| @@ -1331,18 +1274,6 @@
|
| }
|
|
|
|
|
| -void FullCodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* expr) {
|
| - // Call runtime routine to allocate the catch extension object and
|
| - // assign the exception value to the catch variable.
|
| - Comment cmnt(masm_, "[ CatchExtensionObject");
|
| - VisitForStackValue(expr->key());
|
| - VisitForStackValue(expr->value());
|
| - // Create catch extension object.
|
| - __ CallRuntime(Runtime::kCreateCatchExtensionObject, 2);
|
| - context()->Plug(result_register());
|
| -}
|
| -
|
| -
|
| void FullCodeGenerator::VisitThrow(Throw* expr) {
|
| Comment cmnt(masm_, "[ Throw");
|
| VisitForStackValue(expr->exception());
|
| @@ -1368,6 +1299,26 @@
|
| }
|
|
|
|
|
| +bool FullCodeGenerator::TryLiteralCompare(CompareOperation* compare,
|
| + Label* if_true,
|
| + Label* if_false,
|
| + Label* fall_through) {
|
| + Expression *expr;
|
| + Handle<String> check;
|
| + if (compare->IsLiteralCompareTypeof(&expr, &check)) {
|
| + EmitLiteralCompareTypeof(expr, check, if_true, if_false, fall_through);
|
| + return true;
|
| + }
|
| +
|
| + if (compare->IsLiteralCompareUndefined(&expr)) {
|
| + EmitLiteralCompareUndefined(expr, if_true, if_false, fall_through);
|
| + return true;
|
| + }
|
| +
|
| + return false;
|
| +}
|
| +
|
| +
|
| #undef __
|
|
|
|
|
|
|