| 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 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 106 void HBasicBlock::AddInstruction(HInstruction* instr) { | 106 void HBasicBlock::AddInstruction(HInstruction* instr) { |
| 107 ASSERT(!IsStartBlock() || !IsFinished()); | 107 ASSERT(!IsStartBlock() || !IsFinished()); |
| 108 ASSERT(!instr->IsLinked()); | 108 ASSERT(!instr->IsLinked()); |
| 109 ASSERT(!IsFinished()); | 109 ASSERT(!IsFinished()); |
| 110 if (first_ == NULL) { | 110 if (first_ == NULL) { |
| 111 HBlockEntry* entry = new(zone()) HBlockEntry(); | 111 HBlockEntry* entry = new(zone()) HBlockEntry(); |
| 112 entry->InitializeAsFirst(this); | 112 entry->InitializeAsFirst(this); |
| 113 first_ = last_ = entry; | 113 first_ = last_ = entry; |
| 114 } | 114 } |
| 115 instr->InsertAfter(last_); | 115 instr->InsertAfter(last_); |
| 116 last_ = instr; | |
| 117 } | 116 } |
| 118 | 117 |
| 119 | 118 |
| 120 HDeoptimize* HBasicBlock::CreateDeoptimize( | 119 HDeoptimize* HBasicBlock::CreateDeoptimize( |
| 121 HDeoptimize::UseEnvironment has_uses) { | 120 HDeoptimize::UseEnvironment has_uses) { |
| 122 ASSERT(HasEnvironment()); | 121 ASSERT(HasEnvironment()); |
| 123 if (has_uses == HDeoptimize::kNoUses) return new(zone()) HDeoptimize(0); | 122 if (has_uses == HDeoptimize::kNoUses) return new(zone()) HDeoptimize(0); |
| 124 | 123 |
| 125 HEnvironment* environment = last_environment(); | 124 HEnvironment* environment = last_environment(); |
| 126 HDeoptimize* instr = new(zone()) HDeoptimize(environment->length()); | 125 HDeoptimize* instr = new(zone()) HDeoptimize(environment->length()); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 158 void HBasicBlock::Finish(HControlInstruction* end) { | 157 void HBasicBlock::Finish(HControlInstruction* end) { |
| 159 ASSERT(!IsFinished()); | 158 ASSERT(!IsFinished()); |
| 160 AddInstruction(end); | 159 AddInstruction(end); |
| 161 end_ = end; | 160 end_ = end; |
| 162 for (HSuccessorIterator it(end); !it.Done(); it.Advance()) { | 161 for (HSuccessorIterator it(end); !it.Done(); it.Advance()) { |
| 163 it.Current()->RegisterPredecessor(this); | 162 it.Current()->RegisterPredecessor(this); |
| 164 } | 163 } |
| 165 } | 164 } |
| 166 | 165 |
| 167 | 166 |
| 168 void HBasicBlock::Goto(HBasicBlock* block, bool drop_extra) { | 167 void HBasicBlock::Goto(HBasicBlock* block, FunctionState* state) { |
| 168 bool drop_extra = state != NULL && state->drop_extra(); |
| 169 bool arguments_pushed = state != NULL && state->arguments_pushed(); |
| 170 |
| 169 if (block->IsInlineReturnTarget()) { | 171 if (block->IsInlineReturnTarget()) { |
| 170 AddInstruction(new(zone()) HLeaveInlined); | 172 AddInstruction(new(zone()) HLeaveInlined(arguments_pushed)); |
| 171 last_environment_ = last_environment()->DiscardInlined(drop_extra); | 173 last_environment_ = last_environment()->DiscardInlined(drop_extra); |
| 172 } | 174 } |
| 175 |
| 173 AddSimulate(AstNode::kNoNumber); | 176 AddSimulate(AstNode::kNoNumber); |
| 174 HGoto* instr = new(zone()) HGoto(block); | 177 HGoto* instr = new(zone()) HGoto(block); |
| 175 Finish(instr); | 178 Finish(instr); |
| 176 } | 179 } |
| 177 | 180 |
| 178 | 181 |
| 179 void HBasicBlock::AddLeaveInlined(HValue* return_value, | 182 void HBasicBlock::AddLeaveInlined(HValue* return_value, |
| 180 HBasicBlock* target, | 183 HBasicBlock* target, |
| 181 bool drop_extra) { | 184 FunctionState* state) { |
| 185 bool drop_extra = state != NULL && state->drop_extra(); |
| 186 bool arguments_pushed = state != NULL && state->arguments_pushed(); |
| 187 |
| 182 ASSERT(target->IsInlineReturnTarget()); | 188 ASSERT(target->IsInlineReturnTarget()); |
| 183 ASSERT(return_value != NULL); | 189 ASSERT(return_value != NULL); |
| 184 AddInstruction(new(zone()) HLeaveInlined); | 190 AddInstruction(new(zone()) HLeaveInlined(arguments_pushed)); |
| 185 last_environment_ = last_environment()->DiscardInlined(drop_extra); | 191 last_environment_ = last_environment()->DiscardInlined(drop_extra); |
| 186 last_environment()->Push(return_value); | 192 last_environment()->Push(return_value); |
| 187 AddSimulate(AstNode::kNoNumber); | 193 AddSimulate(AstNode::kNoNumber); |
| 188 HGoto* instr = new(zone()) HGoto(target); | 194 HGoto* instr = new(zone()) HGoto(target); |
| 189 Finish(instr); | 195 Finish(instr); |
| 190 } | 196 } |
| 191 | 197 |
| 192 | 198 |
| 193 void HBasicBlock::SetInitialEnvironment(HEnvironment* env) { | 199 void HBasicBlock::SetInitialEnvironment(HEnvironment* env) { |
| 194 ASSERT(!HasEnvironment()); | 200 ASSERT(!HasEnvironment()); |
| (...skipping 1976 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2171 CompilationInfo* info, | 2177 CompilationInfo* info, |
| 2172 TypeFeedbackOracle* oracle, | 2178 TypeFeedbackOracle* oracle, |
| 2173 ReturnHandlingFlag return_handling) | 2179 ReturnHandlingFlag return_handling) |
| 2174 : owner_(owner), | 2180 : owner_(owner), |
| 2175 compilation_info_(info), | 2181 compilation_info_(info), |
| 2176 oracle_(oracle), | 2182 oracle_(oracle), |
| 2177 call_context_(NULL), | 2183 call_context_(NULL), |
| 2178 return_handling_(return_handling), | 2184 return_handling_(return_handling), |
| 2179 function_return_(NULL), | 2185 function_return_(NULL), |
| 2180 test_context_(NULL), | 2186 test_context_(NULL), |
| 2187 entry_(NULL), |
| 2188 arguments_elements_(NULL), |
| 2181 outer_(owner->function_state()) { | 2189 outer_(owner->function_state()) { |
| 2182 if (outer_ != NULL) { | 2190 if (outer_ != NULL) { |
| 2183 // State for an inline function. | 2191 // State for an inline function. |
| 2184 if (owner->ast_context()->IsTest()) { | 2192 if (owner->ast_context()->IsTest()) { |
| 2185 HBasicBlock* if_true = owner->graph()->CreateBasicBlock(); | 2193 HBasicBlock* if_true = owner->graph()->CreateBasicBlock(); |
| 2186 HBasicBlock* if_false = owner->graph()->CreateBasicBlock(); | 2194 HBasicBlock* if_false = owner->graph()->CreateBasicBlock(); |
| 2187 if_true->MarkAsInlineReturnTarget(); | 2195 if_true->MarkAsInlineReturnTarget(); |
| 2188 if_false->MarkAsInlineReturnTarget(); | 2196 if_false->MarkAsInlineReturnTarget(); |
| 2189 Expression* cond = TestContext::cast(owner->ast_context())->condition(); | 2197 Expression* cond = TestContext::cast(owner->ast_context())->condition(); |
| 2190 // The AstContext constructor pushed on the context stack. This newed | 2198 // The AstContext constructor pushed on the context stack. This newed |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2330 } | 2338 } |
| 2331 | 2339 |
| 2332 | 2340 |
| 2333 void TestContext::ReturnControl(HControlInstruction* instr, int ast_id) { | 2341 void TestContext::ReturnControl(HControlInstruction* instr, int ast_id) { |
| 2334 ASSERT(!instr->HasObservableSideEffects()); | 2342 ASSERT(!instr->HasObservableSideEffects()); |
| 2335 HBasicBlock* empty_true = owner()->graph()->CreateBasicBlock(); | 2343 HBasicBlock* empty_true = owner()->graph()->CreateBasicBlock(); |
| 2336 HBasicBlock* empty_false = owner()->graph()->CreateBasicBlock(); | 2344 HBasicBlock* empty_false = owner()->graph()->CreateBasicBlock(); |
| 2337 instr->SetSuccessorAt(0, empty_true); | 2345 instr->SetSuccessorAt(0, empty_true); |
| 2338 instr->SetSuccessorAt(1, empty_false); | 2346 instr->SetSuccessorAt(1, empty_false); |
| 2339 owner()->current_block()->Finish(instr); | 2347 owner()->current_block()->Finish(instr); |
| 2340 empty_true->Goto(if_true(), owner()->function_state()->drop_extra()); | 2348 empty_true->Goto(if_true(), owner()->function_state()); |
| 2341 empty_false->Goto(if_false(), owner()->function_state()->drop_extra()); | 2349 empty_false->Goto(if_false(), owner()->function_state()); |
| 2342 owner()->set_current_block(NULL); | 2350 owner()->set_current_block(NULL); |
| 2343 } | 2351 } |
| 2344 | 2352 |
| 2345 | 2353 |
| 2346 void TestContext::BuildBranch(HValue* value) { | 2354 void TestContext::BuildBranch(HValue* value) { |
| 2347 // We expect the graph to be in edge-split form: there is no edge that | 2355 // We expect the graph to be in edge-split form: there is no edge that |
| 2348 // connects a branch node to a join node. We conservatively ensure that | 2356 // connects a branch node to a join node. We conservatively ensure that |
| 2349 // property by always adding an empty block on the outgoing edges of this | 2357 // property by always adding an empty block on the outgoing edges of this |
| 2350 // branch. | 2358 // branch. |
| 2351 HGraphBuilder* builder = owner(); | 2359 HGraphBuilder* builder = owner(); |
| 2352 if (value != NULL && value->CheckFlag(HValue::kIsArguments)) { | 2360 if (value != NULL && value->CheckFlag(HValue::kIsArguments)) { |
| 2353 builder->Bailout("arguments object value in a test context"); | 2361 builder->Bailout("arguments object value in a test context"); |
| 2354 } | 2362 } |
| 2355 HBasicBlock* empty_true = builder->graph()->CreateBasicBlock(); | 2363 HBasicBlock* empty_true = builder->graph()->CreateBasicBlock(); |
| 2356 HBasicBlock* empty_false = builder->graph()->CreateBasicBlock(); | 2364 HBasicBlock* empty_false = builder->graph()->CreateBasicBlock(); |
| 2357 unsigned test_id = condition()->test_id(); | 2365 unsigned test_id = condition()->test_id(); |
| 2358 ToBooleanStub::Types expected(builder->oracle()->ToBooleanTypes(test_id)); | 2366 ToBooleanStub::Types expected(builder->oracle()->ToBooleanTypes(test_id)); |
| 2359 HBranch* test = new(zone()) HBranch(value, empty_true, empty_false, expected); | 2367 HBranch* test = new(zone()) HBranch(value, empty_true, empty_false, expected); |
| 2360 builder->current_block()->Finish(test); | 2368 builder->current_block()->Finish(test); |
| 2361 | 2369 |
| 2362 empty_true->Goto(if_true(), owner()->function_state()->drop_extra()); | 2370 empty_true->Goto(if_true(), owner()->function_state()); |
| 2363 empty_false->Goto(if_false(), owner()->function_state()->drop_extra()); | 2371 empty_false->Goto(if_false(), owner()->function_state()); |
| 2364 builder->set_current_block(NULL); | 2372 builder->set_current_block(NULL); |
| 2365 } | 2373 } |
| 2366 | 2374 |
| 2367 | 2375 |
| 2368 // HGraphBuilder infrastructure for bailing out and checking bailouts. | 2376 // HGraphBuilder infrastructure for bailing out and checking bailouts. |
| 2369 #define CHECK_BAILOUT(call) \ | 2377 #define CHECK_BAILOUT(call) \ |
| 2370 do { \ | 2378 do { \ |
| 2371 call; \ | 2379 call; \ |
| 2372 if (HasStackOverflow()) return; \ | 2380 if (HasStackOverflow()) return; \ |
| 2373 } while (false) | 2381 } while (false) |
| (...skipping 470 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2844 CHECK_ALIVE(VisitForValue(stmt->expression())); | 2852 CHECK_ALIVE(VisitForValue(stmt->expression())); |
| 2845 HValue* result = environment()->Pop(); | 2853 HValue* result = environment()->Pop(); |
| 2846 current_block()->FinishExit(new(zone()) HReturn(result)); | 2854 current_block()->FinishExit(new(zone()) HReturn(result)); |
| 2847 } else if (function_state()->is_construct()) { | 2855 } else if (function_state()->is_construct()) { |
| 2848 // Return from an inlined construct call. In a test context the return | 2856 // Return from an inlined construct call. In a test context the return |
| 2849 // value will always evaluate to true, in a value context the return value | 2857 // value will always evaluate to true, in a value context the return value |
| 2850 // needs to be a JSObject. | 2858 // needs to be a JSObject. |
| 2851 if (context->IsTest()) { | 2859 if (context->IsTest()) { |
| 2852 TestContext* test = TestContext::cast(context); | 2860 TestContext* test = TestContext::cast(context); |
| 2853 CHECK_ALIVE(VisitForEffect(stmt->expression())); | 2861 CHECK_ALIVE(VisitForEffect(stmt->expression())); |
| 2854 current_block()->Goto(test->if_true(), function_state()->drop_extra()); | 2862 current_block()->Goto(test->if_true(), function_state()); |
| 2855 } else if (context->IsEffect()) { | 2863 } else if (context->IsEffect()) { |
| 2856 CHECK_ALIVE(VisitForEffect(stmt->expression())); | 2864 CHECK_ALIVE(VisitForEffect(stmt->expression())); |
| 2857 current_block()->Goto(function_return(), function_state()->drop_extra()); | 2865 current_block()->Goto(function_return(), function_state()); |
| 2858 } else { | 2866 } else { |
| 2859 ASSERT(context->IsValue()); | 2867 ASSERT(context->IsValue()); |
| 2860 CHECK_ALIVE(VisitForValue(stmt->expression())); | 2868 CHECK_ALIVE(VisitForValue(stmt->expression())); |
| 2861 HValue* return_value = Pop(); | 2869 HValue* return_value = Pop(); |
| 2862 HValue* receiver = environment()->Lookup(0); | 2870 HValue* receiver = environment()->Lookup(0); |
| 2863 HHasInstanceTypeAndBranch* typecheck = | 2871 HHasInstanceTypeAndBranch* typecheck = |
| 2864 new(zone()) HHasInstanceTypeAndBranch(return_value, | 2872 new(zone()) HHasInstanceTypeAndBranch(return_value, |
| 2865 FIRST_SPEC_OBJECT_TYPE, | 2873 FIRST_SPEC_OBJECT_TYPE, |
| 2866 LAST_SPEC_OBJECT_TYPE); | 2874 LAST_SPEC_OBJECT_TYPE); |
| 2867 HBasicBlock* if_spec_object = graph()->CreateBasicBlock(); | 2875 HBasicBlock* if_spec_object = graph()->CreateBasicBlock(); |
| 2868 HBasicBlock* not_spec_object = graph()->CreateBasicBlock(); | 2876 HBasicBlock* not_spec_object = graph()->CreateBasicBlock(); |
| 2869 typecheck->SetSuccessorAt(0, if_spec_object); | 2877 typecheck->SetSuccessorAt(0, if_spec_object); |
| 2870 typecheck->SetSuccessorAt(1, not_spec_object); | 2878 typecheck->SetSuccessorAt(1, not_spec_object); |
| 2871 current_block()->Finish(typecheck); | 2879 current_block()->Finish(typecheck); |
| 2872 if_spec_object->AddLeaveInlined(return_value, | 2880 if_spec_object->AddLeaveInlined(return_value, |
| 2873 function_return(), | 2881 function_return(), |
| 2874 function_state()->drop_extra()); | 2882 function_state()); |
| 2875 not_spec_object->AddLeaveInlined(receiver, | 2883 not_spec_object->AddLeaveInlined(receiver, |
| 2876 function_return(), | 2884 function_return(), |
| 2877 function_state()->drop_extra()); | 2885 function_state()); |
| 2878 } | 2886 } |
| 2879 } else { | 2887 } else { |
| 2880 // Return from an inlined function, visit the subexpression in the | 2888 // Return from an inlined function, visit the subexpression in the |
| 2881 // expression context of the call. | 2889 // expression context of the call. |
| 2882 if (context->IsTest()) { | 2890 if (context->IsTest()) { |
| 2883 TestContext* test = TestContext::cast(context); | 2891 TestContext* test = TestContext::cast(context); |
| 2884 VisitForControl(stmt->expression(), | 2892 VisitForControl(stmt->expression(), |
| 2885 test->if_true(), | 2893 test->if_true(), |
| 2886 test->if_false()); | 2894 test->if_false()); |
| 2887 } else if (context->IsEffect()) { | 2895 } else if (context->IsEffect()) { |
| 2888 CHECK_ALIVE(VisitForEffect(stmt->expression())); | 2896 CHECK_ALIVE(VisitForEffect(stmt->expression())); |
| 2889 current_block()->Goto(function_return(), function_state()->drop_extra()); | 2897 current_block()->Goto(function_return(), function_state()); |
| 2890 } else { | 2898 } else { |
| 2891 ASSERT(context->IsValue()); | 2899 ASSERT(context->IsValue()); |
| 2892 CHECK_ALIVE(VisitForValue(stmt->expression())); | 2900 CHECK_ALIVE(VisitForValue(stmt->expression())); |
| 2893 HValue* return_value = Pop(); | 2901 HValue* return_value = Pop(); |
| 2894 current_block()->AddLeaveInlined(return_value, | 2902 current_block()->AddLeaveInlined(return_value, |
| 2895 function_return(), | 2903 function_return(), |
| 2896 function_state()->drop_extra()); | 2904 function_state()); |
| 2897 } | 2905 } |
| 2898 } | 2906 } |
| 2899 set_current_block(NULL); | 2907 set_current_block(NULL); |
| 2900 } | 2908 } |
| 2901 | 2909 |
| 2902 | 2910 |
| 2903 void HGraphBuilder::VisitWithStatement(WithStatement* stmt) { | 2911 void HGraphBuilder::VisitWithStatement(WithStatement* stmt) { |
| 2904 ASSERT(!HasStackOverflow()); | 2912 ASSERT(!HasStackOverflow()); |
| 2905 ASSERT(current_block() != NULL); | 2913 ASSERT(current_block() != NULL); |
| 2906 ASSERT(current_block()->HasPredecessor()); | 2914 ASSERT(current_block()->HasPredecessor()); |
| (...skipping 2018 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4925 } | 4933 } |
| 4926 | 4934 |
| 4927 bool HGraphBuilder::TryArgumentsAccess(Property* expr) { | 4935 bool HGraphBuilder::TryArgumentsAccess(Property* expr) { |
| 4928 VariableProxy* proxy = expr->obj()->AsVariableProxy(); | 4936 VariableProxy* proxy = expr->obj()->AsVariableProxy(); |
| 4929 if (proxy == NULL) return false; | 4937 if (proxy == NULL) return false; |
| 4930 if (!proxy->var()->IsStackAllocated()) return false; | 4938 if (!proxy->var()->IsStackAllocated()) return false; |
| 4931 if (!environment()->Lookup(proxy->var())->CheckFlag(HValue::kIsArguments)) { | 4939 if (!environment()->Lookup(proxy->var())->CheckFlag(HValue::kIsArguments)) { |
| 4932 return false; | 4940 return false; |
| 4933 } | 4941 } |
| 4934 | 4942 |
| 4935 // Our implementation of arguments (based on this stack frame or an | |
| 4936 // adapter below it) does not work for inlined functions. | |
| 4937 if (function_state()->outer() != NULL) { | 4943 if (function_state()->outer() != NULL) { |
| 4938 Bailout("arguments access in inlined function"); | 4944 // Push arguments when entering inlined function. |
| 4939 return true; | 4945 if (!function_state()->arguments_pushed()) { |
| 4946 HEnvironment* arguments_env = environment()->arguments_environment(); |
| 4947 |
| 4948 HInstruction* insert_after = function_state()->entry(); |
| 4949 ASSERT(insert_after->IsEnterInlined()); |
| 4950 HEnterInlined::cast(insert_after)->set_materializes_arguments(true); |
| 4951 |
| 4952 for (int i = 0; i < arguments_env->parameter_count(); i++) { |
| 4953 HValue* argument = arguments_env->Lookup(i); |
| 4954 HInstruction* push_argument = new(zone()) HPushArgument(argument); |
| 4955 push_argument->InsertAfter(insert_after); |
| 4956 insert_after = push_argument; |
| 4957 } |
| 4958 |
| 4959 HInstruction* arguments_elements = new(zone()) HArgumentsElements(); |
| 4960 arguments_elements->ClearFlag(HValue::kUseGVN); |
| 4961 arguments_elements->InsertAfter(insert_after); |
| 4962 function_state()->set_arguments_elements(arguments_elements); |
| 4963 } |
| 4940 } | 4964 } |
| 4941 | 4965 |
| 4942 HInstruction* result = NULL; | 4966 HInstruction* result = NULL; |
| 4943 if (expr->key()->IsPropertyName()) { | 4967 if (expr->key()->IsPropertyName()) { |
| 4944 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); | 4968 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); |
| 4945 if (!name->IsEqualTo(CStrVector("length"))) return false; | 4969 if (!name->IsEqualTo(CStrVector("length"))) return false; |
| 4946 HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); | 4970 |
| 4947 result = new(zone()) HArgumentsLength(elements); | 4971 if (function_state()->outer() == NULL) { |
| 4972 HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); |
| 4973 result = new(zone()) HArgumentsLength(elements); |
| 4974 } else { |
| 4975 // Number of arguments without receiver. |
| 4976 int argument_count = environment()-> |
| 4977 arguments_environment()->parameter_count() - 1; |
| 4978 result = new(zone()) HConstant( |
| 4979 Handle<Object>(Smi::FromInt(argument_count)), |
| 4980 Representation::Integer32()); |
| 4981 } |
| 4948 } else { | 4982 } else { |
| 4949 Push(graph()->GetArgumentsObject()); | 4983 Push(graph()->GetArgumentsObject()); |
| 4950 VisitForValue(expr->key()); | 4984 VisitForValue(expr->key()); |
| 4951 if (HasStackOverflow() || current_block() == NULL) return true; | 4985 if (HasStackOverflow() || current_block() == NULL) return true; |
| 4952 HValue* key = Pop(); | 4986 HValue* key = Pop(); |
| 4953 Drop(1); // Arguments object. | 4987 Drop(1); // Arguments object. |
| 4954 HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); | 4988 if (function_state()->outer() == NULL) { |
| 4955 HInstruction* length = AddInstruction( | 4989 HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); |
| 4956 new(zone()) HArgumentsLength(elements)); | 4990 HInstruction* length = AddInstruction( |
| 4957 HInstruction* checked_key = | 4991 new(zone()) HArgumentsLength(elements)); |
| 4958 AddInstruction(new(zone()) HBoundsCheck(key, length)); | 4992 HInstruction* checked_key = |
| 4959 result = new(zone()) HAccessArgumentsAt(elements, length, checked_key); | 4993 AddInstruction(new(zone()) HBoundsCheck(key, length)); |
| 4994 result = new(zone()) HAccessArgumentsAt(elements, length, checked_key); |
| 4995 } else { |
| 4996 // Number of arguments without receiver. |
| 4997 HInstruction* elements = function_state()->arguments_elements(); |
| 4998 int argument_count = environment()-> |
| 4999 arguments_environment()->parameter_count() - 1; |
| 5000 HInstruction* length = AddInstruction(new(zone()) HConstant( |
| 5001 Handle<Object>(Smi::FromInt(argument_count)), |
| 5002 Representation::Integer32())); |
| 5003 HInstruction* checked_key = |
| 5004 AddInstruction(new(zone()) HBoundsCheck(key, length)); |
| 5005 result = new(zone()) HAccessArgumentsAt(elements, length, checked_key); |
| 5006 } |
| 4960 } | 5007 } |
| 4961 ast_context()->ReturnInstruction(result, expr->id()); | 5008 ast_context()->ReturnInstruction(result, expr->id()); |
| 4962 return true; | 5009 return true; |
| 4963 } | 5010 } |
| 4964 | 5011 |
| 4965 | 5012 |
| 4966 void HGraphBuilder::VisitProperty(Property* expr) { | 5013 void HGraphBuilder::VisitProperty(Property* expr) { |
| 4967 ASSERT(!HasStackOverflow()); | 5014 ASSERT(!HasStackOverflow()); |
| 4968 ASSERT(current_block() != NULL); | 5015 ASSERT(current_block() != NULL); |
| 4969 ASSERT(current_block()->HasPredecessor()); | 5016 ASSERT(current_block()->HasPredecessor()); |
| (...skipping 387 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5357 // IA32 only, overwrite the caller's context in the deoptimization | 5404 // IA32 only, overwrite the caller's context in the deoptimization |
| 5358 // environment with the correct one. | 5405 // environment with the correct one. |
| 5359 // | 5406 // |
| 5360 // TODO(kmillikin): implement the same inlining on other platforms so we | 5407 // TODO(kmillikin): implement the same inlining on other platforms so we |
| 5361 // can remove the unsightly ifdefs in this function. | 5408 // can remove the unsightly ifdefs in this function. |
| 5362 HConstant* context = new HConstant(Handle<Context>(target->context()), | 5409 HConstant* context = new HConstant(Handle<Context>(target->context()), |
| 5363 Representation::Tagged()); | 5410 Representation::Tagged()); |
| 5364 AddInstruction(context); | 5411 AddInstruction(context); |
| 5365 inner_env->BindContext(context); | 5412 inner_env->BindContext(context); |
| 5366 #endif | 5413 #endif |
| 5367 AddSimulate(return_id); | |
| 5368 current_block()->UpdateEnvironment(inner_env); | |
| 5369 AddInstruction(new(zone()) HEnterInlined(target, | |
| 5370 arguments->length(), | |
| 5371 function, | |
| 5372 call_kind, | |
| 5373 function_state()->is_construct())); | |
| 5374 // If the function uses arguments object create and bind one. | 5414 // If the function uses arguments object create and bind one. |
| 5375 if (function->scope()->arguments() != NULL) { | 5415 if (function->scope()->arguments() != NULL) { |
| 5376 ASSERT(function->scope()->arguments()->IsStackAllocated()); | 5416 ASSERT(function->scope()->arguments()->IsStackAllocated()); |
| 5377 environment()->Bind(function->scope()->arguments(), | 5417 inner_env->Bind(function->scope()->arguments(), |
| 5378 graph()->GetArgumentsObject()); | 5418 graph()->GetArgumentsObject()); |
| 5379 } | 5419 } |
| 5420 |
| 5421 AddSimulate(return_id); |
| 5422 current_block()->UpdateEnvironment(inner_env); |
| 5423 |
| 5424 HInstruction* enter_inlined = |
| 5425 AddInstruction(new(zone()) HEnterInlined(target, |
| 5426 arguments->length(), |
| 5427 function, |
| 5428 call_kind, |
| 5429 function_state()->is_construct(), |
| 5430 function->scope()->arguments())); |
| 5431 function_state()->set_entry(enter_inlined); |
| 5380 VisitDeclarations(target_info.scope()->declarations()); | 5432 VisitDeclarations(target_info.scope()->declarations()); |
| 5381 VisitStatements(function->body()); | 5433 VisitStatements(function->body()); |
| 5382 if (HasStackOverflow()) { | 5434 if (HasStackOverflow()) { |
| 5383 // Bail out if the inline function did, as we cannot residualize a call | 5435 // Bail out if the inline function did, as we cannot residualize a call |
| 5384 // instead. | 5436 // instead. |
| 5385 TraceInline(target, caller, "inline graph construction failed"); | 5437 TraceInline(target, caller, "inline graph construction failed"); |
| 5386 target_shared->DisableOptimization(); | 5438 target_shared->DisableOptimization(); |
| 5387 inline_bailout_ = true; | 5439 inline_bailout_ = true; |
| 5388 delete target_state; | 5440 delete target_state; |
| 5389 return true; | 5441 return true; |
| 5390 } | 5442 } |
| 5391 | 5443 |
| 5392 // Update inlined nodes count. | 5444 // Update inlined nodes count. |
| 5393 inlined_count_ += nodes_added; | 5445 inlined_count_ += nodes_added; |
| 5394 | 5446 |
| 5395 TraceInline(target, caller, NULL); | 5447 TraceInline(target, caller, NULL); |
| 5396 | 5448 |
| 5397 if (current_block() != NULL) { | 5449 if (current_block() != NULL) { |
| 5398 // Add default return value (i.e. undefined for normals calls or the newly | 5450 // Add default return value (i.e. undefined for normals calls or the newly |
| 5399 // allocated receiver for construct calls) if control can fall off the | 5451 // allocated receiver for construct calls) if control can fall off the |
| 5400 // body. In a test context, undefined is false and any JSObject is true. | 5452 // body. In a test context, undefined is false and any JSObject is true. |
| 5401 if (call_context()->IsValue()) { | 5453 if (call_context()->IsValue()) { |
| 5402 ASSERT(function_return() != NULL); | 5454 ASSERT(function_return() != NULL); |
| 5403 HValue* return_value = function_state()->is_construct() | 5455 HValue* return_value = function_state()->is_construct() |
| 5404 ? receiver | 5456 ? receiver |
| 5405 : undefined; | 5457 : undefined; |
| 5406 current_block()->AddLeaveInlined(return_value, | 5458 current_block()->AddLeaveInlined(return_value, |
| 5407 function_return(), | 5459 function_return(), |
| 5408 function_state()->drop_extra()); | 5460 function_state()); |
| 5409 } else if (call_context()->IsEffect()) { | 5461 } else if (call_context()->IsEffect()) { |
| 5410 ASSERT(function_return() != NULL); | 5462 ASSERT(function_return() != NULL); |
| 5411 current_block()->Goto(function_return(), function_state()->drop_extra()); | 5463 current_block()->Goto(function_return(), function_state()); |
| 5412 } else { | 5464 } else { |
| 5413 ASSERT(call_context()->IsTest()); | 5465 ASSERT(call_context()->IsTest()); |
| 5414 ASSERT(inlined_test_context() != NULL); | 5466 ASSERT(inlined_test_context() != NULL); |
| 5415 HBasicBlock* target = function_state()->is_construct() | 5467 HBasicBlock* target = function_state()->is_construct() |
| 5416 ? inlined_test_context()->if_true() | 5468 ? inlined_test_context()->if_true() |
| 5417 : inlined_test_context()->if_false(); | 5469 : inlined_test_context()->if_false(); |
| 5418 current_block()->Goto(target, function_state()->drop_extra()); | 5470 current_block()->Goto(target, function_state()); |
| 5419 } | 5471 } |
| 5420 } | 5472 } |
| 5421 | 5473 |
| 5422 // Fix up the function exits. | 5474 // Fix up the function exits. |
| 5423 if (inlined_test_context() != NULL) { | 5475 if (inlined_test_context() != NULL) { |
| 5424 HBasicBlock* if_true = inlined_test_context()->if_true(); | 5476 HBasicBlock* if_true = inlined_test_context()->if_true(); |
| 5425 HBasicBlock* if_false = inlined_test_context()->if_false(); | 5477 HBasicBlock* if_false = inlined_test_context()->if_false(); |
| 5426 | 5478 |
| 5427 // Pop the return test context from the expression context stack. | 5479 // Pop the return test context from the expression context stack. |
| 5428 ASSERT(ast_context() == inlined_test_context()); | 5480 ASSERT(ast_context() == inlined_test_context()); |
| 5429 ClearInlinedTestContext(); | 5481 ClearInlinedTestContext(); |
| 5430 delete target_state; | 5482 delete target_state; |
| 5431 | 5483 |
| 5432 // Forward to the real test context. | 5484 // Forward to the real test context. |
| 5433 if (if_true->HasPredecessor()) { | 5485 if (if_true->HasPredecessor()) { |
| 5434 if_true->SetJoinId(ast_id); | 5486 if_true->SetJoinId(ast_id); |
| 5435 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); | 5487 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); |
| 5436 if_true->Goto(true_target, function_state()->drop_extra()); | 5488 if_true->Goto(true_target, function_state()); |
| 5437 } | 5489 } |
| 5438 if (if_false->HasPredecessor()) { | 5490 if (if_false->HasPredecessor()) { |
| 5439 if_false->SetJoinId(ast_id); | 5491 if_false->SetJoinId(ast_id); |
| 5440 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); | 5492 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); |
| 5441 if_false->Goto(false_target, function_state()->drop_extra()); | 5493 if_false->Goto(false_target, function_state()); |
| 5442 } | 5494 } |
| 5443 set_current_block(NULL); | 5495 set_current_block(NULL); |
| 5444 return true; | 5496 return true; |
| 5445 | 5497 |
| 5446 } else if (function_return()->HasPredecessor()) { | 5498 } else if (function_return()->HasPredecessor()) { |
| 5447 function_return()->SetJoinId(ast_id); | 5499 function_return()->SetJoinId(ast_id); |
| 5448 set_current_block(function_return()); | 5500 set_current_block(function_return()); |
| 5449 } else { | 5501 } else { |
| 5450 set_current_block(NULL); | 5502 set_current_block(NULL); |
| 5451 } | 5503 } |
| (...skipping 2704 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8156 } | 8208 } |
| 8157 } | 8209 } |
| 8158 | 8210 |
| 8159 #ifdef DEBUG | 8211 #ifdef DEBUG |
| 8160 if (graph_ != NULL) graph_->Verify(false); // No full verify. | 8212 if (graph_ != NULL) graph_->Verify(false); // No full verify. |
| 8161 if (allocator_ != NULL) allocator_->Verify(); | 8213 if (allocator_ != NULL) allocator_->Verify(); |
| 8162 #endif | 8214 #endif |
| 8163 } | 8215 } |
| 8164 | 8216 |
| 8165 } } // namespace v8::internal | 8217 } } // namespace v8::internal |
| OLD | NEW |