OLD | NEW |
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 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 24 matching lines...) Expand all Loading... |
35 #include "fast-codegen.h" | 35 #include "fast-codegen.h" |
36 #include "oprofile-agent.h" | 36 #include "oprofile-agent.h" |
37 #include "rewriter.h" | 37 #include "rewriter.h" |
38 #include "scopes.h" | 38 #include "scopes.h" |
39 #include "usage-analyzer.h" | 39 #include "usage-analyzer.h" |
40 | 40 |
41 namespace v8 { | 41 namespace v8 { |
42 namespace internal { | 42 namespace internal { |
43 | 43 |
44 | 44 |
45 class CodeGenSelector: public AstVisitor { | |
46 public: | |
47 enum CodeGenTag { NORMAL, FAST }; | |
48 | |
49 CodeGenSelector() : has_supported_syntax_(true) {} | |
50 | |
51 CodeGenTag Select(FunctionLiteral* fun); | |
52 | |
53 private: | |
54 void VisitDeclarations(ZoneList<Declaration*>* decls); | |
55 void VisitStatements(ZoneList<Statement*>* stmts); | |
56 | |
57 // AST node visit functions. | |
58 #define DECLARE_VISIT(type) virtual void Visit##type(type* node); | |
59 AST_NODE_LIST(DECLARE_VISIT) | |
60 #undef DECLARE_VISIT | |
61 | |
62 bool has_supported_syntax_; | |
63 | |
64 DISALLOW_COPY_AND_ASSIGN(CodeGenSelector); | |
65 }; | |
66 | |
67 | |
68 static Handle<Code> MakeCode(FunctionLiteral* literal, | 45 static Handle<Code> MakeCode(FunctionLiteral* literal, |
69 Handle<Script> script, | 46 Handle<Script> script, |
70 Handle<Context> context, | 47 Handle<Context> context, |
71 bool is_eval, | 48 bool is_eval, |
72 Handle<SharedFunctionInfo> shared) { | 49 Handle<SharedFunctionInfo> shared) { |
73 ASSERT(literal != NULL); | 50 ASSERT(literal != NULL); |
74 | 51 |
75 // Rewrite the AST by introducing .result assignments where needed. | 52 // Rewrite the AST by introducing .result assignments where needed. |
76 if (!Rewriter::Process(literal) || !AnalyzeVariableUsage(literal)) { | 53 if (!Rewriter::Process(literal) || !AnalyzeVariableUsage(literal)) { |
77 // Signal a stack overflow by returning a null handle. The stack | 54 // Signal a stack overflow by returning a null handle. The stack |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
110 // generator for code in the global scope. Otherwise obey the | 87 // generator for code in the global scope. Otherwise obey the |
111 // explicit hint in the shared function info. | 88 // explicit hint in the shared function info. |
112 // If always_fast_compiler is true, always try the fast compiler. | 89 // If always_fast_compiler is true, always try the fast compiler. |
113 if (shared.is_null() && !literal->scope()->is_global_scope() && | 90 if (shared.is_null() && !literal->scope()->is_global_scope() && |
114 !FLAG_always_fast_compiler) { | 91 !FLAG_always_fast_compiler) { |
115 if (FLAG_trace_bailout) PrintF("Non-global scope\n"); | 92 if (FLAG_trace_bailout) PrintF("Non-global scope\n"); |
116 } else if (!shared.is_null() && !shared->try_fast_codegen() && | 93 } else if (!shared.is_null() && !shared->try_fast_codegen() && |
117 !FLAG_always_fast_compiler) { | 94 !FLAG_always_fast_compiler) { |
118 if (FLAG_trace_bailout) PrintF("No hint to try fast\n"); | 95 if (FLAG_trace_bailout) PrintF("No hint to try fast\n"); |
119 } else { | 96 } else { |
120 CodeGenSelector selector; | 97 FullCodeGenSyntaxChecker checker; |
121 CodeGenSelector::CodeGenTag code_gen = selector.Select(literal); | 98 checker.Check(literal); |
122 if (code_gen == CodeGenSelector::FAST) { | 99 if (checker.has_supported_syntax()) { |
123 return FastCodeGenerator::MakeCode(literal, script, is_eval); | 100 return FullCodeGenerator::MakeCode(literal, script, is_eval); |
124 } | 101 } |
125 ASSERT(code_gen == CodeGenSelector::NORMAL); | |
126 } | 102 } |
127 } | 103 } |
128 return CodeGenerator::MakeCode(literal, script, is_eval); | 104 return CodeGenerator::MakeCode(literal, script, is_eval); |
129 } | 105 } |
130 | 106 |
131 | 107 |
132 static bool IsValidJSON(FunctionLiteral* lit) { | 108 static bool IsValidJSON(FunctionLiteral* lit) { |
133 if (lit->body()->length() != 1) | 109 if (lit->body()->length() != 1) |
134 return false; | 110 return false; |
135 Statement* stmt = lit->body()->at(0); | 111 Statement* stmt = lit->body()->at(0); |
(...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
487 } else { | 463 } else { |
488 // The bodies of function literals have not yet been visited by | 464 // The bodies of function literals have not yet been visited by |
489 // the AST optimizer/analyzer. | 465 // the AST optimizer/analyzer. |
490 if (!Rewriter::Optimize(literal)) { | 466 if (!Rewriter::Optimize(literal)) { |
491 return Handle<JSFunction>::null(); | 467 return Handle<JSFunction>::null(); |
492 } | 468 } |
493 | 469 |
494 // Generate code and return it. | 470 // Generate code and return it. |
495 bool is_compiled = false; | 471 bool is_compiled = false; |
496 if (FLAG_fast_compiler && literal->try_fast_codegen()) { | 472 if (FLAG_fast_compiler && literal->try_fast_codegen()) { |
497 CodeGenSelector selector; | 473 FullCodeGenSyntaxChecker checker; |
498 CodeGenSelector::CodeGenTag code_gen = selector.Select(literal); | 474 checker.Check(literal); |
499 if (code_gen == CodeGenSelector::FAST) { | 475 if (checker.has_supported_syntax()) { |
500 code = FastCodeGenerator::MakeCode(literal, | 476 code = FullCodeGenerator::MakeCode(literal, |
501 script, | 477 script, |
502 false); // Not eval. | 478 false); // Not eval. |
503 is_compiled = true; | 479 is_compiled = true; |
504 } | 480 } |
505 } | 481 } |
506 | 482 |
507 if (!is_compiled) { | 483 if (!is_compiled) { |
508 // We didn't try the fast compiler, or we failed to select it. | 484 // We didn't try the fast compiler, or we failed to select it. |
509 code = CodeGenerator::MakeCode(literal, | 485 code = CodeGenerator::MakeCode(literal, |
510 script, | 486 script, |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
564 fun->shared()->set_is_expression(lit->is_expression()); | 540 fun->shared()->set_is_expression(lit->is_expression()); |
565 fun->shared()->set_is_toplevel(is_toplevel); | 541 fun->shared()->set_is_toplevel(is_toplevel); |
566 fun->shared()->set_inferred_name(*lit->inferred_name()); | 542 fun->shared()->set_inferred_name(*lit->inferred_name()); |
567 fun->shared()->SetThisPropertyAssignmentsInfo( | 543 fun->shared()->SetThisPropertyAssignmentsInfo( |
568 lit->has_only_simple_this_property_assignments(), | 544 lit->has_only_simple_this_property_assignments(), |
569 *lit->this_property_assignments()); | 545 *lit->this_property_assignments()); |
570 fun->shared()->set_try_fast_codegen(lit->try_fast_codegen()); | 546 fun->shared()->set_try_fast_codegen(lit->try_fast_codegen()); |
571 } | 547 } |
572 | 548 |
573 | 549 |
574 CodeGenSelector::CodeGenTag CodeGenSelector::Select(FunctionLiteral* fun) { | |
575 Scope* scope = fun->scope(); | |
576 | |
577 if (scope->num_heap_slots() > 0) { | |
578 // We support functions with a local context if they do not have | |
579 // parameters that need to be copied into the context. | |
580 for (int i = 0, len = scope->num_parameters(); i < len; i++) { | |
581 Slot* slot = scope->parameter(i)->slot(); | |
582 if (slot != NULL && slot->type() == Slot::CONTEXT) { | |
583 if (FLAG_trace_bailout) { | |
584 PrintF("Function has context-allocated parameters.\n"); | |
585 } | |
586 return NORMAL; | |
587 } | |
588 } | |
589 } | |
590 | |
591 has_supported_syntax_ = true; | |
592 VisitDeclarations(scope->declarations()); | |
593 if (!has_supported_syntax_) return NORMAL; | |
594 | |
595 VisitStatements(fun->body()); | |
596 return has_supported_syntax_ ? FAST : NORMAL; | |
597 } | |
598 | |
599 | |
600 #define BAILOUT(reason) \ | |
601 do { \ | |
602 if (FLAG_trace_bailout) { \ | |
603 PrintF("%s\n", reason); \ | |
604 } \ | |
605 has_supported_syntax_ = false; \ | |
606 return; \ | |
607 } while (false) | |
608 | |
609 | |
610 #define CHECK_BAILOUT \ | |
611 do { \ | |
612 if (!has_supported_syntax_) return; \ | |
613 } while (false) | |
614 | |
615 | |
616 void CodeGenSelector::VisitDeclarations(ZoneList<Declaration*>* decls) { | |
617 for (int i = 0; i < decls->length(); i++) { | |
618 Visit(decls->at(i)); | |
619 CHECK_BAILOUT; | |
620 } | |
621 } | |
622 | |
623 | |
624 void CodeGenSelector::VisitStatements(ZoneList<Statement*>* stmts) { | |
625 for (int i = 0, len = stmts->length(); i < len; i++) { | |
626 Visit(stmts->at(i)); | |
627 CHECK_BAILOUT; | |
628 } | |
629 } | |
630 | |
631 | |
632 void CodeGenSelector::VisitDeclaration(Declaration* decl) { | |
633 Property* prop = decl->proxy()->AsProperty(); | |
634 if (prop != NULL) { | |
635 Visit(prop->obj()); | |
636 Visit(prop->key()); | |
637 } | |
638 | |
639 if (decl->fun() != NULL) { | |
640 Visit(decl->fun()); | |
641 } | |
642 } | |
643 | |
644 | |
645 void CodeGenSelector::VisitBlock(Block* stmt) { | |
646 VisitStatements(stmt->statements()); | |
647 } | |
648 | |
649 | |
650 void CodeGenSelector::VisitExpressionStatement(ExpressionStatement* stmt) { | |
651 Visit(stmt->expression()); | |
652 } | |
653 | |
654 | |
655 void CodeGenSelector::VisitEmptyStatement(EmptyStatement* stmt) {} | |
656 | |
657 | |
658 void CodeGenSelector::VisitIfStatement(IfStatement* stmt) { | |
659 Visit(stmt->condition()); | |
660 CHECK_BAILOUT; | |
661 Visit(stmt->then_statement()); | |
662 CHECK_BAILOUT; | |
663 Visit(stmt->else_statement()); | |
664 } | |
665 | |
666 | |
667 void CodeGenSelector::VisitContinueStatement(ContinueStatement* stmt) {} | |
668 | |
669 | |
670 void CodeGenSelector::VisitBreakStatement(BreakStatement* stmt) {} | |
671 | |
672 | |
673 void CodeGenSelector::VisitReturnStatement(ReturnStatement* stmt) { | |
674 Visit(stmt->expression()); | |
675 } | |
676 | |
677 | |
678 void CodeGenSelector::VisitWithEnterStatement(WithEnterStatement* stmt) { | |
679 Visit(stmt->expression()); | |
680 } | |
681 | |
682 | |
683 void CodeGenSelector::VisitWithExitStatement(WithExitStatement* stmt) {} | |
684 | |
685 | |
686 void CodeGenSelector::VisitSwitchStatement(SwitchStatement* stmt) { | |
687 BAILOUT("SwitchStatement"); | |
688 } | |
689 | |
690 | |
691 void CodeGenSelector::VisitDoWhileStatement(DoWhileStatement* stmt) { | |
692 Visit(stmt->cond()); | |
693 CHECK_BAILOUT; | |
694 Visit(stmt->body()); | |
695 } | |
696 | |
697 | |
698 void CodeGenSelector::VisitWhileStatement(WhileStatement* stmt) { | |
699 Visit(stmt->cond()); | |
700 CHECK_BAILOUT; | |
701 Visit(stmt->body()); | |
702 } | |
703 | |
704 | |
705 void CodeGenSelector::VisitForStatement(ForStatement* stmt) { | |
706 BAILOUT("ForStatement"); | |
707 } | |
708 | |
709 | |
710 void CodeGenSelector::VisitForInStatement(ForInStatement* stmt) { | |
711 BAILOUT("ForInStatement"); | |
712 } | |
713 | |
714 | |
715 void CodeGenSelector::VisitTryCatchStatement(TryCatchStatement* stmt) { | |
716 Visit(stmt->try_block()); | |
717 CHECK_BAILOUT; | |
718 Visit(stmt->catch_block()); | |
719 } | |
720 | |
721 | |
722 void CodeGenSelector::VisitTryFinallyStatement(TryFinallyStatement* stmt) { | |
723 Visit(stmt->try_block()); | |
724 CHECK_BAILOUT; | |
725 Visit(stmt->finally_block()); | |
726 } | |
727 | |
728 | |
729 void CodeGenSelector::VisitDebuggerStatement(DebuggerStatement* stmt) {} | |
730 | |
731 | |
732 void CodeGenSelector::VisitFunctionLiteral(FunctionLiteral* expr) {} | |
733 | |
734 | |
735 void CodeGenSelector::VisitFunctionBoilerplateLiteral( | |
736 FunctionBoilerplateLiteral* expr) { | |
737 BAILOUT("FunctionBoilerplateLiteral"); | |
738 } | |
739 | |
740 | |
741 void CodeGenSelector::VisitConditional(Conditional* expr) { | |
742 Visit(expr->condition()); | |
743 CHECK_BAILOUT; | |
744 Visit(expr->then_expression()); | |
745 CHECK_BAILOUT; | |
746 Visit(expr->else_expression()); | |
747 } | |
748 | |
749 | |
750 void CodeGenSelector::VisitSlot(Slot* expr) { | |
751 UNREACHABLE(); | |
752 } | |
753 | |
754 | |
755 void CodeGenSelector::VisitVariableProxy(VariableProxy* expr) { | |
756 Variable* var = expr->var(); | |
757 if (!var->is_global()) { | |
758 Slot* slot = var->slot(); | |
759 if (slot != NULL) { | |
760 Slot::Type type = slot->type(); | |
761 // When LOOKUP slots are enabled, some currently dead code | |
762 // implementing unary typeof will become live. | |
763 if (type == Slot::LOOKUP) { | |
764 BAILOUT("Lookup slot"); | |
765 } | |
766 } else { | |
767 // If not global or a slot, it is a parameter rewritten to an explicit | |
768 // property reference on the (shadow) arguments object. | |
769 #ifdef DEBUG | |
770 Property* property = var->AsProperty(); | |
771 ASSERT_NOT_NULL(property); | |
772 Variable* object = property->obj()->AsVariableProxy()->AsVariable(); | |
773 ASSERT_NOT_NULL(object); | |
774 ASSERT_NOT_NULL(object->slot()); | |
775 ASSERT_NOT_NULL(property->key()->AsLiteral()); | |
776 ASSERT(property->key()->AsLiteral()->handle()->IsSmi()); | |
777 #endif | |
778 } | |
779 } | |
780 } | |
781 | |
782 | |
783 void CodeGenSelector::VisitLiteral(Literal* expr) {} | |
784 | |
785 | |
786 void CodeGenSelector::VisitRegExpLiteral(RegExpLiteral* expr) {} | |
787 | |
788 | |
789 void CodeGenSelector::VisitObjectLiteral(ObjectLiteral* expr) { | |
790 ZoneList<ObjectLiteral::Property*>* properties = expr->properties(); | |
791 | |
792 for (int i = 0, len = properties->length(); i < len; i++) { | |
793 ObjectLiteral::Property* property = properties->at(i); | |
794 if (property->IsCompileTimeValue()) continue; | |
795 Visit(property->key()); | |
796 CHECK_BAILOUT; | |
797 Visit(property->value()); | |
798 CHECK_BAILOUT; | |
799 } | |
800 } | |
801 | |
802 | |
803 void CodeGenSelector::VisitArrayLiteral(ArrayLiteral* expr) { | |
804 ZoneList<Expression*>* subexprs = expr->values(); | |
805 for (int i = 0, len = subexprs->length(); i < len; i++) { | |
806 Expression* subexpr = subexprs->at(i); | |
807 if (subexpr->AsLiteral() != NULL) continue; | |
808 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; | |
809 Visit(subexpr); | |
810 CHECK_BAILOUT; | |
811 } | |
812 } | |
813 | |
814 | |
815 void CodeGenSelector::VisitCatchExtensionObject(CatchExtensionObject* expr) { | |
816 Visit(expr->key()); | |
817 CHECK_BAILOUT; | |
818 Visit(expr->value()); | |
819 } | |
820 | |
821 | |
822 void CodeGenSelector::VisitAssignment(Assignment* expr) { | |
823 // We support plain non-compound assignments to properties, parameters and | |
824 // non-context (stack-allocated) locals, and global variables. | |
825 Token::Value op = expr->op(); | |
826 if (op == Token::INIT_CONST) BAILOUT("initialize constant"); | |
827 | |
828 Variable* var = expr->target()->AsVariableProxy()->AsVariable(); | |
829 Property* prop = expr->target()->AsProperty(); | |
830 ASSERT(var == NULL || prop == NULL); | |
831 if (var != NULL) { | |
832 if (var->mode() == Variable::CONST) { | |
833 BAILOUT("Assignment to const"); | |
834 } | |
835 // All global variables are supported. | |
836 if (!var->is_global()) { | |
837 ASSERT(var->slot() != NULL); | |
838 Slot::Type type = var->slot()->type(); | |
839 if (type == Slot::LOOKUP) { | |
840 BAILOUT("Lookup slot"); | |
841 } | |
842 } | |
843 } else if (prop != NULL) { | |
844 Visit(prop->obj()); | |
845 CHECK_BAILOUT; | |
846 Visit(prop->key()); | |
847 CHECK_BAILOUT; | |
848 } else { | |
849 // This is a throw reference error. | |
850 BAILOUT("non-variable/non-property assignment"); | |
851 } | |
852 | |
853 Visit(expr->value()); | |
854 } | |
855 | |
856 | |
857 void CodeGenSelector::VisitThrow(Throw* expr) { | |
858 Visit(expr->exception()); | |
859 } | |
860 | |
861 | |
862 void CodeGenSelector::VisitProperty(Property* expr) { | |
863 Visit(expr->obj()); | |
864 CHECK_BAILOUT; | |
865 Visit(expr->key()); | |
866 } | |
867 | |
868 | |
869 void CodeGenSelector::VisitCall(Call* expr) { | |
870 Expression* fun = expr->expression(); | |
871 ZoneList<Expression*>* args = expr->arguments(); | |
872 Variable* var = fun->AsVariableProxy()->AsVariable(); | |
873 | |
874 // Check for supported calls | |
875 if (var != NULL && var->is_possibly_eval()) { | |
876 BAILOUT("call to the identifier 'eval'"); | |
877 } else if (var != NULL && !var->is_this() && var->is_global()) { | |
878 // Calls to global variables are supported. | |
879 } else if (var != NULL && var->slot() != NULL && | |
880 var->slot()->type() == Slot::LOOKUP) { | |
881 BAILOUT("call to a lookup slot"); | |
882 } else if (fun->AsProperty() != NULL) { | |
883 Property* prop = fun->AsProperty(); | |
884 Visit(prop->obj()); | |
885 CHECK_BAILOUT; | |
886 Visit(prop->key()); | |
887 CHECK_BAILOUT; | |
888 } else { | |
889 // Otherwise the call is supported if the function expression is. | |
890 Visit(fun); | |
891 } | |
892 // Check all arguments to the call. | |
893 for (int i = 0; i < args->length(); i++) { | |
894 Visit(args->at(i)); | |
895 CHECK_BAILOUT; | |
896 } | |
897 } | |
898 | |
899 | |
900 void CodeGenSelector::VisitCallNew(CallNew* expr) { | |
901 Visit(expr->expression()); | |
902 CHECK_BAILOUT; | |
903 ZoneList<Expression*>* args = expr->arguments(); | |
904 // Check all arguments to the call | |
905 for (int i = 0; i < args->length(); i++) { | |
906 Visit(args->at(i)); | |
907 CHECK_BAILOUT; | |
908 } | |
909 } | |
910 | |
911 | |
912 void CodeGenSelector::VisitCallRuntime(CallRuntime* expr) { | |
913 // Check for inline runtime call | |
914 if (expr->name()->Get(0) == '_' && | |
915 CodeGenerator::FindInlineRuntimeLUT(expr->name()) != NULL) { | |
916 BAILOUT("inlined runtime call"); | |
917 } | |
918 // Check all arguments to the call. (Relies on TEMP meaning STACK.) | |
919 for (int i = 0; i < expr->arguments()->length(); i++) { | |
920 Visit(expr->arguments()->at(i)); | |
921 CHECK_BAILOUT; | |
922 } | |
923 } | |
924 | |
925 | |
926 void CodeGenSelector::VisitUnaryOperation(UnaryOperation* expr) { | |
927 switch (expr->op()) { | |
928 case Token::VOID: | |
929 case Token::NOT: | |
930 case Token::TYPEOF: | |
931 Visit(expr->expression()); | |
932 break; | |
933 case Token::BIT_NOT: | |
934 BAILOUT("UnaryOperation: BIT_NOT"); | |
935 case Token::DELETE: | |
936 BAILOUT("UnaryOperation: DELETE"); | |
937 case Token::ADD: | |
938 BAILOUT("UnaryOperation: ADD"); | |
939 case Token::SUB: | |
940 BAILOUT("UnaryOperation: SUB"); | |
941 default: | |
942 UNREACHABLE(); | |
943 } | |
944 } | |
945 | |
946 | |
947 void CodeGenSelector::VisitCountOperation(CountOperation* expr) { | |
948 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); | |
949 Property* prop = expr->expression()->AsProperty(); | |
950 ASSERT(var == NULL || prop == NULL); | |
951 if (var != NULL) { | |
952 // All global variables are supported. | |
953 if (!var->is_global()) { | |
954 ASSERT(var->slot() != NULL); | |
955 Slot::Type type = var->slot()->type(); | |
956 if (type == Slot::LOOKUP) { | |
957 BAILOUT("CountOperation with lookup slot"); | |
958 } | |
959 } | |
960 } else if (prop != NULL) { | |
961 Visit(prop->obj()); | |
962 CHECK_BAILOUT; | |
963 Visit(prop->key()); | |
964 CHECK_BAILOUT; | |
965 } else { | |
966 // This is a throw reference error. | |
967 BAILOUT("CountOperation non-variable/non-property expression"); | |
968 } | |
969 } | |
970 | |
971 | |
972 void CodeGenSelector::VisitBinaryOperation(BinaryOperation* expr) { | |
973 Visit(expr->left()); | |
974 CHECK_BAILOUT; | |
975 Visit(expr->right()); | |
976 } | |
977 | |
978 | |
979 void CodeGenSelector::VisitCompareOperation(CompareOperation* expr) { | |
980 Visit(expr->left()); | |
981 CHECK_BAILOUT; | |
982 Visit(expr->right()); | |
983 } | |
984 | |
985 | |
986 void CodeGenSelector::VisitThisFunction(ThisFunction* expr) {} | |
987 | |
988 #undef BAILOUT | |
989 #undef CHECK_BAILOUT | |
990 | |
991 | |
992 } } // namespace v8::internal | 550 } } // namespace v8::internal |
OLD | NEW |