| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 83 void BreakableStatementChecker::VisitBreakStatement(BreakStatement* stmt) { | 83 void BreakableStatementChecker::VisitBreakStatement(BreakStatement* stmt) { |
| 84 } | 84 } |
| 85 | 85 |
| 86 | 86 |
| 87 void BreakableStatementChecker::VisitReturnStatement(ReturnStatement* stmt) { | 87 void BreakableStatementChecker::VisitReturnStatement(ReturnStatement* stmt) { |
| 88 // Return is breakable if the expression is. | 88 // Return is breakable if the expression is. |
| 89 Visit(stmt->expression()); | 89 Visit(stmt->expression()); |
| 90 } | 90 } |
| 91 | 91 |
| 92 | 92 |
| 93 void BreakableStatementChecker::VisitWithEnterStatement( | 93 void BreakableStatementChecker::VisitEnterWithContextStatement( |
| 94 WithEnterStatement* stmt) { | 94 EnterWithContextStatement* stmt) { |
| 95 Visit(stmt->expression()); | 95 Visit(stmt->expression()); |
| 96 } | 96 } |
| 97 | 97 |
| 98 | 98 |
| 99 void BreakableStatementChecker::VisitWithExitStatement( | 99 void BreakableStatementChecker::VisitExitContextStatement( |
| 100 WithExitStatement* stmt) { | 100 ExitContextStatement* stmt) { |
| 101 } | 101 } |
| 102 | 102 |
| 103 | 103 |
| 104 void BreakableStatementChecker::VisitSwitchStatement(SwitchStatement* stmt) { | 104 void BreakableStatementChecker::VisitSwitchStatement(SwitchStatement* stmt) { |
| 105 // Switch statements breakable if the tag expression is. | 105 // Switch statements breakable if the tag expression is. |
| 106 Visit(stmt->tag()); | 106 Visit(stmt->tag()); |
| 107 } | 107 } |
| 108 | 108 |
| 109 | 109 |
| 110 void BreakableStatementChecker::VisitDoWhileStatement(DoWhileStatement* stmt) { | 110 void BreakableStatementChecker::VisitDoWhileStatement(DoWhileStatement* stmt) { |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 180 | 180 |
| 181 | 181 |
| 182 void BreakableStatementChecker::VisitObjectLiteral(ObjectLiteral* expr) { | 182 void BreakableStatementChecker::VisitObjectLiteral(ObjectLiteral* expr) { |
| 183 } | 183 } |
| 184 | 184 |
| 185 | 185 |
| 186 void BreakableStatementChecker::VisitArrayLiteral(ArrayLiteral* expr) { | 186 void BreakableStatementChecker::VisitArrayLiteral(ArrayLiteral* expr) { |
| 187 } | 187 } |
| 188 | 188 |
| 189 | 189 |
| 190 void BreakableStatementChecker::VisitCatchExtensionObject( | |
| 191 CatchExtensionObject* expr) { | |
| 192 } | |
| 193 | |
| 194 | |
| 195 void BreakableStatementChecker::VisitAssignment(Assignment* expr) { | 190 void BreakableStatementChecker::VisitAssignment(Assignment* expr) { |
| 196 // If assigning to a property (including a global property) the assignment is | 191 // If assigning to a property (including a global property) the assignment is |
| 197 // breakable. | 192 // breakable. |
| 198 Variable* var = expr->target()->AsVariableProxy()->AsVariable(); | 193 Variable* var = expr->target()->AsVariableProxy()->AsVariable(); |
| 199 Property* prop = expr->target()->AsProperty(); | 194 Property* prop = expr->target()->AsProperty(); |
| 200 if (prop != NULL || (var != NULL && var->is_global())) { | 195 if (prop != NULL || (var != NULL && var->is_global())) { |
| 201 is_breakable_ = true; | 196 is_breakable_ = true; |
| 202 return; | 197 return; |
| 203 } | 198 } |
| 204 | 199 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 240 } | 235 } |
| 241 | 236 |
| 242 | 237 |
| 243 void BreakableStatementChecker::VisitCountOperation(CountOperation* expr) { | 238 void BreakableStatementChecker::VisitCountOperation(CountOperation* expr) { |
| 244 Visit(expr->expression()); | 239 Visit(expr->expression()); |
| 245 } | 240 } |
| 246 | 241 |
| 247 | 242 |
| 248 void BreakableStatementChecker::VisitBinaryOperation(BinaryOperation* expr) { | 243 void BreakableStatementChecker::VisitBinaryOperation(BinaryOperation* expr) { |
| 249 Visit(expr->left()); | 244 Visit(expr->left()); |
| 250 Visit(expr->right()); | 245 if (expr->op() != Token::AND && |
| 246 expr->op() != Token::OR) { |
| 247 Visit(expr->right()); |
| 248 } |
| 251 } | 249 } |
| 252 | 250 |
| 253 | 251 |
| 254 void BreakableStatementChecker::VisitCompareToNull(CompareToNull* expr) { | 252 void BreakableStatementChecker::VisitCompareToNull(CompareToNull* expr) { |
| 255 Visit(expr->expression()); | 253 Visit(expr->expression()); |
| 256 } | 254 } |
| 257 | 255 |
| 258 | 256 |
| 259 void BreakableStatementChecker::VisitCompareOperation(CompareOperation* expr) { | 257 void BreakableStatementChecker::VisitCompareOperation(CompareOperation* expr) { |
| 260 Visit(expr->left()); | 258 Visit(expr->left()); |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 341 isolate()->factory()-> | 339 isolate()->factory()-> |
| 342 NewDeoptimizationOutputData(length, TENURED); | 340 NewDeoptimizationOutputData(length, TENURED); |
| 343 for (int i = 0; i < length; i++) { | 341 for (int i = 0; i < length; i++) { |
| 344 data->SetAstId(i, Smi::FromInt(bailout_entries_[i].id)); | 342 data->SetAstId(i, Smi::FromInt(bailout_entries_[i].id)); |
| 345 data->SetPcAndState(i, Smi::FromInt(bailout_entries_[i].pc_and_state)); | 343 data->SetPcAndState(i, Smi::FromInt(bailout_entries_[i].pc_and_state)); |
| 346 } | 344 } |
| 347 code->set_deoptimization_data(*data); | 345 code->set_deoptimization_data(*data); |
| 348 } | 346 } |
| 349 | 347 |
| 350 | 348 |
| 351 void FullCodeGenerator::PrepareForBailout(AstNode* node, State state) { | 349 void FullCodeGenerator::PrepareForBailout(Expression* node, State state) { |
| 352 PrepareForBailoutForId(node->id(), state); | 350 PrepareForBailoutForId(node->id(), state); |
| 353 } | 351 } |
| 354 | 352 |
| 355 | 353 |
| 356 void FullCodeGenerator::RecordJSReturnSite(Call* call) { | 354 void FullCodeGenerator::RecordJSReturnSite(Call* call) { |
| 357 // We record the offset of the function return so we can rebuild the frame | 355 // We record the offset of the function return so we can rebuild the frame |
| 358 // if the function was inlined, i.e., this is the return address in the | 356 // if the function was inlined, i.e., this is the return address in the |
| 359 // inlined function's frame. | 357 // inlined function's frame. |
| 360 // | 358 // |
| 361 // The state is ignored. We defensively set it to TOS_REG, which is the | 359 // The state is ignored. We defensively set it to TOS_REG, which is the |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 399 } | 397 } |
| 400 | 398 |
| 401 | 399 |
| 402 int FullCodeGenerator::SlotOffset(Slot* slot) { | 400 int FullCodeGenerator::SlotOffset(Slot* slot) { |
| 403 ASSERT(slot != NULL); | 401 ASSERT(slot != NULL); |
| 404 // Offset is negative because higher indexes are at lower addresses. | 402 // Offset is negative because higher indexes are at lower addresses. |
| 405 int offset = -slot->index() * kPointerSize; | 403 int offset = -slot->index() * kPointerSize; |
| 406 // Adjust by a (parameter or local) base offset. | 404 // Adjust by a (parameter or local) base offset. |
| 407 switch (slot->type()) { | 405 switch (slot->type()) { |
| 408 case Slot::PARAMETER: | 406 case Slot::PARAMETER: |
| 409 offset += (scope()->num_parameters() + 1) * kPointerSize; | 407 offset += (info_->scope()->num_parameters() + 1) * kPointerSize; |
| 410 break; | 408 break; |
| 411 case Slot::LOCAL: | 409 case Slot::LOCAL: |
| 412 offset += JavaScriptFrameConstants::kLocal0Offset; | 410 offset += JavaScriptFrameConstants::kLocal0Offset; |
| 413 break; | 411 break; |
| 414 case Slot::CONTEXT: | 412 case Slot::CONTEXT: |
| 415 case Slot::LOOKUP: | 413 case Slot::LOOKUP: |
| 416 UNREACHABLE(); | 414 UNREACHABLE(); |
| 417 } | 415 } |
| 418 return offset; | 416 return offset; |
| 419 } | 417 } |
| (...skipping 19 matching lines...) Expand all Loading... |
| 439 | 437 |
| 440 void FullCodeGenerator::StackValueContext::Plug(Register reg) const { | 438 void FullCodeGenerator::StackValueContext::Plug(Register reg) const { |
| 441 __ push(reg); | 439 __ push(reg); |
| 442 } | 440 } |
| 443 | 441 |
| 444 | 442 |
| 445 void FullCodeGenerator::TestContext::Plug(Register reg) const { | 443 void FullCodeGenerator::TestContext::Plug(Register reg) const { |
| 446 // For simplicity we always test the accumulator register. | 444 // For simplicity we always test the accumulator register. |
| 447 __ Move(result_register(), reg); | 445 __ Move(result_register(), reg); |
| 448 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | 446 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); |
| 449 codegen()->DoTest(true_label_, false_label_, fall_through_); | 447 codegen()->DoTest(this); |
| 450 } | 448 } |
| 451 | 449 |
| 452 | 450 |
| 453 void FullCodeGenerator::EffectContext::PlugTOS() const { | 451 void FullCodeGenerator::EffectContext::PlugTOS() const { |
| 454 __ Drop(1); | 452 __ Drop(1); |
| 455 } | 453 } |
| 456 | 454 |
| 457 | 455 |
| 458 void FullCodeGenerator::AccumulatorValueContext::PlugTOS() const { | 456 void FullCodeGenerator::AccumulatorValueContext::PlugTOS() const { |
| 459 __ pop(result_register()); | 457 __ pop(result_register()); |
| 460 } | 458 } |
| 461 | 459 |
| 462 | 460 |
| 463 void FullCodeGenerator::StackValueContext::PlugTOS() const { | 461 void FullCodeGenerator::StackValueContext::PlugTOS() const { |
| 464 } | 462 } |
| 465 | 463 |
| 466 | 464 |
| 467 void FullCodeGenerator::TestContext::PlugTOS() const { | 465 void FullCodeGenerator::TestContext::PlugTOS() const { |
| 468 // For simplicity we always test the accumulator register. | 466 // For simplicity we always test the accumulator register. |
| 469 __ pop(result_register()); | 467 __ pop(result_register()); |
| 470 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | 468 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); |
| 471 codegen()->DoTest(true_label_, false_label_, fall_through_); | 469 codegen()->DoTest(this); |
| 472 } | 470 } |
| 473 | 471 |
| 474 | 472 |
| 475 void FullCodeGenerator::EffectContext::PrepareTest( | 473 void FullCodeGenerator::EffectContext::PrepareTest( |
| 476 Label* materialize_true, | 474 Label* materialize_true, |
| 477 Label* materialize_false, | 475 Label* materialize_false, |
| 478 Label** if_true, | 476 Label** if_true, |
| 479 Label** if_false, | 477 Label** if_false, |
| 480 Label** fall_through) const { | 478 Label** fall_through) const { |
| 481 // In an effect context, the true and the false case branch to the | 479 // In an effect context, the true and the false case branch to the |
| (...skipping 29 matching lines...) Expand all Loading... |
| 511 Label* materialize_false, | 509 Label* materialize_false, |
| 512 Label** if_true, | 510 Label** if_true, |
| 513 Label** if_false, | 511 Label** if_false, |
| 514 Label** fall_through) const { | 512 Label** fall_through) const { |
| 515 *if_true = true_label_; | 513 *if_true = true_label_; |
| 516 *if_false = false_label_; | 514 *if_false = false_label_; |
| 517 *fall_through = fall_through_; | 515 *fall_through = fall_through_; |
| 518 } | 516 } |
| 519 | 517 |
| 520 | 518 |
| 519 void FullCodeGenerator::DoTest(const TestContext* context) { |
| 520 DoTest(context->condition(), |
| 521 context->true_label(), |
| 522 context->false_label(), |
| 523 context->fall_through()); |
| 524 } |
| 525 |
| 526 |
| 521 void FullCodeGenerator::VisitDeclarations( | 527 void FullCodeGenerator::VisitDeclarations( |
| 522 ZoneList<Declaration*>* declarations) { | 528 ZoneList<Declaration*>* declarations) { |
| 523 int length = declarations->length(); | 529 int length = declarations->length(); |
| 524 int globals = 0; | 530 int globals = 0; |
| 525 for (int i = 0; i < length; i++) { | 531 for (int i = 0; i < length; i++) { |
| 526 Declaration* decl = declarations->at(i); | 532 Declaration* decl = declarations->at(i); |
| 527 Variable* var = decl->proxy()->var(); | 533 Variable* var = decl->proxy()->var(); |
| 528 Slot* slot = var->AsSlot(); | 534 Slot* slot = var->AsSlot(); |
| 529 | 535 |
| 530 // If it was not possible to allocate the variable at compile | 536 // If it was not possible to allocate the variable at compile |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 570 } | 576 } |
| 571 } | 577 } |
| 572 // Invoke the platform-dependent code generator to do the actual | 578 // Invoke the platform-dependent code generator to do the actual |
| 573 // declaration the global variables and functions. | 579 // declaration the global variables and functions. |
| 574 DeclareGlobals(array); | 580 DeclareGlobals(array); |
| 575 } | 581 } |
| 576 } | 582 } |
| 577 | 583 |
| 578 | 584 |
| 579 void FullCodeGenerator::SetFunctionPosition(FunctionLiteral* fun) { | 585 void FullCodeGenerator::SetFunctionPosition(FunctionLiteral* fun) { |
| 580 if (FLAG_debug_info) { | 586 CodeGenerator::RecordPositions(masm_, fun->start_position()); |
| 581 CodeGenerator::RecordPositions(masm_, fun->start_position()); | |
| 582 } | |
| 583 } | 587 } |
| 584 | 588 |
| 585 | 589 |
| 586 void FullCodeGenerator::SetReturnPosition(FunctionLiteral* fun) { | 590 void FullCodeGenerator::SetReturnPosition(FunctionLiteral* fun) { |
| 587 if (FLAG_debug_info) { | 591 CodeGenerator::RecordPositions(masm_, fun->end_position() - 1); |
| 588 CodeGenerator::RecordPositions(masm_, fun->end_position() - 1); | |
| 589 } | |
| 590 } | 592 } |
| 591 | 593 |
| 592 | 594 |
| 593 void FullCodeGenerator::SetStatementPosition(Statement* stmt) { | 595 void FullCodeGenerator::SetStatementPosition(Statement* stmt) { |
| 594 if (FLAG_debug_info) { | |
| 595 #ifdef ENABLE_DEBUGGER_SUPPORT | 596 #ifdef ENABLE_DEBUGGER_SUPPORT |
| 596 if (!isolate()->debugger()->IsDebuggerActive()) { | 597 if (!isolate()->debugger()->IsDebuggerActive()) { |
| 597 CodeGenerator::RecordPositions(masm_, stmt->statement_pos()); | 598 CodeGenerator::RecordPositions(masm_, stmt->statement_pos()); |
| 598 } else { | 599 } else { |
| 599 // Check if the statement will be breakable without adding a debug break | 600 // Check if the statement will be breakable without adding a debug break |
| 600 // slot. | 601 // slot. |
| 601 BreakableStatementChecker checker; | 602 BreakableStatementChecker checker; |
| 602 checker.Check(stmt); | 603 checker.Check(stmt); |
| 603 // Record the statement position right here if the statement is not | 604 // Record the statement position right here if the statement is not |
| 604 // breakable. For breakable statements the actual recording of the | 605 // breakable. For breakable statements the actual recording of the |
| 605 // position will be postponed to the breakable code (typically an IC). | 606 // position will be postponed to the breakable code (typically an IC). |
| 606 bool position_recorded = CodeGenerator::RecordPositions( | 607 bool position_recorded = CodeGenerator::RecordPositions( |
| 607 masm_, stmt->statement_pos(), !checker.is_breakable()); | 608 masm_, stmt->statement_pos(), !checker.is_breakable()); |
| 608 // If the position recording did record a new position generate a debug | 609 // If the position recording did record a new position generate a debug |
| 609 // break slot to make the statement breakable. | 610 // break slot to make the statement breakable. |
| 610 if (position_recorded) { | 611 if (position_recorded) { |
| 611 Debug::GenerateSlot(masm_); | 612 Debug::GenerateSlot(masm_); |
| 612 } | |
| 613 } | 613 } |
| 614 } |
| 614 #else | 615 #else |
| 615 CodeGenerator::RecordPositions(masm_, stmt->statement_pos()); | 616 CodeGenerator::RecordPositions(masm_, stmt->statement_pos()); |
| 616 #endif | 617 #endif |
| 617 } | |
| 618 } | 618 } |
| 619 | 619 |
| 620 | 620 |
| 621 void FullCodeGenerator::SetExpressionPosition(Expression* expr, int pos) { | 621 void FullCodeGenerator::SetExpressionPosition(Expression* expr, int pos) { |
| 622 if (FLAG_debug_info) { | |
| 623 #ifdef ENABLE_DEBUGGER_SUPPORT | 622 #ifdef ENABLE_DEBUGGER_SUPPORT |
| 624 if (!isolate()->debugger()->IsDebuggerActive()) { | 623 if (!isolate()->debugger()->IsDebuggerActive()) { |
| 625 CodeGenerator::RecordPositions(masm_, pos); | 624 CodeGenerator::RecordPositions(masm_, pos); |
| 626 } else { | 625 } else { |
| 627 // Check if the expression will be breakable without adding a debug break | 626 // Check if the expression will be breakable without adding a debug break |
| 628 // slot. | 627 // slot. |
| 629 BreakableStatementChecker checker; | 628 BreakableStatementChecker checker; |
| 630 checker.Check(expr); | 629 checker.Check(expr); |
| 631 // Record a statement position right here if the expression is not | 630 // Record a statement position right here if the expression is not |
| 632 // breakable. For breakable expressions the actual recording of the | 631 // breakable. For breakable expressions the actual recording of the |
| 633 // position will be postponed to the breakable code (typically an IC). | 632 // position will be postponed to the breakable code (typically an IC). |
| 634 // NOTE this will record a statement position for something which might | 633 // NOTE this will record a statement position for something which might |
| 635 // not be a statement. As stepping in the debugger will only stop at | 634 // not be a statement. As stepping in the debugger will only stop at |
| 636 // statement positions this is used for e.g. the condition expression of | 635 // statement positions this is used for e.g. the condition expression of |
| 637 // a do while loop. | 636 // a do while loop. |
| 638 bool position_recorded = CodeGenerator::RecordPositions( | 637 bool position_recorded = CodeGenerator::RecordPositions( |
| 639 masm_, pos, !checker.is_breakable()); | 638 masm_, pos, !checker.is_breakable()); |
| 640 // If the position recording did record a new position generate a debug | 639 // If the position recording did record a new position generate a debug |
| 641 // break slot to make the statement breakable. | 640 // break slot to make the statement breakable. |
| 642 if (position_recorded) { | 641 if (position_recorded) { |
| 643 Debug::GenerateSlot(masm_); | 642 Debug::GenerateSlot(masm_); |
| 644 } | |
| 645 } | 643 } |
| 644 } |
| 646 #else | 645 #else |
| 647 CodeGenerator::RecordPositions(masm_, pos); | 646 CodeGenerator::RecordPositions(masm_, pos); |
| 648 #endif | 647 #endif |
| 649 } | |
| 650 } | 648 } |
| 651 | 649 |
| 652 | 650 |
| 653 void FullCodeGenerator::SetStatementPosition(int pos) { | 651 void FullCodeGenerator::SetStatementPosition(int pos) { |
| 654 if (FLAG_debug_info) { | 652 CodeGenerator::RecordPositions(masm_, pos); |
| 655 CodeGenerator::RecordPositions(masm_, pos); | |
| 656 } | |
| 657 } | 653 } |
| 658 | 654 |
| 659 | 655 |
| 660 void FullCodeGenerator::SetSourcePosition(int pos) { | 656 void FullCodeGenerator::SetSourcePosition(int pos) { |
| 661 if (FLAG_debug_info && pos != RelocInfo::kNoPosition) { | 657 if (pos != RelocInfo::kNoPosition) { |
| 662 masm_->positions_recorder()->RecordPosition(pos); | 658 masm_->positions_recorder()->RecordPosition(pos); |
| 663 } | 659 } |
| 664 } | 660 } |
| 665 | 661 |
| 666 | 662 |
| 667 // Lookup table for code generators for special runtime calls which are | 663 // Lookup table for code generators for special runtime calls which are |
| 668 // generated inline. | 664 // generated inline. |
| 669 #define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \ | 665 #define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \ |
| 670 &FullCodeGenerator::Emit##Name, | 666 &FullCodeGenerator::Emit##Name, |
| 671 | 667 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 694 const Runtime::Function* function = node->function(); | 690 const Runtime::Function* function = node->function(); |
| 695 ASSERT(function != NULL); | 691 ASSERT(function != NULL); |
| 696 ASSERT(function->intrinsic_type == Runtime::INLINE); | 692 ASSERT(function->intrinsic_type == Runtime::INLINE); |
| 697 InlineFunctionGenerator generator = | 693 InlineFunctionGenerator generator = |
| 698 FindInlineFunctionGenerator(function->function_id); | 694 FindInlineFunctionGenerator(function->function_id); |
| 699 ((*this).*(generator))(args); | 695 ((*this).*(generator))(args); |
| 700 } | 696 } |
| 701 | 697 |
| 702 | 698 |
| 703 void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { | 699 void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { |
| 704 Comment cmnt(masm_, "[ BinaryOperation"); | 700 switch (expr->op()) { |
| 705 Token::Value op = expr->op(); | |
| 706 Expression* left = expr->left(); | |
| 707 Expression* right = expr->right(); | |
| 708 | |
| 709 OverwriteMode mode = NO_OVERWRITE; | |
| 710 if (left->ResultOverwriteAllowed()) { | |
| 711 mode = OVERWRITE_LEFT; | |
| 712 } else if (right->ResultOverwriteAllowed()) { | |
| 713 mode = OVERWRITE_RIGHT; | |
| 714 } | |
| 715 | |
| 716 switch (op) { | |
| 717 case Token::COMMA: | 701 case Token::COMMA: |
| 718 VisitForEffect(left); | 702 return VisitComma(expr); |
| 719 if (context()->IsTest()) ForwardBailoutToChild(expr); | |
| 720 context()->HandleExpression(right); | |
| 721 break; | |
| 722 | |
| 723 case Token::OR: | 703 case Token::OR: |
| 724 case Token::AND: | 704 case Token::AND: |
| 725 EmitLogicalOperation(expr); | 705 return VisitLogicalExpression(expr); |
| 726 break; | |
| 727 | |
| 728 case Token::ADD: | |
| 729 case Token::SUB: | |
| 730 case Token::DIV: | |
| 731 case Token::MOD: | |
| 732 case Token::MUL: | |
| 733 case Token::BIT_OR: | |
| 734 case Token::BIT_AND: | |
| 735 case Token::BIT_XOR: | |
| 736 case Token::SHL: | |
| 737 case Token::SHR: | |
| 738 case Token::SAR: { | |
| 739 // Load both operands. | |
| 740 VisitForStackValue(left); | |
| 741 VisitForAccumulatorValue(right); | |
| 742 | |
| 743 SetSourcePosition(expr->position()); | |
| 744 if (ShouldInlineSmiCase(op)) { | |
| 745 EmitInlineSmiBinaryOp(expr, op, mode, left, right); | |
| 746 } else { | |
| 747 EmitBinaryOp(expr, op, mode); | |
| 748 } | |
| 749 break; | |
| 750 } | |
| 751 | |
| 752 default: | 706 default: |
| 753 UNREACHABLE(); | 707 return VisitArithmeticExpression(expr); |
| 754 } | 708 } |
| 755 } | 709 } |
| 756 | 710 |
| 757 | 711 |
| 758 void FullCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) { | 712 void FullCodeGenerator::VisitComma(BinaryOperation* expr) { |
| 759 Label eval_right, done; | 713 Comment cmnt(masm_, "[ Comma"); |
| 714 VisitForEffect(expr->left()); |
| 715 if (context()->IsTest()) ForwardBailoutToChild(expr); |
| 716 VisitInCurrentContext(expr->right()); |
| 717 } |
| 760 | 718 |
| 761 context()->EmitLogicalLeft(expr, &eval_right, &done); | |
| 762 | 719 |
| 763 PrepareForBailoutForId(expr->RightId(), NO_REGISTERS); | 720 void FullCodeGenerator::VisitLogicalExpression(BinaryOperation* expr) { |
| 764 __ bind(&eval_right); | 721 bool is_logical_and = expr->op() == Token::AND; |
| 765 if (context()->IsTest()) ForwardBailoutToChild(expr); | 722 Comment cmnt(masm_, is_logical_and ? "[ Logical AND" : "[ Logical OR"); |
| 766 context()->HandleExpression(expr->right()); | 723 Expression* left = expr->left(); |
| 724 Expression* right = expr->right(); |
| 725 int right_id = expr->RightId(); |
| 726 Label done; |
| 767 | 727 |
| 728 if (context()->IsTest()) { |
| 729 Label eval_right; |
| 730 const TestContext* test = TestContext::cast(context()); |
| 731 if (is_logical_and) { |
| 732 VisitForControl(left, &eval_right, test->false_label(), &eval_right); |
| 733 } else { |
| 734 VisitForControl(left, test->true_label(), &eval_right, &eval_right); |
| 735 } |
| 736 PrepareForBailoutForId(right_id, NO_REGISTERS); |
| 737 __ bind(&eval_right); |
| 738 ForwardBailoutToChild(expr); |
| 739 |
| 740 } else if (context()->IsAccumulatorValue()) { |
| 741 VisitForAccumulatorValue(left); |
| 742 // We want the value in the accumulator for the test, and on the stack in |
| 743 // case we need it. |
| 744 __ push(result_register()); |
| 745 Label discard, restore; |
| 746 PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); |
| 747 if (is_logical_and) { |
| 748 DoTest(left, &discard, &restore, &restore); |
| 749 } else { |
| 750 DoTest(left, &restore, &discard, &restore); |
| 751 } |
| 752 __ bind(&restore); |
| 753 __ pop(result_register()); |
| 754 __ jmp(&done); |
| 755 __ bind(&discard); |
| 756 __ Drop(1); |
| 757 PrepareForBailoutForId(right_id, NO_REGISTERS); |
| 758 |
| 759 } else if (context()->IsStackValue()) { |
| 760 VisitForAccumulatorValue(left); |
| 761 // We want the value in the accumulator for the test, and on the stack in |
| 762 // case we need it. |
| 763 __ push(result_register()); |
| 764 Label discard; |
| 765 PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); |
| 766 if (is_logical_and) { |
| 767 DoTest(left, &discard, &done, &discard); |
| 768 } else { |
| 769 DoTest(left, &done, &discard, &discard); |
| 770 } |
| 771 __ bind(&discard); |
| 772 __ Drop(1); |
| 773 PrepareForBailoutForId(right_id, NO_REGISTERS); |
| 774 |
| 775 } else { |
| 776 ASSERT(context()->IsEffect()); |
| 777 Label eval_right; |
| 778 if (is_logical_and) { |
| 779 VisitForControl(left, &eval_right, &done, &eval_right); |
| 780 } else { |
| 781 VisitForControl(left, &done, &eval_right, &eval_right); |
| 782 } |
| 783 PrepareForBailoutForId(right_id, NO_REGISTERS); |
| 784 __ bind(&eval_right); |
| 785 } |
| 786 |
| 787 VisitInCurrentContext(right); |
| 768 __ bind(&done); | 788 __ bind(&done); |
| 769 } | 789 } |
| 770 | 790 |
| 771 | 791 |
| 772 void FullCodeGenerator::EffectContext::EmitLogicalLeft(BinaryOperation* expr, | 792 void FullCodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) { |
| 773 Label* eval_right, | 793 Token::Value op = expr->op(); |
| 774 Label* done) const { | 794 Comment cmnt(masm_, "[ ArithmeticExpression"); |
| 775 if (expr->op() == Token::OR) { | 795 Expression* left = expr->left(); |
| 776 codegen()->VisitForControl(expr->left(), done, eval_right, eval_right); | 796 Expression* right = expr->right(); |
| 797 OverwriteMode mode = |
| 798 left->ResultOverwriteAllowed() |
| 799 ? OVERWRITE_LEFT |
| 800 : (right->ResultOverwriteAllowed() ? OVERWRITE_RIGHT : NO_OVERWRITE); |
| 801 |
| 802 VisitForStackValue(left); |
| 803 VisitForAccumulatorValue(right); |
| 804 |
| 805 SetSourcePosition(expr->position()); |
| 806 if (ShouldInlineSmiCase(op)) { |
| 807 EmitInlineSmiBinaryOp(expr, op, mode, left, right); |
| 777 } else { | 808 } else { |
| 778 ASSERT(expr->op() == Token::AND); | 809 EmitBinaryOp(expr, op, mode); |
| 779 codegen()->VisitForControl(expr->left(), eval_right, done, eval_right); | |
| 780 } | 810 } |
| 781 } | 811 } |
| 782 | 812 |
| 783 | |
| 784 void FullCodeGenerator::AccumulatorValueContext::EmitLogicalLeft( | |
| 785 BinaryOperation* expr, | |
| 786 Label* eval_right, | |
| 787 Label* done) const { | |
| 788 HandleExpression(expr->left()); | |
| 789 // We want the value in the accumulator for the test, and on the stack in case | |
| 790 // we need it. | |
| 791 __ push(result_register()); | |
| 792 Label discard, restore; | |
| 793 if (expr->op() == Token::OR) { | |
| 794 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | |
| 795 codegen()->DoTest(&restore, &discard, &restore); | |
| 796 } else { | |
| 797 ASSERT(expr->op() == Token::AND); | |
| 798 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | |
| 799 codegen()->DoTest(&discard, &restore, &restore); | |
| 800 } | |
| 801 __ bind(&restore); | |
| 802 __ pop(result_register()); | |
| 803 __ jmp(done); | |
| 804 __ bind(&discard); | |
| 805 __ Drop(1); | |
| 806 } | |
| 807 | |
| 808 | |
| 809 void FullCodeGenerator::StackValueContext::EmitLogicalLeft( | |
| 810 BinaryOperation* expr, | |
| 811 Label* eval_right, | |
| 812 Label* done) const { | |
| 813 codegen()->VisitForAccumulatorValue(expr->left()); | |
| 814 // We want the value in the accumulator for the test, and on the stack in case | |
| 815 // we need it. | |
| 816 __ push(result_register()); | |
| 817 Label discard; | |
| 818 if (expr->op() == Token::OR) { | |
| 819 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | |
| 820 codegen()->DoTest(done, &discard, &discard); | |
| 821 } else { | |
| 822 ASSERT(expr->op() == Token::AND); | |
| 823 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | |
| 824 codegen()->DoTest(&discard, done, &discard); | |
| 825 } | |
| 826 __ bind(&discard); | |
| 827 __ Drop(1); | |
| 828 } | |
| 829 | |
| 830 | |
| 831 void FullCodeGenerator::TestContext::EmitLogicalLeft(BinaryOperation* expr, | |
| 832 Label* eval_right, | |
| 833 Label* done) const { | |
| 834 if (expr->op() == Token::OR) { | |
| 835 codegen()->VisitForControl(expr->left(), | |
| 836 true_label_, eval_right, eval_right); | |
| 837 } else { | |
| 838 ASSERT(expr->op() == Token::AND); | |
| 839 codegen()->VisitForControl(expr->left(), | |
| 840 eval_right, false_label_, eval_right); | |
| 841 } | |
| 842 } | |
| 843 | |
| 844 | 813 |
| 845 void FullCodeGenerator::ForwardBailoutToChild(Expression* expr) { | 814 void FullCodeGenerator::ForwardBailoutToChild(Expression* expr) { |
| 846 if (!info_->HasDeoptimizationSupport()) return; | 815 if (!info_->HasDeoptimizationSupport()) return; |
| 847 ASSERT(context()->IsTest()); | 816 ASSERT(context()->IsTest()); |
| 848 ASSERT(expr == forward_bailout_stack_->expr()); | 817 ASSERT(expr == forward_bailout_stack_->expr()); |
| 849 forward_bailout_pending_ = forward_bailout_stack_; | 818 forward_bailout_pending_ = forward_bailout_stack_; |
| 850 } | 819 } |
| 851 | 820 |
| 852 | 821 |
| 853 void FullCodeGenerator::EffectContext::HandleExpression( | 822 void FullCodeGenerator::VisitInCurrentContext(Expression* expr) { |
| 854 Expression* expr) const { | 823 if (context()->IsTest()) { |
| 855 codegen()->HandleInNonTestContext(expr, NO_REGISTERS); | 824 ForwardBailoutStack stack(expr, forward_bailout_pending_); |
| 856 } | 825 ForwardBailoutStack* saved = forward_bailout_stack_; |
| 857 | 826 forward_bailout_pending_ = NULL; |
| 858 | 827 forward_bailout_stack_ = &stack; |
| 859 void FullCodeGenerator::AccumulatorValueContext::HandleExpression( | 828 Visit(expr); |
| 860 Expression* expr) const { | 829 forward_bailout_stack_ = saved; |
| 861 codegen()->HandleInNonTestContext(expr, TOS_REG); | 830 } else { |
| 862 } | 831 ASSERT(forward_bailout_pending_ == NULL); |
| 863 | 832 Visit(expr); |
| 864 | 833 State state = context()->IsAccumulatorValue() ? TOS_REG : NO_REGISTERS; |
| 865 void FullCodeGenerator::StackValueContext::HandleExpression( | 834 PrepareForBailout(expr, state); |
| 866 Expression* expr) const { | 835 // Forwarding bailouts to children is a one shot operation. It should have |
| 867 codegen()->HandleInNonTestContext(expr, NO_REGISTERS); | 836 // been processed at this point. |
| 868 } | 837 ASSERT(forward_bailout_pending_ == NULL); |
| 869 | 838 } |
| 870 | |
| 871 void FullCodeGenerator::TestContext::HandleExpression(Expression* expr) const { | |
| 872 codegen()->VisitInTestContext(expr); | |
| 873 } | |
| 874 | |
| 875 | |
| 876 void FullCodeGenerator::HandleInNonTestContext(Expression* expr, State state) { | |
| 877 ASSERT(forward_bailout_pending_ == NULL); | |
| 878 AstVisitor::Visit(expr); | |
| 879 PrepareForBailout(expr, state); | |
| 880 // Forwarding bailouts to children is a one shot operation. It | |
| 881 // should have been processed at this point. | |
| 882 ASSERT(forward_bailout_pending_ == NULL); | |
| 883 } | |
| 884 | |
| 885 | |
| 886 void FullCodeGenerator::VisitInTestContext(Expression* expr) { | |
| 887 ForwardBailoutStack stack(expr, forward_bailout_pending_); | |
| 888 ForwardBailoutStack* saved = forward_bailout_stack_; | |
| 889 forward_bailout_pending_ = NULL; | |
| 890 forward_bailout_stack_ = &stack; | |
| 891 AstVisitor::Visit(expr); | |
| 892 forward_bailout_stack_ = saved; | |
| 893 } | 839 } |
| 894 | 840 |
| 895 | 841 |
| 896 void FullCodeGenerator::VisitBlock(Block* stmt) { | 842 void FullCodeGenerator::VisitBlock(Block* stmt) { |
| 897 Comment cmnt(masm_, "[ Block"); | 843 Comment cmnt(masm_, "[ Block"); |
| 898 Breakable nested_statement(this, stmt); | 844 Breakable nested_statement(this, stmt); |
| 899 SetStatementPosition(stmt); | 845 SetStatementPosition(stmt); |
| 900 | 846 |
| 901 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); | 847 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); |
| 902 VisitStatements(stmt->statements()); | 848 VisitStatements(stmt->statements()); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 935 Visit(stmt->else_statement()); | 881 Visit(stmt->else_statement()); |
| 936 } else { | 882 } else { |
| 937 VisitForControl(stmt->condition(), &then_part, &done, &then_part); | 883 VisitForControl(stmt->condition(), &then_part, &done, &then_part); |
| 938 PrepareForBailoutForId(stmt->ThenId(), NO_REGISTERS); | 884 PrepareForBailoutForId(stmt->ThenId(), NO_REGISTERS); |
| 939 __ bind(&then_part); | 885 __ bind(&then_part); |
| 940 Visit(stmt->then_statement()); | 886 Visit(stmt->then_statement()); |
| 941 | 887 |
| 942 PrepareForBailoutForId(stmt->ElseId(), NO_REGISTERS); | 888 PrepareForBailoutForId(stmt->ElseId(), NO_REGISTERS); |
| 943 } | 889 } |
| 944 __ bind(&done); | 890 __ bind(&done); |
| 945 PrepareForBailoutForId(stmt->id(), NO_REGISTERS); | 891 PrepareForBailoutForId(stmt->IfId(), NO_REGISTERS); |
| 946 } | 892 } |
| 947 | 893 |
| 948 | 894 |
| 949 void FullCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) { | 895 void FullCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) { |
| 950 Comment cmnt(masm_, "[ ContinueStatement"); | 896 Comment cmnt(masm_, "[ ContinueStatement"); |
| 951 SetStatementPosition(stmt); | 897 SetStatementPosition(stmt); |
| 952 NestedStatement* current = nesting_stack_; | 898 NestedStatement* current = nesting_stack_; |
| 953 int stack_depth = 0; | 899 int stack_depth = 0; |
| 954 // When continuing, we clobber the unpredictable value in the accumulator | 900 // When continuing, we clobber the unpredictable value in the accumulator |
| 955 // with one that's safe for GC. If we hit an exit from the try block of | 901 // with one that's safe for GC. If we hit an exit from the try block of |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1000 while (current != NULL) { | 946 while (current != NULL) { |
| 1001 stack_depth = current->Exit(stack_depth); | 947 stack_depth = current->Exit(stack_depth); |
| 1002 current = current->outer(); | 948 current = current->outer(); |
| 1003 } | 949 } |
| 1004 __ Drop(stack_depth); | 950 __ Drop(stack_depth); |
| 1005 | 951 |
| 1006 EmitReturnSequence(); | 952 EmitReturnSequence(); |
| 1007 } | 953 } |
| 1008 | 954 |
| 1009 | 955 |
| 1010 void FullCodeGenerator::VisitWithEnterStatement(WithEnterStatement* stmt) { | 956 void FullCodeGenerator::VisitEnterWithContextStatement( |
| 1011 Comment cmnt(masm_, "[ WithEnterStatement"); | 957 EnterWithContextStatement* stmt) { |
| 958 Comment cmnt(masm_, "[ EnterWithContextStatement"); |
| 1012 SetStatementPosition(stmt); | 959 SetStatementPosition(stmt); |
| 1013 | 960 |
| 1014 VisitForStackValue(stmt->expression()); | 961 VisitForStackValue(stmt->expression()); |
| 1015 if (stmt->is_catch_block()) { | 962 PushFunctionArgumentForContextAllocation(); |
| 1016 __ CallRuntime(Runtime::kPushCatchContext, 1); | 963 __ CallRuntime(Runtime::kPushWithContext, 2); |
| 1017 } else { | |
| 1018 __ CallRuntime(Runtime::kPushContext, 1); | |
| 1019 } | |
| 1020 // Both runtime calls return the new context in both the context and the | |
| 1021 // result registers. | |
| 1022 | |
| 1023 // Update local stack frame context field. | |
| 1024 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register()); | 964 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register()); |
| 1025 } | 965 } |
| 1026 | 966 |
| 1027 | 967 |
| 1028 void FullCodeGenerator::VisitWithExitStatement(WithExitStatement* stmt) { | 968 void FullCodeGenerator::VisitExitContextStatement(ExitContextStatement* stmt) { |
| 1029 Comment cmnt(masm_, "[ WithExitStatement"); | 969 Comment cmnt(masm_, "[ ExitContextStatement"); |
| 1030 SetStatementPosition(stmt); | 970 SetStatementPosition(stmt); |
| 1031 | 971 |
| 1032 // Pop context. | 972 // Pop context. |
| 1033 LoadContextField(context_register(), Context::PREVIOUS_INDEX); | 973 LoadContextField(context_register(), Context::PREVIOUS_INDEX); |
| 1034 // Update local stack frame context field. | 974 // Update local stack frame context field. |
| 1035 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register()); | 975 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register()); |
| 1036 } | 976 } |
| 1037 | 977 |
| 1038 | 978 |
| 1039 void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { | 979 void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1160 // At this point, the exception is in a register, and store it in | 1100 // At this point, the exception is in a register, and store it in |
| 1161 // the temporary local variable (prints as ".catch-var") before | 1101 // the temporary local variable (prints as ".catch-var") before |
| 1162 // executing the catch block. The catch block has been rewritten | 1102 // executing the catch block. The catch block has been rewritten |
| 1163 // to introduce a new scope to bind the catch variable and to remove | 1103 // to introduce a new scope to bind the catch variable and to remove |
| 1164 // that scope again afterwards. | 1104 // that scope again afterwards. |
| 1165 | 1105 |
| 1166 Label try_handler_setup, catch_entry, done; | 1106 Label try_handler_setup, catch_entry, done; |
| 1167 __ Call(&try_handler_setup); | 1107 __ Call(&try_handler_setup); |
| 1168 // Try handler code, exception in result register. | 1108 // Try handler code, exception in result register. |
| 1169 | 1109 |
| 1170 // Store exception in local .catch variable before executing catch block. | 1110 // Extend the context before executing the catch block. |
| 1171 { | 1111 { Comment cmnt(masm_, "[ Extend catch context"); |
| 1172 // The catch variable is *always* a variable proxy for a local variable. | 1112 __ Push(stmt->variable()->name()); |
| 1173 Variable* catch_var = stmt->catch_var()->AsVariableProxy()->AsVariable(); | 1113 __ push(result_register()); |
| 1174 ASSERT_NOT_NULL(catch_var); | 1114 PushFunctionArgumentForContextAllocation(); |
| 1175 Slot* variable_slot = catch_var->AsSlot(); | 1115 __ CallRuntime(Runtime::kPushCatchContext, 3); |
| 1176 ASSERT_NOT_NULL(variable_slot); | 1116 StoreToFrameField(StandardFrameConstants::kContextOffset, |
| 1177 ASSERT_EQ(Slot::LOCAL, variable_slot->type()); | 1117 context_register()); |
| 1178 StoreToFrameField(SlotOffset(variable_slot), result_register()); | |
| 1179 } | 1118 } |
| 1180 | 1119 |
| 1120 Scope* saved_scope = scope(); |
| 1121 scope_ = stmt->scope(); |
| 1122 ASSERT(scope_->declarations()->is_empty()); |
| 1181 Visit(stmt->catch_block()); | 1123 Visit(stmt->catch_block()); |
| 1124 scope_ = saved_scope; |
| 1182 __ jmp(&done); | 1125 __ jmp(&done); |
| 1183 | 1126 |
| 1184 // Try block code. Sets up the exception handler chain. | 1127 // Try block code. Sets up the exception handler chain. |
| 1185 __ bind(&try_handler_setup); | 1128 __ bind(&try_handler_setup); |
| 1186 { | 1129 { |
| 1187 TryCatch try_block(this, &catch_entry); | 1130 TryCatch try_block(this, &catch_entry); |
| 1188 __ PushTryHandler(IN_JAVASCRIPT, TRY_CATCH_HANDLER); | 1131 __ PushTryHandler(IN_JAVASCRIPT, TRY_CATCH_HANDLER); |
| 1189 Visit(stmt->try_block()); | 1132 Visit(stmt->try_block()); |
| 1190 __ PopTryHandler(); | 1133 __ PopTryHandler(); |
| 1191 } | 1134 } |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1280 __ bind(&true_case); | 1223 __ bind(&true_case); |
| 1281 SetExpressionPosition(expr->then_expression(), | 1224 SetExpressionPosition(expr->then_expression(), |
| 1282 expr->then_expression_position()); | 1225 expr->then_expression_position()); |
| 1283 if (context()->IsTest()) { | 1226 if (context()->IsTest()) { |
| 1284 const TestContext* for_test = TestContext::cast(context()); | 1227 const TestContext* for_test = TestContext::cast(context()); |
| 1285 VisitForControl(expr->then_expression(), | 1228 VisitForControl(expr->then_expression(), |
| 1286 for_test->true_label(), | 1229 for_test->true_label(), |
| 1287 for_test->false_label(), | 1230 for_test->false_label(), |
| 1288 NULL); | 1231 NULL); |
| 1289 } else { | 1232 } else { |
| 1290 context()->HandleExpression(expr->then_expression()); | 1233 VisitInCurrentContext(expr->then_expression()); |
| 1291 __ jmp(&done); | 1234 __ jmp(&done); |
| 1292 } | 1235 } |
| 1293 | 1236 |
| 1294 PrepareForBailoutForId(expr->ElseId(), NO_REGISTERS); | 1237 PrepareForBailoutForId(expr->ElseId(), NO_REGISTERS); |
| 1295 __ bind(&false_case); | 1238 __ bind(&false_case); |
| 1296 if (context()->IsTest()) ForwardBailoutToChild(expr); | 1239 if (context()->IsTest()) ForwardBailoutToChild(expr); |
| 1297 SetExpressionPosition(expr->else_expression(), | 1240 SetExpressionPosition(expr->else_expression(), |
| 1298 expr->else_expression_position()); | 1241 expr->else_expression_position()); |
| 1299 context()->HandleExpression(expr->else_expression()); | 1242 VisitInCurrentContext(expr->else_expression()); |
| 1300 // If control flow falls through Visit, merge it with true case here. | 1243 // If control flow falls through Visit, merge it with true case here. |
| 1301 if (!context()->IsTest()) { | 1244 if (!context()->IsTest()) { |
| 1302 __ bind(&done); | 1245 __ bind(&done); |
| 1303 } | 1246 } |
| 1304 } | 1247 } |
| 1305 | 1248 |
| 1306 | 1249 |
| 1307 void FullCodeGenerator::VisitLiteral(Literal* expr) { | 1250 void FullCodeGenerator::VisitLiteral(Literal* expr) { |
| 1308 Comment cmnt(masm_, "[ Literal"); | 1251 Comment cmnt(masm_, "[ Literal"); |
| 1309 context()->Plug(expr->handle()); | 1252 context()->Plug(expr->handle()); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1324 } | 1267 } |
| 1325 | 1268 |
| 1326 | 1269 |
| 1327 void FullCodeGenerator::VisitSharedFunctionInfoLiteral( | 1270 void FullCodeGenerator::VisitSharedFunctionInfoLiteral( |
| 1328 SharedFunctionInfoLiteral* expr) { | 1271 SharedFunctionInfoLiteral* expr) { |
| 1329 Comment cmnt(masm_, "[ SharedFunctionInfoLiteral"); | 1272 Comment cmnt(masm_, "[ SharedFunctionInfoLiteral"); |
| 1330 EmitNewClosure(expr->shared_function_info(), false); | 1273 EmitNewClosure(expr->shared_function_info(), false); |
| 1331 } | 1274 } |
| 1332 | 1275 |
| 1333 | 1276 |
| 1334 void FullCodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* expr) { | |
| 1335 // Call runtime routine to allocate the catch extension object and | |
| 1336 // assign the exception value to the catch variable. | |
| 1337 Comment cmnt(masm_, "[ CatchExtensionObject"); | |
| 1338 VisitForStackValue(expr->key()); | |
| 1339 VisitForStackValue(expr->value()); | |
| 1340 // Create catch extension object. | |
| 1341 __ CallRuntime(Runtime::kCreateCatchExtensionObject, 2); | |
| 1342 context()->Plug(result_register()); | |
| 1343 } | |
| 1344 | |
| 1345 | |
| 1346 void FullCodeGenerator::VisitThrow(Throw* expr) { | 1277 void FullCodeGenerator::VisitThrow(Throw* expr) { |
| 1347 Comment cmnt(masm_, "[ Throw"); | 1278 Comment cmnt(masm_, "[ Throw"); |
| 1348 VisitForStackValue(expr->exception()); | 1279 VisitForStackValue(expr->exception()); |
| 1349 __ CallRuntime(Runtime::kThrow, 1); | 1280 __ CallRuntime(Runtime::kThrow, 1); |
| 1350 // Never returns here. | 1281 // Never returns here. |
| 1351 } | 1282 } |
| 1352 | 1283 |
| 1353 | 1284 |
| 1354 int FullCodeGenerator::TryFinally::Exit(int stack_depth) { | 1285 int FullCodeGenerator::TryFinally::Exit(int stack_depth) { |
| 1355 // The macros used here must preserve the result register. | 1286 // The macros used here must preserve the result register. |
| 1356 __ Drop(stack_depth); | 1287 __ Drop(stack_depth); |
| 1357 __ PopTryHandler(); | 1288 __ PopTryHandler(); |
| 1358 __ Call(finally_entry_); | 1289 __ Call(finally_entry_); |
| 1359 return 0; | 1290 return 0; |
| 1360 } | 1291 } |
| 1361 | 1292 |
| 1362 | 1293 |
| 1363 int FullCodeGenerator::TryCatch::Exit(int stack_depth) { | 1294 int FullCodeGenerator::TryCatch::Exit(int stack_depth) { |
| 1364 // The macros used here must preserve the result register. | 1295 // The macros used here must preserve the result register. |
| 1365 __ Drop(stack_depth); | 1296 __ Drop(stack_depth); |
| 1366 __ PopTryHandler(); | 1297 __ PopTryHandler(); |
| 1367 return 0; | 1298 return 0; |
| 1368 } | 1299 } |
| 1369 | 1300 |
| 1370 | 1301 |
| 1302 bool FullCodeGenerator::TryLiteralCompare(CompareOperation* compare, |
| 1303 Label* if_true, |
| 1304 Label* if_false, |
| 1305 Label* fall_through) { |
| 1306 Expression *expr; |
| 1307 Handle<String> check; |
| 1308 if (compare->IsLiteralCompareTypeof(&expr, &check)) { |
| 1309 EmitLiteralCompareTypeof(expr, check, if_true, if_false, fall_through); |
| 1310 return true; |
| 1311 } |
| 1312 |
| 1313 if (compare->IsLiteralCompareUndefined(&expr)) { |
| 1314 EmitLiteralCompareUndefined(expr, if_true, if_false, fall_through); |
| 1315 return true; |
| 1316 } |
| 1317 |
| 1318 return false; |
| 1319 } |
| 1320 |
| 1321 |
| 1371 #undef __ | 1322 #undef __ |
| 1372 | 1323 |
| 1373 | 1324 |
| 1374 } } // namespace v8::internal | 1325 } } // namespace v8::internal |
| OLD | NEW |