OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 525 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
536 | 536 |
537 | 537 |
538 HConstant* HGraph::GetConstantHole() { | 538 HConstant* HGraph::GetConstantHole() { |
539 return GetConstant(&constant_hole_, isolate()->heap()->the_hole_value()); | 539 return GetConstant(&constant_hole_, isolate()->heap()->the_hole_value()); |
540 } | 540 } |
541 | 541 |
542 | 542 |
543 HGraphBuilder::HGraphBuilder(CompilationInfo* info, | 543 HGraphBuilder::HGraphBuilder(CompilationInfo* info, |
544 TypeFeedbackOracle* oracle) | 544 TypeFeedbackOracle* oracle) |
545 : function_state_(NULL), | 545 : function_state_(NULL), |
546 initial_function_state_(this, info, oracle, false), | 546 initial_function_state_(this, info, oracle, NORMAL_RETURN), |
547 ast_context_(NULL), | 547 ast_context_(NULL), |
548 break_scope_(NULL), | 548 break_scope_(NULL), |
549 graph_(NULL), | 549 graph_(NULL), |
550 current_block_(NULL), | 550 current_block_(NULL), |
551 inlined_count_(0), | 551 inlined_count_(0), |
552 zone_(info->isolate()->zone()), | 552 zone_(info->isolate()->zone()), |
553 inline_bailout_(false) { | 553 inline_bailout_(false) { |
554 // This is not initialized in the initializer list because the | 554 // This is not initialized in the initializer list because the |
555 // constructor for the initial state relies on function_state_ == NULL | 555 // constructor for the initial state relies on function_state_ == NULL |
556 // to know it's the initial state. | 556 // to know it's the initial state. |
(...skipping 1462 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2019 } | 2019 } |
2020 } | 2020 } |
2021 } | 2021 } |
2022 | 2022 |
2023 | 2023 |
2024 // Implementation of utility class to encapsulate the translation state for | 2024 // Implementation of utility class to encapsulate the translation state for |
2025 // a (possibly inlined) function. | 2025 // a (possibly inlined) function. |
2026 FunctionState::FunctionState(HGraphBuilder* owner, | 2026 FunctionState::FunctionState(HGraphBuilder* owner, |
2027 CompilationInfo* info, | 2027 CompilationInfo* info, |
2028 TypeFeedbackOracle* oracle, | 2028 TypeFeedbackOracle* oracle, |
2029 bool drop_extra) | 2029 ReturnHandlingFlag return_handling) |
2030 : owner_(owner), | 2030 : owner_(owner), |
2031 compilation_info_(info), | 2031 compilation_info_(info), |
2032 oracle_(oracle), | 2032 oracle_(oracle), |
2033 call_context_(NULL), | 2033 call_context_(NULL), |
2034 drop_extra_(drop_extra), | 2034 return_handling_(return_handling), |
2035 function_return_(NULL), | 2035 function_return_(NULL), |
2036 test_context_(NULL), | 2036 test_context_(NULL), |
2037 outer_(owner->function_state()) { | 2037 outer_(owner->function_state()) { |
2038 if (outer_ != NULL) { | 2038 if (outer_ != NULL) { |
2039 // State for an inline function. | 2039 // State for an inline function. |
2040 if (owner->ast_context()->IsTest()) { | 2040 if (owner->ast_context()->IsTest()) { |
2041 HBasicBlock* if_true = owner->graph()->CreateBasicBlock(); | 2041 HBasicBlock* if_true = owner->graph()->CreateBasicBlock(); |
2042 HBasicBlock* if_false = owner->graph()->CreateBasicBlock(); | 2042 HBasicBlock* if_false = owner->graph()->CreateBasicBlock(); |
2043 if_true->MarkAsInlineReturnTarget(); | 2043 if_true->MarkAsInlineReturnTarget(); |
2044 if_false->MarkAsInlineReturnTarget(); | 2044 if_false->MarkAsInlineReturnTarget(); |
(...skipping 22 matching lines...) Expand all Loading... |
2067 | 2067 |
2068 // Implementation of utility classes to represent an expression's context in | 2068 // Implementation of utility classes to represent an expression's context in |
2069 // the AST. | 2069 // the AST. |
2070 AstContext::AstContext(HGraphBuilder* owner, Expression::Context kind) | 2070 AstContext::AstContext(HGraphBuilder* owner, Expression::Context kind) |
2071 : owner_(owner), | 2071 : owner_(owner), |
2072 kind_(kind), | 2072 kind_(kind), |
2073 outer_(owner->ast_context()), | 2073 outer_(owner->ast_context()), |
2074 for_typeof_(false) { | 2074 for_typeof_(false) { |
2075 owner->set_ast_context(this); // Push. | 2075 owner->set_ast_context(this); // Push. |
2076 #ifdef DEBUG | 2076 #ifdef DEBUG |
2077 ASSERT(!owner->environment()->is_arguments_adaptor()); | 2077 ASSERT(owner->environment()->frame_type() == JS_FUNCTION); |
2078 original_length_ = owner->environment()->length(); | 2078 original_length_ = owner->environment()->length(); |
2079 #endif | 2079 #endif |
2080 } | 2080 } |
2081 | 2081 |
2082 | 2082 |
2083 AstContext::~AstContext() { | 2083 AstContext::~AstContext() { |
2084 owner_->set_ast_context(outer_); // Pop. | 2084 owner_->set_ast_context(outer_); // Pop. |
2085 } | 2085 } |
2086 | 2086 |
2087 | 2087 |
2088 EffectContext::~EffectContext() { | 2088 EffectContext::~EffectContext() { |
2089 ASSERT(owner()->HasStackOverflow() || | 2089 ASSERT(owner()->HasStackOverflow() || |
2090 owner()->current_block() == NULL || | 2090 owner()->current_block() == NULL || |
2091 (owner()->environment()->length() == original_length_ && | 2091 (owner()->environment()->length() == original_length_ && |
2092 !owner()->environment()->is_arguments_adaptor())); | 2092 owner()->environment()->frame_type() == JS_FUNCTION)); |
2093 } | 2093 } |
2094 | 2094 |
2095 | 2095 |
2096 ValueContext::~ValueContext() { | 2096 ValueContext::~ValueContext() { |
2097 ASSERT(owner()->HasStackOverflow() || | 2097 ASSERT(owner()->HasStackOverflow() || |
2098 owner()->current_block() == NULL || | 2098 owner()->current_block() == NULL || |
2099 (owner()->environment()->length() == original_length_ + 1 && | 2099 (owner()->environment()->length() == original_length_ + 1 && |
2100 !owner()->environment()->is_arguments_adaptor())); | 2100 owner()->environment()->frame_type() == JS_FUNCTION)); |
2101 } | 2101 } |
2102 | 2102 |
2103 | 2103 |
2104 void EffectContext::ReturnValue(HValue* value) { | 2104 void EffectContext::ReturnValue(HValue* value) { |
2105 // The value is simply ignored. | 2105 // The value is simply ignored. |
2106 } | 2106 } |
2107 | 2107 |
2108 | 2108 |
2109 void ValueContext::ReturnValue(HValue* value) { | 2109 void ValueContext::ReturnValue(HValue* value) { |
2110 // The value is tracked in the bailout environment, and communicated | 2110 // The value is tracked in the bailout environment, and communicated |
(...skipping 341 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2452 current_block()->AddPhi(instr); | 2452 current_block()->AddPhi(instr); |
2453 } | 2453 } |
2454 | 2454 |
2455 | 2455 |
2456 void HGraphBuilder::PushAndAdd(HInstruction* instr) { | 2456 void HGraphBuilder::PushAndAdd(HInstruction* instr) { |
2457 Push(instr); | 2457 Push(instr); |
2458 AddInstruction(instr); | 2458 AddInstruction(instr); |
2459 } | 2459 } |
2460 | 2460 |
2461 | 2461 |
2462 template <int V> | 2462 template <class Instruction> |
2463 HInstruction* HGraphBuilder::PreProcessCall(HCall<V>* call) { | 2463 HInstruction* HGraphBuilder::PreProcessCall(Instruction* call) { |
2464 int count = call->argument_count(); | 2464 int count = call->argument_count(); |
2465 ZoneList<HValue*> arguments(count); | 2465 ZoneList<HValue*> arguments(count); |
2466 for (int i = 0; i < count; ++i) { | 2466 for (int i = 0; i < count; ++i) { |
2467 arguments.Add(Pop()); | 2467 arguments.Add(Pop()); |
2468 } | 2468 } |
2469 | 2469 |
2470 while (!arguments.is_empty()) { | 2470 while (!arguments.is_empty()) { |
2471 AddInstruction(new(zone()) HPushArgument(arguments.RemoveLast())); | 2471 AddInstruction(new(zone()) HPushArgument(arguments.RemoveLast())); |
2472 } | 2472 } |
2473 return call; | 2473 return call; |
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2665 void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) { | 2665 void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) { |
2666 ASSERT(!HasStackOverflow()); | 2666 ASSERT(!HasStackOverflow()); |
2667 ASSERT(current_block() != NULL); | 2667 ASSERT(current_block() != NULL); |
2668 ASSERT(current_block()->HasPredecessor()); | 2668 ASSERT(current_block()->HasPredecessor()); |
2669 AstContext* context = call_context(); | 2669 AstContext* context = call_context(); |
2670 if (context == NULL) { | 2670 if (context == NULL) { |
2671 // Not an inlined return, so an actual one. | 2671 // Not an inlined return, so an actual one. |
2672 CHECK_ALIVE(VisitForValue(stmt->expression())); | 2672 CHECK_ALIVE(VisitForValue(stmt->expression())); |
2673 HValue* result = environment()->Pop(); | 2673 HValue* result = environment()->Pop(); |
2674 current_block()->FinishExit(new(zone()) HReturn(result)); | 2674 current_block()->FinishExit(new(zone()) HReturn(result)); |
2675 set_current_block(NULL); | 2675 } else if (function_state()->is_construct()) { |
| 2676 // Return from an inlined construct call. In a test context the return |
| 2677 // value will always evaluate to true, in a value context the return value |
| 2678 // needs to be a JSObject. |
| 2679 if (context->IsTest()) { |
| 2680 TestContext* test = TestContext::cast(context); |
| 2681 CHECK_ALIVE(VisitForEffect(stmt->expression())); |
| 2682 current_block()->Goto(test->if_true(), function_state()->drop_extra()); |
| 2683 } else if (context->IsEffect()) { |
| 2684 CHECK_ALIVE(VisitForEffect(stmt->expression())); |
| 2685 current_block()->Goto(function_return(), function_state()->drop_extra()); |
| 2686 } else { |
| 2687 ASSERT(context->IsValue()); |
| 2688 CHECK_ALIVE(VisitForValue(stmt->expression())); |
| 2689 HValue* return_value = Pop(); |
| 2690 HValue* receiver = environment()->Lookup(0); |
| 2691 HHasInstanceTypeAndBranch* typecheck = |
| 2692 new(zone()) HHasInstanceTypeAndBranch(return_value, |
| 2693 FIRST_SPEC_OBJECT_TYPE, |
| 2694 LAST_SPEC_OBJECT_TYPE); |
| 2695 HBasicBlock* if_spec_object = graph()->CreateBasicBlock(); |
| 2696 HBasicBlock* not_spec_object = graph()->CreateBasicBlock(); |
| 2697 typecheck->SetSuccessorAt(0, if_spec_object); |
| 2698 typecheck->SetSuccessorAt(1, not_spec_object); |
| 2699 current_block()->Finish(typecheck); |
| 2700 if_spec_object->AddLeaveInlined(return_value, |
| 2701 function_return(), |
| 2702 function_state()->drop_extra()); |
| 2703 not_spec_object->AddLeaveInlined(receiver, |
| 2704 function_return(), |
| 2705 function_state()->drop_extra()); |
| 2706 } |
2676 } else { | 2707 } else { |
2677 // Return from an inlined function, visit the subexpression in the | 2708 // Return from an inlined function, visit the subexpression in the |
2678 // expression context of the call. | 2709 // expression context of the call. |
2679 if (context->IsTest()) { | 2710 if (context->IsTest()) { |
2680 TestContext* test = TestContext::cast(context); | 2711 TestContext* test = TestContext::cast(context); |
2681 VisitForControl(stmt->expression(), | 2712 VisitForControl(stmt->expression(), |
2682 test->if_true(), | 2713 test->if_true(), |
2683 test->if_false()); | 2714 test->if_false()); |
2684 } else if (context->IsEffect()) { | 2715 } else if (context->IsEffect()) { |
2685 CHECK_ALIVE(VisitForEffect(stmt->expression())); | 2716 CHECK_ALIVE(VisitForEffect(stmt->expression())); |
2686 current_block()->Goto(function_return(), function_state()->drop_extra()); | 2717 current_block()->Goto(function_return(), function_state()->drop_extra()); |
2687 } else { | 2718 } else { |
2688 ASSERT(context->IsValue()); | 2719 ASSERT(context->IsValue()); |
2689 CHECK_ALIVE(VisitForValue(stmt->expression())); | 2720 CHECK_ALIVE(VisitForValue(stmt->expression())); |
2690 HValue* return_value = environment()->Pop(); | 2721 HValue* return_value = Pop(); |
2691 current_block()->AddLeaveInlined(return_value, | 2722 current_block()->AddLeaveInlined(return_value, |
2692 function_return(), | 2723 function_return(), |
2693 function_state()->drop_extra()); | 2724 function_state()->drop_extra()); |
2694 } | 2725 } |
2695 set_current_block(NULL); | |
2696 } | 2726 } |
| 2727 set_current_block(NULL); |
2697 } | 2728 } |
2698 | 2729 |
2699 | 2730 |
2700 void HGraphBuilder::VisitWithStatement(WithStatement* stmt) { | 2731 void HGraphBuilder::VisitWithStatement(WithStatement* stmt) { |
2701 ASSERT(!HasStackOverflow()); | 2732 ASSERT(!HasStackOverflow()); |
2702 ASSERT(current_block() != NULL); | 2733 ASSERT(current_block() != NULL); |
2703 ASSERT(current_block()->HasPredecessor()); | 2734 ASSERT(current_block()->HasPredecessor()); |
2704 return Bailout("WithStatement"); | 2735 return Bailout("WithStatement"); |
2705 } | 2736 } |
2706 | 2737 |
(...skipping 1997 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4704 HCompareMap* compare = | 4735 HCompareMap* compare = |
4705 new(zone()) HCompareMap(receiver, map, if_true, if_false); | 4736 new(zone()) HCompareMap(receiver, map, if_true, if_false); |
4706 current_block()->Finish(compare); | 4737 current_block()->Finish(compare); |
4707 | 4738 |
4708 set_current_block(if_true); | 4739 set_current_block(if_true); |
4709 AddCheckConstantFunction(expr, receiver, map, false); | 4740 AddCheckConstantFunction(expr, receiver, map, false); |
4710 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { | 4741 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { |
4711 PrintF("Trying to inline the polymorphic call to %s\n", | 4742 PrintF("Trying to inline the polymorphic call to %s\n", |
4712 *name->ToCString()); | 4743 *name->ToCString()); |
4713 } | 4744 } |
4714 if (FLAG_polymorphic_inlining && TryInline(expr)) { | 4745 if (FLAG_polymorphic_inlining && TryInlineCall(expr)) { |
4715 // Trying to inline will signal that we should bailout from the | 4746 // Trying to inline will signal that we should bailout from the |
4716 // entire compilation by setting stack overflow on the visitor. | 4747 // entire compilation by setting stack overflow on the visitor. |
4717 if (HasStackOverflow()) return; | 4748 if (HasStackOverflow()) return; |
4718 } else { | 4749 } else { |
4719 HCallConstantFunction* call = | 4750 HCallConstantFunction* call = |
4720 new(zone()) HCallConstantFunction(expr->target(), argument_count); | 4751 new(zone()) HCallConstantFunction(expr->target(), argument_count); |
4721 call->set_position(expr->position()); | 4752 call->set_position(expr->position()); |
4722 PreProcessCall(call); | 4753 PreProcessCall(call); |
4723 AddInstruction(call); | 4754 AddInstruction(call); |
4724 if (!ast_context()->IsEffect()) Push(call); | 4755 if (!ast_context()->IsEffect()) Push(call); |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4774 if (reason == NULL) { | 4805 if (reason == NULL) { |
4775 PrintF("Inlined %s called from %s.\n", *target_name, *caller_name); | 4806 PrintF("Inlined %s called from %s.\n", *target_name, *caller_name); |
4776 } else { | 4807 } else { |
4777 PrintF("Did not inline %s called from %s (%s).\n", | 4808 PrintF("Did not inline %s called from %s (%s).\n", |
4778 *target_name, *caller_name, reason); | 4809 *target_name, *caller_name, reason); |
4779 } | 4810 } |
4780 } | 4811 } |
4781 } | 4812 } |
4782 | 4813 |
4783 | 4814 |
4784 bool HGraphBuilder::TryInline(Call* expr, bool drop_extra) { | 4815 bool HGraphBuilder::TryInline(CallKind call_kind, |
| 4816 Handle<JSFunction> target, |
| 4817 ZoneList<Expression*>* arguments, |
| 4818 HValue* receiver, |
| 4819 int ast_id, |
| 4820 int return_id, |
| 4821 ReturnHandlingFlag return_handling) { |
4785 if (!FLAG_use_inlining) return false; | 4822 if (!FLAG_use_inlining) return false; |
4786 | 4823 |
4787 // The function call we are inlining is a method call if the call | |
4788 // is a property call. | |
4789 CallKind call_kind = (expr->expression()->AsProperty() == NULL) | |
4790 ? CALL_AS_FUNCTION | |
4791 : CALL_AS_METHOD; | |
4792 | |
4793 // Precondition: call is monomorphic and we have found a target with the | 4824 // Precondition: call is monomorphic and we have found a target with the |
4794 // appropriate arity. | 4825 // appropriate arity. |
4795 Handle<JSFunction> caller = info()->closure(); | 4826 Handle<JSFunction> caller = info()->closure(); |
4796 Handle<JSFunction> target = expr->target(); | |
4797 Handle<SharedFunctionInfo> target_shared(target->shared()); | 4827 Handle<SharedFunctionInfo> target_shared(target->shared()); |
4798 | 4828 |
4799 // Do a quick check on source code length to avoid parsing large | 4829 // Do a quick check on source code length to avoid parsing large |
4800 // inlining candidates. | 4830 // inlining candidates. |
4801 if ((FLAG_limit_inlining && target->shared()->SourceSize() > kMaxSourceSize) | 4831 if ((FLAG_limit_inlining && target->shared()->SourceSize() > kMaxSourceSize) |
4802 || target->shared()->SourceSize() > kUnlimitedMaxSourceSize) { | 4832 || target->shared()->SourceSize() > kUnlimitedMaxSourceSize) { |
4803 TraceInline(target, caller, "target text too big"); | 4833 TraceInline(target, caller, "target text too big"); |
4804 return false; | 4834 return false; |
4805 } | 4835 } |
4806 | 4836 |
(...skipping 16 matching lines...) Expand all Loading... |
4823 | 4853 |
4824 | 4854 |
4825 // Don't inline deeper than kMaxInliningLevels calls. | 4855 // Don't inline deeper than kMaxInliningLevels calls. |
4826 HEnvironment* env = environment(); | 4856 HEnvironment* env = environment(); |
4827 int current_level = 1; | 4857 int current_level = 1; |
4828 while (env->outer() != NULL) { | 4858 while (env->outer() != NULL) { |
4829 if (current_level == Compiler::kMaxInliningLevels) { | 4859 if (current_level == Compiler::kMaxInliningLevels) { |
4830 TraceInline(target, caller, "inline depth limit reached"); | 4860 TraceInline(target, caller, "inline depth limit reached"); |
4831 return false; | 4861 return false; |
4832 } | 4862 } |
4833 if (!env->outer()->is_arguments_adaptor()) { | 4863 if (env->outer()->frame_type() == JS_FUNCTION) { |
4834 current_level++; | 4864 current_level++; |
4835 } | 4865 } |
4836 env = env->outer(); | 4866 env = env->outer(); |
4837 } | 4867 } |
4838 | 4868 |
4839 // Don't inline recursive functions. | 4869 // Don't inline recursive functions. |
4840 for (FunctionState* state = function_state(); | 4870 for (FunctionState* state = function_state(); |
4841 state != NULL; | 4871 state != NULL; |
4842 state = state->outer()) { | 4872 state = state->outer()) { |
4843 if (state->compilation_info()->closure()->shared() == *target_shared) { | 4873 if (state->compilation_info()->closure()->shared() == *target_shared) { |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4934 | 4964 |
4935 // Save the pending call context and type feedback oracle. Set up new ones | 4965 // Save the pending call context and type feedback oracle. Set up new ones |
4936 // for the inlined function. | 4966 // for the inlined function. |
4937 ASSERT(target_shared->has_deoptimization_support()); | 4967 ASSERT(target_shared->has_deoptimization_support()); |
4938 TypeFeedbackOracle target_oracle( | 4968 TypeFeedbackOracle target_oracle( |
4939 Handle<Code>(target_shared->code()), | 4969 Handle<Code>(target_shared->code()), |
4940 Handle<Context>(target->context()->global_context()), | 4970 Handle<Context>(target->context()->global_context()), |
4941 isolate()); | 4971 isolate()); |
4942 // The function state is new-allocated because we need to delete it | 4972 // The function state is new-allocated because we need to delete it |
4943 // in two different places. | 4973 // in two different places. |
4944 FunctionState* target_state = | 4974 FunctionState* target_state = new FunctionState( |
4945 new FunctionState(this, &target_info, &target_oracle, drop_extra); | 4975 this, &target_info, &target_oracle, return_handling); |
4946 | 4976 |
4947 HConstant* undefined = graph()->GetConstantUndefined(); | 4977 HConstant* undefined = graph()->GetConstantUndefined(); |
4948 HEnvironment* inner_env = | 4978 HEnvironment* inner_env = |
4949 environment()->CopyForInlining(target, | 4979 environment()->CopyForInlining(target, |
4950 expr->arguments()->length(), | 4980 arguments->length(), |
4951 function, | 4981 function, |
4952 undefined, | 4982 undefined, |
4953 call_kind); | 4983 call_kind, |
| 4984 function_state()->is_construct()); |
4954 #ifdef V8_TARGET_ARCH_IA32 | 4985 #ifdef V8_TARGET_ARCH_IA32 |
4955 // IA32 only, overwrite the caller's context in the deoptimization | 4986 // IA32 only, overwrite the caller's context in the deoptimization |
4956 // environment with the correct one. | 4987 // environment with the correct one. |
4957 // | 4988 // |
4958 // TODO(kmillikin): implement the same inlining on other platforms so we | 4989 // TODO(kmillikin): implement the same inlining on other platforms so we |
4959 // can remove the unsightly ifdefs in this function. | 4990 // can remove the unsightly ifdefs in this function. |
4960 HConstant* context = new HConstant(Handle<Context>(target->context()), | 4991 HConstant* context = new HConstant(Handle<Context>(target->context()), |
4961 Representation::Tagged()); | 4992 Representation::Tagged()); |
4962 AddInstruction(context); | 4993 AddInstruction(context); |
4963 inner_env->BindContext(context); | 4994 inner_env->BindContext(context); |
4964 #endif | 4995 #endif |
4965 HBasicBlock* body_entry = CreateBasicBlock(inner_env); | 4996 HBasicBlock* body_entry = CreateBasicBlock(inner_env); |
4966 current_block()->Goto(body_entry); | 4997 current_block()->Goto(body_entry); |
4967 body_entry->SetJoinId(expr->ReturnId()); | 4998 body_entry->SetJoinId(return_id); |
4968 set_current_block(body_entry); | 4999 set_current_block(body_entry); |
4969 AddInstruction(new(zone()) HEnterInlined(target, | 5000 AddInstruction(new(zone()) HEnterInlined(target, |
4970 expr->arguments()->length(), | 5001 arguments->length(), |
4971 function, | 5002 function, |
4972 call_kind)); | 5003 call_kind, |
| 5004 function_state()->is_construct())); |
4973 VisitDeclarations(target_info.scope()->declarations()); | 5005 VisitDeclarations(target_info.scope()->declarations()); |
4974 VisitStatements(function->body()); | 5006 VisitStatements(function->body()); |
4975 if (HasStackOverflow()) { | 5007 if (HasStackOverflow()) { |
4976 // Bail out if the inline function did, as we cannot residualize a call | 5008 // Bail out if the inline function did, as we cannot residualize a call |
4977 // instead. | 5009 // instead. |
4978 TraceInline(target, caller, "inline graph construction failed"); | 5010 TraceInline(target, caller, "inline graph construction failed"); |
4979 target_shared->DisableOptimization(*target); | 5011 target_shared->DisableOptimization(*target); |
4980 inline_bailout_ = true; | 5012 inline_bailout_ = true; |
4981 delete target_state; | 5013 delete target_state; |
4982 return true; | 5014 return true; |
4983 } | 5015 } |
4984 | 5016 |
4985 // Update inlined nodes count. | 5017 // Update inlined nodes count. |
4986 inlined_count_ += nodes_added; | 5018 inlined_count_ += nodes_added; |
4987 | 5019 |
4988 TraceInline(target, caller, NULL); | 5020 TraceInline(target, caller, NULL); |
4989 | 5021 |
4990 if (current_block() != NULL) { | 5022 if (current_block() != NULL) { |
4991 // Add a return of undefined if control can fall off the body. In a | 5023 // Add default return value (i.e. undefined for normals calls or the newly |
4992 // test context, undefined is false. | 5024 // allocated receiver for construct calls) if control can fall off the |
4993 if (inlined_test_context() == NULL) { | 5025 // body. In a test context, undefined is false and any JSObject is true. |
| 5026 if (call_context()->IsValue()) { |
4994 ASSERT(function_return() != NULL); | 5027 ASSERT(function_return() != NULL); |
4995 ASSERT(call_context()->IsEffect() || call_context()->IsValue()); | 5028 HValue* return_value = function_state()->is_construct() |
4996 if (call_context()->IsEffect()) { | 5029 ? receiver |
4997 current_block()->Goto(function_return(), drop_extra); | 5030 : undefined; |
4998 } else { | 5031 current_block()->AddLeaveInlined(return_value, |
4999 current_block()->AddLeaveInlined(undefined, | 5032 function_return(), |
5000 function_return(), | 5033 function_state()->drop_extra()); |
5001 drop_extra); | 5034 } else if (call_context()->IsEffect()) { |
5002 } | 5035 ASSERT(function_return() != NULL); |
| 5036 current_block()->Goto(function_return(), function_state()->drop_extra()); |
5003 } else { | 5037 } else { |
5004 // The graph builder assumes control can reach both branches of a | |
5005 // test, so we materialize the undefined value and test it rather than | |
5006 // simply jumping to the false target. | |
5007 // | |
5008 // TODO(3168478): refactor to avoid this. | |
5009 ASSERT(call_context()->IsTest()); | 5038 ASSERT(call_context()->IsTest()); |
5010 HBasicBlock* empty_true = graph()->CreateBasicBlock(); | 5039 ASSERT(inlined_test_context() != NULL); |
5011 HBasicBlock* empty_false = graph()->CreateBasicBlock(); | 5040 HBasicBlock* target = function_state()->is_construct() |
5012 HBranch* test = new(zone()) HBranch(undefined, empty_true, empty_false); | 5041 ? inlined_test_context()->if_true() |
5013 current_block()->Finish(test); | 5042 : inlined_test_context()->if_false(); |
5014 | 5043 current_block()->Goto(target, function_state()->drop_extra()); |
5015 empty_true->Goto(inlined_test_context()->if_true(), drop_extra); | |
5016 empty_false->Goto(inlined_test_context()->if_false(), drop_extra); | |
5017 } | 5044 } |
5018 } | 5045 } |
5019 | 5046 |
5020 // Fix up the function exits. | 5047 // Fix up the function exits. |
5021 if (inlined_test_context() != NULL) { | 5048 if (inlined_test_context() != NULL) { |
5022 HBasicBlock* if_true = inlined_test_context()->if_true(); | 5049 HBasicBlock* if_true = inlined_test_context()->if_true(); |
5023 HBasicBlock* if_false = inlined_test_context()->if_false(); | 5050 HBasicBlock* if_false = inlined_test_context()->if_false(); |
5024 | 5051 |
5025 // Pop the return test context from the expression context stack. | 5052 // Pop the return test context from the expression context stack. |
5026 ASSERT(ast_context() == inlined_test_context()); | 5053 ASSERT(ast_context() == inlined_test_context()); |
5027 ClearInlinedTestContext(); | 5054 ClearInlinedTestContext(); |
5028 delete target_state; | 5055 delete target_state; |
5029 | 5056 |
5030 // Forward to the real test context. | 5057 // Forward to the real test context. |
5031 if (if_true->HasPredecessor()) { | 5058 if (if_true->HasPredecessor()) { |
5032 if_true->SetJoinId(expr->id()); | 5059 if_true->SetJoinId(ast_id); |
5033 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); | 5060 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); |
5034 if_true->Goto(true_target, function_state()->drop_extra()); | 5061 if_true->Goto(true_target, function_state()->drop_extra()); |
5035 } | 5062 } |
5036 if (if_false->HasPredecessor()) { | 5063 if (if_false->HasPredecessor()) { |
5037 if_false->SetJoinId(expr->id()); | 5064 if_false->SetJoinId(ast_id); |
5038 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); | 5065 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); |
5039 if_false->Goto(false_target, function_state()->drop_extra()); | 5066 if_false->Goto(false_target, function_state()->drop_extra()); |
5040 } | 5067 } |
5041 set_current_block(NULL); | 5068 set_current_block(NULL); |
5042 return true; | 5069 return true; |
5043 | 5070 |
5044 } else if (function_return()->HasPredecessor()) { | 5071 } else if (function_return()->HasPredecessor()) { |
5045 function_return()->SetJoinId(expr->id()); | 5072 function_return()->SetJoinId(ast_id); |
5046 set_current_block(function_return()); | 5073 set_current_block(function_return()); |
5047 } else { | 5074 } else { |
5048 set_current_block(NULL); | 5075 set_current_block(NULL); |
5049 } | 5076 } |
5050 delete target_state; | 5077 delete target_state; |
5051 return true; | 5078 return true; |
5052 } | 5079 } |
5053 | 5080 |
5054 | 5081 |
| 5082 bool HGraphBuilder::TryInlineCall(Call* expr, bool drop_extra) { |
| 5083 // The function call we are inlining is a method call if the call |
| 5084 // is a property call. |
| 5085 CallKind call_kind = (expr->expression()->AsProperty() == NULL) |
| 5086 ? CALL_AS_FUNCTION |
| 5087 : CALL_AS_METHOD; |
| 5088 |
| 5089 return TryInline(call_kind, |
| 5090 expr->target(), |
| 5091 expr->arguments(), |
| 5092 NULL, |
| 5093 expr->id(), |
| 5094 expr->ReturnId(), |
| 5095 drop_extra ? DROP_EXTRA_ON_RETURN : NORMAL_RETURN); |
| 5096 } |
| 5097 |
| 5098 |
| 5099 bool HGraphBuilder::TryInlineConstruct(CallNew* expr, HValue* receiver) { |
| 5100 return TryInline(CALL_AS_FUNCTION, |
| 5101 expr->target(), |
| 5102 expr->arguments(), |
| 5103 receiver, |
| 5104 expr->id(), |
| 5105 expr->ReturnId(), |
| 5106 CONSTRUCT_CALL_RETURN); |
| 5107 } |
| 5108 |
| 5109 |
5055 bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr, | 5110 bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr, |
5056 HValue* receiver, | 5111 HValue* receiver, |
5057 Handle<Map> receiver_map, | 5112 Handle<Map> receiver_map, |
5058 CheckType check_type) { | 5113 CheckType check_type) { |
5059 ASSERT(check_type != RECEIVER_MAP_CHECK || !receiver_map.is_null()); | 5114 ASSERT(check_type != RECEIVER_MAP_CHECK || !receiver_map.is_null()); |
5060 // Try to inline calls like Math.* as operations in the calling function. | 5115 // Try to inline calls like Math.* as operations in the calling function. |
5061 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; | 5116 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; |
5062 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); | 5117 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); |
5063 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 5118 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
5064 switch (id) { | 5119 switch (id) { |
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5328 expr->check_type() != RECEIVER_MAP_CHECK) { | 5383 expr->check_type() != RECEIVER_MAP_CHECK) { |
5329 // When the target has a custom call IC generator, use the IC, | 5384 // When the target has a custom call IC generator, use the IC, |
5330 // because it is likely to generate better code. Also use the IC | 5385 // because it is likely to generate better code. Also use the IC |
5331 // when a primitive receiver check is required. | 5386 // when a primitive receiver check is required. |
5332 HValue* context = environment()->LookupContext(); | 5387 HValue* context = environment()->LookupContext(); |
5333 call = PreProcessCall( | 5388 call = PreProcessCall( |
5334 new(zone()) HCallNamed(context, name, argument_count)); | 5389 new(zone()) HCallNamed(context, name, argument_count)); |
5335 } else { | 5390 } else { |
5336 AddCheckConstantFunction(expr, receiver, receiver_map, true); | 5391 AddCheckConstantFunction(expr, receiver, receiver_map, true); |
5337 | 5392 |
5338 if (TryInline(expr)) return; | 5393 if (TryInlineCall(expr)) return; |
5339 call = PreProcessCall( | 5394 call = PreProcessCall( |
5340 new(zone()) HCallConstantFunction(expr->target(), | 5395 new(zone()) HCallConstantFunction(expr->target(), |
5341 argument_count)); | 5396 argument_count)); |
5342 } | 5397 } |
5343 } else if (types != NULL && types->length() > 1) { | 5398 } else if (types != NULL && types->length() > 1) { |
5344 ASSERT(expr->check_type() == RECEIVER_MAP_CHECK); | 5399 ASSERT(expr->check_type() == RECEIVER_MAP_CHECK); |
5345 HandlePolymorphicCallNamed(expr, receiver, types, name); | 5400 HandlePolymorphicCallNamed(expr, receiver, types, name); |
5346 return; | 5401 return; |
5347 | 5402 |
5348 } else { | 5403 } else { |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5384 // Replace the global object with the global receiver. | 5439 // Replace the global object with the global receiver. |
5385 HGlobalReceiver* global_receiver = | 5440 HGlobalReceiver* global_receiver = |
5386 new(zone()) HGlobalReceiver(global_object); | 5441 new(zone()) HGlobalReceiver(global_object); |
5387 // Index of the receiver from the top of the expression stack. | 5442 // Index of the receiver from the top of the expression stack. |
5388 const int receiver_index = argument_count - 1; | 5443 const int receiver_index = argument_count - 1; |
5389 AddInstruction(global_receiver); | 5444 AddInstruction(global_receiver); |
5390 ASSERT(environment()->ExpressionStackAt(receiver_index)-> | 5445 ASSERT(environment()->ExpressionStackAt(receiver_index)-> |
5391 IsGlobalObject()); | 5446 IsGlobalObject()); |
5392 environment()->SetExpressionStackAt(receiver_index, global_receiver); | 5447 environment()->SetExpressionStackAt(receiver_index, global_receiver); |
5393 | 5448 |
5394 if (TryInline(expr)) return; | 5449 if (TryInlineCall(expr)) return; |
5395 call = PreProcessCall(new(zone()) HCallKnownGlobal(expr->target(), | 5450 call = PreProcessCall(new(zone()) HCallKnownGlobal(expr->target(), |
5396 argument_count)); | 5451 argument_count)); |
5397 } else { | 5452 } else { |
5398 HValue* context = environment()->LookupContext(); | 5453 HValue* context = environment()->LookupContext(); |
5399 HGlobalObject* receiver = new(zone()) HGlobalObject(context); | 5454 HGlobalObject* receiver = new(zone()) HGlobalObject(context); |
5400 AddInstruction(receiver); | 5455 AddInstruction(receiver); |
5401 PushAndAdd(new(zone()) HPushArgument(receiver)); | 5456 PushAndAdd(new(zone()) HPushArgument(receiver)); |
5402 CHECK_ALIVE(VisitArgumentList(expr->arguments())); | 5457 CHECK_ALIVE(VisitArgumentList(expr->arguments())); |
5403 | 5458 |
5404 call = new(zone()) HCallGlobal(context, var->name(), argument_count); | 5459 call = new(zone()) HCallGlobal(context, var->name(), argument_count); |
5405 Drop(argument_count); | 5460 Drop(argument_count); |
5406 } | 5461 } |
5407 | 5462 |
5408 } else if (expr->IsMonomorphic()) { | 5463 } else if (expr->IsMonomorphic()) { |
5409 // The function is on the stack in the unoptimized code during | 5464 // The function is on the stack in the unoptimized code during |
5410 // evaluation of the arguments. | 5465 // evaluation of the arguments. |
5411 CHECK_ALIVE(VisitForValue(expr->expression())); | 5466 CHECK_ALIVE(VisitForValue(expr->expression())); |
5412 HValue* function = Top(); | 5467 HValue* function = Top(); |
5413 HValue* context = environment()->LookupContext(); | 5468 HValue* context = environment()->LookupContext(); |
5414 HGlobalObject* global = new(zone()) HGlobalObject(context); | 5469 HGlobalObject* global = new(zone()) HGlobalObject(context); |
5415 HGlobalReceiver* receiver = new(zone()) HGlobalReceiver(global); | 5470 HGlobalReceiver* receiver = new(zone()) HGlobalReceiver(global); |
5416 AddInstruction(global); | 5471 AddInstruction(global); |
5417 PushAndAdd(receiver); | 5472 PushAndAdd(receiver); |
5418 CHECK_ALIVE(VisitExpressions(expr->arguments())); | 5473 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
5419 AddInstruction(new(zone()) HCheckFunction(function, expr->target())); | 5474 AddInstruction(new(zone()) HCheckFunction(function, expr->target())); |
5420 if (TryInline(expr, true)) { // Drop function from environment. | 5475 if (TryInlineCall(expr, true)) { // Drop function from environment. |
5421 return; | 5476 return; |
5422 } else { | 5477 } else { |
5423 call = PreProcessCall(new(zone()) HInvokeFunction(context, | 5478 call = PreProcessCall(new(zone()) HInvokeFunction(context, |
5424 function, | 5479 function, |
5425 argument_count)); | 5480 argument_count)); |
5426 Drop(1); // The function. | 5481 Drop(1); // The function. |
5427 } | 5482 } |
5428 | 5483 |
5429 } else { | 5484 } else { |
5430 CHECK_ALIVE(VisitForValue(expr->expression())); | 5485 CHECK_ALIVE(VisitForValue(expr->expression())); |
5431 HValue* function = Top(); | 5486 HValue* function = Top(); |
5432 HValue* context = environment()->LookupContext(); | 5487 HValue* context = environment()->LookupContext(); |
5433 HGlobalObject* global_object = new(zone()) HGlobalObject(context); | 5488 HGlobalObject* global_object = new(zone()) HGlobalObject(context); |
5434 HGlobalReceiver* receiver = new(zone()) HGlobalReceiver(global_object); | 5489 HGlobalReceiver* receiver = new(zone()) HGlobalReceiver(global_object); |
5435 AddInstruction(global_object); | 5490 AddInstruction(global_object); |
5436 AddInstruction(receiver); | 5491 AddInstruction(receiver); |
5437 PushAndAdd(new(zone()) HPushArgument(receiver)); | 5492 PushAndAdd(new(zone()) HPushArgument(receiver)); |
5438 CHECK_ALIVE(VisitArgumentList(expr->arguments())); | 5493 CHECK_ALIVE(VisitArgumentList(expr->arguments())); |
5439 | 5494 |
5440 call = new(zone()) HCallFunction(context, function, argument_count); | 5495 call = new(zone()) HCallFunction(context, function, argument_count); |
5441 Drop(argument_count + 1); | 5496 Drop(argument_count + 1); |
5442 } | 5497 } |
5443 } | 5498 } |
5444 | 5499 |
5445 call->set_position(expr->position()); | 5500 call->set_position(expr->position()); |
5446 return ast_context()->ReturnInstruction(call, expr->id()); | 5501 return ast_context()->ReturnInstruction(call, expr->id()); |
5447 } | 5502 } |
5448 | 5503 |
5449 | 5504 |
| 5505 // Checks whether allocation using the given constructor can be inlined. |
| 5506 static bool IsAllocationInlineable(Handle<JSFunction> constructor) { |
| 5507 return constructor->has_initial_map() && |
| 5508 constructor->initial_map()->instance_type() == JS_OBJECT_TYPE; |
| 5509 } |
| 5510 |
| 5511 |
5450 void HGraphBuilder::VisitCallNew(CallNew* expr) { | 5512 void HGraphBuilder::VisitCallNew(CallNew* expr) { |
5451 ASSERT(!HasStackOverflow()); | 5513 ASSERT(!HasStackOverflow()); |
5452 ASSERT(current_block() != NULL); | 5514 ASSERT(current_block() != NULL); |
5453 ASSERT(current_block()->HasPredecessor()); | 5515 ASSERT(current_block()->HasPredecessor()); |
5454 // The constructor function is also used as the receiver argument to the | 5516 expr->RecordTypeFeedback(oracle()); |
5455 // JS construct call builtin. | 5517 int argument_count = expr->arguments()->length() + 1; // Plus constructor. |
5456 HValue* constructor = NULL; | |
5457 CHECK_ALIVE(constructor = VisitArgument(expr->expression())); | |
5458 CHECK_ALIVE(VisitArgumentList(expr->arguments())); | |
5459 | |
5460 HValue* context = environment()->LookupContext(); | 5518 HValue* context = environment()->LookupContext(); |
5461 | 5519 |
5462 // The constructor is both an operand to the instruction and an argument | 5520 if (FLAG_inline_construct && |
5463 // to the construct call. | 5521 expr->IsMonomorphic() && |
5464 int arg_count = expr->arguments()->length() + 1; // Plus constructor. | 5522 IsAllocationInlineable(expr->target())) { |
5465 HCallNew* call = new(zone()) HCallNew(context, constructor, arg_count); | 5523 // The constructor function is on the stack in the unoptimized code |
5466 call->set_position(expr->position()); | 5524 // during evaluation of the arguments. |
5467 Drop(arg_count); | 5525 CHECK_ALIVE(VisitForValue(expr->expression())); |
5468 return ast_context()->ReturnInstruction(call, expr->id()); | 5526 HValue* function = Top(); |
| 5527 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
| 5528 Handle<JSFunction> constructor = expr->target(); |
| 5529 AddInstruction(new(zone()) HCheckFunction(function, constructor)); |
| 5530 |
| 5531 // Replace the constructor function with a newly allocated receiver. |
| 5532 HInstruction* receiver = new(zone()) HAllocateObject(context, constructor); |
| 5533 // Index of the receiver from the top of the expression stack. |
| 5534 const int receiver_index = argument_count - 1; |
| 5535 AddInstruction(receiver); |
| 5536 ASSERT(environment()->ExpressionStackAt(receiver_index) == function); |
| 5537 environment()->SetExpressionStackAt(receiver_index, receiver); |
| 5538 |
| 5539 if (TryInlineConstruct(expr, receiver)) return; |
| 5540 |
| 5541 // TODO(mstarzinger): For now we remove the previous HAllocateObject and |
| 5542 // add HPushArgument for the arguments in case inlining failed. What we |
| 5543 // actually should do is emit HInvokeFunction on the constructor instead |
| 5544 // of using HCallNew as a fallback. |
| 5545 receiver->DeleteAndReplaceWith(NULL); |
| 5546 environment()->SetExpressionStackAt(receiver_index, function); |
| 5547 HInstruction* call = PreProcessCall( |
| 5548 new(zone()) HCallNew(context, function, argument_count)); |
| 5549 call->set_position(expr->position()); |
| 5550 return ast_context()->ReturnInstruction(call, expr->id()); |
| 5551 } else { |
| 5552 // The constructor function is both an operand to the instruction and an |
| 5553 // argument to the construct call. |
| 5554 HValue* constructor = NULL; |
| 5555 CHECK_ALIVE(constructor = VisitArgument(expr->expression())); |
| 5556 CHECK_ALIVE(VisitArgumentList(expr->arguments())); |
| 5557 HInstruction* call = |
| 5558 new(zone()) HCallNew(context, constructor, argument_count); |
| 5559 Drop(argument_count); |
| 5560 call->set_position(expr->position()); |
| 5561 return ast_context()->ReturnInstruction(call, expr->id()); |
| 5562 } |
5469 } | 5563 } |
5470 | 5564 |
5471 | 5565 |
5472 // Support for generating inlined runtime functions. | 5566 // Support for generating inlined runtime functions. |
5473 | 5567 |
5474 // Lookup table for generators for runtime calls that are generated inline. | 5568 // Lookup table for generators for runtime calls that are generated inline. |
5475 // Elements of the table are member pointers to functions of HGraphBuilder. | 5569 // Elements of the table are member pointers to functions of HGraphBuilder. |
5476 #define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \ | 5570 #define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \ |
5477 &HGraphBuilder::Generate##Name, | 5571 &HGraphBuilder::Generate##Name, |
5478 | 5572 |
(...skipping 1024 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6503 CallRuntime* call) { | 6597 CallRuntime* call) { |
6504 return Bailout( | 6598 return Bailout( |
6505 "inlined runtime function: IsStringWrapperSafeForDefaultValueOf"); | 6599 "inlined runtime function: IsStringWrapperSafeForDefaultValueOf"); |
6506 } | 6600 } |
6507 | 6601 |
6508 | 6602 |
6509 // Support for construct call checks. | 6603 // Support for construct call checks. |
6510 void HGraphBuilder::GenerateIsConstructCall(CallRuntime* call) { | 6604 void HGraphBuilder::GenerateIsConstructCall(CallRuntime* call) { |
6511 ASSERT(call->arguments()->length() == 0); | 6605 ASSERT(call->arguments()->length() == 0); |
6512 if (function_state()->outer() != NULL) { | 6606 if (function_state()->outer() != NULL) { |
6513 // We are generating graph for inlined function. Currently | 6607 // We are generating graph for inlined function. |
6514 // constructor inlining is not supported and we can just return | 6608 HValue* value = function_state()->is_construct() |
6515 // false from %_IsConstructCall(). | 6609 ? graph()->GetConstantTrue() |
6516 return ast_context()->ReturnValue(graph()->GetConstantFalse()); | 6610 : graph()->GetConstantFalse(); |
| 6611 return ast_context()->ReturnValue(value); |
6517 } else { | 6612 } else { |
6518 return ast_context()->ReturnControl(new(zone()) HIsConstructCallAndBranch, | 6613 return ast_context()->ReturnControl(new(zone()) HIsConstructCallAndBranch, |
6519 call->id()); | 6614 call->id()); |
6520 } | 6615 } |
6521 } | 6616 } |
6522 | 6617 |
6523 | 6618 |
6524 // Support for arguments.length and arguments[?]. | 6619 // Support for arguments.length and arguments[?]. |
6525 void HGraphBuilder::GenerateArgumentsLength(CallRuntime* call) { | 6620 void HGraphBuilder::GenerateArgumentsLength(CallRuntime* call) { |
6526 // Our implementation of arguments (based on this stack frame or an | 6621 // Our implementation of arguments (based on this stack frame or an |
(...skipping 367 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6894 #undef CHECK_BAILOUT | 6989 #undef CHECK_BAILOUT |
6895 #undef CHECK_ALIVE | 6990 #undef CHECK_ALIVE |
6896 | 6991 |
6897 | 6992 |
6898 HEnvironment::HEnvironment(HEnvironment* outer, | 6993 HEnvironment::HEnvironment(HEnvironment* outer, |
6899 Scope* scope, | 6994 Scope* scope, |
6900 Handle<JSFunction> closure) | 6995 Handle<JSFunction> closure) |
6901 : closure_(closure), | 6996 : closure_(closure), |
6902 values_(0), | 6997 values_(0), |
6903 assigned_variables_(4), | 6998 assigned_variables_(4), |
| 6999 frame_type_(JS_FUNCTION), |
6904 parameter_count_(0), | 7000 parameter_count_(0), |
6905 specials_count_(1), | 7001 specials_count_(1), |
6906 local_count_(0), | 7002 local_count_(0), |
6907 outer_(outer), | 7003 outer_(outer), |
6908 pop_count_(0), | 7004 pop_count_(0), |
6909 push_count_(0), | 7005 push_count_(0), |
6910 ast_id_(AstNode::kNoNumber), | 7006 ast_id_(AstNode::kNoNumber) { |
6911 arguments_adaptor_(false) { | |
6912 Initialize(scope->num_parameters() + 1, scope->num_stack_slots(), 0); | 7007 Initialize(scope->num_parameters() + 1, scope->num_stack_slots(), 0); |
6913 } | 7008 } |
6914 | 7009 |
6915 | 7010 |
6916 HEnvironment::HEnvironment(const HEnvironment* other) | 7011 HEnvironment::HEnvironment(const HEnvironment* other) |
6917 : values_(0), | 7012 : values_(0), |
6918 assigned_variables_(0), | 7013 assigned_variables_(0), |
| 7014 frame_type_(JS_FUNCTION), |
6919 parameter_count_(0), | 7015 parameter_count_(0), |
6920 specials_count_(1), | 7016 specials_count_(1), |
6921 local_count_(0), | 7017 local_count_(0), |
6922 outer_(NULL), | 7018 outer_(NULL), |
6923 pop_count_(0), | 7019 pop_count_(0), |
6924 push_count_(0), | 7020 push_count_(0), |
6925 ast_id_(other->ast_id()), | 7021 ast_id_(other->ast_id()) { |
6926 arguments_adaptor_(false) { | |
6927 Initialize(other); | 7022 Initialize(other); |
6928 } | 7023 } |
6929 | 7024 |
6930 | 7025 |
6931 HEnvironment::HEnvironment(HEnvironment* outer, | 7026 HEnvironment::HEnvironment(HEnvironment* outer, |
6932 Handle<JSFunction> closure, | 7027 Handle<JSFunction> closure, |
| 7028 FrameType frame_type, |
6933 int arguments) | 7029 int arguments) |
6934 : closure_(closure), | 7030 : closure_(closure), |
6935 values_(arguments), | 7031 values_(arguments), |
6936 assigned_variables_(0), | 7032 assigned_variables_(0), |
| 7033 frame_type_(frame_type), |
6937 parameter_count_(arguments), | 7034 parameter_count_(arguments), |
6938 local_count_(0), | 7035 local_count_(0), |
6939 outer_(outer), | 7036 outer_(outer), |
6940 pop_count_(0), | 7037 pop_count_(0), |
6941 push_count_(0), | 7038 push_count_(0), |
6942 ast_id_(AstNode::kNoNumber), | 7039 ast_id_(AstNode::kNoNumber) { |
6943 arguments_adaptor_(true) { | |
6944 } | 7040 } |
6945 | 7041 |
6946 | 7042 |
6947 void HEnvironment::Initialize(int parameter_count, | 7043 void HEnvironment::Initialize(int parameter_count, |
6948 int local_count, | 7044 int local_count, |
6949 int stack_height) { | 7045 int stack_height) { |
6950 parameter_count_ = parameter_count; | 7046 parameter_count_ = parameter_count; |
6951 local_count_ = local_count; | 7047 local_count_ = local_count; |
6952 | 7048 |
6953 // Avoid reallocating the temporaries' backing store on the first Push. | 7049 // Avoid reallocating the temporaries' backing store on the first Push. |
6954 int total = parameter_count + specials_count_ + local_count + stack_height; | 7050 int total = parameter_count + specials_count_ + local_count + stack_height; |
6955 values_.Initialize(total + 4); | 7051 values_.Initialize(total + 4); |
6956 for (int i = 0; i < total; ++i) values_.Add(NULL); | 7052 for (int i = 0; i < total; ++i) values_.Add(NULL); |
6957 } | 7053 } |
6958 | 7054 |
6959 | 7055 |
6960 void HEnvironment::Initialize(const HEnvironment* other) { | 7056 void HEnvironment::Initialize(const HEnvironment* other) { |
6961 closure_ = other->closure(); | 7057 closure_ = other->closure(); |
6962 values_.AddAll(other->values_); | 7058 values_.AddAll(other->values_); |
6963 assigned_variables_.AddAll(other->assigned_variables_); | 7059 assigned_variables_.AddAll(other->assigned_variables_); |
| 7060 frame_type_ = other->frame_type_; |
6964 parameter_count_ = other->parameter_count_; | 7061 parameter_count_ = other->parameter_count_; |
6965 local_count_ = other->local_count_; | 7062 local_count_ = other->local_count_; |
6966 if (other->outer_ != NULL) outer_ = other->outer_->Copy(); // Deep copy. | 7063 if (other->outer_ != NULL) outer_ = other->outer_->Copy(); // Deep copy. |
6967 pop_count_ = other->pop_count_; | 7064 pop_count_ = other->pop_count_; |
6968 push_count_ = other->push_count_; | 7065 push_count_ = other->push_count_; |
6969 ast_id_ = other->ast_id_; | 7066 ast_id_ = other->ast_id_; |
6970 arguments_adaptor_ = other->arguments_adaptor_; | |
6971 } | 7067 } |
6972 | 7068 |
6973 | 7069 |
6974 void HEnvironment::AddIncomingEdge(HBasicBlock* block, HEnvironment* other) { | 7070 void HEnvironment::AddIncomingEdge(HBasicBlock* block, HEnvironment* other) { |
6975 ASSERT(!block->IsLoopHeader()); | 7071 ASSERT(!block->IsLoopHeader()); |
6976 ASSERT(values_.length() == other->values_.length()); | 7072 ASSERT(values_.length() == other->values_.length()); |
6977 | 7073 |
6978 int length = values_.length(); | 7074 int length = values_.length(); |
6979 for (int i = 0; i < length; ++i) { | 7075 for (int i = 0; i < length; ++i) { |
6980 HValue* value = values_[i]; | 7076 HValue* value = values_[i]; |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7062 HPhi* phi = new(loop_header->zone()) HPhi(i); | 7158 HPhi* phi = new(loop_header->zone()) HPhi(i); |
7063 phi->AddInput(values_[i]); | 7159 phi->AddInput(values_[i]); |
7064 new_env->values_[i] = phi; | 7160 new_env->values_[i] = phi; |
7065 loop_header->AddPhi(phi); | 7161 loop_header->AddPhi(phi); |
7066 } | 7162 } |
7067 new_env->ClearHistory(); | 7163 new_env->ClearHistory(); |
7068 return new_env; | 7164 return new_env; |
7069 } | 7165 } |
7070 | 7166 |
7071 | 7167 |
| 7168 HEnvironment* HEnvironment::CreateStubEnvironment(HEnvironment* outer, |
| 7169 Handle<JSFunction> target, |
| 7170 FrameType frame_type, |
| 7171 int arguments) const { |
| 7172 HEnvironment* new_env = new(closure()->GetIsolate()->zone()) |
| 7173 HEnvironment(outer, target, frame_type, arguments + 1); |
| 7174 for (int i = 0; i <= arguments; ++i) { // Include receiver. |
| 7175 new_env->Push(ExpressionStackAt(arguments - i)); |
| 7176 } |
| 7177 new_env->ClearHistory(); |
| 7178 return new_env; |
| 7179 } |
| 7180 |
| 7181 |
7072 HEnvironment* HEnvironment::CopyForInlining( | 7182 HEnvironment* HEnvironment::CopyForInlining( |
7073 Handle<JSFunction> target, | 7183 Handle<JSFunction> target, |
7074 int arguments, | 7184 int arguments, |
7075 FunctionLiteral* function, | 7185 FunctionLiteral* function, |
7076 HConstant* undefined, | 7186 HConstant* undefined, |
7077 CallKind call_kind) const { | 7187 CallKind call_kind, |
7078 ASSERT(!is_arguments_adaptor()); | 7188 bool is_construct) const { |
| 7189 ASSERT(frame_type() == JS_FUNCTION); |
7079 | 7190 |
7080 Zone* zone = closure()->GetIsolate()->zone(); | 7191 Zone* zone = closure()->GetIsolate()->zone(); |
7081 | 7192 |
7082 // Outer environment is a copy of this one without the arguments. | 7193 // Outer environment is a copy of this one without the arguments. |
7083 int arity = function->scope()->num_parameters(); | 7194 int arity = function->scope()->num_parameters(); |
7084 | 7195 |
7085 HEnvironment* outer = Copy(); | 7196 HEnvironment* outer = Copy(); |
7086 outer->Drop(arguments + 1); // Including receiver. | 7197 outer->Drop(arguments + 1); // Including receiver. |
7087 outer->ClearHistory(); | 7198 outer->ClearHistory(); |
7088 | 7199 |
| 7200 if (is_construct) { |
| 7201 // Create artificial constructor stub environment. The receiver should |
| 7202 // actually be the constructor function, but we pass the newly allocated |
| 7203 // object instead, DoComputeConstructStubFrame() relies on that. |
| 7204 outer = CreateStubEnvironment(outer, target, JS_CONSTRUCT, arguments); |
| 7205 } |
| 7206 |
7089 if (arity != arguments) { | 7207 if (arity != arguments) { |
7090 // Create artificial arguments adaptation environment. | 7208 // Create artificial arguments adaptation environment. |
7091 outer = new(zone) HEnvironment(outer, target, arguments + 1); | 7209 outer = CreateStubEnvironment(outer, target, ARGUMENTS_ADAPTOR, arguments); |
7092 for (int i = 0; i <= arguments; ++i) { // Include receiver. | |
7093 outer->Push(ExpressionStackAt(arguments - i)); | |
7094 } | |
7095 outer->ClearHistory(); | |
7096 } | 7210 } |
7097 | 7211 |
7098 HEnvironment* inner = | 7212 HEnvironment* inner = |
7099 new(zone) HEnvironment(outer, function->scope(), target); | 7213 new(zone) HEnvironment(outer, function->scope(), target); |
7100 // Get the argument values from the original environment. | 7214 // Get the argument values from the original environment. |
7101 for (int i = 0; i <= arity; ++i) { // Include receiver. | 7215 for (int i = 0; i <= arity; ++i) { // Include receiver. |
7102 HValue* push = (i <= arguments) ? | 7216 HValue* push = (i <= arguments) ? |
7103 ExpressionStackAt(arguments - i) : undefined; | 7217 ExpressionStackAt(arguments - i) : undefined; |
7104 inner->SetValueAt(i, push); | 7218 inner->SetValueAt(i, push); |
7105 } | 7219 } |
(...skipping 347 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7453 } | 7567 } |
7454 } | 7568 } |
7455 | 7569 |
7456 #ifdef DEBUG | 7570 #ifdef DEBUG |
7457 if (graph_ != NULL) graph_->Verify(false); // No full verify. | 7571 if (graph_ != NULL) graph_->Verify(false); // No full verify. |
7458 if (allocator_ != NULL) allocator_->Verify(); | 7572 if (allocator_ != NULL) allocator_->Verify(); |
7459 #endif | 7573 #endif |
7460 } | 7574 } |
7461 | 7575 |
7462 } } // namespace v8::internal | 7576 } } // namespace v8::internal |
OLD | NEW |