Chromium Code Reviews| 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, false, false), |
|
Vyacheslav Egorov (Chromium)
2012/02/13 15:01:39
I think we should come up with enum at least for i
Michael Starzinger
2012/02/27 14:16:32
Done. Merged drop_extra and is_construct into one
| |
| 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 bool drop_extra, |
| 2030 bool is_construct) | |
| 2030 : owner_(owner), | 2031 : owner_(owner), |
| 2031 compilation_info_(info), | 2032 compilation_info_(info), |
| 2032 oracle_(oracle), | 2033 oracle_(oracle), |
| 2033 call_context_(NULL), | 2034 call_context_(NULL), |
| 2034 drop_extra_(drop_extra), | 2035 drop_extra_(drop_extra), |
| 2036 is_construct_(is_construct), | |
| 2035 function_return_(NULL), | 2037 function_return_(NULL), |
| 2036 test_context_(NULL), | 2038 test_context_(NULL), |
| 2037 outer_(owner->function_state()) { | 2039 outer_(owner->function_state()) { |
| 2038 if (outer_ != NULL) { | 2040 if (outer_ != NULL) { |
| 2039 // State for an inline function. | 2041 // State for an inline function. |
| 2040 if (owner->ast_context()->IsTest()) { | 2042 if (owner->ast_context()->IsTest()) { |
| 2041 HBasicBlock* if_true = owner->graph()->CreateBasicBlock(); | 2043 HBasicBlock* if_true = owner->graph()->CreateBasicBlock(); |
| 2042 HBasicBlock* if_false = owner->graph()->CreateBasicBlock(); | 2044 HBasicBlock* if_false = owner->graph()->CreateBasicBlock(); |
| 2043 if_true->MarkAsInlineReturnTarget(); | 2045 if_true->MarkAsInlineReturnTarget(); |
| 2044 if_false->MarkAsInlineReturnTarget(); | 2046 if_false->MarkAsInlineReturnTarget(); |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 2067 | 2069 |
| 2068 // Implementation of utility classes to represent an expression's context in | 2070 // Implementation of utility classes to represent an expression's context in |
| 2069 // the AST. | 2071 // the AST. |
| 2070 AstContext::AstContext(HGraphBuilder* owner, Expression::Context kind) | 2072 AstContext::AstContext(HGraphBuilder* owner, Expression::Context kind) |
| 2071 : owner_(owner), | 2073 : owner_(owner), |
| 2072 kind_(kind), | 2074 kind_(kind), |
| 2073 outer_(owner->ast_context()), | 2075 outer_(owner->ast_context()), |
| 2074 for_typeof_(false) { | 2076 for_typeof_(false) { |
| 2075 owner->set_ast_context(this); // Push. | 2077 owner->set_ast_context(this); // Push. |
| 2076 #ifdef DEBUG | 2078 #ifdef DEBUG |
| 2077 ASSERT(!owner->environment()->is_arguments_adaptor()); | 2079 ASSERT(owner->environment()->frame_type() == JS_FUNCTION); |
| 2078 original_length_ = owner->environment()->length(); | 2080 original_length_ = owner->environment()->length(); |
| 2079 #endif | 2081 #endif |
| 2080 } | 2082 } |
| 2081 | 2083 |
| 2082 | 2084 |
| 2083 AstContext::~AstContext() { | 2085 AstContext::~AstContext() { |
| 2084 owner_->set_ast_context(outer_); // Pop. | 2086 owner_->set_ast_context(outer_); // Pop. |
| 2085 } | 2087 } |
| 2086 | 2088 |
| 2087 | 2089 |
| 2088 EffectContext::~EffectContext() { | 2090 EffectContext::~EffectContext() { |
| 2089 ASSERT(owner()->HasStackOverflow() || | 2091 ASSERT(owner()->HasStackOverflow() || |
| 2090 owner()->current_block() == NULL || | 2092 owner()->current_block() == NULL || |
| 2091 (owner()->environment()->length() == original_length_ && | 2093 (owner()->environment()->length() == original_length_ && |
| 2092 !owner()->environment()->is_arguments_adaptor())); | 2094 owner()->environment()->frame_type() == JS_FUNCTION)); |
| 2093 } | 2095 } |
| 2094 | 2096 |
| 2095 | 2097 |
| 2096 ValueContext::~ValueContext() { | 2098 ValueContext::~ValueContext() { |
| 2097 ASSERT(owner()->HasStackOverflow() || | 2099 ASSERT(owner()->HasStackOverflow() || |
| 2098 owner()->current_block() == NULL || | 2100 owner()->current_block() == NULL || |
| 2099 (owner()->environment()->length() == original_length_ + 1 && | 2101 (owner()->environment()->length() == original_length_ + 1 && |
| 2100 !owner()->environment()->is_arguments_adaptor())); | 2102 owner()->environment()->frame_type() == JS_FUNCTION)); |
| 2101 } | 2103 } |
| 2102 | 2104 |
| 2103 | 2105 |
| 2104 void EffectContext::ReturnValue(HValue* value) { | 2106 void EffectContext::ReturnValue(HValue* value) { |
| 2105 // The value is simply ignored. | 2107 // The value is simply ignored. |
| 2106 } | 2108 } |
| 2107 | 2109 |
| 2108 | 2110 |
| 2109 void ValueContext::ReturnValue(HValue* value) { | 2111 void ValueContext::ReturnValue(HValue* value) { |
| 2110 // The value is tracked in the bailout environment, and communicated | 2112 // The value is tracked in the bailout environment, and communicated |
| (...skipping 554 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2665 void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) { | 2667 void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) { |
| 2666 ASSERT(!HasStackOverflow()); | 2668 ASSERT(!HasStackOverflow()); |
| 2667 ASSERT(current_block() != NULL); | 2669 ASSERT(current_block() != NULL); |
| 2668 ASSERT(current_block()->HasPredecessor()); | 2670 ASSERT(current_block()->HasPredecessor()); |
| 2669 AstContext* context = call_context(); | 2671 AstContext* context = call_context(); |
| 2670 if (context == NULL) { | 2672 if (context == NULL) { |
| 2671 // Not an inlined return, so an actual one. | 2673 // Not an inlined return, so an actual one. |
| 2672 CHECK_ALIVE(VisitForValue(stmt->expression())); | 2674 CHECK_ALIVE(VisitForValue(stmt->expression())); |
| 2673 HValue* result = environment()->Pop(); | 2675 HValue* result = environment()->Pop(); |
| 2674 current_block()->FinishExit(new(zone()) HReturn(result)); | 2676 current_block()->FinishExit(new(zone()) HReturn(result)); |
| 2675 set_current_block(NULL); | 2677 } else if (function_state()->is_construct()) { |
| 2678 // Return from an inlined construct call. In a test context the return | |
| 2679 // value will always evaluate to true, in a value context the return value | |
| 2680 // needs to be a JSObject. | |
| 2681 if (context->IsTest()) { | |
| 2682 TestContext* test = TestContext::cast(context); | |
| 2683 CHECK_ALIVE(VisitForEffect(stmt->expression())); | |
| 2684 current_block()->Goto(test->if_true(), function_state()->drop_extra()); | |
| 2685 } else if (context->IsEffect()) { | |
| 2686 CHECK_ALIVE(VisitForEffect(stmt->expression())); | |
| 2687 current_block()->Goto(function_return(), function_state()->drop_extra()); | |
| 2688 } else { | |
| 2689 ASSERT(context->IsValue()); | |
| 2690 CHECK_ALIVE(VisitForValue(stmt->expression())); | |
| 2691 HValue* return_value = Pop(); | |
| 2692 HValue* receiver = environment()->Lookup(0); | |
| 2693 HHasInstanceTypeAndBranch* typecheck = | |
| 2694 new(zone()) HHasInstanceTypeAndBranch(return_value, | |
| 2695 FIRST_SPEC_OBJECT_TYPE, | |
| 2696 LAST_SPEC_OBJECT_TYPE); | |
| 2697 HBasicBlock* if_spec_object = graph()->CreateBasicBlock(); | |
| 2698 HBasicBlock* not_spec_object = graph()->CreateBasicBlock(); | |
| 2699 typecheck->SetSuccessorAt(0, if_spec_object); | |
| 2700 typecheck->SetSuccessorAt(1, not_spec_object); | |
| 2701 current_block()->Finish(typecheck); | |
| 2702 if_spec_object->AddLeaveInlined(return_value, | |
| 2703 function_return(), | |
| 2704 function_state()->drop_extra()); | |
| 2705 not_spec_object->AddLeaveInlined(receiver, | |
| 2706 function_return(), | |
| 2707 function_state()->drop_extra()); | |
| 2708 } | |
| 2676 } else { | 2709 } else { |
| 2677 // Return from an inlined function, visit the subexpression in the | 2710 // Return from an inlined function, visit the subexpression in the |
| 2678 // expression context of the call. | 2711 // expression context of the call. |
| 2679 if (context->IsTest()) { | 2712 if (context->IsTest()) { |
| 2680 TestContext* test = TestContext::cast(context); | 2713 TestContext* test = TestContext::cast(context); |
| 2681 VisitForControl(stmt->expression(), | 2714 VisitForControl(stmt->expression(), |
| 2682 test->if_true(), | 2715 test->if_true(), |
| 2683 test->if_false()); | 2716 test->if_false()); |
| 2684 } else if (context->IsEffect()) { | 2717 } else if (context->IsEffect()) { |
| 2685 CHECK_ALIVE(VisitForEffect(stmt->expression())); | 2718 CHECK_ALIVE(VisitForEffect(stmt->expression())); |
| 2686 current_block()->Goto(function_return(), function_state()->drop_extra()); | 2719 current_block()->Goto(function_return(), function_state()->drop_extra()); |
| 2687 } else { | 2720 } else { |
| 2688 ASSERT(context->IsValue()); | 2721 ASSERT(context->IsValue()); |
| 2689 CHECK_ALIVE(VisitForValue(stmt->expression())); | 2722 CHECK_ALIVE(VisitForValue(stmt->expression())); |
| 2690 HValue* return_value = environment()->Pop(); | 2723 HValue* return_value = Pop(); |
| 2691 current_block()->AddLeaveInlined(return_value, | 2724 current_block()->AddLeaveInlined(return_value, |
| 2692 function_return(), | 2725 function_return(), |
| 2693 function_state()->drop_extra()); | 2726 function_state()->drop_extra()); |
| 2694 } | 2727 } |
| 2695 set_current_block(NULL); | |
| 2696 } | 2728 } |
| 2729 set_current_block(NULL); | |
| 2697 } | 2730 } |
| 2698 | 2731 |
| 2699 | 2732 |
| 2700 void HGraphBuilder::VisitWithStatement(WithStatement* stmt) { | 2733 void HGraphBuilder::VisitWithStatement(WithStatement* stmt) { |
| 2701 ASSERT(!HasStackOverflow()); | 2734 ASSERT(!HasStackOverflow()); |
| 2702 ASSERT(current_block() != NULL); | 2735 ASSERT(current_block() != NULL); |
| 2703 ASSERT(current_block()->HasPredecessor()); | 2736 ASSERT(current_block()->HasPredecessor()); |
| 2704 return Bailout("WithStatement"); | 2737 return Bailout("WithStatement"); |
| 2705 } | 2738 } |
| 2706 | 2739 |
| (...skipping 1997 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4704 HCompareMap* compare = | 4737 HCompareMap* compare = |
| 4705 new(zone()) HCompareMap(receiver, map, if_true, if_false); | 4738 new(zone()) HCompareMap(receiver, map, if_true, if_false); |
| 4706 current_block()->Finish(compare); | 4739 current_block()->Finish(compare); |
| 4707 | 4740 |
| 4708 set_current_block(if_true); | 4741 set_current_block(if_true); |
| 4709 AddCheckConstantFunction(expr, receiver, map, false); | 4742 AddCheckConstantFunction(expr, receiver, map, false); |
| 4710 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { | 4743 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { |
| 4711 PrintF("Trying to inline the polymorphic call to %s\n", | 4744 PrintF("Trying to inline the polymorphic call to %s\n", |
| 4712 *name->ToCString()); | 4745 *name->ToCString()); |
| 4713 } | 4746 } |
| 4714 if (FLAG_polymorphic_inlining && TryInline(expr)) { | 4747 if (FLAG_polymorphic_inlining && TryInlineCall(expr)) { |
| 4715 // Trying to inline will signal that we should bailout from the | 4748 // Trying to inline will signal that we should bailout from the |
| 4716 // entire compilation by setting stack overflow on the visitor. | 4749 // entire compilation by setting stack overflow on the visitor. |
| 4717 if (HasStackOverflow()) return; | 4750 if (HasStackOverflow()) return; |
| 4718 } else { | 4751 } else { |
| 4719 HCallConstantFunction* call = | 4752 HCallConstantFunction* call = |
| 4720 new(zone()) HCallConstantFunction(expr->target(), argument_count); | 4753 new(zone()) HCallConstantFunction(expr->target(), argument_count); |
| 4721 call->set_position(expr->position()); | 4754 call->set_position(expr->position()); |
| 4722 PreProcessCall(call); | 4755 PreProcessCall(call); |
| 4723 AddInstruction(call); | 4756 AddInstruction(call); |
| 4724 if (!ast_context()->IsEffect()) Push(call); | 4757 if (!ast_context()->IsEffect()) Push(call); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4774 if (reason == NULL) { | 4807 if (reason == NULL) { |
| 4775 PrintF("Inlined %s called from %s.\n", *target_name, *caller_name); | 4808 PrintF("Inlined %s called from %s.\n", *target_name, *caller_name); |
| 4776 } else { | 4809 } else { |
| 4777 PrintF("Did not inline %s called from %s (%s).\n", | 4810 PrintF("Did not inline %s called from %s (%s).\n", |
| 4778 *target_name, *caller_name, reason); | 4811 *target_name, *caller_name, reason); |
| 4779 } | 4812 } |
| 4780 } | 4813 } |
| 4781 } | 4814 } |
| 4782 | 4815 |
| 4783 | 4816 |
| 4784 bool HGraphBuilder::TryInline(Call* expr, bool drop_extra) { | 4817 bool HGraphBuilder::TryInline(CallKind call_kind, |
| 4818 Handle<JSFunction> target, | |
| 4819 ZoneList<Expression*>* arguments, | |
| 4820 HValue* receiver, | |
| 4821 int ast_id, | |
| 4822 int return_id, | |
| 4823 bool drop_extra, | |
|
Vyacheslav Egorov (Chromium)
2012/02/13 15:01:39
Consider introducing enums
Michael Starzinger
2012/02/27 14:16:32
Done. Merged drop_extra and is_construct into one
| |
| 4824 bool is_construct) { | |
| 4785 if (!FLAG_use_inlining) return false; | 4825 if (!FLAG_use_inlining) return false; |
| 4786 | 4826 |
| 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 | 4827 // Precondition: call is monomorphic and we have found a target with the |
| 4794 // appropriate arity. | 4828 // appropriate arity. |
| 4795 Handle<JSFunction> caller = info()->closure(); | 4829 Handle<JSFunction> caller = info()->closure(); |
| 4796 Handle<JSFunction> target = expr->target(); | |
| 4797 Handle<SharedFunctionInfo> target_shared(target->shared()); | 4830 Handle<SharedFunctionInfo> target_shared(target->shared()); |
| 4798 | 4831 |
| 4799 // Do a quick check on source code length to avoid parsing large | 4832 // Do a quick check on source code length to avoid parsing large |
| 4800 // inlining candidates. | 4833 // inlining candidates. |
| 4801 if ((FLAG_limit_inlining && target->shared()->SourceSize() > kMaxSourceSize) | 4834 if ((FLAG_limit_inlining && target->shared()->SourceSize() > kMaxSourceSize) |
| 4802 || target->shared()->SourceSize() > kUnlimitedMaxSourceSize) { | 4835 || target->shared()->SourceSize() > kUnlimitedMaxSourceSize) { |
| 4803 TraceInline(target, caller, "target text too big"); | 4836 TraceInline(target, caller, "target text too big"); |
| 4804 return false; | 4837 return false; |
| 4805 } | 4838 } |
| 4806 | 4839 |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 4823 | 4856 |
| 4824 | 4857 |
| 4825 // Don't inline deeper than kMaxInliningLevels calls. | 4858 // Don't inline deeper than kMaxInliningLevels calls. |
| 4826 HEnvironment* env = environment(); | 4859 HEnvironment* env = environment(); |
| 4827 int current_level = 1; | 4860 int current_level = 1; |
| 4828 while (env->outer() != NULL) { | 4861 while (env->outer() != NULL) { |
| 4829 if (current_level == Compiler::kMaxInliningLevels) { | 4862 if (current_level == Compiler::kMaxInliningLevels) { |
| 4830 TraceInline(target, caller, "inline depth limit reached"); | 4863 TraceInline(target, caller, "inline depth limit reached"); |
| 4831 return false; | 4864 return false; |
| 4832 } | 4865 } |
| 4833 if (!env->outer()->is_arguments_adaptor()) { | 4866 if (env->outer()->frame_type() == JS_FUNCTION) { |
| 4834 current_level++; | 4867 current_level++; |
| 4835 } | 4868 } |
| 4836 env = env->outer(); | 4869 env = env->outer(); |
| 4837 } | 4870 } |
| 4838 | 4871 |
| 4839 // Don't inline recursive functions. | 4872 // Don't inline recursive functions. |
| 4840 for (FunctionState* state = function_state(); | 4873 for (FunctionState* state = function_state(); |
| 4841 state != NULL; | 4874 state != NULL; |
| 4842 state = state->outer()) { | 4875 state = state->outer()) { |
| 4843 if (state->compilation_info()->closure()->shared() == *target_shared) { | 4876 if (state->compilation_info()->closure()->shared() == *target_shared) { |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4934 | 4967 |
| 4935 // Save the pending call context and type feedback oracle. Set up new ones | 4968 // Save the pending call context and type feedback oracle. Set up new ones |
| 4936 // for the inlined function. | 4969 // for the inlined function. |
| 4937 ASSERT(target_shared->has_deoptimization_support()); | 4970 ASSERT(target_shared->has_deoptimization_support()); |
| 4938 TypeFeedbackOracle target_oracle( | 4971 TypeFeedbackOracle target_oracle( |
| 4939 Handle<Code>(target_shared->code()), | 4972 Handle<Code>(target_shared->code()), |
| 4940 Handle<Context>(target->context()->global_context()), | 4973 Handle<Context>(target->context()->global_context()), |
| 4941 isolate()); | 4974 isolate()); |
| 4942 // The function state is new-allocated because we need to delete it | 4975 // The function state is new-allocated because we need to delete it |
| 4943 // in two different places. | 4976 // in two different places. |
| 4944 FunctionState* target_state = | 4977 FunctionState* target_state = new FunctionState( |
| 4945 new FunctionState(this, &target_info, &target_oracle, drop_extra); | 4978 this, &target_info, &target_oracle, drop_extra, is_construct); |
| 4946 | 4979 |
| 4947 HConstant* undefined = graph()->GetConstantUndefined(); | 4980 HConstant* undefined = graph()->GetConstantUndefined(); |
| 4948 HEnvironment* inner_env = | 4981 HEnvironment* inner_env = |
| 4949 environment()->CopyForInlining(target, | 4982 environment()->CopyForInlining(target, |
| 4950 expr->arguments()->length(), | 4983 arguments->length(), |
| 4951 function, | 4984 function, |
| 4952 undefined, | 4985 undefined, |
| 4953 call_kind); | 4986 call_kind, |
| 4987 is_construct); | |
| 4954 #ifdef V8_TARGET_ARCH_IA32 | 4988 #ifdef V8_TARGET_ARCH_IA32 |
| 4955 // IA32 only, overwrite the caller's context in the deoptimization | 4989 // IA32 only, overwrite the caller's context in the deoptimization |
| 4956 // environment with the correct one. | 4990 // environment with the correct one. |
| 4957 // | 4991 // |
| 4958 // TODO(kmillikin): implement the same inlining on other platforms so we | 4992 // TODO(kmillikin): implement the same inlining on other platforms so we |
| 4959 // can remove the unsightly ifdefs in this function. | 4993 // can remove the unsightly ifdefs in this function. |
| 4960 HConstant* context = new HConstant(Handle<Context>(target->context()), | 4994 HConstant* context = new HConstant(Handle<Context>(target->context()), |
| 4961 Representation::Tagged()); | 4995 Representation::Tagged()); |
| 4962 AddInstruction(context); | 4996 AddInstruction(context); |
| 4963 inner_env->BindContext(context); | 4997 inner_env->BindContext(context); |
| 4964 #endif | 4998 #endif |
| 4965 HBasicBlock* body_entry = CreateBasicBlock(inner_env); | 4999 HBasicBlock* body_entry = CreateBasicBlock(inner_env); |
| 4966 current_block()->Goto(body_entry); | 5000 current_block()->Goto(body_entry); |
| 4967 body_entry->SetJoinId(expr->ReturnId()); | 5001 body_entry->SetJoinId(return_id); |
| 4968 set_current_block(body_entry); | 5002 set_current_block(body_entry); |
| 4969 AddInstruction(new(zone()) HEnterInlined(target, | 5003 AddInstruction(new(zone()) HEnterInlined(target, |
| 4970 expr->arguments()->length(), | 5004 arguments->length(), |
| 4971 function, | 5005 function, |
| 4972 call_kind)); | 5006 call_kind, |
| 5007 is_construct)); | |
| 4973 VisitDeclarations(target_info.scope()->declarations()); | 5008 VisitDeclarations(target_info.scope()->declarations()); |
| 4974 VisitStatements(function->body()); | 5009 VisitStatements(function->body()); |
| 4975 if (HasStackOverflow()) { | 5010 if (HasStackOverflow()) { |
| 4976 // Bail out if the inline function did, as we cannot residualize a call | 5011 // Bail out if the inline function did, as we cannot residualize a call |
| 4977 // instead. | 5012 // instead. |
| 4978 TraceInline(target, caller, "inline graph construction failed"); | 5013 TraceInline(target, caller, "inline graph construction failed"); |
| 4979 target_shared->DisableOptimization(*target); | 5014 target_shared->DisableOptimization(*target); |
| 4980 inline_bailout_ = true; | 5015 inline_bailout_ = true; |
| 4981 delete target_state; | 5016 delete target_state; |
| 4982 return true; | 5017 return true; |
| 4983 } | 5018 } |
| 4984 | 5019 |
| 4985 // Update inlined nodes count. | 5020 // Update inlined nodes count. |
| 4986 inlined_count_ += nodes_added; | 5021 inlined_count_ += nodes_added; |
| 4987 | 5022 |
| 4988 TraceInline(target, caller, NULL); | 5023 TraceInline(target, caller, NULL); |
| 4989 | 5024 |
| 4990 if (current_block() != NULL) { | 5025 if (current_block() != NULL) { |
| 4991 // Add a return of undefined if control can fall off the body. In a | 5026 // Add default return value (i.e. undefined for normals calls or the newly |
| 4992 // test context, undefined is false. | 5027 // allocated receiver for construct calls) if control can fall off the |
| 5028 // body. In a test context, undefined is false and any JSObject is true. | |
| 5029 HValue* return_value = is_construct ? receiver : undefined; | |
| 4993 if (inlined_test_context() == NULL) { | 5030 if (inlined_test_context() == NULL) { |
| 4994 ASSERT(function_return() != NULL); | 5031 ASSERT(function_return() != NULL); |
| 4995 ASSERT(call_context()->IsEffect() || call_context()->IsValue()); | 5032 ASSERT(call_context()->IsEffect() || call_context()->IsValue()); |
| 4996 if (call_context()->IsEffect()) { | 5033 if (call_context()->IsEffect()) { |
| 4997 current_block()->Goto(function_return(), drop_extra); | 5034 current_block()->Goto(function_return(), drop_extra); |
| 4998 } else { | 5035 } else { |
| 4999 current_block()->AddLeaveInlined(undefined, | 5036 current_block()->AddLeaveInlined(return_value, |
| 5000 function_return(), | 5037 function_return(), |
| 5001 drop_extra); | 5038 drop_extra); |
| 5002 } | 5039 } |
| 5003 } else { | 5040 } else { |
| 5004 // The graph builder assumes control can reach both branches of a | 5041 // The graph builder assumes control can reach both branches of a |
| 5005 // test, so we materialize the undefined value and test it rather than | 5042 // test, so we materialize the undefined value and test it rather than |
| 5006 // simply jumping to the false target. | 5043 // simply jumping to the false target. |
| 5007 // | 5044 // |
| 5008 // TODO(3168478): refactor to avoid this. | 5045 // TODO(3168478): refactor to avoid this. |
|
Vyacheslav Egorov (Chromium)
2012/02/13 15:01:39
It seems this comment&todo is outdated (see r7601)
Michael Starzinger
2012/02/27 14:16:32
Done.
| |
| 5009 ASSERT(call_context()->IsTest()); | 5046 ASSERT(call_context()->IsTest()); |
| 5010 HBasicBlock* empty_true = graph()->CreateBasicBlock(); | 5047 HBasicBlock* empty_true = graph()->CreateBasicBlock(); |
| 5011 HBasicBlock* empty_false = graph()->CreateBasicBlock(); | 5048 HBasicBlock* empty_false = graph()->CreateBasicBlock(); |
| 5012 HBranch* test = new(zone()) HBranch(undefined, empty_true, empty_false); | 5049 HBranch* test = |
| 5050 new(zone()) HBranch(return_value, empty_true, empty_false); | |
| 5013 current_block()->Finish(test); | 5051 current_block()->Finish(test); |
| 5014 | 5052 |
| 5015 empty_true->Goto(inlined_test_context()->if_true(), drop_extra); | 5053 empty_true->Goto(inlined_test_context()->if_true(), drop_extra); |
| 5016 empty_false->Goto(inlined_test_context()->if_false(), drop_extra); | 5054 empty_false->Goto(inlined_test_context()->if_false(), drop_extra); |
| 5017 } | 5055 } |
| 5018 } | 5056 } |
| 5019 | 5057 |
| 5020 // Fix up the function exits. | 5058 // Fix up the function exits. |
| 5021 if (inlined_test_context() != NULL) { | 5059 if (inlined_test_context() != NULL) { |
| 5022 HBasicBlock* if_true = inlined_test_context()->if_true(); | 5060 HBasicBlock* if_true = inlined_test_context()->if_true(); |
| 5023 HBasicBlock* if_false = inlined_test_context()->if_false(); | 5061 HBasicBlock* if_false = inlined_test_context()->if_false(); |
| 5024 | 5062 |
| 5025 // Pop the return test context from the expression context stack. | 5063 // Pop the return test context from the expression context stack. |
| 5026 ASSERT(ast_context() == inlined_test_context()); | 5064 ASSERT(ast_context() == inlined_test_context()); |
| 5027 ClearInlinedTestContext(); | 5065 ClearInlinedTestContext(); |
| 5028 delete target_state; | 5066 delete target_state; |
| 5029 | 5067 |
| 5030 // Forward to the real test context. | 5068 // Forward to the real test context. |
| 5031 if (if_true->HasPredecessor()) { | 5069 if (if_true->HasPredecessor()) { |
| 5032 if_true->SetJoinId(expr->id()); | 5070 if_true->SetJoinId(ast_id); |
| 5033 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); | 5071 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); |
| 5034 if_true->Goto(true_target, function_state()->drop_extra()); | 5072 if_true->Goto(true_target, function_state()->drop_extra()); |
| 5035 } | 5073 } |
| 5036 if (if_false->HasPredecessor()) { | 5074 if (if_false->HasPredecessor()) { |
| 5037 if_false->SetJoinId(expr->id()); | 5075 if_false->SetJoinId(ast_id); |
| 5038 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); | 5076 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); |
| 5039 if_false->Goto(false_target, function_state()->drop_extra()); | 5077 if_false->Goto(false_target, function_state()->drop_extra()); |
| 5040 } | 5078 } |
| 5041 set_current_block(NULL); | 5079 set_current_block(NULL); |
| 5042 return true; | 5080 return true; |
| 5043 | 5081 |
| 5044 } else if (function_return()->HasPredecessor()) { | 5082 } else if (function_return()->HasPredecessor()) { |
| 5045 function_return()->SetJoinId(expr->id()); | 5083 function_return()->SetJoinId(ast_id); |
| 5046 set_current_block(function_return()); | 5084 set_current_block(function_return()); |
| 5047 } else { | 5085 } else { |
| 5048 set_current_block(NULL); | 5086 set_current_block(NULL); |
| 5049 } | 5087 } |
| 5050 delete target_state; | 5088 delete target_state; |
| 5051 return true; | 5089 return true; |
| 5052 } | 5090 } |
| 5053 | 5091 |
| 5054 | 5092 |
| 5093 bool HGraphBuilder::TryInlineCall(Call* expr, bool drop_extra) { | |
| 5094 Handle<JSFunction> target = expr->target(); | |
| 5095 ZoneList<Expression*>* arguments = expr->arguments(); | |
| 5096 HValue* receiver = NULL; | |
| 5097 int return_id = expr->ReturnId(); | |
| 5098 int ast_id = expr->id(); | |
| 5099 | |
| 5100 // The function call we are inlining is a method call if the call | |
| 5101 // is a property call. | |
| 5102 CallKind call_kind = (expr->expression()->AsProperty() == NULL) | |
| 5103 ? CALL_AS_FUNCTION | |
| 5104 : CALL_AS_METHOD; | |
| 5105 | |
| 5106 return TryInline(call_kind, target, arguments, receiver, ast_id, return_id, | |
| 5107 drop_extra, false); | |
| 5108 } | |
| 5109 | |
| 5110 | |
| 5111 bool HGraphBuilder::TryInlineConstruct(CallNew* expr, HValue* receiver) { | |
| 5112 Handle<JSFunction> target = expr->target(); | |
| 5113 ZoneList<Expression*>* arguments = expr->arguments(); | |
| 5114 CallKind call_kind = CALL_AS_FUNCTION; | |
| 5115 int return_id = expr->ReturnId(); | |
| 5116 int ast_id = expr->id(); | |
| 5117 | |
| 5118 return TryInline(call_kind, target, arguments, receiver, ast_id, return_id, | |
| 5119 false, true); | |
| 5120 } | |
| 5121 | |
| 5122 | |
| 5055 bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr, | 5123 bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr, |
| 5056 HValue* receiver, | 5124 HValue* receiver, |
| 5057 Handle<Map> receiver_map, | 5125 Handle<Map> receiver_map, |
| 5058 CheckType check_type) { | 5126 CheckType check_type) { |
| 5059 ASSERT(check_type != RECEIVER_MAP_CHECK || !receiver_map.is_null()); | 5127 ASSERT(check_type != RECEIVER_MAP_CHECK || !receiver_map.is_null()); |
| 5060 // Try to inline calls like Math.* as operations in the calling function. | 5128 // Try to inline calls like Math.* as operations in the calling function. |
| 5061 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; | 5129 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; |
| 5062 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); | 5130 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); |
| 5063 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 5131 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
| 5064 switch (id) { | 5132 switch (id) { |
| (...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5328 expr->check_type() != RECEIVER_MAP_CHECK) { | 5396 expr->check_type() != RECEIVER_MAP_CHECK) { |
| 5329 // When the target has a custom call IC generator, use the IC, | 5397 // 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 | 5398 // because it is likely to generate better code. Also use the IC |
| 5331 // when a primitive receiver check is required. | 5399 // when a primitive receiver check is required. |
| 5332 HValue* context = environment()->LookupContext(); | 5400 HValue* context = environment()->LookupContext(); |
| 5333 call = PreProcessCall( | 5401 call = PreProcessCall( |
| 5334 new(zone()) HCallNamed(context, name, argument_count)); | 5402 new(zone()) HCallNamed(context, name, argument_count)); |
| 5335 } else { | 5403 } else { |
| 5336 AddCheckConstantFunction(expr, receiver, receiver_map, true); | 5404 AddCheckConstantFunction(expr, receiver, receiver_map, true); |
| 5337 | 5405 |
| 5338 if (TryInline(expr)) return; | 5406 if (TryInlineCall(expr)) return; |
| 5339 call = PreProcessCall( | 5407 call = PreProcessCall( |
| 5340 new(zone()) HCallConstantFunction(expr->target(), | 5408 new(zone()) HCallConstantFunction(expr->target(), |
| 5341 argument_count)); | 5409 argument_count)); |
| 5342 } | 5410 } |
| 5343 } else if (types != NULL && types->length() > 1) { | 5411 } else if (types != NULL && types->length() > 1) { |
| 5344 ASSERT(expr->check_type() == RECEIVER_MAP_CHECK); | 5412 ASSERT(expr->check_type() == RECEIVER_MAP_CHECK); |
| 5345 HandlePolymorphicCallNamed(expr, receiver, types, name); | 5413 HandlePolymorphicCallNamed(expr, receiver, types, name); |
| 5346 return; | 5414 return; |
| 5347 | 5415 |
| 5348 } else { | 5416 } else { |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5384 // Replace the global object with the global receiver. | 5452 // Replace the global object with the global receiver. |
| 5385 HGlobalReceiver* global_receiver = | 5453 HGlobalReceiver* global_receiver = |
| 5386 new(zone()) HGlobalReceiver(global_object); | 5454 new(zone()) HGlobalReceiver(global_object); |
| 5387 // Index of the receiver from the top of the expression stack. | 5455 // Index of the receiver from the top of the expression stack. |
| 5388 const int receiver_index = argument_count - 1; | 5456 const int receiver_index = argument_count - 1; |
| 5389 AddInstruction(global_receiver); | 5457 AddInstruction(global_receiver); |
| 5390 ASSERT(environment()->ExpressionStackAt(receiver_index)-> | 5458 ASSERT(environment()->ExpressionStackAt(receiver_index)-> |
| 5391 IsGlobalObject()); | 5459 IsGlobalObject()); |
| 5392 environment()->SetExpressionStackAt(receiver_index, global_receiver); | 5460 environment()->SetExpressionStackAt(receiver_index, global_receiver); |
| 5393 | 5461 |
| 5394 if (TryInline(expr)) return; | 5462 if (TryInlineCall(expr)) return; |
| 5395 call = PreProcessCall(new(zone()) HCallKnownGlobal(expr->target(), | 5463 call = PreProcessCall(new(zone()) HCallKnownGlobal(expr->target(), |
| 5396 argument_count)); | 5464 argument_count)); |
| 5397 } else { | 5465 } else { |
| 5398 HValue* context = environment()->LookupContext(); | 5466 HValue* context = environment()->LookupContext(); |
| 5399 HGlobalObject* receiver = new(zone()) HGlobalObject(context); | 5467 HGlobalObject* receiver = new(zone()) HGlobalObject(context); |
| 5400 AddInstruction(receiver); | 5468 AddInstruction(receiver); |
| 5401 PushAndAdd(new(zone()) HPushArgument(receiver)); | 5469 PushAndAdd(new(zone()) HPushArgument(receiver)); |
| 5402 CHECK_ALIVE(VisitArgumentList(expr->arguments())); | 5470 CHECK_ALIVE(VisitArgumentList(expr->arguments())); |
| 5403 | 5471 |
| 5404 call = new(zone()) HCallGlobal(context, var->name(), argument_count); | 5472 call = new(zone()) HCallGlobal(context, var->name(), argument_count); |
| 5405 Drop(argument_count); | 5473 Drop(argument_count); |
| 5406 } | 5474 } |
| 5407 | 5475 |
| 5408 } else if (expr->IsMonomorphic()) { | 5476 } else if (expr->IsMonomorphic()) { |
| 5409 // The function is on the stack in the unoptimized code during | 5477 // The function is on the stack in the unoptimized code during |
| 5410 // evaluation of the arguments. | 5478 // evaluation of the arguments. |
| 5411 CHECK_ALIVE(VisitForValue(expr->expression())); | 5479 CHECK_ALIVE(VisitForValue(expr->expression())); |
| 5412 HValue* function = Top(); | 5480 HValue* function = Top(); |
| 5413 HValue* context = environment()->LookupContext(); | 5481 HValue* context = environment()->LookupContext(); |
| 5414 HGlobalObject* global = new(zone()) HGlobalObject(context); | 5482 HGlobalObject* global = new(zone()) HGlobalObject(context); |
| 5415 HGlobalReceiver* receiver = new(zone()) HGlobalReceiver(global); | 5483 HGlobalReceiver* receiver = new(zone()) HGlobalReceiver(global); |
| 5416 AddInstruction(global); | 5484 AddInstruction(global); |
| 5417 PushAndAdd(receiver); | 5485 PushAndAdd(receiver); |
| 5418 CHECK_ALIVE(VisitExpressions(expr->arguments())); | 5486 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
| 5419 AddInstruction(new(zone()) HCheckFunction(function, expr->target())); | 5487 AddInstruction(new(zone()) HCheckFunction(function, expr->target())); |
| 5420 if (TryInline(expr, true)) { // Drop function from environment. | 5488 if (TryInlineCall(expr, true)) { // Drop function from environment. |
| 5421 return; | 5489 return; |
| 5422 } else { | 5490 } else { |
| 5423 call = PreProcessCall(new(zone()) HInvokeFunction(context, | 5491 call = PreProcessCall(new(zone()) HInvokeFunction(context, |
| 5424 function, | 5492 function, |
| 5425 argument_count)); | 5493 argument_count)); |
| 5426 Drop(1); // The function. | 5494 Drop(1); // The function. |
| 5427 } | 5495 } |
| 5428 | 5496 |
| 5429 } else { | 5497 } else { |
| 5430 CHECK_ALIVE(VisitForValue(expr->expression())); | 5498 CHECK_ALIVE(VisitForValue(expr->expression())); |
| 5431 HValue* function = Top(); | 5499 HValue* function = Top(); |
| 5432 HValue* context = environment()->LookupContext(); | 5500 HValue* context = environment()->LookupContext(); |
| 5433 HGlobalObject* global_object = new(zone()) HGlobalObject(context); | 5501 HGlobalObject* global_object = new(zone()) HGlobalObject(context); |
| 5434 HGlobalReceiver* receiver = new(zone()) HGlobalReceiver(global_object); | 5502 HGlobalReceiver* receiver = new(zone()) HGlobalReceiver(global_object); |
| 5435 AddInstruction(global_object); | 5503 AddInstruction(global_object); |
| 5436 AddInstruction(receiver); | 5504 AddInstruction(receiver); |
| 5437 PushAndAdd(new(zone()) HPushArgument(receiver)); | 5505 PushAndAdd(new(zone()) HPushArgument(receiver)); |
| 5438 CHECK_ALIVE(VisitArgumentList(expr->arguments())); | 5506 CHECK_ALIVE(VisitArgumentList(expr->arguments())); |
| 5439 | 5507 |
| 5440 call = new(zone()) HCallFunction(context, function, argument_count); | 5508 call = new(zone()) HCallFunction(context, function, argument_count); |
| 5441 Drop(argument_count + 1); | 5509 Drop(argument_count + 1); |
| 5442 } | 5510 } |
| 5443 } | 5511 } |
| 5444 | 5512 |
| 5445 call->set_position(expr->position()); | 5513 call->set_position(expr->position()); |
| 5446 return ast_context()->ReturnInstruction(call, expr->id()); | 5514 return ast_context()->ReturnInstruction(call, expr->id()); |
| 5447 } | 5515 } |
| 5448 | 5516 |
| 5449 | 5517 |
| 5518 // Checks whether allocation using the given constructor can be inlined. | |
| 5519 static bool IsAllocationInlineable(Handle<JSFunction> constructor) { | |
| 5520 return constructor->has_initial_map() && | |
| 5521 constructor->initial_map()->instance_type() == JS_OBJECT_TYPE; | |
| 5522 } | |
| 5523 | |
| 5524 | |
| 5450 void HGraphBuilder::VisitCallNew(CallNew* expr) { | 5525 void HGraphBuilder::VisitCallNew(CallNew* expr) { |
| 5451 ASSERT(!HasStackOverflow()); | 5526 ASSERT(!HasStackOverflow()); |
| 5452 ASSERT(current_block() != NULL); | 5527 ASSERT(current_block() != NULL); |
| 5453 ASSERT(current_block()->HasPredecessor()); | 5528 ASSERT(current_block()->HasPredecessor()); |
| 5454 // The constructor function is also used as the receiver argument to the | 5529 expr->RecordTypeFeedback(oracle()); |
| 5455 // JS construct call builtin. | 5530 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(); | 5531 HValue* context = environment()->LookupContext(); |
| 5461 | 5532 |
| 5462 // The constructor is both an operand to the instruction and an argument | 5533 if (FLAG_inline_construct && |
| 5463 // to the construct call. | 5534 expr->IsMonomorphic() && |
| 5464 int arg_count = expr->arguments()->length() + 1; // Plus constructor. | 5535 IsAllocationInlineable(expr->target())) { |
| 5465 HCallNew* call = new(zone()) HCallNew(context, constructor, arg_count); | 5536 // The constructor function is on the stack in the unoptimized code |
| 5466 call->set_position(expr->position()); | 5537 // during evaluation of the arguments. |
| 5467 Drop(arg_count); | 5538 CHECK_ALIVE(VisitForValue(expr->expression())); |
| 5468 return ast_context()->ReturnInstruction(call, expr->id()); | 5539 HValue* function = Top(); |
| 5540 CHECK_ALIVE(VisitExpressions(expr->arguments())); | |
| 5541 Handle<JSFunction> constructor = expr->target(); | |
| 5542 AddInstruction(new(zone()) HCheckFunction(function, constructor)); | |
| 5543 | |
| 5544 // Replace the constructor function with a newly allocated receiver. | |
| 5545 HInstruction* receiver = new(zone()) HAllocateObject(context, | |
| 5546 function, | |
| 5547 constructor); | |
| 5548 // Index of the receiver from the top of the expression stack. | |
| 5549 const int receiver_index = argument_count - 1; | |
| 5550 AddInstruction(receiver); | |
| 5551 ASSERT(environment()->ExpressionStackAt(receiver_index) == function); | |
| 5552 environment()->SetExpressionStackAt(receiver_index, receiver); | |
| 5553 | |
| 5554 if (TryInlineConstruct(expr, receiver)) return; | |
| 5555 HInstruction* call = PreProcessCall( | |
|
Vyacheslav Egorov (Chromium)
2012/02/13 15:01:39
Is lazy bailout handled correctly on this call-sit
Michael Starzinger
2012/02/27 14:16:32
Done. I temporarily disabled partial inlining as s
| |
| 5556 new(zone()) HInvokeFunction(context, function, argument_count)); | |
| 5557 PushAndAdd(call); | |
| 5558 AddSimulate(expr->id()); | |
| 5559 | |
| 5560 // Check whether return value of constructor is a JSObject. | |
| 5561 HValue* return_value = Pop(); | |
| 5562 HHasInstanceTypeAndBranch* typecheck = | |
|
Vyacheslav Egorov (Chromium)
2012/02/13 15:01:39
Branch construction code seems to be duplicated wi
Michael Starzinger
2012/02/27 14:16:32
Comment no longer applies after addressing previou
| |
| 5563 new(zone()) HHasInstanceTypeAndBranch(return_value, | |
| 5564 FIRST_SPEC_OBJECT_TYPE, | |
| 5565 LAST_SPEC_OBJECT_TYPE); | |
| 5566 HBasicBlock* if_spec_object = graph()->CreateBasicBlock(); | |
| 5567 HBasicBlock* not_spec_object = graph()->CreateBasicBlock(); | |
| 5568 typecheck->SetSuccessorAt(0, if_spec_object); | |
| 5569 typecheck->SetSuccessorAt(1, not_spec_object); | |
| 5570 current_block()->Finish(typecheck); | |
| 5571 if_spec_object->last_environment()->Push(return_value); | |
| 5572 not_spec_object->last_environment()->Push(receiver); | |
| 5573 set_current_block(CreateJoin(if_spec_object, not_spec_object, expr->id())); | |
| 5574 return ast_context()->ReturnValue(Pop()); | |
| 5575 } else { | |
| 5576 // The constructor function is both an operand to the instruction and an | |
| 5577 // argument to the construct call. | |
| 5578 HValue* constructor = NULL; | |
| 5579 CHECK_ALIVE(constructor = VisitArgument(expr->expression())); | |
| 5580 CHECK_ALIVE(VisitArgumentList(expr->arguments())); | |
| 5581 HInstruction* call = | |
| 5582 new(zone()) HCallNew(context, constructor, argument_count); | |
| 5583 Drop(argument_count); | |
| 5584 call->set_position(expr->position()); | |
| 5585 return ast_context()->ReturnInstruction(call, expr->id()); | |
| 5586 } | |
| 5469 } | 5587 } |
| 5470 | 5588 |
| 5471 | 5589 |
| 5472 // Support for generating inlined runtime functions. | 5590 // Support for generating inlined runtime functions. |
| 5473 | 5591 |
| 5474 // Lookup table for generators for runtime calls that are generated inline. | 5592 // Lookup table for generators for runtime calls that are generated inline. |
| 5475 // Elements of the table are member pointers to functions of HGraphBuilder. | 5593 // Elements of the table are member pointers to functions of HGraphBuilder. |
| 5476 #define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \ | 5594 #define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \ |
| 5477 &HGraphBuilder::Generate##Name, | 5595 &HGraphBuilder::Generate##Name, |
| 5478 | 5596 |
| (...skipping 1024 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6503 CallRuntime* call) { | 6621 CallRuntime* call) { |
| 6504 return Bailout( | 6622 return Bailout( |
| 6505 "inlined runtime function: IsStringWrapperSafeForDefaultValueOf"); | 6623 "inlined runtime function: IsStringWrapperSafeForDefaultValueOf"); |
| 6506 } | 6624 } |
| 6507 | 6625 |
| 6508 | 6626 |
| 6509 // Support for construct call checks. | 6627 // Support for construct call checks. |
| 6510 void HGraphBuilder::GenerateIsConstructCall(CallRuntime* call) { | 6628 void HGraphBuilder::GenerateIsConstructCall(CallRuntime* call) { |
| 6511 ASSERT(call->arguments()->length() == 0); | 6629 ASSERT(call->arguments()->length() == 0); |
| 6512 if (function_state()->outer() != NULL) { | 6630 if (function_state()->outer() != NULL) { |
| 6513 // We are generating graph for inlined function. Currently | 6631 // We are generating graph for inlined function. |
| 6514 // constructor inlining is not supported and we can just return | 6632 HValue* value = function_state()->is_construct() |
| 6515 // false from %_IsConstructCall(). | 6633 ? graph()->GetConstantTrue() |
| 6516 return ast_context()->ReturnValue(graph()->GetConstantFalse()); | 6634 : graph()->GetConstantFalse(); |
| 6635 return ast_context()->ReturnValue(value); | |
| 6517 } else { | 6636 } else { |
| 6518 return ast_context()->ReturnControl(new(zone()) HIsConstructCallAndBranch, | 6637 return ast_context()->ReturnControl(new(zone()) HIsConstructCallAndBranch, |
| 6519 call->id()); | 6638 call->id()); |
| 6520 } | 6639 } |
| 6521 } | 6640 } |
| 6522 | 6641 |
| 6523 | 6642 |
| 6524 // Support for arguments.length and arguments[?]. | 6643 // Support for arguments.length and arguments[?]. |
| 6525 void HGraphBuilder::GenerateArgumentsLength(CallRuntime* call) { | 6644 void HGraphBuilder::GenerateArgumentsLength(CallRuntime* call) { |
| 6526 // Our implementation of arguments (based on this stack frame or an | 6645 // 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 | 7013 #undef CHECK_BAILOUT |
| 6895 #undef CHECK_ALIVE | 7014 #undef CHECK_ALIVE |
| 6896 | 7015 |
| 6897 | 7016 |
| 6898 HEnvironment::HEnvironment(HEnvironment* outer, | 7017 HEnvironment::HEnvironment(HEnvironment* outer, |
| 6899 Scope* scope, | 7018 Scope* scope, |
| 6900 Handle<JSFunction> closure) | 7019 Handle<JSFunction> closure) |
| 6901 : closure_(closure), | 7020 : closure_(closure), |
| 6902 values_(0), | 7021 values_(0), |
| 6903 assigned_variables_(4), | 7022 assigned_variables_(4), |
| 7023 frame_type_(JS_FUNCTION), | |
| 6904 parameter_count_(0), | 7024 parameter_count_(0), |
| 6905 specials_count_(1), | 7025 specials_count_(1), |
| 6906 local_count_(0), | 7026 local_count_(0), |
| 6907 outer_(outer), | 7027 outer_(outer), |
| 6908 pop_count_(0), | 7028 pop_count_(0), |
| 6909 push_count_(0), | 7029 push_count_(0), |
| 6910 ast_id_(AstNode::kNoNumber), | 7030 ast_id_(AstNode::kNoNumber) { |
| 6911 arguments_adaptor_(false) { | |
| 6912 Initialize(scope->num_parameters() + 1, scope->num_stack_slots(), 0); | 7031 Initialize(scope->num_parameters() + 1, scope->num_stack_slots(), 0); |
| 6913 } | 7032 } |
| 6914 | 7033 |
| 6915 | 7034 |
| 6916 HEnvironment::HEnvironment(const HEnvironment* other) | 7035 HEnvironment::HEnvironment(const HEnvironment* other) |
| 6917 : values_(0), | 7036 : values_(0), |
| 6918 assigned_variables_(0), | 7037 assigned_variables_(0), |
| 7038 frame_type_(JS_FUNCTION), | |
| 6919 parameter_count_(0), | 7039 parameter_count_(0), |
| 6920 specials_count_(1), | 7040 specials_count_(1), |
| 6921 local_count_(0), | 7041 local_count_(0), |
| 6922 outer_(NULL), | 7042 outer_(NULL), |
| 6923 pop_count_(0), | 7043 pop_count_(0), |
| 6924 push_count_(0), | 7044 push_count_(0), |
| 6925 ast_id_(other->ast_id()), | 7045 ast_id_(other->ast_id()) { |
| 6926 arguments_adaptor_(false) { | |
| 6927 Initialize(other); | 7046 Initialize(other); |
| 6928 } | 7047 } |
| 6929 | 7048 |
| 6930 | 7049 |
| 6931 HEnvironment::HEnvironment(HEnvironment* outer, | 7050 HEnvironment::HEnvironment(HEnvironment* outer, |
| 6932 Handle<JSFunction> closure, | 7051 Handle<JSFunction> closure, |
| 6933 int arguments) | 7052 int arguments) |
| 6934 : closure_(closure), | 7053 : closure_(closure), |
| 6935 values_(arguments), | 7054 values_(arguments), |
| 6936 assigned_variables_(0), | 7055 assigned_variables_(0), |
| 7056 frame_type_(ARGUMENTS_ADAPTOR), | |
| 6937 parameter_count_(arguments), | 7057 parameter_count_(arguments), |
| 6938 local_count_(0), | 7058 local_count_(0), |
| 6939 outer_(outer), | 7059 outer_(outer), |
| 6940 pop_count_(0), | 7060 pop_count_(0), |
| 6941 push_count_(0), | 7061 push_count_(0), |
| 6942 ast_id_(AstNode::kNoNumber), | 7062 ast_id_(AstNode::kNoNumber) { |
| 6943 arguments_adaptor_(true) { | |
| 6944 } | 7063 } |
| 6945 | 7064 |
| 6946 | 7065 |
| 7066 HEnvironment::HEnvironment(HEnvironment* outer, | |
| 7067 Handle<JSFunction> closure) | |
| 7068 : closure_(closure), | |
| 7069 values_(0), | |
| 7070 assigned_variables_(0), | |
| 7071 frame_type_(JS_CONSTRUCT), | |
| 7072 parameter_count_(0), | |
| 7073 local_count_(0), | |
| 7074 outer_(outer), | |
| 7075 pop_count_(0), | |
| 7076 push_count_(0), | |
| 7077 ast_id_(AstNode::kNoNumber) { | |
| 7078 } | |
| 7079 | |
| 7080 | |
| 6947 void HEnvironment::Initialize(int parameter_count, | 7081 void HEnvironment::Initialize(int parameter_count, |
| 6948 int local_count, | 7082 int local_count, |
| 6949 int stack_height) { | 7083 int stack_height) { |
| 6950 parameter_count_ = parameter_count; | 7084 parameter_count_ = parameter_count; |
| 6951 local_count_ = local_count; | 7085 local_count_ = local_count; |
| 6952 | 7086 |
| 6953 // Avoid reallocating the temporaries' backing store on the first Push. | 7087 // Avoid reallocating the temporaries' backing store on the first Push. |
| 6954 int total = parameter_count + specials_count_ + local_count + stack_height; | 7088 int total = parameter_count + specials_count_ + local_count + stack_height; |
| 6955 values_.Initialize(total + 4); | 7089 values_.Initialize(total + 4); |
| 6956 for (int i = 0; i < total; ++i) values_.Add(NULL); | 7090 for (int i = 0; i < total; ++i) values_.Add(NULL); |
| 6957 } | 7091 } |
| 6958 | 7092 |
| 6959 | 7093 |
| 6960 void HEnvironment::Initialize(const HEnvironment* other) { | 7094 void HEnvironment::Initialize(const HEnvironment* other) { |
| 6961 closure_ = other->closure(); | 7095 closure_ = other->closure(); |
| 6962 values_.AddAll(other->values_); | 7096 values_.AddAll(other->values_); |
| 6963 assigned_variables_.AddAll(other->assigned_variables_); | 7097 assigned_variables_.AddAll(other->assigned_variables_); |
| 7098 frame_type_ = other->frame_type_; | |
| 6964 parameter_count_ = other->parameter_count_; | 7099 parameter_count_ = other->parameter_count_; |
| 6965 local_count_ = other->local_count_; | 7100 local_count_ = other->local_count_; |
| 6966 if (other->outer_ != NULL) outer_ = other->outer_->Copy(); // Deep copy. | 7101 if (other->outer_ != NULL) outer_ = other->outer_->Copy(); // Deep copy. |
| 6967 pop_count_ = other->pop_count_; | 7102 pop_count_ = other->pop_count_; |
| 6968 push_count_ = other->push_count_; | 7103 push_count_ = other->push_count_; |
| 6969 ast_id_ = other->ast_id_; | 7104 ast_id_ = other->ast_id_; |
| 6970 arguments_adaptor_ = other->arguments_adaptor_; | |
| 6971 } | 7105 } |
| 6972 | 7106 |
| 6973 | 7107 |
| 6974 void HEnvironment::AddIncomingEdge(HBasicBlock* block, HEnvironment* other) { | 7108 void HEnvironment::AddIncomingEdge(HBasicBlock* block, HEnvironment* other) { |
| 6975 ASSERT(!block->IsLoopHeader()); | 7109 ASSERT(!block->IsLoopHeader()); |
| 6976 ASSERT(values_.length() == other->values_.length()); | 7110 ASSERT(values_.length() == other->values_.length()); |
| 6977 | 7111 |
| 6978 int length = values_.length(); | 7112 int length = values_.length(); |
| 6979 for (int i = 0; i < length; ++i) { | 7113 for (int i = 0; i < length; ++i) { |
| 6980 HValue* value = values_[i]; | 7114 HValue* value = values_[i]; |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 7067 new_env->ClearHistory(); | 7201 new_env->ClearHistory(); |
| 7068 return new_env; | 7202 return new_env; |
| 7069 } | 7203 } |
| 7070 | 7204 |
| 7071 | 7205 |
| 7072 HEnvironment* HEnvironment::CopyForInlining( | 7206 HEnvironment* HEnvironment::CopyForInlining( |
| 7073 Handle<JSFunction> target, | 7207 Handle<JSFunction> target, |
| 7074 int arguments, | 7208 int arguments, |
| 7075 FunctionLiteral* function, | 7209 FunctionLiteral* function, |
| 7076 HConstant* undefined, | 7210 HConstant* undefined, |
| 7077 CallKind call_kind) const { | 7211 CallKind call_kind, |
| 7078 ASSERT(!is_arguments_adaptor()); | 7212 bool is_construct) const { |
| 7213 ASSERT(frame_type() == JS_FUNCTION); | |
| 7079 | 7214 |
| 7080 Zone* zone = closure()->GetIsolate()->zone(); | 7215 Zone* zone = closure()->GetIsolate()->zone(); |
| 7081 | 7216 |
| 7082 // Outer environment is a copy of this one without the arguments. | 7217 // Outer environment is a copy of this one without the arguments. |
| 7083 int arity = function->scope()->num_parameters(); | 7218 int arity = function->scope()->num_parameters(); |
| 7084 | 7219 |
| 7085 HEnvironment* outer = Copy(); | 7220 HEnvironment* outer = Copy(); |
| 7086 outer->Drop(arguments + 1); // Including receiver. | 7221 outer->Drop(arguments + 1); // Including receiver. |
| 7087 outer->ClearHistory(); | 7222 outer->ClearHistory(); |
| 7088 | 7223 |
| 7224 if (is_construct) { | |
| 7225 // Create artificial constructor stub environment. The receiver should | |
| 7226 // actually be the constructor function, but we pass the newly allocated | |
| 7227 // object instead, DoComputeConstructStubFrame() relies on that. | |
| 7228 outer = new(zone) HEnvironment(outer, target); | |
| 7229 for (int i = 0; i <= arguments; ++i) { // Include receiver. | |
| 7230 outer->Push(ExpressionStackAt(arguments - i)); | |
| 7231 } | |
| 7232 outer->ClearHistory(); | |
| 7233 } | |
| 7234 | |
| 7089 if (arity != arguments) { | 7235 if (arity != arguments) { |
| 7090 // Create artificial arguments adaptation environment. | 7236 // Create artificial arguments adaptation environment. |
| 7091 outer = new(zone) HEnvironment(outer, target, arguments + 1); | 7237 outer = new(zone) HEnvironment(outer, target, arguments + 1); |
|
Vyacheslav Egorov (Chromium)
2012/02/13 15:01:39
I think HEnvironent constructor for the "artificia
Michael Starzinger
2012/02/27 14:16:32
Done.
| |
| 7092 for (int i = 0; i <= arguments; ++i) { // Include receiver. | 7238 for (int i = 0; i <= arguments; ++i) { // Include receiver. |
| 7093 outer->Push(ExpressionStackAt(arguments - i)); | 7239 outer->Push(ExpressionStackAt(arguments - i)); |
| 7094 } | 7240 } |
| 7095 outer->ClearHistory(); | 7241 outer->ClearHistory(); |
| 7096 } | 7242 } |
| 7097 | 7243 |
| 7098 HEnvironment* inner = | 7244 HEnvironment* inner = |
| 7099 new(zone) HEnvironment(outer, function->scope(), target); | 7245 new(zone) HEnvironment(outer, function->scope(), target); |
| 7100 // Get the argument values from the original environment. | 7246 // Get the argument values from the original environment. |
| 7101 for (int i = 0; i <= arity; ++i) { // Include receiver. | 7247 for (int i = 0; i <= arity; ++i) { // Include receiver. |
| (...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 7453 } | 7599 } |
| 7454 } | 7600 } |
| 7455 | 7601 |
| 7456 #ifdef DEBUG | 7602 #ifdef DEBUG |
| 7457 if (graph_ != NULL) graph_->Verify(false); // No full verify. | 7603 if (graph_ != NULL) graph_->Verify(false); // No full verify. |
| 7458 if (allocator_ != NULL) allocator_->Verify(); | 7604 if (allocator_ != NULL) allocator_->Verify(); |
| 7459 #endif | 7605 #endif |
| 7460 } | 7606 } |
| 7461 | 7607 |
| 7462 } } // namespace v8::internal | 7608 } } // namespace v8::internal |
| OLD | NEW |