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 474 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2848 CHECK_ALIVE(VisitForValue(stmt->expression())); | 2856 CHECK_ALIVE(VisitForValue(stmt->expression())); |
2849 HValue* result = environment()->Pop(); | 2857 HValue* result = environment()->Pop(); |
2850 current_block()->FinishExit(new(zone()) HReturn(result)); | 2858 current_block()->FinishExit(new(zone()) HReturn(result)); |
2851 } else if (function_state()->is_construct()) { | 2859 } else if (function_state()->is_construct()) { |
2852 // Return from an inlined construct call. In a test context the return | 2860 // Return from an inlined construct call. In a test context the return |
2853 // value will always evaluate to true, in a value context the return value | 2861 // value will always evaluate to true, in a value context the return value |
2854 // needs to be a JSObject. | 2862 // needs to be a JSObject. |
2855 if (context->IsTest()) { | 2863 if (context->IsTest()) { |
2856 TestContext* test = TestContext::cast(context); | 2864 TestContext* test = TestContext::cast(context); |
2857 CHECK_ALIVE(VisitForEffect(stmt->expression())); | 2865 CHECK_ALIVE(VisitForEffect(stmt->expression())); |
2858 current_block()->Goto(test->if_true(), function_state()->drop_extra()); | 2866 current_block()->Goto(test->if_true(), function_state()); |
2859 } else if (context->IsEffect()) { | 2867 } else if (context->IsEffect()) { |
2860 CHECK_ALIVE(VisitForEffect(stmt->expression())); | 2868 CHECK_ALIVE(VisitForEffect(stmt->expression())); |
2861 current_block()->Goto(function_return(), function_state()->drop_extra()); | 2869 current_block()->Goto(function_return(), function_state()); |
2862 } else { | 2870 } else { |
2863 ASSERT(context->IsValue()); | 2871 ASSERT(context->IsValue()); |
2864 CHECK_ALIVE(VisitForValue(stmt->expression())); | 2872 CHECK_ALIVE(VisitForValue(stmt->expression())); |
2865 HValue* return_value = Pop(); | 2873 HValue* return_value = Pop(); |
2866 HValue* receiver = environment()->Lookup(0); | 2874 HValue* receiver = environment()->Lookup(0); |
2867 HHasInstanceTypeAndBranch* typecheck = | 2875 HHasInstanceTypeAndBranch* typecheck = |
2868 new(zone()) HHasInstanceTypeAndBranch(return_value, | 2876 new(zone()) HHasInstanceTypeAndBranch(return_value, |
2869 FIRST_SPEC_OBJECT_TYPE, | 2877 FIRST_SPEC_OBJECT_TYPE, |
2870 LAST_SPEC_OBJECT_TYPE); | 2878 LAST_SPEC_OBJECT_TYPE); |
2871 HBasicBlock* if_spec_object = graph()->CreateBasicBlock(); | 2879 HBasicBlock* if_spec_object = graph()->CreateBasicBlock(); |
2872 HBasicBlock* not_spec_object = graph()->CreateBasicBlock(); | 2880 HBasicBlock* not_spec_object = graph()->CreateBasicBlock(); |
2873 typecheck->SetSuccessorAt(0, if_spec_object); | 2881 typecheck->SetSuccessorAt(0, if_spec_object); |
2874 typecheck->SetSuccessorAt(1, not_spec_object); | 2882 typecheck->SetSuccessorAt(1, not_spec_object); |
2875 current_block()->Finish(typecheck); | 2883 current_block()->Finish(typecheck); |
2876 if_spec_object->AddLeaveInlined(return_value, | 2884 if_spec_object->AddLeaveInlined(return_value, |
2877 function_return(), | 2885 function_return(), |
2878 function_state()->drop_extra()); | 2886 function_state()); |
2879 not_spec_object->AddLeaveInlined(receiver, | 2887 not_spec_object->AddLeaveInlined(receiver, |
2880 function_return(), | 2888 function_return(), |
2881 function_state()->drop_extra()); | 2889 function_state()); |
2882 } | 2890 } |
2883 } else { | 2891 } else { |
2884 // Return from an inlined function, visit the subexpression in the | 2892 // Return from an inlined function, visit the subexpression in the |
2885 // expression context of the call. | 2893 // expression context of the call. |
2886 if (context->IsTest()) { | 2894 if (context->IsTest()) { |
2887 TestContext* test = TestContext::cast(context); | 2895 TestContext* test = TestContext::cast(context); |
2888 VisitForControl(stmt->expression(), | 2896 VisitForControl(stmt->expression(), |
2889 test->if_true(), | 2897 test->if_true(), |
2890 test->if_false()); | 2898 test->if_false()); |
2891 } else if (context->IsEffect()) { | 2899 } else if (context->IsEffect()) { |
2892 CHECK_ALIVE(VisitForEffect(stmt->expression())); | 2900 CHECK_ALIVE(VisitForEffect(stmt->expression())); |
2893 current_block()->Goto(function_return(), function_state()->drop_extra()); | 2901 current_block()->Goto(function_return(), function_state()); |
2894 } else { | 2902 } else { |
2895 ASSERT(context->IsValue()); | 2903 ASSERT(context->IsValue()); |
2896 CHECK_ALIVE(VisitForValue(stmt->expression())); | 2904 CHECK_ALIVE(VisitForValue(stmt->expression())); |
2897 HValue* return_value = Pop(); | 2905 HValue* return_value = Pop(); |
2898 current_block()->AddLeaveInlined(return_value, | 2906 current_block()->AddLeaveInlined(return_value, |
2899 function_return(), | 2907 function_return(), |
2900 function_state()->drop_extra()); | 2908 function_state()); |
2901 } | 2909 } |
2902 } | 2910 } |
2903 set_current_block(NULL); | 2911 set_current_block(NULL); |
2904 } | 2912 } |
2905 | 2913 |
2906 | 2914 |
2907 void HGraphBuilder::VisitWithStatement(WithStatement* stmt) { | 2915 void HGraphBuilder::VisitWithStatement(WithStatement* stmt) { |
2908 ASSERT(!HasStackOverflow()); | 2916 ASSERT(!HasStackOverflow()); |
2909 ASSERT(current_block() != NULL); | 2917 ASSERT(current_block() != NULL); |
2910 ASSERT(current_block()->HasPredecessor()); | 2918 ASSERT(current_block()->HasPredecessor()); |
(...skipping 2066 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4977 HValue* value) { | 4985 HValue* value) { |
4978 HValue* context = environment()->LookupContext(); | 4986 HValue* context = environment()->LookupContext(); |
4979 return new(zone()) HStoreKeyedGeneric( | 4987 return new(zone()) HStoreKeyedGeneric( |
4980 context, | 4988 context, |
4981 object, | 4989 object, |
4982 key, | 4990 key, |
4983 value, | 4991 value, |
4984 function_strict_mode_flag()); | 4992 function_strict_mode_flag()); |
4985 } | 4993 } |
4986 | 4994 |
| 4995 |
| 4996 void HGraphBuilder::EnsureArgumentsArePushedForAccess() { |
| 4997 // Outermost function already has arguments on the stack. |
| 4998 if (function_state()->outer() == NULL) return; |
| 4999 |
| 5000 if (function_state()->arguments_pushed()) return; |
| 5001 |
| 5002 // Push arguments when entering inlined function. |
| 5003 HEnterInlined* entry = function_state()->entry(); |
| 5004 |
| 5005 ZoneList<HValue*>* arguments_values = entry->arguments_values(); |
| 5006 |
| 5007 HInstruction* insert_after = entry; |
| 5008 for (int i = 0; i < arguments_values->length(); i++) { |
| 5009 HValue* argument = arguments_values->at(i); |
| 5010 HInstruction* push_argument = new(zone()) HPushArgument(argument); |
| 5011 push_argument->InsertAfter(insert_after); |
| 5012 insert_after = push_argument; |
| 5013 } |
| 5014 |
| 5015 HArgumentsElements* arguments_elements = |
| 5016 new(zone()) HArgumentsElements(true); |
| 5017 arguments_elements->ClearFlag(HValue::kUseGVN); |
| 5018 arguments_elements->InsertAfter(insert_after); |
| 5019 function_state()->set_arguments_elements(arguments_elements); |
| 5020 } |
| 5021 |
| 5022 |
4987 bool HGraphBuilder::TryArgumentsAccess(Property* expr) { | 5023 bool HGraphBuilder::TryArgumentsAccess(Property* expr) { |
4988 VariableProxy* proxy = expr->obj()->AsVariableProxy(); | 5024 VariableProxy* proxy = expr->obj()->AsVariableProxy(); |
4989 if (proxy == NULL) return false; | 5025 if (proxy == NULL) return false; |
4990 if (!proxy->var()->IsStackAllocated()) return false; | 5026 if (!proxy->var()->IsStackAllocated()) return false; |
4991 if (!environment()->Lookup(proxy->var())->CheckFlag(HValue::kIsArguments)) { | 5027 if (!environment()->Lookup(proxy->var())->CheckFlag(HValue::kIsArguments)) { |
4992 return false; | 5028 return false; |
4993 } | 5029 } |
4994 | 5030 |
4995 // Our implementation of arguments (based on this stack frame or an | |
4996 // adapter below it) does not work for inlined functions. | |
4997 if (function_state()->outer() != NULL) { | |
4998 Bailout("arguments access in inlined function"); | |
4999 return true; | |
5000 } | |
5001 | |
5002 HInstruction* result = NULL; | 5031 HInstruction* result = NULL; |
5003 if (expr->key()->IsPropertyName()) { | 5032 if (expr->key()->IsPropertyName()) { |
5004 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); | 5033 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); |
5005 if (!name->IsEqualTo(CStrVector("length"))) return false; | 5034 if (!name->IsEqualTo(CStrVector("length"))) return false; |
5006 HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); | 5035 |
5007 result = new(zone()) HArgumentsLength(elements); | 5036 if (function_state()->outer() == NULL) { |
| 5037 HInstruction* elements = AddInstruction( |
| 5038 new(zone()) HArgumentsElements(false)); |
| 5039 result = new(zone()) HArgumentsLength(elements); |
| 5040 } else { |
| 5041 // Number of arguments without receiver. |
| 5042 int argument_count = environment()-> |
| 5043 arguments_environment()->parameter_count() - 1; |
| 5044 result = new(zone()) HConstant( |
| 5045 Handle<Object>(Smi::FromInt(argument_count)), |
| 5046 Representation::Integer32()); |
| 5047 } |
5008 } else { | 5048 } else { |
5009 Push(graph()->GetArgumentsObject()); | 5049 Push(graph()->GetArgumentsObject()); |
5010 VisitForValue(expr->key()); | 5050 VisitForValue(expr->key()); |
5011 if (HasStackOverflow() || current_block() == NULL) return true; | 5051 if (HasStackOverflow() || current_block() == NULL) return true; |
5012 HValue* key = Pop(); | 5052 HValue* key = Pop(); |
5013 Drop(1); // Arguments object. | 5053 Drop(1); // Arguments object. |
5014 HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); | 5054 if (function_state()->outer() == NULL) { |
5015 HInstruction* length = AddInstruction( | 5055 HInstruction* elements = AddInstruction( |
5016 new(zone()) HArgumentsLength(elements)); | 5056 new(zone()) HArgumentsElements(false)); |
5017 HInstruction* checked_key = | 5057 HInstruction* length = AddInstruction( |
5018 AddInstruction(new(zone()) HBoundsCheck(key, length)); | 5058 new(zone()) HArgumentsLength(elements)); |
5019 result = new(zone()) HAccessArgumentsAt(elements, length, checked_key); | 5059 HInstruction* checked_key = |
| 5060 AddInstruction(new(zone()) HBoundsCheck(key, length)); |
| 5061 result = new(zone()) HAccessArgumentsAt(elements, length, checked_key); |
| 5062 } else { |
| 5063 EnsureArgumentsArePushedForAccess(); |
| 5064 |
| 5065 // Number of arguments without receiver. |
| 5066 HInstruction* elements = function_state()->arguments_elements(); |
| 5067 int argument_count = environment()-> |
| 5068 arguments_environment()->parameter_count() - 1; |
| 5069 HInstruction* length = AddInstruction(new(zone()) HConstant( |
| 5070 Handle<Object>(Smi::FromInt(argument_count)), |
| 5071 Representation::Integer32())); |
| 5072 HInstruction* checked_key = |
| 5073 AddInstruction(new(zone()) HBoundsCheck(key, length)); |
| 5074 result = new(zone()) HAccessArgumentsAt(elements, length, checked_key); |
| 5075 } |
5020 } | 5076 } |
5021 ast_context()->ReturnInstruction(result, expr->id()); | 5077 ast_context()->ReturnInstruction(result, expr->id()); |
5022 return true; | 5078 return true; |
5023 } | 5079 } |
5024 | 5080 |
5025 | 5081 |
5026 void HGraphBuilder::VisitProperty(Property* expr) { | 5082 void HGraphBuilder::VisitProperty(Property* expr) { |
5027 ASSERT(!HasStackOverflow()); | 5083 ASSERT(!HasStackOverflow()); |
5028 ASSERT(current_block() != NULL); | 5084 ASSERT(current_block() != NULL); |
5029 ASSERT(current_block()->HasPredecessor()); | 5085 ASSERT(current_block()->HasPredecessor()); |
(...skipping 386 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5416 // IA32 only, overwrite the caller's context in the deoptimization | 5472 // IA32 only, overwrite the caller's context in the deoptimization |
5417 // environment with the correct one. | 5473 // environment with the correct one. |
5418 // | 5474 // |
5419 // TODO(kmillikin): implement the same inlining on other platforms so we | 5475 // TODO(kmillikin): implement the same inlining on other platforms so we |
5420 // can remove the unsightly ifdefs in this function. | 5476 // can remove the unsightly ifdefs in this function. |
5421 HConstant* context = new HConstant(Handle<Context>(target->context()), | 5477 HConstant* context = new HConstant(Handle<Context>(target->context()), |
5422 Representation::Tagged()); | 5478 Representation::Tagged()); |
5423 AddInstruction(context); | 5479 AddInstruction(context); |
5424 inner_env->BindContext(context); | 5480 inner_env->BindContext(context); |
5425 #endif | 5481 #endif |
| 5482 |
5426 AddSimulate(return_id); | 5483 AddSimulate(return_id); |
5427 current_block()->UpdateEnvironment(inner_env); | 5484 current_block()->UpdateEnvironment(inner_env); |
5428 AddInstruction(new(zone()) HEnterInlined(target, | 5485 |
5429 arguments->length(), | 5486 ZoneList<HValue*>* arguments_values = NULL; |
5430 function, | 5487 |
5431 call_kind, | 5488 // If the function uses arguments copy current arguments values |
5432 function_state()->is_construct(), | 5489 // to use them for materialization. |
5433 function->scope()->arguments())); | 5490 if (function->scope()->arguments() != NULL) { |
| 5491 HEnvironment* arguments_env = inner_env->arguments_environment(); |
| 5492 int arguments_count = arguments_env->parameter_count(); |
| 5493 arguments_values = new(zone()) ZoneList<HValue*>(arguments_count); |
| 5494 for (int i = 0; i < arguments_count; i++) { |
| 5495 arguments_values->Add(arguments_env->Lookup(i)); |
| 5496 } |
| 5497 } |
| 5498 |
| 5499 HEnterInlined* enter_inlined = |
| 5500 new(zone()) HEnterInlined(target, |
| 5501 arguments->length(), |
| 5502 function, |
| 5503 call_kind, |
| 5504 function_state()->is_construct(), |
| 5505 function->scope()->arguments(), |
| 5506 arguments_values); |
| 5507 function_state()->set_entry(enter_inlined); |
| 5508 AddInstruction(enter_inlined); |
| 5509 |
5434 // If the function uses arguments object create and bind one. | 5510 // If the function uses arguments object create and bind one. |
5435 if (function->scope()->arguments() != NULL) { | 5511 if (function->scope()->arguments() != NULL) { |
5436 ASSERT(function->scope()->arguments()->IsStackAllocated()); | 5512 ASSERT(function->scope()->arguments()->IsStackAllocated()); |
5437 environment()->Bind(function->scope()->arguments(), | 5513 inner_env->Bind(function->scope()->arguments(), |
5438 graph()->GetArgumentsObject()); | 5514 graph()->GetArgumentsObject()); |
5439 } | 5515 } |
| 5516 |
| 5517 |
5440 VisitDeclarations(target_info.scope()->declarations()); | 5518 VisitDeclarations(target_info.scope()->declarations()); |
5441 VisitStatements(function->body()); | 5519 VisitStatements(function->body()); |
5442 if (HasStackOverflow()) { | 5520 if (HasStackOverflow()) { |
5443 // Bail out if the inline function did, as we cannot residualize a call | 5521 // Bail out if the inline function did, as we cannot residualize a call |
5444 // instead. | 5522 // instead. |
5445 TraceInline(target, caller, "inline graph construction failed"); | 5523 TraceInline(target, caller, "inline graph construction failed"); |
5446 target_shared->DisableOptimization(); | 5524 target_shared->DisableOptimization(); |
5447 inline_bailout_ = true; | 5525 inline_bailout_ = true; |
5448 delete target_state; | 5526 delete target_state; |
5449 return true; | 5527 return true; |
5450 } | 5528 } |
5451 | 5529 |
5452 // Update inlined nodes count. | 5530 // Update inlined nodes count. |
5453 inlined_count_ += nodes_added; | 5531 inlined_count_ += nodes_added; |
5454 | 5532 |
5455 TraceInline(target, caller, NULL); | 5533 TraceInline(target, caller, NULL); |
5456 | 5534 |
5457 if (current_block() != NULL) { | 5535 if (current_block() != NULL) { |
5458 // Add default return value (i.e. undefined for normals calls or the newly | 5536 // Add default return value (i.e. undefined for normals calls or the newly |
5459 // allocated receiver for construct calls) if control can fall off the | 5537 // allocated receiver for construct calls) if control can fall off the |
5460 // body. In a test context, undefined is false and any JSObject is true. | 5538 // body. In a test context, undefined is false and any JSObject is true. |
5461 if (call_context()->IsValue()) { | 5539 if (call_context()->IsValue()) { |
5462 ASSERT(function_return() != NULL); | 5540 ASSERT(function_return() != NULL); |
5463 HValue* return_value = function_state()->is_construct() | 5541 HValue* return_value = function_state()->is_construct() |
5464 ? receiver | 5542 ? receiver |
5465 : undefined; | 5543 : undefined; |
5466 current_block()->AddLeaveInlined(return_value, | 5544 current_block()->AddLeaveInlined(return_value, |
5467 function_return(), | 5545 function_return(), |
5468 function_state()->drop_extra()); | 5546 function_state()); |
5469 } else if (call_context()->IsEffect()) { | 5547 } else if (call_context()->IsEffect()) { |
5470 ASSERT(function_return() != NULL); | 5548 ASSERT(function_return() != NULL); |
5471 current_block()->Goto(function_return(), function_state()->drop_extra()); | 5549 current_block()->Goto(function_return(), function_state()); |
5472 } else { | 5550 } else { |
5473 ASSERT(call_context()->IsTest()); | 5551 ASSERT(call_context()->IsTest()); |
5474 ASSERT(inlined_test_context() != NULL); | 5552 ASSERT(inlined_test_context() != NULL); |
5475 HBasicBlock* target = function_state()->is_construct() | 5553 HBasicBlock* target = function_state()->is_construct() |
5476 ? inlined_test_context()->if_true() | 5554 ? inlined_test_context()->if_true() |
5477 : inlined_test_context()->if_false(); | 5555 : inlined_test_context()->if_false(); |
5478 current_block()->Goto(target, function_state()->drop_extra()); | 5556 current_block()->Goto(target, function_state()); |
5479 } | 5557 } |
5480 } | 5558 } |
5481 | 5559 |
5482 // Fix up the function exits. | 5560 // Fix up the function exits. |
5483 if (inlined_test_context() != NULL) { | 5561 if (inlined_test_context() != NULL) { |
5484 HBasicBlock* if_true = inlined_test_context()->if_true(); | 5562 HBasicBlock* if_true = inlined_test_context()->if_true(); |
5485 HBasicBlock* if_false = inlined_test_context()->if_false(); | 5563 HBasicBlock* if_false = inlined_test_context()->if_false(); |
5486 | 5564 |
5487 // Pop the return test context from the expression context stack. | 5565 // Pop the return test context from the expression context stack. |
5488 ASSERT(ast_context() == inlined_test_context()); | 5566 ASSERT(ast_context() == inlined_test_context()); |
5489 ClearInlinedTestContext(); | 5567 ClearInlinedTestContext(); |
5490 delete target_state; | 5568 delete target_state; |
5491 | 5569 |
5492 // Forward to the real test context. | 5570 // Forward to the real test context. |
5493 if (if_true->HasPredecessor()) { | 5571 if (if_true->HasPredecessor()) { |
5494 if_true->SetJoinId(ast_id); | 5572 if_true->SetJoinId(ast_id); |
5495 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); | 5573 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); |
5496 if_true->Goto(true_target, function_state()->drop_extra()); | 5574 if_true->Goto(true_target, function_state()); |
5497 } | 5575 } |
5498 if (if_false->HasPredecessor()) { | 5576 if (if_false->HasPredecessor()) { |
5499 if_false->SetJoinId(ast_id); | 5577 if_false->SetJoinId(ast_id); |
5500 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); | 5578 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); |
5501 if_false->Goto(false_target, function_state()->drop_extra()); | 5579 if_false->Goto(false_target, function_state()); |
5502 } | 5580 } |
5503 set_current_block(NULL); | 5581 set_current_block(NULL); |
5504 return true; | 5582 return true; |
5505 | 5583 |
5506 } else if (function_return()->HasPredecessor()) { | 5584 } else if (function_return()->HasPredecessor()) { |
5507 function_return()->SetJoinId(ast_id); | 5585 function_return()->SetJoinId(ast_id); |
5508 set_current_block(function_return()); | 5586 set_current_block(function_return()); |
5509 } else { | 5587 } else { |
5510 set_current_block(NULL); | 5588 set_current_block(NULL); |
5511 } | 5589 } |
(...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5800 if (HasStackOverflow() || current_block() == NULL) return true; | 5878 if (HasStackOverflow() || current_block() == NULL) return true; |
5801 HValue* function = Top(); | 5879 HValue* function = Top(); |
5802 AddCheckConstantFunction(expr, function, function_map, true); | 5880 AddCheckConstantFunction(expr, function, function_map, true); |
5803 Drop(1); | 5881 Drop(1); |
5804 | 5882 |
5805 VisitForValue(args->at(0)); | 5883 VisitForValue(args->at(0)); |
5806 if (HasStackOverflow() || current_block() == NULL) return true; | 5884 if (HasStackOverflow() || current_block() == NULL) return true; |
5807 HValue* receiver = Pop(); | 5885 HValue* receiver = Pop(); |
5808 | 5886 |
5809 if (function_state()->outer() == NULL) { | 5887 if (function_state()->outer() == NULL) { |
5810 HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); | 5888 HInstruction* elements = AddInstruction( |
| 5889 new(zone()) HArgumentsElements(false)); |
5811 HInstruction* length = | 5890 HInstruction* length = |
5812 AddInstruction(new(zone()) HArgumentsLength(elements)); | 5891 AddInstruction(new(zone()) HArgumentsLength(elements)); |
5813 HValue* wrapped_receiver = | 5892 HValue* wrapped_receiver = |
5814 AddInstruction(new(zone()) HWrapReceiver(receiver, function)); | 5893 AddInstruction(new(zone()) HWrapReceiver(receiver, function)); |
5815 HInstruction* result = | 5894 HInstruction* result = |
5816 new(zone()) HApplyArguments(function, | 5895 new(zone()) HApplyArguments(function, |
5817 wrapped_receiver, | 5896 wrapped_receiver, |
5818 length, | 5897 length, |
5819 elements); | 5898 elements); |
5820 result->set_position(expr->position()); | 5899 result->set_position(expr->position()); |
(...skipping 1449 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7270 } | 7349 } |
7271 | 7350 |
7272 | 7351 |
7273 // Support for arguments.length and arguments[?]. | 7352 // Support for arguments.length and arguments[?]. |
7274 void HGraphBuilder::GenerateArgumentsLength(CallRuntime* call) { | 7353 void HGraphBuilder::GenerateArgumentsLength(CallRuntime* call) { |
7275 // Our implementation of arguments (based on this stack frame or an | 7354 // Our implementation of arguments (based on this stack frame or an |
7276 // adapter below it) does not work for inlined functions. This runtime | 7355 // adapter below it) does not work for inlined functions. This runtime |
7277 // function is blacklisted by AstNode::IsInlineable. | 7356 // function is blacklisted by AstNode::IsInlineable. |
7278 ASSERT(function_state()->outer() == NULL); | 7357 ASSERT(function_state()->outer() == NULL); |
7279 ASSERT(call->arguments()->length() == 0); | 7358 ASSERT(call->arguments()->length() == 0); |
7280 HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); | 7359 HInstruction* elements = AddInstruction( |
| 7360 new(zone()) HArgumentsElements(false)); |
7281 HArgumentsLength* result = new(zone()) HArgumentsLength(elements); | 7361 HArgumentsLength* result = new(zone()) HArgumentsLength(elements); |
7282 return ast_context()->ReturnInstruction(result, call->id()); | 7362 return ast_context()->ReturnInstruction(result, call->id()); |
7283 } | 7363 } |
7284 | 7364 |
7285 | 7365 |
7286 void HGraphBuilder::GenerateArguments(CallRuntime* call) { | 7366 void HGraphBuilder::GenerateArguments(CallRuntime* call) { |
7287 // Our implementation of arguments (based on this stack frame or an | 7367 // Our implementation of arguments (based on this stack frame or an |
7288 // adapter below it) does not work for inlined functions. This runtime | 7368 // adapter below it) does not work for inlined functions. This runtime |
7289 // function is blacklisted by AstNode::IsInlineable. | 7369 // function is blacklisted by AstNode::IsInlineable. |
7290 ASSERT(function_state()->outer() == NULL); | 7370 ASSERT(function_state()->outer() == NULL); |
7291 ASSERT(call->arguments()->length() == 1); | 7371 ASSERT(call->arguments()->length() == 1); |
7292 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 7372 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
7293 HValue* index = Pop(); | 7373 HValue* index = Pop(); |
7294 HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); | 7374 HInstruction* elements = AddInstruction( |
| 7375 new(zone()) HArgumentsElements(false)); |
7295 HInstruction* length = AddInstruction(new(zone()) HArgumentsLength(elements)); | 7376 HInstruction* length = AddInstruction(new(zone()) HArgumentsLength(elements)); |
7296 HAccessArgumentsAt* result = | 7377 HAccessArgumentsAt* result = |
7297 new(zone()) HAccessArgumentsAt(elements, length, index); | 7378 new(zone()) HAccessArgumentsAt(elements, length, index); |
7298 return ast_context()->ReturnInstruction(result, call->id()); | 7379 return ast_context()->ReturnInstruction(result, call->id()); |
7299 } | 7380 } |
7300 | 7381 |
7301 | 7382 |
7302 // Support for accessing the class and value fields of an object. | 7383 // Support for accessing the class and value fields of an object. |
7303 void HGraphBuilder::GenerateClassOf(CallRuntime* call) { | 7384 void HGraphBuilder::GenerateClassOf(CallRuntime* call) { |
7304 // The special form detected by IsClassOfTest is detected before we get here | 7385 // The special form detected by IsClassOfTest is detected before we get here |
(...skipping 934 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8239 } | 8320 } |
8240 } | 8321 } |
8241 | 8322 |
8242 #ifdef DEBUG | 8323 #ifdef DEBUG |
8243 if (graph_ != NULL) graph_->Verify(false); // No full verify. | 8324 if (graph_ != NULL) graph_->Verify(false); // No full verify. |
8244 if (allocator_ != NULL) allocator_->Verify(); | 8325 if (allocator_ != NULL) allocator_->Verify(); |
8245 #endif | 8326 #endif |
8246 } | 8327 } |
8247 | 8328 |
8248 } } // namespace v8::internal | 8329 } } // namespace v8::internal |
OLD | NEW |