Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 46 #endif | 46 #endif |
| 47 | 47 |
| 48 namespace v8 { | 48 namespace v8 { |
| 49 namespace internal { | 49 namespace internal { |
| 50 | 50 |
| 51 HBasicBlock::HBasicBlock(HGraph* graph) | 51 HBasicBlock::HBasicBlock(HGraph* graph) |
| 52 : block_id_(graph->GetNextBlockID()), | 52 : block_id_(graph->GetNextBlockID()), |
| 53 graph_(graph), | 53 graph_(graph), |
| 54 phis_(4), | 54 phis_(4), |
| 55 first_(NULL), | 55 first_(NULL), |
| 56 last_(NULL), | 56 cached_(NULL), |
| 57 end_(NULL), | 57 end_(NULL), |
| 58 loop_information_(NULL), | 58 loop_information_(NULL), |
| 59 predecessors_(2), | 59 predecessors_(2), |
| 60 dominator_(NULL), | 60 dominator_(NULL), |
| 61 dominated_blocks_(4), | 61 dominated_blocks_(4), |
| 62 last_environment_(NULL), | 62 last_environment_(NULL), |
| 63 argument_count_(-1), | 63 argument_count_(-1), |
| 64 first_instruction_index_(-1), | 64 first_instruction_index_(-1), |
| 65 last_instruction_index_(-1), | 65 last_instruction_index_(-1), |
| 66 deleted_phis_(4), | 66 deleted_phis_(4), |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 103 ASSERT(!IsFinished()); | 103 ASSERT(!IsFinished()); |
| 104 if (first_ == NULL) { | 104 if (first_ == NULL) { |
| 105 HBlockEntry* entry = new HBlockEntry(); | 105 HBlockEntry* entry = new HBlockEntry(); |
| 106 entry->InitializeAsFirst(this); | 106 entry->InitializeAsFirst(this); |
| 107 first_ = entry; | 107 first_ = entry; |
| 108 } | 108 } |
| 109 instr->InsertAfter(GetLastInstruction()); | 109 instr->InsertAfter(GetLastInstruction()); |
| 110 } | 110 } |
| 111 | 111 |
| 112 | 112 |
| 113 HInstruction* HBasicBlock::GetLastInstruction() { | 113 HInstruction* HBasicBlock::GetLastInstruction() { |
|
fschneider
2010/12/20 16:13:02
I'd strongly favor removing this function together
Kevin Millikin (Chromium)
2010/12/21 11:16:37
Strongly agreed.
| |
| 114 if (end_ != NULL) return end_->previous(); | 114 if (end_ != NULL) return end_->previous(); |
| 115 if (first_ == NULL) return NULL; | 115 if (first_ == NULL) return NULL; |
| 116 if (last_ == NULL) last_ = first_; | 116 // Search starting from cached_ if we have it and it hasn't been removed |
| 117 while (last_->next() != NULL) last_ = last_->next(); | 117 // from this block. |
| 118 return last_; | 118 if (cached_ == NULL || cached_->block() != this) cached_ = first_; |
| 119 while (cached_->next() != NULL) cached_ = cached_->next(); | |
| 120 return cached_; | |
| 119 } | 121 } |
| 120 | 122 |
| 121 | 123 |
| 122 HSimulate* HBasicBlock::CreateSimulate(int id) { | 124 HSimulate* HBasicBlock::CreateSimulate(int id) { |
| 123 ASSERT(HasEnvironment()); | 125 ASSERT(HasEnvironment()); |
| 124 HEnvironment* environment = last_environment(); | 126 HEnvironment* environment = last_environment(); |
| 125 ASSERT(id == AstNode::kNoNumber || | 127 ASSERT(id == AstNode::kNoNumber || |
| 126 environment->closure()->shared()->VerifyBailoutId(id)); | 128 environment->closure()->shared()->VerifyBailoutId(id)); |
| 127 | 129 |
| 128 int push_count = environment->push_count(); | 130 int push_count = environment->push_count(); |
| (...skipping 2038 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2167 | 2169 |
| 2168 | 2170 |
| 2169 void HGraphBuilder::VisitForControl(Expression* expr, | 2171 void HGraphBuilder::VisitForControl(Expression* expr, |
| 2170 HBasicBlock* true_block, | 2172 HBasicBlock* true_block, |
| 2171 HBasicBlock* false_block) { | 2173 HBasicBlock* false_block) { |
| 2172 TestContext for_test(this, true_block, false_block); | 2174 TestContext for_test(this, true_block, false_block); |
| 2173 Visit(expr); | 2175 Visit(expr); |
| 2174 } | 2176 } |
| 2175 | 2177 |
| 2176 | 2178 |
| 2177 HValue* HGraphBuilder::VisitArgument(Expression* expr) { | 2179 void HGraphBuilder::VisitArgument(Expression* expr) { |
| 2178 VisitForValue(expr); | 2180 VISIT_FOR_VALUE(expr); |
| 2179 if (HasStackOverflow() || !subgraph()->HasExit()) return NULL; | 2181 if (!subgraph()->HasExit()) return; |
| 2180 return environment()->Top(); | 2182 HValue* value = Pop(); |
| 2183 HPushArgument* instr = new HPushArgument(value); | |
| 2184 AddInstruction(instr); | |
| 2185 Push(instr); | |
| 2181 } | 2186 } |
| 2182 | 2187 |
| 2183 | 2188 |
| 2184 void HGraphBuilder::VisitArgumentList(ZoneList<Expression*>* arguments) { | 2189 void HGraphBuilder::VisitArgumentList(ZoneList<Expression*>* arguments) { |
| 2185 for (int i = 0; i < arguments->length(); i++) { | 2190 for (int i = 0; i < arguments->length(); i++) { |
| 2186 VisitArgument(arguments->at(i)); | 2191 VisitArgument(arguments->at(i)); |
| 2187 if (HasStackOverflow() || !current_subgraph_->HasExit()) return; | 2192 if (HasStackOverflow() || !subgraph()->HasExit()) return; |
| 2188 } | 2193 } |
| 2189 } | 2194 } |
| 2190 | 2195 |
| 2191 | 2196 |
| 2192 HGraph* HGraphBuilder::CreateGraph(CompilationInfo* info) { | 2197 HGraph* HGraphBuilder::CreateGraph(CompilationInfo* info) { |
| 2193 ASSERT(current_subgraph_ == NULL); | 2198 ASSERT(current_subgraph_ == NULL); |
| 2194 graph_ = new HGraph(info); | 2199 graph_ = new HGraph(info); |
| 2195 | 2200 |
| 2196 { | 2201 { |
| 2197 HPhase phase("Block building"); | 2202 HPhase phase("Block building"); |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2288 current_subgraph_->exit_block()->AddPhi(instr); | 2293 current_subgraph_->exit_block()->AddPhi(instr); |
| 2289 } | 2294 } |
| 2290 | 2295 |
| 2291 | 2296 |
| 2292 void HGraphBuilder::PushAndAdd(HInstruction* instr) { | 2297 void HGraphBuilder::PushAndAdd(HInstruction* instr) { |
| 2293 Push(instr); | 2298 Push(instr); |
| 2294 AddInstruction(instr); | 2299 AddInstruction(instr); |
| 2295 } | 2300 } |
| 2296 | 2301 |
| 2297 | 2302 |
| 2298 void HGraphBuilder::PushArgumentsForStubCall(int argument_count) { | |
| 2299 const int kMaxStubArguments = 4; | |
| 2300 ASSERT_GE(kMaxStubArguments, argument_count); | |
| 2301 // Push the arguments on the stack. | |
| 2302 HValue* arguments[kMaxStubArguments]; | |
| 2303 for (int i = argument_count - 1; i >= 0; i--) { | |
| 2304 arguments[i] = Pop(); | |
| 2305 } | |
| 2306 for (int i = 0; i < argument_count; i++) { | |
| 2307 AddInstruction(new HPushArgument(arguments[i])); | |
| 2308 } | |
| 2309 } | |
| 2310 | |
| 2311 | |
| 2312 void HGraphBuilder::ProcessCall(HCall* call) { | |
| 2313 for (int i = call->argument_count() - 1; i >= 0; --i) { | |
| 2314 HValue* value = Pop(); | |
| 2315 HPushArgument* push = new HPushArgument(value); | |
| 2316 call->SetArgumentAt(i, push); | |
| 2317 } | |
| 2318 | |
| 2319 for (int i = 0; i < call->argument_count(); ++i) { | |
| 2320 AddInstruction(call->PushArgumentAt(i)); | |
| 2321 } | |
| 2322 } | |
| 2323 | |
| 2324 | |
| 2325 void HGraphBuilder::SetupScope(Scope* scope) { | 2303 void HGraphBuilder::SetupScope(Scope* scope) { |
| 2326 // We don't yet handle the function name for named function expressions. | 2304 // We don't yet handle the function name for named function expressions. |
| 2327 if (scope->function() != NULL) BAILOUT("named function expression"); | 2305 if (scope->function() != NULL) BAILOUT("named function expression"); |
| 2328 | 2306 |
| 2329 // We can't handle heap-allocated locals. | 2307 // We can't handle heap-allocated locals. |
| 2330 if (scope->num_heap_slots() > 0) BAILOUT("heap allocated locals"); | 2308 if (scope->num_heap_slots() > 0) BAILOUT("heap allocated locals"); |
| 2331 | 2309 |
| 2332 HConstant* undefined_constant = | 2310 HConstant* undefined_constant = |
| 2333 new HConstant(Factory::undefined_value(), Representation::Tagged()); | 2311 new HConstant(Factory::undefined_value(), Representation::Tagged()); |
| 2334 AddInstruction(undefined_constant); | 2312 AddInstruction(undefined_constant); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2369 | 2347 |
| 2370 HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) { | 2348 HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) { |
| 2371 HBasicBlock* b = graph()->CreateBasicBlock(); | 2349 HBasicBlock* b = graph()->CreateBasicBlock(); |
| 2372 b->SetInitialEnvironment(env); | 2350 b->SetInitialEnvironment(env); |
| 2373 return b; | 2351 return b; |
| 2374 } | 2352 } |
| 2375 | 2353 |
| 2376 | 2354 |
| 2377 HSubgraph* HGraphBuilder::CreateInlinedSubgraph(HEnvironment* outer, | 2355 HSubgraph* HGraphBuilder::CreateInlinedSubgraph(HEnvironment* outer, |
| 2378 Handle<JSFunction> target, | 2356 Handle<JSFunction> target, |
| 2379 FunctionLiteral* function) { | 2357 FunctionLiteral* function, |
| 2358 HGlobalReceiver* receiver) { | |
| 2380 HConstant* undefined = graph()->GetConstantUndefined(); | 2359 HConstant* undefined = graph()->GetConstantUndefined(); |
| 2381 HEnvironment* inner = | 2360 HEnvironment* inner = |
| 2382 outer->CopyForInlining(target, function, true, undefined); | 2361 outer->CopyForInlining(target, function, true, undefined, receiver); |
| 2383 HSubgraph* subgraph = new HSubgraph(graph()); | 2362 HSubgraph* subgraph = new HSubgraph(graph()); |
| 2384 subgraph->Initialize(CreateBasicBlock(inner)); | 2363 subgraph->Initialize(CreateBasicBlock(inner)); |
| 2385 return subgraph; | 2364 return subgraph; |
| 2386 } | 2365 } |
| 2387 | 2366 |
| 2388 | 2367 |
| 2389 HSubgraph* HGraphBuilder::CreateGotoSubgraph(HEnvironment* env) { | 2368 HSubgraph* HGraphBuilder::CreateGotoSubgraph(HEnvironment* env) { |
| 2390 HSubgraph* subgraph = new HSubgraph(graph()); | 2369 HSubgraph* subgraph = new HSubgraph(graph()); |
| 2391 HEnvironment* new_env = env->CopyWithoutHistory(); | 2370 HEnvironment* new_env = env->CopyWithoutHistory(); |
| 2392 subgraph->Initialize(CreateBasicBlock(new_env)); | 2371 subgraph->Initialize(CreateBasicBlock(new_env)); |
| (...skipping 667 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3060 ast_context()->ReturnValue(Pop()); | 3039 ast_context()->ReturnValue(Pop()); |
| 3061 } | 3040 } |
| 3062 | 3041 |
| 3063 | 3042 |
| 3064 void HGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) { | 3043 void HGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) { |
| 3065 BAILOUT("CatchExtensionObject"); | 3044 BAILOUT("CatchExtensionObject"); |
| 3066 } | 3045 } |
| 3067 | 3046 |
| 3068 | 3047 |
| 3069 HBasicBlock* HGraphBuilder::BuildTypeSwitch(ZoneMapList* maps, | 3048 HBasicBlock* HGraphBuilder::BuildTypeSwitch(ZoneMapList* maps, |
| 3070 ZoneList<HSubgraph*>* subgraphs, | 3049 ZoneList<HSubgraph*>* body_graphs, |
| 3050 HSubgraph* default_graph, | |
| 3071 HValue* receiver, | 3051 HValue* receiver, |
| 3072 int join_id) { | 3052 int join_id) { |
| 3073 ASSERT(subgraphs->length() == (maps->length() + 1)); | 3053 ASSERT(body_graphs->length() == maps->length()); |
| 3054 // Create one block to join them all. | |
| 3055 HBasicBlock* join_block = graph()->CreateBasicBlock(); | |
| 3074 | 3056 |
| 3075 // Build map compare subgraphs for all but the first map. | 3057 // Add a smi check before the first map check. |
| 3076 ZoneList<HSubgraph*> map_compare_subgraphs(maps->length() - 1); | 3058 AddInstruction(new HCheckNonSmi(receiver)); |
| 3077 for (int i = maps->length() - 1; i > 0; --i) { | 3059 |
| 3078 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3060 for (int i = 0; i < maps->length(); ++i) { |
| 3079 SubgraphScope scope(this, subgraph); | 3061 // Add a branch to the current subgraph. Use a fresh false subgraph for |
| 3080 HSubgraph* else_subgraph = | 3062 // each compare except the last, which uses the default. |
| 3081 (i == (maps->length() - 1)) | 3063 HSubgraph* true_subgraph = body_graphs->at(i); |
| 3082 ? subgraphs->last() | 3064 HSubgraph* false_subgraph = (i == maps->length() - 1) |
| 3083 : map_compare_subgraphs.last(); | 3065 ? default_graph |
| 3084 current_subgraph_->exit_block()->Finish( | 3066 : CreateBranchSubgraph(environment()); |
| 3085 new HCompareMapAndBranch(receiver, | 3067 HCompareMapAndBranch* compare = |
| 3086 maps->at(i), | 3068 new HCompareMapAndBranch(receiver, maps->at(i), |
| 3087 subgraphs->at(i)->entry_block(), | 3069 true_subgraph->entry_block(), |
| 3088 else_subgraph->entry_block())); | 3070 false_subgraph->entry_block()); |
| 3089 map_compare_subgraphs.Add(subgraph); | 3071 subgraph()->exit_block()->Finish(compare); |
| 3072 | |
| 3073 // Add a jump from the true subgraph's exit to the join block. | |
| 3074 if (true_subgraph->HasExit()) { | |
| 3075 true_subgraph->exit_block()->Goto(join_block); | |
| 3076 } | |
| 3077 | |
| 3078 // Set the current graph cursor to the false graph. | |
| 3079 subgraph()->set_exit_block(false_subgraph->exit_block()); | |
| 3090 } | 3080 } |
| 3091 | 3081 |
| 3092 // Generate first map check to end the current block. | 3082 // Add a jump from the default to the join block if necessary. |
| 3093 AddInstruction(new HCheckNonSmi(receiver)); | 3083 if (subgraph()->HasExit()) { |
| 3094 HSubgraph* else_subgraph = | 3084 subgraph()->exit_block()->Goto(join_block); |
| 3095 (maps->length() == 1) ? subgraphs->at(1) : map_compare_subgraphs.last(); | |
| 3096 current_subgraph_->exit_block()->Finish( | |
| 3097 new HCompareMapAndBranch(receiver, | |
| 3098 Handle<Map>(maps->first()), | |
| 3099 subgraphs->first()->entry_block(), | |
| 3100 else_subgraph->entry_block())); | |
| 3101 | |
| 3102 // Join all the call subgraphs in a new basic block and make | |
| 3103 // this basic block the current basic block. | |
| 3104 HBasicBlock* join_block = graph_->CreateBasicBlock(); | |
| 3105 for (int i = 0; i < subgraphs->length(); ++i) { | |
| 3106 if (subgraphs->at(i)->HasExit()) { | |
| 3107 subgraphs->at(i)->exit_block()->Goto(join_block); | |
| 3108 } | |
| 3109 } | 3085 } |
| 3110 | 3086 |
| 3111 if (join_block->predecessors()->is_empty()) return NULL; | 3087 // Return the join block if it is reachable. |
| 3112 join_block->SetJoinId(join_id); | 3088 if (join_block->predecessors()->is_empty()) { |
| 3113 return join_block; | 3089 return NULL; |
| 3090 } else { | |
| 3091 join_block->SetJoinId(join_id); | |
| 3092 return join_block; | |
| 3093 } | |
| 3114 } | 3094 } |
| 3115 | 3095 |
| 3116 | 3096 |
| 3117 // Sets the lookup result and returns true if the store can be inlined. | 3097 // Sets the lookup result and returns true if the store can be inlined. |
| 3118 static bool ComputeStoredField(Handle<Map> type, | 3098 static bool ComputeStoredField(Handle<Map> type, |
| 3119 Handle<String> name, | 3099 Handle<String> name, |
| 3120 LookupResult* lookup) { | 3100 LookupResult* lookup) { |
| 3121 type->LookupInDescriptors(NULL, *name, lookup); | 3101 type->LookupInDescriptors(NULL, *name, lookup); |
| 3122 if (!lookup->IsPropertyOrTransition()) return false; | 3102 if (!lookup->IsPropertyOrTransition()) return false; |
| 3123 if (lookup->type() == FIELD) return true; | 3103 if (lookup->type() == FIELD) return true; |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3202 } | 3182 } |
| 3203 | 3183 |
| 3204 | 3184 |
| 3205 void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr, | 3185 void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr, |
| 3206 HValue* object, | 3186 HValue* object, |
| 3207 HValue* value, | 3187 HValue* value, |
| 3208 ZoneMapList* types, | 3188 ZoneMapList* types, |
| 3209 Handle<String> name) { | 3189 Handle<String> name) { |
| 3210 int number_of_types = Min(types->length(), kMaxStorePolymorphism); | 3190 int number_of_types = Min(types->length(), kMaxStorePolymorphism); |
| 3211 ZoneMapList maps(number_of_types); | 3191 ZoneMapList maps(number_of_types); |
| 3212 ZoneList<HSubgraph*> subgraphs(number_of_types + 1); | 3192 ZoneList<HSubgraph*> store_graphs(number_of_types); |
| 3213 bool needs_generic = (types->length() > kMaxStorePolymorphism); | 3193 bool needs_generic = (types->length() > kMaxStorePolymorphism); |
| 3214 | 3194 |
| 3215 // Build subgraphs for each of the specific maps. | 3195 // Build subgraphs for each of the specific maps. |
| 3216 // | 3196 // |
| 3217 // TODO(ager): We should recognize when the prototype chains for | 3197 // TODO(ager): We should recognize when the prototype chains for different |
| 3218 // different maps are identical. In that case we can avoid | 3198 // maps are identical. In that case we can avoid repeatedly generating the |
| 3219 // repeatedly generating the same prototype map checks. | 3199 // same prototype map checks. |
| 3220 for (int i = 0; i < number_of_types; ++i) { | 3200 for (int i = 0; i < number_of_types; ++i) { |
| 3221 Handle<Map> map = types->at(i); | 3201 Handle<Map> map = types->at(i); |
| 3222 LookupResult lookup; | 3202 LookupResult lookup; |
| 3223 if (ComputeStoredField(map, name, &lookup)) { | 3203 if (ComputeStoredField(map, name, &lookup)) { |
| 3224 maps.Add(map); | 3204 HSubgraph* store_graph = CreateBranchSubgraph(environment()); |
| 3225 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3205 SubgraphScope scope(this, store_graph); |
| 3226 SubgraphScope scope(this, subgraph); | |
| 3227 HInstruction* instr = | 3206 HInstruction* instr = |
| 3228 BuildStoreNamedField(object, name, value, map, &lookup, false); | 3207 BuildStoreNamedField(object, name, value, map, &lookup, false); |
| 3229 Push(value); | 3208 Push(value); |
| 3230 instr->set_position(expr->position()); | 3209 instr->set_position(expr->position()); |
| 3231 AddInstruction(instr); | 3210 AddInstruction(instr); |
| 3232 subgraphs.Add(subgraph); | 3211 // BuildTypeSwitch will add an HGoto at the end of the store subgraph, |
| 3212 // which will emit a simulate capturing the side effect of the store. | |
| 3213 maps.Add(map); | |
| 3214 store_graphs.Add(store_graph); | |
| 3233 } else { | 3215 } else { |
| 3216 // We could not resolve the field statically so we need an IC store. | |
| 3234 needs_generic = true; | 3217 needs_generic = true; |
| 3235 } | 3218 } |
| 3236 } | 3219 } |
| 3237 | 3220 |
| 3238 // If none of the properties were named fields we generate a | 3221 // If none of the properties were resolved statically we generate a |
| 3239 // generic store. | 3222 // generic store. |
| 3240 if (maps.length() == 0) { | 3223 if (maps.is_empty()) { |
| 3241 HInstruction* instr = new HStoreNamedGeneric(object, name, value); | 3224 HInstruction* instr = new HStoreNamedGeneric(object, name, value); |
| 3242 Push(value); | 3225 Push(value); |
| 3243 instr->set_position(expr->position()); | 3226 instr->set_position(expr->position()); |
| 3244 AddInstruction(instr); | 3227 AddInstruction(instr); |
| 3245 if (instr->HasSideEffects()) AddSimulate(expr->id()); | 3228 if (instr->HasSideEffects()) AddSimulate(expr->id()); |
| 3246 } else { | 3229 ast_context()->ReturnValue(Pop()); |
| 3247 // Build subgraph for generic store through IC. | 3230 return; |
| 3248 { | |
| 3249 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | |
| 3250 SubgraphScope scope(this, subgraph); | |
| 3251 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { | |
| 3252 subgraph->FinishExit(new HDeoptimize()); | |
| 3253 } else { | |
| 3254 HInstruction* instr = new HStoreNamedGeneric(object, name, value); | |
| 3255 Push(value); | |
| 3256 instr->set_position(expr->position()); | |
| 3257 AddInstruction(instr); | |
| 3258 } | |
| 3259 subgraphs.Add(subgraph); | |
| 3260 } | |
| 3261 | |
| 3262 HBasicBlock* new_exit_block = | |
| 3263 BuildTypeSwitch(&maps, &subgraphs, object, expr->AssignmentId()); | |
| 3264 subgraph()->set_exit_block(new_exit_block); | |
| 3265 } | 3231 } |
| 3266 | 3232 |
| 3233 // Build subgraph for generic store through IC. | |
| 3234 HSubgraph* default_graph = CreateBranchSubgraph(environment()); | |
| 3235 { | |
| 3236 SubgraphScope scope(this, default_graph); | |
| 3237 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { | |
| 3238 default_graph->FinishExit(new HDeoptimize()); | |
|
fschneider
2010/12/20 16:13:02
Leave out () after HDeoptimize.
Kevin Millikin (Chromium)
2010/12/21 11:16:37
Thanks.
| |
| 3239 } else { | |
| 3240 HInstruction* instr = new HStoreNamedGeneric(object, name, value); | |
| 3241 Push(value); | |
| 3242 instr->set_position(expr->position()); | |
| 3243 AddInstruction(instr); | |
| 3244 } | |
| 3245 } | |
| 3246 | |
| 3247 HBasicBlock* new_exit_block = BuildTypeSwitch(&maps, | |
| 3248 &store_graphs, | |
| 3249 default_graph, | |
| 3250 object, | |
| 3251 expr->AssignmentId()); | |
| 3252 subgraph()->set_exit_block(new_exit_block); | |
| 3267 if (subgraph()->HasExit()) ast_context()->ReturnValue(Pop()); | 3253 if (subgraph()->HasExit()) ast_context()->ReturnValue(Pop()); |
| 3268 } | 3254 } |
| 3269 | 3255 |
| 3270 | 3256 |
| 3271 void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) { | 3257 void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) { |
| 3272 Property* prop = expr->target()->AsProperty(); | 3258 Property* prop = expr->target()->AsProperty(); |
| 3273 ASSERT(prop != NULL); | 3259 ASSERT(prop != NULL); |
| 3274 expr->RecordTypeFeedback(oracle()); | 3260 expr->RecordTypeFeedback(oracle()); |
| 3275 VISIT_FOR_VALUE(prop->obj()); | 3261 VISIT_FOR_VALUE(prop->obj()); |
| 3276 | 3262 |
| (...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3509 current_subgraph_->FinishExit(instr); | 3495 current_subgraph_->FinishExit(instr); |
| 3510 } | 3496 } |
| 3511 | 3497 |
| 3512 | 3498 |
| 3513 void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr, | 3499 void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr, |
| 3514 HValue* object, | 3500 HValue* object, |
| 3515 ZoneMapList* types, | 3501 ZoneMapList* types, |
| 3516 Handle<String> name) { | 3502 Handle<String> name) { |
| 3517 int number_of_types = Min(types->length(), kMaxLoadPolymorphism); | 3503 int number_of_types = Min(types->length(), kMaxLoadPolymorphism); |
| 3518 ZoneMapList maps(number_of_types); | 3504 ZoneMapList maps(number_of_types); |
| 3519 ZoneList<HSubgraph*> subgraphs(number_of_types + 1); | 3505 ZoneList<HSubgraph*> load_graphs(number_of_types); |
| 3520 bool needs_generic = (types->length() > kMaxLoadPolymorphism); | 3506 bool needs_generic = (types->length() > kMaxLoadPolymorphism); |
| 3521 | 3507 |
| 3522 // Build subgraphs for each of the specific maps. | 3508 // Build subgraphs for each of the specific maps. |
| 3523 // | 3509 // |
| 3524 // TODO(ager): We should recognize when the prototype chains for | 3510 // TODO(ager): We should recognize when the prototype chains for different |
| 3525 // different maps are identical. In that case we can avoid | 3511 // maps are identical. In that case we can avoid repeatedly generating the |
| 3526 // repeatedly generating the same prototype map checks. | 3512 // same prototype map checks. |
| 3527 for (int i = 0; i < number_of_types; ++i) { | 3513 for (int i = 0; i < number_of_types; ++i) { |
| 3528 Handle<Map> map = types->at(i); | 3514 Handle<Map> map = types->at(i); |
| 3529 LookupResult lookup; | 3515 LookupResult lookup; |
| 3530 map->LookupInDescriptors(NULL, *name, &lookup); | 3516 map->LookupInDescriptors(NULL, *name, &lookup); |
| 3531 if (lookup.IsProperty() && lookup.type() == FIELD) { | 3517 if (lookup.IsProperty() && lookup.type() == FIELD) { |
| 3532 maps.Add(map); | 3518 HSubgraph* load_graph = CreateBranchSubgraph(environment()); |
| 3533 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3519 SubgraphScope scope(this, load_graph); |
| 3534 SubgraphScope scope(this, subgraph); | |
| 3535 HInstruction* instr = | 3520 HInstruction* instr = |
| 3536 BuildLoadNamedField(object, expr, map, &lookup, false); | 3521 BuildLoadNamedField(object, expr, map, &lookup, false); |
| 3537 instr->set_position(expr->position()); | 3522 instr->set_position(expr->position()); |
| 3538 PushAndAdd(instr); | 3523 PushAndAdd(instr); |
| 3539 subgraphs.Add(subgraph); | 3524 // BuildTypeSwitch will add an HGoto at the end of the load subgraph, |
| 3525 // which will emit a simulate if the load has side effects. | |
| 3526 maps.Add(map); | |
| 3527 load_graphs.Add(load_graph); | |
| 3540 } else { | 3528 } else { |
| 3529 // We could not resolve the field statically so we need an IC load. | |
| 3541 needs_generic = true; | 3530 needs_generic = true; |
| 3542 } | 3531 } |
| 3543 } | 3532 } |
| 3544 | 3533 |
| 3545 // If none of the properties were named fields we generate a | 3534 // If none of the properties were resolved statically we generate a |
| 3546 // generic load. | 3535 // generic load. |
| 3547 if (maps.length() == 0) { | 3536 if (maps.is_empty()) { |
| 3548 HInstruction* instr = BuildLoadNamedGeneric(object, expr); | 3537 HInstruction* instr = BuildLoadNamedGeneric(object, expr); |
| 3549 instr->set_position(expr->position()); | 3538 instr->set_position(expr->position()); |
| 3550 PushAndAdd(instr); | 3539 PushAndAdd(instr); |
| 3551 if (instr->HasSideEffects()) AddSimulate(expr->id()); | 3540 if (instr->HasSideEffects()) AddSimulate(expr->id()); |
| 3552 } else { | 3541 ast_context()->ReturnValue(Pop()); |
| 3553 // Build subgraph for generic load through IC. | 3542 return; |
| 3554 { | |
| 3555 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | |
| 3556 SubgraphScope scope(this, subgraph); | |
| 3557 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { | |
| 3558 subgraph->FinishExit(new HDeoptimize()); | |
| 3559 } else { | |
| 3560 HInstruction* instr = BuildLoadNamedGeneric(object, expr); | |
| 3561 instr->set_position(expr->position()); | |
| 3562 PushAndAdd(instr); | |
| 3563 } | |
| 3564 subgraphs.Add(subgraph); | |
| 3565 } | |
| 3566 | |
| 3567 HBasicBlock* new_exit_block = | |
| 3568 BuildTypeSwitch(&maps, &subgraphs, object, expr->id()); | |
| 3569 subgraph()->set_exit_block(new_exit_block); | |
| 3570 } | 3543 } |
| 3571 | 3544 |
| 3545 // Build subgraph for generic load through IC. | |
| 3546 HSubgraph* default_graph = CreateBranchSubgraph(environment()); | |
| 3547 { | |
| 3548 SubgraphScope scope(this, default_graph); | |
| 3549 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { | |
| 3550 default_graph->FinishExit(new HDeoptimize()); | |
|
fschneider
2010/12/20 16:13:02
Leave out () after HDeoptimize.
| |
| 3551 } else { | |
| 3552 HInstruction* instr = BuildLoadNamedGeneric(object, expr); | |
| 3553 instr->set_position(expr->position()); | |
| 3554 PushAndAdd(instr); | |
| 3555 } | |
| 3556 } | |
| 3557 | |
| 3558 HBasicBlock* new_exit_block = BuildTypeSwitch(&maps, | |
| 3559 &load_graphs, | |
| 3560 default_graph, | |
| 3561 object, | |
| 3562 expr->id()); | |
| 3563 subgraph()->set_exit_block(new_exit_block); | |
| 3572 if (subgraph()->HasExit()) ast_context()->ReturnValue(Pop()); | 3564 if (subgraph()->HasExit()) ast_context()->ReturnValue(Pop()); |
| 3573 } | 3565 } |
| 3574 | 3566 |
| 3575 | 3567 |
| 3576 HInstruction* HGraphBuilder::BuildLoadNamedField(HValue* object, | 3568 HInstruction* HGraphBuilder::BuildLoadNamedField(HValue* object, |
| 3577 Property* expr, | 3569 Property* expr, |
| 3578 Handle<Map> type, | 3570 Handle<Map> type, |
| 3579 LookupResult* lookup, | 3571 LookupResult* lookup, |
| 3580 bool smi_and_map_check) { | 3572 bool smi_and_map_check) { |
| 3581 if (smi_and_map_check) { | 3573 if (smi_and_map_check) { |
| (...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3772 } | 3764 } |
| 3773 } | 3765 } |
| 3774 | 3766 |
| 3775 | 3767 |
| 3776 void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, | 3768 void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, |
| 3777 HValue* receiver, | 3769 HValue* receiver, |
| 3778 ZoneMapList* types, | 3770 ZoneMapList* types, |
| 3779 Handle<String> name) { | 3771 Handle<String> name) { |
| 3780 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 3772 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
| 3781 int number_of_types = Min(types->length(), kMaxCallPolymorphism); | 3773 int number_of_types = Min(types->length(), kMaxCallPolymorphism); |
| 3782 ZoneMapList maps(number_of_types); | 3774 ZoneMapList inlined_maps(number_of_types); |
| 3783 ZoneList<HSubgraph*> subgraphs(number_of_types + 1); | 3775 ZoneMapList non_inlined_maps(number_of_types); |
| 3776 ZoneList<HSubgraph*> inlined_graphs(number_of_types); | |
| 3777 ZoneList<HSubgraph*> non_inlined_graphs(number_of_types); | |
| 3784 bool needs_generic = (types->length() > kMaxCallPolymorphism); | 3778 bool needs_generic = (types->length() > kMaxCallPolymorphism); |
| 3785 | 3779 |
| 3780 // All the gymnastics with the pushed arguments are to cope with | |
| 3781 // assumptions about the graph construction order (e.g, we must have a | |
| 3782 // fully determined environment before emitting any instruction in a | |
| 3783 // block, and it's not simple to patch a subset of the uses of a value). | |
| 3784 // | |
| 3785 // Remove the pushed function arguments from the graph before handling the | |
| 3786 // variants. Record the actual argument values before removing the | |
| 3787 // PushArgument instructions because that will clear their operands. | |
| 3788 ZoneList<HValue*> arguments(argument_count); | |
| 3789 for (int i = argument_count - 1; i >= 0; --i) { | |
| 3790 HPushArgument* push_argument = | |
| 3791 HPushArgument::cast(environment()->ExpressionStackAt(i)); | |
| 3792 arguments.Add(push_argument->argument()); | |
| 3793 } | |
| 3794 ReplaceAndDeleteArguments(environment(), argument_count); | |
| 3795 Drop(argument_count); | |
| 3796 for (int i = 0; i < argument_count; ++i) { | |
| 3797 Push(arguments[i]); | |
| 3798 } | |
| 3799 | |
| 3786 // Build subgraphs for each of the specific maps. | 3800 // Build subgraphs for each of the specific maps. |
| 3787 // | 3801 // |
| 3788 // TODO(ager): We should recognize when the prototype chains for different | 3802 // TODO(ager): We should recognize when the prototype chains for different |
| 3789 // maps are identical. In that case we can avoid repeatedly generating the | 3803 // maps are identical. In that case we can avoid repeatedly generating the |
| 3790 // same prototype map checks. | 3804 // same prototype map checks. |
| 3791 for (int i = 0; i < number_of_types; ++i) { | 3805 for (int i = 0; i < number_of_types; ++i) { |
| 3792 Handle<Map> map = types->at(i); | 3806 Handle<Map> map = types->at(i); |
| 3793 if (expr->ComputeTarget(map, name)) { | 3807 if (expr->ComputeTarget(map, name)) { |
| 3794 maps.Add(map); | 3808 HSubgraph* call_graph = CreateBranchSubgraph(environment()); |
| 3795 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3809 SubgraphScope scope(this, call_graph); |
| 3796 SubgraphScope scope(this, subgraph); | 3810 // On entry to each call subgraph, push the arguments in case a call |
| 3811 // is made. If the call is inlined, these pushes will be deleted. | |
| 3812 Drop(argument_count); | |
| 3813 for (int i = 0; i < argument_count; ++i) { | |
| 3814 PushAndAdd(new HPushArgument(arguments[i])); | |
| 3815 } | |
| 3797 AddCheckConstantFunction(expr, receiver, map, false); | 3816 AddCheckConstantFunction(expr, receiver, map, false); |
| 3798 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { | 3817 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { |
| 3799 PrintF("Trying to inline the polymorphic call to %s\n", | 3818 PrintF("Trying to inline the polymorphic call to %s\n", |
| 3800 *name->ToCString()); | 3819 *name->ToCString()); |
| 3801 } | 3820 } |
| 3802 if (!FLAG_polymorphic_inlining || !TryInline(expr)) { | 3821 HEnvironment* original_env = environment()->Copy(); |
| 3822 const bool kIsKnownGlobal = true; | |
| 3823 if (FLAG_polymorphic_inlining && TryInline(expr, !kIsKnownGlobal)) { | |
| 3824 // Delete the pushed arguments. | |
| 3825 ReplaceAndDeleteArguments(original_env, argument_count); | |
| 3826 inlined_maps.Add(map); | |
| 3827 inlined_graphs.Add(call_graph); | |
| 3828 } else { | |
| 3803 // Check for bailout, as trying to inline might fail due to bailout | 3829 // Check for bailout, as trying to inline might fail due to bailout |
| 3804 // during hydrogen processing. | 3830 // during hydrogen processing. |
| 3805 CHECK_BAILOUT; | 3831 CHECK_BAILOUT; |
| 3806 HCall* call = new HCallConstantFunction(expr->target(), argument_count); | 3832 HCall* call = |
| 3833 new HCallConstantFunction(expr->target(), argument_count); | |
| 3807 call->set_position(expr->position()); | 3834 call->set_position(expr->position()); |
| 3808 ProcessCall(call); | 3835 Drop(argument_count); |
| 3809 PushAndAdd(call); | 3836 PushAndAdd(call); |
| 3837 non_inlined_maps.Add(map); | |
| 3838 non_inlined_graphs.Add(call_graph); | |
| 3810 } | 3839 } |
| 3811 subgraphs.Add(subgraph); | 3840 |
| 3812 } else { | 3841 } else { |
| 3842 // We could not resolve the target statically so we need an IC call. | |
| 3813 needs_generic = true; | 3843 needs_generic = true; |
| 3814 } | 3844 } |
| 3815 } | 3845 } |
| 3816 | 3846 |
| 3817 // If we couldn't compute the target for any of the maps just perform an | 3847 // If we couldn't compute the target for any of the maps just perform an |
| 3818 // IC call. | 3848 // IC call. |
| 3819 if (maps.length() == 0) { | 3849 if (inlined_maps.is_empty() && non_inlined_maps.is_empty()) { |
| 3850 Drop(argument_count); | |
| 3851 for (int i = 0; i < argument_count; ++i) { | |
| 3852 PushAndAdd(new HPushArgument(arguments[i])); | |
| 3853 } | |
| 3820 HCall* call = new HCallNamed(name, argument_count); | 3854 HCall* call = new HCallNamed(name, argument_count); |
| 3821 call->set_position(expr->position()); | 3855 call->set_position(expr->position()); |
| 3822 ProcessCall(call); | 3856 Drop(argument_count); |
| 3823 ast_context()->ReturnInstruction(call, expr->id()); | 3857 ast_context()->ReturnInstruction(call, expr->id()); |
| 3824 } else { | 3858 return; |
| 3825 // Build subgraph for generic call through IC. | 3859 } |
| 3826 { | 3860 |
| 3827 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3861 // Build subgraph for generic call through IC. With |
| 3828 SubgraphScope scope(this, subgraph); | 3862 // --deoptimize-uncommon-cases we will deoptimize instead of calling the |
| 3829 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { | 3863 // IC unless there were more maps than the polymorphic limit. |
| 3830 subgraph->FinishExit(new HDeoptimize()); | 3864 HSubgraph* default_graph = CreateBranchSubgraph(environment()); |
| 3831 } else { | 3865 needs_generic = needs_generic || !FLAG_deoptimize_uncommon_cases; |
| 3832 HCall* call = new HCallNamed(name, argument_count); | 3866 { |
| 3833 call->set_position(expr->position()); | 3867 SubgraphScope scope(this, default_graph); |
| 3834 ProcessCall(call); | 3868 if (needs_generic) { |
| 3835 PushAndAdd(call); | 3869 Drop(argument_count); |
| 3870 for (int i = 0; i < argument_count; ++i) { | |
| 3871 PushAndAdd(new HPushArgument(arguments[i])); | |
| 3836 } | 3872 } |
| 3837 subgraphs.Add(subgraph); | 3873 HCall* call = new HCallNamed(name, argument_count); |
| 3874 call->set_position(expr->position()); | |
| 3875 Drop(argument_count); | |
| 3876 PushAndAdd(call); | |
| 3877 } else { | |
| 3878 default_graph->FinishExit(new HDeoptimize()); | |
| 3838 } | 3879 } |
| 3880 } | |
| 3839 | 3881 |
| 3840 HBasicBlock* new_exit_block = | 3882 // If there were no inlined variants, build a simple type switch. |
| 3841 BuildTypeSwitch(&maps, &subgraphs, receiver, expr->id()); | 3883 if (inlined_maps.is_empty()) { |
| 3884 HBasicBlock* new_exit_block = BuildTypeSwitch(&non_inlined_maps, | |
| 3885 &non_inlined_graphs, | |
| 3886 default_graph, | |
| 3887 receiver, | |
| 3888 expr->id()); | |
| 3842 subgraph()->set_exit_block(new_exit_block); | 3889 subgraph()->set_exit_block(new_exit_block); |
| 3843 if (new_exit_block != NULL) ast_context()->ReturnValue(Pop()); | 3890 if (subgraph()->HasExit()) ast_context()->ReturnValue(Pop()); |
| 3891 return; | |
| 3844 } | 3892 } |
| 3893 | |
| 3894 // We have at least one inlined variant. If there are any non-inlined | |
| 3895 // variants, build a type switch of them to use as the default for the | |
| 3896 // inlined variants (if any). Otherwise use the default. | |
|
fschneider
2010/12/20 16:13:02
Remove a space after .
| |
| 3897 HSubgraph* non_inlined_subgraph = default_graph; | |
| 3898 if (!non_inlined_maps.is_empty()) { | |
| 3899 non_inlined_subgraph = CreateBranchSubgraph(environment()); | |
| 3900 SubgraphScope scope(this, non_inlined_subgraph); | |
| 3901 HBasicBlock* non_inlined_exit = BuildTypeSwitch(&non_inlined_maps, | |
| 3902 &non_inlined_graphs, | |
| 3903 default_graph, | |
| 3904 receiver, | |
| 3905 expr->ReturnId()); | |
| 3906 subgraph()->set_exit_block(non_inlined_exit); | |
| 3907 } | |
| 3908 | |
| 3909 HBasicBlock* new_exit_block = BuildTypeSwitch(&inlined_maps, | |
| 3910 &inlined_graphs, | |
| 3911 non_inlined_subgraph, | |
| 3912 receiver, | |
| 3913 expr->id()); | |
| 3914 subgraph()->set_exit_block(new_exit_block); | |
| 3915 if (subgraph()->HasExit()) ast_context()->ReturnValue(Pop()); | |
| 3845 } | 3916 } |
| 3846 | 3917 |
| 3847 | 3918 |
| 3848 void HGraphBuilder::TraceInline(Handle<JSFunction> target, bool result) { | 3919 void HGraphBuilder::TraceInline(Handle<JSFunction> target, bool result) { |
| 3849 SmartPointer<char> callee = target->shared()->DebugName()->ToCString(); | 3920 SmartPointer<char> callee = target->shared()->DebugName()->ToCString(); |
| 3850 SmartPointer<char> caller = | 3921 SmartPointer<char> caller = |
| 3851 graph()->info()->function()->debug_name()->ToCString(); | 3922 graph()->info()->function()->debug_name()->ToCString(); |
| 3852 if (result) { | 3923 if (result) { |
| 3853 PrintF("Inlined %s called from %s.\n", *callee, *caller); | 3924 PrintF("Inlined %s called from %s.\n", *callee, *caller); |
| 3854 } else { | 3925 } else { |
| 3855 PrintF("Do not inline %s called from %s.\n", *callee, *caller); | 3926 PrintF("Do not inline %s called from %s.\n", *callee, *caller); |
| 3856 } | 3927 } |
| 3857 } | 3928 } |
| 3858 | 3929 |
| 3859 | 3930 |
| 3860 bool HGraphBuilder::TryInline(Call* expr) { | 3931 bool HGraphBuilder::TryInline(Call* expr, bool is_known_global) { |
| 3861 if (!FLAG_use_inlining) return false; | 3932 if (!FLAG_use_inlining) return false; |
| 3862 | 3933 |
| 3863 // Precondition: call is monomorphic and we have found a target with the | 3934 // Precondition: call is monomorphic and we have found a target with the |
| 3864 // appropriate arity. | 3935 // appropriate arity. |
| 3865 Handle<JSFunction> target = expr->target(); | 3936 Handle<JSFunction> target = expr->target(); |
| 3866 | 3937 |
| 3867 // Do a quick check on source code length to avoid parsing large | 3938 // Do a quick check on source code length to avoid parsing large |
| 3868 // inlining candidates. | 3939 // inlining candidates. |
| 3869 if (FLAG_limit_inlining && target->shared()->SourceSize() > kMaxSourceSize) { | 3940 if (FLAG_limit_inlining && target->shared()->SourceSize() > kMaxSourceSize) { |
| 3870 if (FLAG_trace_inlining) TraceInline(target, false); | 3941 if (FLAG_trace_inlining) TraceInline(target, false); |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3973 } else { | 4044 } else { |
| 3974 // Inlined body is treated as if it occurs in the original call context. | 4045 // Inlined body is treated as if it occurs in the original call context. |
| 3975 function_return_ = graph()->CreateBasicBlock(); | 4046 function_return_ = graph()->CreateBasicBlock(); |
| 3976 function_return_->MarkAsInlineReturnTarget(); | 4047 function_return_->MarkAsInlineReturnTarget(); |
| 3977 } | 4048 } |
| 3978 call_context_ = ast_context(); | 4049 call_context_ = ast_context(); |
| 3979 TypeFeedbackOracle new_oracle(Handle<Code>(shared->code())); | 4050 TypeFeedbackOracle new_oracle(Handle<Code>(shared->code())); |
| 3980 oracle_ = &new_oracle; | 4051 oracle_ = &new_oracle; |
| 3981 graph()->info()->SetOsrAstId(AstNode::kNoNumber); | 4052 graph()->info()->SetOsrAstId(AstNode::kNoNumber); |
| 3982 | 4053 |
| 3983 HSubgraph* body = CreateInlinedSubgraph(env, target, function); | 4054 HGlobalReceiver* global_receiver = NULL; |
| 4055 if (is_known_global) global_receiver = new HGlobalReceiver; | |
| 4056 HSubgraph* body = CreateInlinedSubgraph(env, target, function, global_receiver ); | |
|
fschneider
2010/12/20 16:13:02
Long line.
Kevin Millikin (Chromium)
2010/12/21 11:16:37
Thanks.
| |
| 3984 body->exit_block()->AddInstruction(new HEnterInlined(target, function)); | 4057 body->exit_block()->AddInstruction(new HEnterInlined(target, function)); |
| 3985 AddToSubgraph(body, function->body()); | 4058 AddToSubgraph(body, function->body()); |
| 3986 if (HasStackOverflow()) { | 4059 if (HasStackOverflow()) { |
| 3987 // Bail out if the inline function did, as we cannot residualize a call | 4060 // Bail out if the inline function did, as we cannot residualize a call |
| 3988 // instead. | 4061 // instead. |
| 3989 delete test_context; | 4062 delete test_context; |
| 3990 call_context_ = saved_call_context; | 4063 call_context_ = saved_call_context; |
| 3991 function_return_ = saved_function_return; | 4064 function_return_ = saved_function_return; |
| 3992 oracle_ = saved_oracle; | 4065 oracle_ = saved_oracle; |
| 3993 graph()->info()->SetOsrAstId(saved_osr_ast_id); | 4066 graph()->info()->SetOsrAstId(saved_osr_ast_id); |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 4018 new HBranch(empty_true, empty_false, return_value); | 4091 new HBranch(empty_true, empty_false, return_value); |
| 4019 body->exit_block()->Finish(branch); | 4092 body->exit_block()->Finish(branch); |
| 4020 | 4093 |
| 4021 HValue* const no_return_value = NULL; | 4094 HValue* const no_return_value = NULL; |
| 4022 empty_true->AddLeaveInlined(no_return_value, test_context->if_true()); | 4095 empty_true->AddLeaveInlined(no_return_value, test_context->if_true()); |
| 4023 empty_false->AddLeaveInlined(no_return_value, test_context->if_false()); | 4096 empty_false->AddLeaveInlined(no_return_value, test_context->if_false()); |
| 4024 } | 4097 } |
| 4025 body->set_exit_block(NULL); | 4098 body->set_exit_block(NULL); |
| 4026 } | 4099 } |
| 4027 | 4100 |
| 4028 // Record the environment at the inlined function call. | 4101 // Insert the global receiver if it was a global function. |
| 4029 AddSimulate(expr->ReturnId()); | 4102 if (is_known_global) AddInstruction(global_receiver); |
| 4030 | 4103 |
| 4031 // Jump to the function entry (without re-recording the environment). | 4104 // Jump to the function entry. |
| 4032 subgraph()->exit_block()->Finish(new HGoto(body->entry_block())); | 4105 subgraph()->exit_block()->Goto(body->entry_block(), false); |
| 4106 body->entry_block()->SetJoinId(expr->ReturnId()); | |
| 4033 | 4107 |
| 4034 // Fix up the function exits. | 4108 // Fix up the function exits. |
| 4035 if (test_context != NULL) { | 4109 if (test_context != NULL) { |
| 4036 HBasicBlock* if_true = test_context->if_true(); | 4110 HBasicBlock* if_true = test_context->if_true(); |
| 4037 HBasicBlock* if_false = test_context->if_false(); | 4111 HBasicBlock* if_false = test_context->if_false(); |
| 4038 if_true->SetJoinId(expr->id()); | 4112 if_true->SetJoinId(expr->id()); |
| 4039 if_false->SetJoinId(expr->id()); | 4113 if_false->SetJoinId(expr->id()); |
| 4040 ASSERT(ast_context() == test_context); | 4114 ASSERT(ast_context() == test_context); |
| 4041 delete test_context; // Destructor pops from expression context stack. | 4115 delete test_context; // Destructor pops from expression context stack. |
| 4042 | 4116 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4078 void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) { | 4152 void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) { |
| 4079 ASSERT(target->IsInlineReturnTarget()); | 4153 ASSERT(target->IsInlineReturnTarget()); |
| 4080 AddInstruction(new HLeaveInlined); | 4154 AddInstruction(new HLeaveInlined); |
| 4081 HEnvironment* outer = last_environment()->outer(); | 4155 HEnvironment* outer = last_environment()->outer(); |
| 4082 if (return_value != NULL) outer->Push(return_value); | 4156 if (return_value != NULL) outer->Push(return_value); |
| 4083 UpdateEnvironment(outer); | 4157 UpdateEnvironment(outer); |
| 4084 Goto(target); | 4158 Goto(target); |
| 4085 } | 4159 } |
| 4086 | 4160 |
| 4087 | 4161 |
| 4162 void HGraphBuilder::ReplaceAndDeleteArguments(HEnvironment* env, int count) { | |
| 4163 for (int i = 0; i < count; ++i) { | |
| 4164 HPushArgument* push = HPushArgument::cast(env->ExpressionStackAt(i)); | |
| 4165 HValue* value = push->argument(); | |
| 4166 push->ReplaceAndDelete(value); | |
| 4167 } | |
| 4168 } | |
| 4169 | |
| 4170 | |
| 4088 bool HGraphBuilder::TryMathFunctionInline(Call* expr) { | 4171 bool HGraphBuilder::TryMathFunctionInline(Call* expr) { |
| 4089 // Try to inline calls like Math.* as operations in the calling function. | 4172 // Try to inline calls like Math.* as operations in the calling function. |
| 4090 if (!expr->target()->shared()->IsBuiltinMathFunction()) return false; | 4173 if (!expr->target()->shared()->IsBuiltinMathFunction()) return false; |
| 4091 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); | 4174 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); |
| 4092 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 4175 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
| 4093 switch (id) { | 4176 switch (id) { |
| 4094 case kMathRound: | 4177 case kMathRound: |
| 4095 case kMathFloor: | 4178 case kMathFloor: |
| 4096 case kMathAbs: | 4179 case kMathAbs: |
| 4097 case kMathSqrt: | 4180 case kMathSqrt: |
| 4098 case kMathLog: | 4181 case kMathLog: |
| 4099 if (argument_count == 2) { | 4182 if (argument_count == 2) { |
| 4100 HValue* argument = Pop(); | 4183 // Since we won't be making a call we should not push the argument |
| 4101 Drop(1); // Receiver. | 4184 // subexpressions. Instead of deleting them from the graph we could |
| 4185 // make an earlier decision that we have an inlined math function | |
| 4186 // (i.e., before the argument subexpressions are translated). | |
| 4187 HValue* argument = HPushArgument::cast(Top())->argument(); | |
| 4188 ReplaceAndDeleteArguments(environment(), 2); // Including receiver. | |
| 4189 Drop(2); // Receiver. | |
| 4102 HUnaryMathOperation* op = new HUnaryMathOperation(argument, id); | 4190 HUnaryMathOperation* op = new HUnaryMathOperation(argument, id); |
| 4103 op->set_position(expr->position()); | 4191 op->set_position(expr->position()); |
| 4104 ast_context()->ReturnInstruction(op, expr->id()); | 4192 ast_context()->ReturnInstruction(op, expr->id()); |
| 4105 return true; | 4193 return true; |
| 4106 } | 4194 } |
| 4107 break; | 4195 break; |
| 4108 case kMathPow: | 4196 case kMathPow: |
| 4109 if (argument_count == 3) { | 4197 if (argument_count == 3) { |
| 4110 HValue* right = Pop(); | 4198 HValue* push_left = environment()->ExpressionStackAt(1); |
|
fschneider
2010/12/20 16:13:02
Can you write the following here instead?
Replace
Kevin Millikin (Chromium)
2010/12/21 11:16:37
Not really, right now. ReplaceAndDeleteArguments
| |
| 4111 HValue* left = Pop(); | 4199 HValue* push_right = environment()->ExpressionStackAt(0); |
| 4112 Pop(); // Pop receiver. | 4200 HValue* left = HPushArgument::cast(push_left)->argument(); |
| 4201 HValue* right = HPushArgument::cast(push_right)->argument(); | |
| 4202 ReplaceAndDeleteArguments(environment(), 3); // Including receiver. | |
| 4203 Drop(3); | |
| 4113 HInstruction* result = NULL; | 4204 HInstruction* result = NULL; |
| 4114 // Use sqrt() if exponent is 0.5 or -0.5. | 4205 // Use sqrt() if exponent is 0.5 or -0.5. |
| 4115 if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) { | 4206 if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) { |
| 4116 double exponent = HConstant::cast(right)->DoubleValue(); | 4207 double exponent = HConstant::cast(right)->DoubleValue(); |
| 4117 if (exponent == 0.5) { | 4208 if (exponent == 0.5) { |
| 4118 result = new HUnaryMathOperation(left, kMathPowHalf); | 4209 result = new HUnaryMathOperation(left, kMathPowHalf); |
| 4119 ast_context()->ReturnInstruction(result, expr->id()); | 4210 ast_context()->ReturnInstruction(result, expr->id()); |
| 4120 return true; | 4211 return true; |
| 4121 } else if (exponent == -0.5) { | 4212 } else if (exponent == -0.5) { |
| 4122 HConstant* double_one = | 4213 HConstant* double_one = |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4205 HCall* call = NULL; | 4296 HCall* call = NULL; |
| 4206 | 4297 |
| 4207 Property* prop = callee->AsProperty(); | 4298 Property* prop = callee->AsProperty(); |
| 4208 if (prop != NULL) { | 4299 if (prop != NULL) { |
| 4209 if (!prop->key()->IsPropertyName()) { | 4300 if (!prop->key()->IsPropertyName()) { |
| 4210 // Keyed function call. | 4301 // Keyed function call. |
| 4211 VisitArgument(prop->obj()); | 4302 VisitArgument(prop->obj()); |
| 4212 CHECK_BAILOUT; | 4303 CHECK_BAILOUT; |
| 4213 | 4304 |
| 4214 VISIT_FOR_VALUE(prop->key()); | 4305 VISIT_FOR_VALUE(prop->key()); |
| 4215 // Push receiver and key like the non-optimized code generator expects it. | 4306 // The unoptimized code expects the key below the receiver when |
| 4307 // evaluating the argument subexpressions. | |
| 4216 HValue* key = Pop(); | 4308 HValue* key = Pop(); |
| 4217 HValue* receiver = Pop(); | 4309 HValue* receiver = Pop(); |
| 4218 Push(key); | 4310 Push(key); |
| 4219 Push(receiver); | 4311 Push(receiver); |
| 4220 | 4312 |
| 4221 VisitArgumentList(expr->arguments()); | 4313 VisitArgumentList(expr->arguments()); |
| 4222 CHECK_BAILOUT; | 4314 CHECK_BAILOUT; |
| 4223 | 4315 |
| 4224 call = new HCallKeyed(key, argument_count); | 4316 call = new HCallKeyed(key, argument_count); |
| 4225 call->set_position(expr->position()); | 4317 call->set_position(expr->position()); |
| 4226 ProcessCall(call); | 4318 Drop(argument_count + 1); // 1 is the key. |
| 4227 Drop(1); // Key. | |
| 4228 ast_context()->ReturnInstruction(call, expr->id()); | 4319 ast_context()->ReturnInstruction(call, expr->id()); |
| 4229 return; | 4320 return; |
| 4230 } | 4321 } |
| 4231 | 4322 |
| 4232 // Named function call. | 4323 // Named function call. |
| 4233 expr->RecordTypeFeedback(oracle()); | 4324 expr->RecordTypeFeedback(oracle()); |
| 4234 | 4325 |
| 4235 if (TryCallApply(expr)) return; | 4326 if (TryCallApply(expr)) return; |
| 4236 CHECK_BAILOUT; | 4327 CHECK_BAILOUT; |
| 4237 | 4328 |
| 4238 HValue* receiver = VisitArgument(prop->obj()); | 4329 // The receiver is pushed as an argument and also used as a value to |
| 4239 CHECK_BAILOUT; | 4330 // check that we're calling the expected function. |
| 4331 VISIT_FOR_VALUE(prop->obj()); | |
| 4332 HValue* receiver = Pop(); | |
| 4333 HPushArgument* push_receiver = new HPushArgument(receiver); | |
| 4334 AddInstruction(push_receiver); | |
|
fschneider
2010/12/20 16:13:02
PushAndAdd(push_receiver);
Kevin Millikin (Chromium)
2010/12/21 11:16:37
I like to keep them separate. PushAndAdd is consi
| |
| 4335 Push(push_receiver); | |
| 4336 | |
| 4240 VisitArgumentList(expr->arguments()); | 4337 VisitArgumentList(expr->arguments()); |
| 4241 CHECK_BAILOUT; | 4338 CHECK_BAILOUT; |
| 4242 | 4339 |
| 4243 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); | 4340 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); |
| 4244 | 4341 |
| 4245 expr->RecordTypeFeedback(oracle()); | 4342 expr->RecordTypeFeedback(oracle()); |
| 4246 ZoneMapList* types = expr->GetReceiverTypes(); | 4343 ZoneMapList* types = expr->GetReceiverTypes(); |
| 4247 | 4344 |
| 4248 if (expr->IsMonomorphic()) { | 4345 if (expr->IsMonomorphic()) { |
| 4249 AddCheckConstantFunction(expr, receiver, types->first(), true); | 4346 AddCheckConstantFunction(expr, receiver, types->first(), true); |
| 4250 | 4347 |
| 4251 if (TryMathFunctionInline(expr)) { | 4348 if (TryMathFunctionInline(expr)) return; |
| 4252 return; | 4349 |
| 4253 } else if (TryInline(expr)) { | 4350 HEnvironment* original_env = environment()->Copy(); |
| 4351 const bool kIsKnownGlobal = true; | |
| 4352 if (TryInline(expr, !kIsKnownGlobal)) { // Not a known global. | |
| 4353 ReplaceAndDeleteArguments(original_env, argument_count); | |
| 4254 if (subgraph()->HasExit()) { | 4354 if (subgraph()->HasExit()) { |
| 4255 HValue* return_value = Pop(); | 4355 HValue* return_value = Pop(); |
| 4256 // If we inlined a function in a test context then we need to emit | 4356 // If we inlined a function in a test context then we need to emit |
| 4257 // a simulate here to shadow the ones at the end of the | 4357 // a simulate here to shadow the ones at the end of the |
| 4258 // predecessor blocks. Those environments contain the return | 4358 // predecessor blocks. Those environments contain the return |
| 4259 // value on top and do not correspond to any actual state of the | 4359 // value on top and do not correspond to any actual state of the |
| 4260 // unoptimized code. | 4360 // unoptimized code. |
| 4261 if (ast_context()->IsEffect()) AddSimulate(expr->id()); | 4361 if (ast_context()->IsEffect()) AddSimulate(expr->id()); |
| 4262 ast_context()->ReturnValue(return_value); | 4362 ast_context()->ReturnValue(return_value); |
| 4263 } | 4363 } |
| 4264 return; | 4364 return; |
| 4265 } else { | |
| 4266 // Check for bailout, as the TryInline call in the if condition above | |
| 4267 // might return false due to bailout during hydrogen processing. | |
| 4268 CHECK_BAILOUT; | |
| 4269 call = new HCallConstantFunction(expr->target(), argument_count); | |
| 4270 } | 4365 } |
| 4271 | 4366 |
| 4367 // Check for bailout, as the TryInline call in the if condition above | |
| 4368 // might return false due to bailout during hydrogen processing. | |
| 4369 CHECK_BAILOUT; | |
| 4370 call = new HCallConstantFunction(expr->target(), argument_count); | |
| 4371 | |
| 4272 } else if (types != NULL && types->length() > 1) { | 4372 } else if (types != NULL && types->length() > 1) { |
| 4273 HandlePolymorphicCallNamed(expr, receiver, types, name); | 4373 HandlePolymorphicCallNamed(expr, receiver, types, name); |
| 4274 return; | 4374 return; |
| 4275 | 4375 |
| 4276 } else { | 4376 } else { |
| 4277 call = new HCallNamed(name, argument_count); | 4377 call = new HCallNamed(name, argument_count); |
| 4278 } | 4378 } |
| 4279 | 4379 |
| 4280 } else { | 4380 } else { |
| 4281 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); | 4381 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); |
| 4282 bool global_call = (var != NULL) && var->is_global() && !var->is_this(); | 4382 bool global_call = (var != NULL) && var->is_global() && !var->is_this(); |
| 4283 | 4383 |
| 4284 if (!global_call) { | |
| 4285 ++argument_count; | |
| 4286 VisitArgument(expr->expression()); | |
| 4287 CHECK_BAILOUT; | |
| 4288 } | |
| 4289 | |
| 4290 if (global_call) { | 4384 if (global_call) { |
| 4291 // If there is a global property cell for the name at compile time and | 4385 // If there is a global property cell for the name at compile time and |
| 4292 // access check is not enabled we assume that the function will not change | 4386 // access check is not enabled we assume that the function will not change |
| 4293 // and generate optimized code for calling the function. | 4387 // and generate optimized code for calling the function. |
| 4294 CompilationInfo* info = graph()->info(); | 4388 CompilationInfo* info = graph()->info(); |
| 4295 bool known_global_function = info->has_global_object() && | 4389 bool known_global_function = info->has_global_object() && |
| 4296 !info->global_object()->IsAccessCheckNeeded() && | 4390 !info->global_object()->IsAccessCheckNeeded() && |
| 4297 expr->ComputeGlobalTarget(Handle<GlobalObject>(info->global_object()), | 4391 expr->ComputeGlobalTarget(Handle<GlobalObject>(info->global_object()), |
| 4298 var->name()); | 4392 var->name()); |
| 4299 if (known_global_function) { | 4393 if (known_global_function) { |
| 4300 // Push the global object instead of the global receiver because | 4394 // Push the global object instead of the global receiver because the |
| 4301 // code generated by the full code generator expects it. | 4395 // unoptimized code expects it. The call instruction will patch to |
| 4302 PushAndAdd(new HGlobalObject); | 4396 // the global receiver. |
| 4397 HGlobalObject* global_object = new HGlobalObject; | |
| 4398 HPushArgument* push_global = new HPushArgument(global_object); | |
| 4399 AddInstruction(global_object); | |
| 4400 AddInstruction(push_global); | |
| 4401 Push(push_global); | |
| 4402 | |
| 4303 VisitArgumentList(expr->arguments()); | 4403 VisitArgumentList(expr->arguments()); |
| 4304 CHECK_BAILOUT; | 4404 CHECK_BAILOUT; |
| 4305 | 4405 |
| 4306 VISIT_FOR_VALUE(expr->expression()); | 4406 VISIT_FOR_VALUE(expr->expression()); |
| 4307 HValue* function = Pop(); | 4407 HValue* function = Pop(); |
| 4308 AddInstruction(new HCheckFunction(function, expr->target())); | 4408 AddInstruction(new HCheckFunction(function, expr->target())); |
| 4309 | 4409 |
| 4310 // Replace the global object with the global receiver. | 4410 const bool is_known_global = true; |
| 4311 HGlobalReceiver* global_receiver = new HGlobalReceiver; | 4411 HEnvironment* original_env = environment()->Copy(); |
| 4312 // Index of the receiver from the top of the expression stack. | 4412 if (TryInline(expr, is_known_global)) { |
| 4313 const int receiver_index = argument_count - 1; | 4413 ReplaceAndDeleteArguments(original_env, argument_count); |
| 4314 AddInstruction(global_receiver); | |
| 4315 ASSERT(environment()->ExpressionStackAt(receiver_index)-> | |
| 4316 IsGlobalObject()); | |
| 4317 environment()->SetExpressionStackAt(receiver_index, global_receiver); | |
| 4318 | |
| 4319 if (TryInline(expr)) { | |
| 4320 if (subgraph()->HasExit()) { | 4414 if (subgraph()->HasExit()) { |
| 4321 HValue* return_value = Pop(); | 4415 HValue* return_value = Pop(); |
| 4322 // If we inlined a function in a test context then we need to | 4416 // If we inlined a function in a test context then we need to |
| 4323 // emit a simulate here to shadow the ones at the end of the | 4417 // emit a simulate here to shadow the ones at the end of the |
| 4324 // predecessor blocks. Those environments contain the return | 4418 // predecessor blocks. Those environments contain the return |
| 4325 // value on top and do not correspond to any actual state of the | 4419 // value on top and do not correspond to any actual state of the |
| 4326 // unoptimized code. | 4420 // unoptimized code. |
| 4327 if (ast_context()->IsEffect()) AddSimulate(expr->id()); | 4421 if (ast_context()->IsEffect()) AddSimulate(expr->id()); |
| 4328 ast_context()->ReturnValue(return_value); | 4422 ast_context()->ReturnValue(return_value); |
| 4329 } | 4423 } |
| 4330 return; | 4424 return; |
| 4331 } | 4425 } |
| 4332 // Check for bailout, as trying to inline might fail due to bailout | 4426 // Check for bailout, as trying to inline might fail due to bailout |
| 4333 // during hydrogen processing. | 4427 // during hydrogen processing. |
| 4334 CHECK_BAILOUT; | 4428 CHECK_BAILOUT; |
| 4335 | 4429 |
| 4336 call = new HCallKnownGlobal(expr->target(), argument_count); | 4430 HGlobalReceiver* global_receiver = new HGlobalReceiver; |
| 4431 AddInstruction(global_receiver); | |
| 4432 call = new HCallKnownGlobal(global_receiver, | |
| 4433 expr->target(), | |
| 4434 argument_count); | |
| 4337 } else { | 4435 } else { |
| 4338 PushAndAdd(new HGlobalObject); | 4436 HGlobalObject* receiver = new HGlobalObject; |
| 4437 HPushArgument* push_receiver = new HPushArgument(receiver); | |
| 4438 AddInstruction(receiver); | |
| 4439 AddInstruction(push_receiver); | |
| 4440 Push(push_receiver); | |
| 4441 | |
| 4339 VisitArgumentList(expr->arguments()); | 4442 VisitArgumentList(expr->arguments()); |
| 4340 CHECK_BAILOUT; | 4443 CHECK_BAILOUT; |
| 4341 | 4444 |
| 4342 call = new HCallGlobal(var->name(), argument_count); | 4445 call = new HCallGlobal(var->name(), argument_count); |
| 4343 } | 4446 } |
| 4344 | 4447 |
| 4345 } else { | 4448 } else { |
| 4346 PushAndAdd(new HGlobalReceiver); | 4449 // The function to call is passed as an extra argument. |
| 4450 VisitArgument(expr->expression()); | |
| 4451 CHECK_BAILOUT; | |
| 4452 HGlobalReceiver* receiver = new HGlobalReceiver; | |
| 4453 HPushArgument* push_receiver = new HPushArgument(receiver); | |
| 4454 AddInstruction(receiver); | |
| 4455 AddInstruction(push_receiver); | |
| 4456 Push(push_receiver); | |
| 4457 | |
| 4347 VisitArgumentList(expr->arguments()); | 4458 VisitArgumentList(expr->arguments()); |
| 4348 CHECK_BAILOUT; | 4459 CHECK_BAILOUT; |
| 4349 | 4460 |
| 4350 call = new HCallFunction(argument_count); | 4461 call = new HCallFunction(argument_count + 1); |
| 4351 } | 4462 } |
| 4352 } | 4463 } |
| 4353 | 4464 |
| 4354 call->set_position(expr->position()); | 4465 call->set_position(expr->position()); |
| 4355 ProcessCall(call); | 4466 Drop(call->argument_count()); |
| 4356 ast_context()->ReturnInstruction(call, expr->id()); | 4467 ast_context()->ReturnInstruction(call, expr->id()); |
| 4357 } | 4468 } |
| 4358 | 4469 |
| 4359 | 4470 |
| 4360 void HGraphBuilder::VisitCallNew(CallNew* expr) { | 4471 void HGraphBuilder::VisitCallNew(CallNew* expr) { |
| 4361 // The constructor function is also used as the receiver argument to the | 4472 // The constructor function is also used as the receiver argument to the |
| 4362 // JS construct call builtin. | 4473 // JS construct call builtin. |
| 4363 VisitArgument(expr->expression()); | 4474 VISIT_FOR_VALUE(expr->expression()); |
| 4364 CHECK_BAILOUT; | 4475 HValue* constructor = Pop(); |
| 4476 HPushArgument* push_constructor = new HPushArgument(constructor); | |
| 4477 AddInstruction(push_constructor); | |
| 4478 Push(push_constructor); | |
|
fschneider
2010/12/20 16:13:02
could be shortened to:
PushAndAdd(new HPushArgume
| |
| 4479 | |
| 4365 VisitArgumentList(expr->arguments()); | 4480 VisitArgumentList(expr->arguments()); |
| 4366 CHECK_BAILOUT; | 4481 CHECK_BAILOUT; |
| 4367 | 4482 |
| 4368 int argument_count = expr->arguments()->length() + 1; // Plus constructor. | 4483 int argument_count = expr->arguments()->length() + 1; // Plus constructor. |
| 4369 HCall* call = new HCallNew(argument_count); | 4484 HCall* call = new HCallNew(constructor, argument_count); |
| 4370 call->set_position(expr->position()); | 4485 call->set_position(expr->position()); |
| 4371 ProcessCall(call); | 4486 Drop(argument_count); |
| 4372 ast_context()->ReturnInstruction(call, expr->id()); | 4487 ast_context()->ReturnInstruction(call, expr->id()); |
| 4373 } | 4488 } |
| 4374 | 4489 |
| 4375 | 4490 |
| 4376 // Support for generating inlined runtime functions. | 4491 // Support for generating inlined runtime functions. |
| 4377 | 4492 |
| 4378 // Lookup table for generators for runtime calls that are generated inline. | 4493 // Lookup table for generators for runtime calls that are generated inline. |
| 4379 // Elements of the table are member pointers to functions of HGraphBuilder. | 4494 // Elements of the table are member pointers to functions of HGraphBuilder. |
| 4380 #define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \ | 4495 #define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \ |
| 4381 &HGraphBuilder::Generate##Name, | 4496 &HGraphBuilder::Generate##Name, |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 4394 ast_context()->ReturnValue(graph()->GetConstantUndefined()); | 4509 ast_context()->ReturnValue(graph()->GetConstantUndefined()); |
| 4395 return; | 4510 return; |
| 4396 } | 4511 } |
| 4397 | 4512 |
| 4398 Runtime::Function* function = expr->function(); | 4513 Runtime::Function* function = expr->function(); |
| 4399 if (expr->is_jsruntime()) { | 4514 if (expr->is_jsruntime()) { |
| 4400 BAILOUT("call to a JavaScript runtime function"); | 4515 BAILOUT("call to a JavaScript runtime function"); |
| 4401 } | 4516 } |
| 4402 ASSERT(function != NULL); | 4517 ASSERT(function != NULL); |
| 4403 | 4518 |
| 4404 VisitArgumentList(expr->arguments()); | |
| 4405 CHECK_BAILOUT; | |
| 4406 | |
| 4407 int argument_count = expr->arguments()->length(); | |
| 4408 if (function->intrinsic_type == Runtime::INLINE) { | 4519 if (function->intrinsic_type == Runtime::INLINE) { |
| 4409 ASSERT(name->length() > 0); | 4520 ASSERT(name->length() > 0); |
| 4410 ASSERT(name->Get(0) == '_'); | 4521 ASSERT(name->Get(0) == '_'); |
| 4411 // Call to an inline function. | 4522 // Call to an inline function. |
| 4412 int lookup_index = static_cast<int>(function->function_id) - | 4523 int lookup_index = static_cast<int>(function->function_id) - |
| 4413 static_cast<int>(Runtime::kFirstInlineFunction); | 4524 static_cast<int>(Runtime::kFirstInlineFunction); |
| 4414 ASSERT(lookup_index >= 0); | 4525 ASSERT(lookup_index >= 0); |
| 4415 ASSERT(static_cast<size_t>(lookup_index) < | 4526 ASSERT(static_cast<size_t>(lookup_index) < |
| 4416 ARRAY_SIZE(kInlineFunctionGenerators)); | 4527 ARRAY_SIZE(kInlineFunctionGenerators)); |
| 4417 InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index]; | 4528 InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index]; |
| 4418 | 4529 |
| 4419 // Call the inline code generator using the pointer-to-member. | 4530 // Call the inline code generator using the pointer-to-member. |
| 4420 (this->*generator)(argument_count, expr->id()); | 4531 (this->*generator)(expr); |
| 4421 } else { | 4532 } else { |
| 4422 ASSERT(function->intrinsic_type == Runtime::RUNTIME); | 4533 ASSERT(function->intrinsic_type == Runtime::RUNTIME); |
| 4534 VisitArgumentList(expr->arguments()); | |
| 4535 CHECK_BAILOUT; | |
| 4536 int argument_count = expr->arguments()->length(); | |
| 4423 HCall* call = new HCallRuntime(name, expr->function(), argument_count); | 4537 HCall* call = new HCallRuntime(name, expr->function(), argument_count); |
| 4424 call->set_position(RelocInfo::kNoPosition); | 4538 call->set_position(RelocInfo::kNoPosition); |
| 4425 ProcessCall(call); | 4539 Drop(argument_count); |
| 4426 ast_context()->ReturnInstruction(call, expr->id()); | 4540 ast_context()->ReturnInstruction(call, expr->id()); |
| 4427 } | 4541 } |
| 4428 } | 4542 } |
| 4429 | 4543 |
| 4430 | 4544 |
| 4431 void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { | 4545 void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { |
| 4432 Token::Value op = expr->op(); | 4546 Token::Value op = expr->op(); |
| 4433 if (op == Token::VOID) { | 4547 if (op == Token::VOID) { |
| 4434 VISIT_FOR_EFFECT(expr->expression()); | 4548 VISIT_FOR_EFFECT(expr->expression()); |
| 4435 ast_context()->ReturnValue(graph()->GetConstantUndefined()); | 4549 ast_context()->ReturnValue(graph()->GetConstantUndefined()); |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4590 // to simulate the expression stack after this instruction. | 4704 // to simulate the expression stack after this instruction. |
| 4591 HInstruction* after = BuildIncrement(before, inc); | 4705 HInstruction* after = BuildIncrement(before, inc); |
| 4592 AddInstruction(after); | 4706 AddInstruction(after); |
| 4593 | 4707 |
| 4594 HInstruction* store = BuildStoreNamed(obj, after, prop); | 4708 HInstruction* store = BuildStoreNamed(obj, after, prop); |
| 4595 AddInstruction(store); | 4709 AddInstruction(store); |
| 4596 | 4710 |
| 4597 // Overwrite the receiver in the bailout environment with the result | 4711 // Overwrite the receiver in the bailout environment with the result |
| 4598 // of the operation, and the placeholder with the original value if | 4712 // of the operation, and the placeholder with the original value if |
| 4599 // necessary. | 4713 // necessary. |
| 4600 environment()->SetExpressionStackAt(0, after); | 4714 if (has_extra) { |
| 4601 if (has_extra) environment()->SetExpressionStackAt(1, before); | 4715 Drop(2); |
| 4716 Push(before); | |
| 4717 } else { | |
| 4718 Drop(1); | |
| 4719 } | |
| 4720 Push(after); | |
| 4602 if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); | 4721 if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
| 4603 Drop(has_extra ? 2 : 1); | 4722 Drop(has_extra ? 2 : 1); |
| 4604 | 4723 |
| 4605 ast_context()->ReturnValue(expr->is_postfix() ? before : after); | 4724 ast_context()->ReturnValue(expr->is_postfix() ? before : after); |
| 4606 | 4725 |
| 4607 } else { | 4726 } else { |
| 4608 // Keyed property. | 4727 // Keyed property. |
| 4609 | 4728 |
| 4610 // Match the full code generator stack by simulate an extra stack element | 4729 // Match the full code generator stack by simulate an extra stack element |
| 4611 // for postfix operations in a non-effect context. | 4730 // for postfix operations in a non-effect context. |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 4633 AddInstruction(after); | 4752 AddInstruction(after); |
| 4634 | 4753 |
| 4635 HInstruction* store = is_fast_elements | 4754 HInstruction* store = is_fast_elements |
| 4636 ? BuildStoreKeyedFastElement(obj, key, after, prop) | 4755 ? BuildStoreKeyedFastElement(obj, key, after, prop) |
| 4637 : new HStoreKeyedGeneric(obj, key, after); | 4756 : new HStoreKeyedGeneric(obj, key, after); |
| 4638 AddInstruction(store); | 4757 AddInstruction(store); |
| 4639 | 4758 |
| 4640 // Drop the key from the bailout environment. Overwrite the receiver | 4759 // Drop the key from the bailout environment. Overwrite the receiver |
| 4641 // with the result of the operation, and the placeholder with the | 4760 // with the result of the operation, and the placeholder with the |
| 4642 // original value if necessary. | 4761 // original value if necessary. |
| 4643 Drop(1); | 4762 if (has_extra) { |
| 4644 environment()->SetExpressionStackAt(0, after); | 4763 Drop(3); |
| 4645 if (has_extra) environment()->SetExpressionStackAt(1, before); | 4764 Push(before); |
| 4765 } else { | |
| 4766 Drop(2); | |
| 4767 } | |
| 4768 Push(after); | |
| 4646 if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); | 4769 if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
| 4647 Drop(has_extra ? 2 : 1); | 4770 Drop(has_extra ? 2 : 1); |
| 4648 | 4771 |
| 4649 ast_context()->ReturnValue(expr->is_postfix() ? before : after); | 4772 ast_context()->ReturnValue(expr->is_postfix() ? before : after); |
| 4650 } | 4773 } |
| 4651 | 4774 |
| 4652 } else { | 4775 } else { |
| 4653 BAILOUT("invalid lhs in count operation"); | 4776 BAILOUT("invalid lhs in count operation"); |
| 4654 } | 4777 } |
| 4655 } | 4778 } |
| (...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4896 (slot != NULL && slot->type() == Slot::LOOKUP) || | 5019 (slot != NULL && slot->type() == Slot::LOOKUP) || |
| 4897 decl->mode() == Variable::CONST || | 5020 decl->mode() == Variable::CONST || |
| 4898 decl->fun() != NULL) { | 5021 decl->fun() != NULL) { |
| 4899 BAILOUT("unsupported declaration"); | 5022 BAILOUT("unsupported declaration"); |
| 4900 } | 5023 } |
| 4901 } | 5024 } |
| 4902 | 5025 |
| 4903 | 5026 |
| 4904 // Generators for inline runtime functions. | 5027 // Generators for inline runtime functions. |
| 4905 // Support for types. | 5028 // Support for types. |
| 4906 void HGraphBuilder::GenerateIsSmi(int argument_count, int ast_id) { | 5029 void HGraphBuilder::GenerateIsSmi(CallRuntime* call) { |
| 4907 ASSERT(argument_count == 1); | 5030 ASSERT(call->arguments()->length() == 1); |
| 5031 VISIT_FOR_VALUE(call->arguments()->at(0)); | |
| 4908 HValue* value = Pop(); | 5032 HValue* value = Pop(); |
| 4909 HIsSmi* result = new HIsSmi(value); | 5033 HIsSmi* result = new HIsSmi(value); |
| 4910 ast_context()->ReturnInstruction(result, ast_id); | 5034 ast_context()->ReturnInstruction(result, call->id()); |
| 4911 } | 5035 } |
| 4912 | 5036 |
| 4913 | 5037 |
| 4914 void HGraphBuilder::GenerateIsSpecObject(int argument_count, int ast_id) { | 5038 void HGraphBuilder::GenerateIsSpecObject(CallRuntime* call) { |
| 4915 ASSERT(argument_count == 1); | 5039 ASSERT(call->arguments()->length() == 1); |
| 5040 VISIT_FOR_VALUE(call->arguments()->at(0)); | |
| 4916 HValue* value = Pop(); | 5041 HValue* value = Pop(); |
| 4917 HHasInstanceType* result = | 5042 HHasInstanceType* result = |
| 4918 new HHasInstanceType(value, FIRST_JS_OBJECT_TYPE, LAST_TYPE); | 5043 new HHasInstanceType(value, FIRST_JS_OBJECT_TYPE, LAST_TYPE); |
| 4919 ast_context()->ReturnInstruction(result, ast_id); | 5044 ast_context()->ReturnInstruction(result, call->id()); |
| 4920 } | 5045 } |
| 4921 | 5046 |
| 4922 | 5047 |
| 4923 void HGraphBuilder::GenerateIsFunction(int argument_count, int ast_id) { | 5048 void HGraphBuilder::GenerateIsFunction(CallRuntime* call) { |
| 4924 ASSERT(argument_count == 1); | 5049 ASSERT(call->arguments()->length() == 1); |
| 5050 VISIT_FOR_VALUE(call->arguments()->at(0)); | |
| 4925 HValue* value = Pop(); | 5051 HValue* value = Pop(); |
| 4926 HHasInstanceType* result = new HHasInstanceType(value, JS_FUNCTION_TYPE); | 5052 HHasInstanceType* result = new HHasInstanceType(value, JS_FUNCTION_TYPE); |
| 4927 ast_context()->ReturnInstruction(result, ast_id); | 5053 ast_context()->ReturnInstruction(result, call->id()); |
| 4928 } | 5054 } |
| 4929 | 5055 |
| 4930 | 5056 |
| 4931 void HGraphBuilder::GenerateHasCachedArrayIndex(int argument_count, | 5057 void HGraphBuilder::GenerateHasCachedArrayIndex(CallRuntime* call) { |
| 4932 int ast_id) { | 5058 ASSERT(call->arguments()->length() == 1); |
| 4933 ASSERT(argument_count == 1); | 5059 VISIT_FOR_VALUE(call->arguments()->at(0)); |
| 4934 HValue* value = Pop(); | 5060 HValue* value = Pop(); |
| 4935 HHasCachedArrayIndex* result = new HHasCachedArrayIndex(value); | 5061 HHasCachedArrayIndex* result = new HHasCachedArrayIndex(value); |
| 4936 ast_context()->ReturnInstruction(result, ast_id); | 5062 ast_context()->ReturnInstruction(result, call->id()); |
| 4937 } | 5063 } |
| 4938 | 5064 |
| 4939 | 5065 |
| 4940 void HGraphBuilder::GenerateIsArray(int argument_count, int ast_id) { | 5066 void HGraphBuilder::GenerateIsArray(CallRuntime* call) { |
| 4941 ASSERT(argument_count == 1); | 5067 ASSERT(call->arguments()->length() == 1); |
| 5068 VISIT_FOR_VALUE(call->arguments()->at(0)); | |
| 4942 HValue* value = Pop(); | 5069 HValue* value = Pop(); |
| 4943 HHasInstanceType* result = new HHasInstanceType(value, JS_ARRAY_TYPE); | 5070 HHasInstanceType* result = new HHasInstanceType(value, JS_ARRAY_TYPE); |
| 4944 ast_context()->ReturnInstruction(result, ast_id); | 5071 ast_context()->ReturnInstruction(result, call->id()); |
| 4945 } | 5072 } |
| 4946 | 5073 |
| 4947 | 5074 |
| 4948 void HGraphBuilder::GenerateIsRegExp(int argument_count, int ast_id) { | 5075 void HGraphBuilder::GenerateIsRegExp(CallRuntime* call) { |
| 4949 ASSERT(argument_count == 1); | 5076 ASSERT(call->arguments()->length() == 1); |
| 5077 VISIT_FOR_VALUE(call->arguments()->at(0)); | |
| 4950 HValue* value = Pop(); | 5078 HValue* value = Pop(); |
| 4951 HHasInstanceType* result = new HHasInstanceType(value, JS_REGEXP_TYPE); | 5079 HHasInstanceType* result = new HHasInstanceType(value, JS_REGEXP_TYPE); |
| 4952 ast_context()->ReturnInstruction(result, ast_id); | 5080 ast_context()->ReturnInstruction(result, call->id()); |
| 4953 } | 5081 } |
| 4954 | 5082 |
| 4955 | 5083 |
| 4956 void HGraphBuilder::GenerateIsObject(int argument_count, int ast_id) { | 5084 void HGraphBuilder::GenerateIsObject(CallRuntime* call) { |
| 4957 ASSERT(argument_count == 1); | 5085 ASSERT(call->arguments()->length() == 1); |
| 4958 | 5086 VISIT_FOR_VALUE(call->arguments()->at(0)); |
| 4959 HValue* value = Pop(); | 5087 HValue* value = Pop(); |
| 4960 HIsObject* test = new HIsObject(value); | 5088 HIsObject* test = new HIsObject(value); |
| 4961 ast_context()->ReturnInstruction(test, ast_id); | 5089 ast_context()->ReturnInstruction(test, call->id()); |
| 4962 } | 5090 } |
| 4963 | 5091 |
| 4964 | 5092 |
| 4965 void HGraphBuilder::GenerateIsNonNegativeSmi(int argument_count, | 5093 void HGraphBuilder::GenerateIsNonNegativeSmi(CallRuntime* call) { |
| 4966 int ast_id) { | |
| 4967 BAILOUT("inlined runtime function: IsNonNegativeSmi"); | 5094 BAILOUT("inlined runtime function: IsNonNegativeSmi"); |
| 4968 } | 5095 } |
| 4969 | 5096 |
| 4970 | 5097 |
| 4971 void HGraphBuilder::GenerateIsUndetectableObject(int argument_count, | 5098 void HGraphBuilder::GenerateIsUndetectableObject(CallRuntime* call) { |
| 4972 int ast_id) { | |
| 4973 BAILOUT("inlined runtime function: IsUndetectableObject"); | 5099 BAILOUT("inlined runtime function: IsUndetectableObject"); |
| 4974 } | 5100 } |
| 4975 | 5101 |
| 4976 | 5102 |
| 4977 void HGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf( | 5103 void HGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf( |
| 4978 int argument_count, | 5104 CallRuntime* call) { |
| 4979 int ast_id) { | |
| 4980 BAILOUT("inlined runtime function: IsStringWrapperSafeForDefaultValueOf"); | 5105 BAILOUT("inlined runtime function: IsStringWrapperSafeForDefaultValueOf"); |
| 4981 } | 5106 } |
| 4982 | 5107 |
| 4983 | 5108 |
| 4984 // Support for construct call checks. | 5109 // Support for construct call checks. |
| 4985 void HGraphBuilder::GenerateIsConstructCall(int argument_count, int ast_id) { | 5110 void HGraphBuilder::GenerateIsConstructCall(CallRuntime* call) { |
| 4986 BAILOUT("inlined runtime function: IsConstructCall"); | 5111 BAILOUT("inlined runtime function: IsConstructCall"); |
| 4987 } | 5112 } |
| 4988 | 5113 |
| 4989 | 5114 |
| 4990 // Support for arguments.length and arguments[?]. | 5115 // Support for arguments.length and arguments[?]. |
| 4991 void HGraphBuilder::GenerateArgumentsLength(int argument_count, int ast_id) { | 5116 void HGraphBuilder::GenerateArgumentsLength(CallRuntime* call) { |
| 4992 ASSERT(argument_count == 0); | 5117 ASSERT(call->arguments()->length() == 0); |
| 4993 HInstruction* elements = AddInstruction(new HArgumentsElements); | 5118 HInstruction* elements = AddInstruction(new HArgumentsElements); |
| 4994 HArgumentsLength* result = new HArgumentsLength(elements); | 5119 HArgumentsLength* result = new HArgumentsLength(elements); |
| 4995 ast_context()->ReturnInstruction(result, ast_id); | 5120 ast_context()->ReturnInstruction(result, call->id()); |
| 4996 } | 5121 } |
| 4997 | 5122 |
| 4998 | 5123 |
| 4999 void HGraphBuilder::GenerateArguments(int argument_count, int ast_id) { | 5124 void HGraphBuilder::GenerateArguments(CallRuntime* call) { |
| 5000 ASSERT(argument_count == 1); | 5125 ASSERT(call->arguments()->length() == 1); |
| 5126 VISIT_FOR_VALUE(call->arguments()->at(0)); | |
| 5001 HValue* index = Pop(); | 5127 HValue* index = Pop(); |
| 5002 HInstruction* elements = AddInstruction(new HArgumentsElements); | 5128 HInstruction* elements = AddInstruction(new HArgumentsElements); |
| 5003 HInstruction* length = AddInstruction(new HArgumentsLength(elements)); | 5129 HInstruction* length = AddInstruction(new HArgumentsLength(elements)); |
| 5004 HAccessArgumentsAt* result = new HAccessArgumentsAt(elements, length, index); | 5130 HAccessArgumentsAt* result = new HAccessArgumentsAt(elements, length, index); |
| 5005 ast_context()->ReturnInstruction(result, ast_id); | 5131 ast_context()->ReturnInstruction(result, call->id()); |
| 5006 } | 5132 } |
| 5007 | 5133 |
| 5008 | 5134 |
| 5009 // Support for accessing the class and value fields of an object. | 5135 // Support for accessing the class and value fields of an object. |
| 5010 void HGraphBuilder::GenerateClassOf(int argument_count, int ast_id) { | 5136 void HGraphBuilder::GenerateClassOf(CallRuntime* call) { |
| 5011 // The special form detected by IsClassOfTest is detected before we get here | 5137 // The special form detected by IsClassOfTest is detected before we get here |
| 5012 // and does not cause a bailout. | 5138 // and does not cause a bailout. |
| 5013 BAILOUT("inlined runtime function: ClassOf"); | 5139 BAILOUT("inlined runtime function: ClassOf"); |
| 5014 } | 5140 } |
| 5015 | 5141 |
| 5016 | 5142 |
| 5017 void HGraphBuilder::GenerateValueOf(int argument_count, int ast_id) { | 5143 void HGraphBuilder::GenerateValueOf(CallRuntime* call) { |
| 5018 ASSERT(argument_count == 1); | 5144 ASSERT(call->arguments()->length() == 1); |
| 5145 VISIT_FOR_VALUE(call->arguments()->at(0)); | |
| 5019 HValue* value = Pop(); | 5146 HValue* value = Pop(); |
| 5020 HValueOf* result = new HValueOf(value); | 5147 HValueOf* result = new HValueOf(value); |
| 5021 ast_context()->ReturnInstruction(result, ast_id); | 5148 ast_context()->ReturnInstruction(result, call->id()); |
| 5022 } | 5149 } |
| 5023 | 5150 |
| 5024 | 5151 |
| 5025 void HGraphBuilder::GenerateSetValueOf(int argument_count, int ast_id) { | 5152 void HGraphBuilder::GenerateSetValueOf(CallRuntime* call) { |
| 5026 BAILOUT("inlined runtime function: SetValueOf"); | 5153 BAILOUT("inlined runtime function: SetValueOf"); |
| 5027 } | 5154 } |
| 5028 | 5155 |
| 5029 | 5156 |
| 5030 // Fast support for charCodeAt(n). | 5157 // Fast support for charCodeAt(n). |
| 5031 void HGraphBuilder::GenerateStringCharCodeAt(int argument_count, int ast_id) { | 5158 void HGraphBuilder::GenerateStringCharCodeAt(CallRuntime* call) { |
| 5032 BAILOUT("inlined runtime function: StringCharCodeAt"); | 5159 BAILOUT("inlined runtime function: StringCharCodeAt"); |
| 5033 } | 5160 } |
| 5034 | 5161 |
| 5035 | 5162 |
| 5036 // Fast support for string.charAt(n) and string[n]. | 5163 // Fast support for string.charAt(n) and string[n]. |
| 5037 void HGraphBuilder::GenerateStringCharFromCode(int argument_count, | 5164 void HGraphBuilder::GenerateStringCharFromCode(CallRuntime* call) { |
| 5038 int ast_id) { | |
| 5039 BAILOUT("inlined runtime function: StringCharFromCode"); | 5165 BAILOUT("inlined runtime function: StringCharFromCode"); |
| 5040 } | 5166 } |
| 5041 | 5167 |
| 5042 | 5168 |
| 5043 // Fast support for string.charAt(n) and string[n]. | 5169 // Fast support for string.charAt(n) and string[n]. |
| 5044 void HGraphBuilder::GenerateStringCharAt(int argument_count, int ast_id) { | 5170 void HGraphBuilder::GenerateStringCharAt(CallRuntime* call) { |
| 5045 ASSERT_EQ(2, argument_count); | 5171 const int kArgumentCount = 2; |
| 5046 PushArgumentsForStubCall(argument_count); | 5172 ASSERT(call->arguments()->length() == kArgumentCount); |
| 5047 HCallStub* result = new HCallStub(CodeStub::StringCharAt, argument_count); | 5173 VisitArgumentList(call->arguments()); |
|
fschneider
2010/12/20 16:13:02
I'd replace all VisitArgumentList followed by a ch
| |
| 5048 ast_context()->ReturnInstruction(result, ast_id); | 5174 if (HasStackOverflow() || !subgraph()->HasExit()) return; |
| 5175 HCallStub* result = new HCallStub(CodeStub::StringCharAt, kArgumentCount); | |
| 5176 Drop(kArgumentCount); | |
| 5177 ast_context()->ReturnInstruction(result, call->id()); | |
| 5049 } | 5178 } |
| 5050 | 5179 |
| 5051 | 5180 |
| 5052 // Fast support for object equality testing. | 5181 // Fast support for object equality testing. |
| 5053 void HGraphBuilder::GenerateObjectEquals(int argument_count, int ast_id) { | 5182 void HGraphBuilder::GenerateObjectEquals(CallRuntime* call) { |
| 5054 ASSERT(argument_count == 2); | 5183 ASSERT(call->arguments()->length() == 2); |
| 5184 VISIT_FOR_VALUE(call->arguments()->at(0)); | |
| 5185 VISIT_FOR_VALUE(call->arguments()->at(1)); | |
| 5055 HValue* right = Pop(); | 5186 HValue* right = Pop(); |
| 5056 HValue* left = Pop(); | 5187 HValue* left = Pop(); |
| 5057 HCompareJSObjectEq* result = new HCompareJSObjectEq(left, right); | 5188 HCompareJSObjectEq* result = new HCompareJSObjectEq(left, right); |
| 5058 ast_context()->ReturnInstruction(result, ast_id); | 5189 ast_context()->ReturnInstruction(result, call->id()); |
| 5059 } | 5190 } |
| 5060 | 5191 |
| 5061 | 5192 |
| 5062 void HGraphBuilder::GenerateLog(int argument_count, int ast_id) { | 5193 void HGraphBuilder::GenerateLog(CallRuntime* call) { |
| 5063 UNREACHABLE(); // We caught this in VisitCallRuntime. | 5194 UNREACHABLE(); // We caught this in VisitCallRuntime. |
| 5064 } | 5195 } |
| 5065 | 5196 |
| 5066 | 5197 |
| 5067 // Fast support for Math.random(). | 5198 // Fast support for Math.random(). |
| 5068 void HGraphBuilder::GenerateRandomHeapNumber(int argument_count, int ast_id) { | 5199 void HGraphBuilder::GenerateRandomHeapNumber(CallRuntime* call) { |
| 5069 BAILOUT("inlined runtime function: RandomHeapNumber"); | 5200 BAILOUT("inlined runtime function: RandomHeapNumber"); |
| 5070 } | 5201 } |
| 5071 | 5202 |
| 5072 | 5203 |
| 5073 // Fast support for StringAdd. | 5204 // Fast support for StringAdd. |
| 5074 void HGraphBuilder::GenerateStringAdd(int argument_count, int ast_id) { | 5205 void HGraphBuilder::GenerateStringAdd(CallRuntime* call) { |
| 5075 ASSERT_EQ(2, argument_count); | 5206 const int kArgumentCount = 2; |
| 5076 PushArgumentsForStubCall(argument_count); | 5207 ASSERT(call->arguments()->length() == kArgumentCount); |
| 5077 HCallStub* result = new HCallStub(CodeStub::StringAdd, argument_count); | 5208 VisitArgumentList(call->arguments()); |
| 5078 ast_context()->ReturnInstruction(result, ast_id); | 5209 if (HasStackOverflow() || !subgraph()->HasExit()) return; |
| 5210 HCallStub* result = new HCallStub(CodeStub::StringAdd, kArgumentCount); | |
| 5211 Drop(kArgumentCount); | |
| 5212 ast_context()->ReturnInstruction(result, call->id()); | |
| 5079 } | 5213 } |
| 5080 | 5214 |
| 5081 | 5215 |
| 5082 // Fast support for SubString. | 5216 // Fast support for SubString. |
| 5083 void HGraphBuilder::GenerateSubString(int argument_count, int ast_id) { | 5217 void HGraphBuilder::GenerateSubString(CallRuntime* call) { |
| 5084 ASSERT_EQ(3, argument_count); | 5218 const int kArgumentCount = 3; |
| 5085 PushArgumentsForStubCall(argument_count); | 5219 ASSERT(call->arguments()->length() == kArgumentCount); |
| 5086 HCallStub* result = new HCallStub(CodeStub::SubString, argument_count); | 5220 VisitArgumentList(call->arguments()); |
| 5087 ast_context()->ReturnInstruction(result, ast_id); | 5221 if (HasStackOverflow() || !subgraph()->HasExit()) return; |
| 5222 HCallStub* result = new HCallStub(CodeStub::SubString, kArgumentCount); | |
| 5223 Drop(kArgumentCount); | |
| 5224 ast_context()->ReturnInstruction(result, call->id()); | |
|
fschneider
2010/12/20 16:13:02
There seems a lot of duplicated code for all runti
Kevin Millikin (Chromium)
2010/12/21 11:16:37
Maybe. It seems premature. Refactoring is easier
| |
| 5088 } | 5225 } |
| 5089 | 5226 |
| 5090 | 5227 |
| 5091 // Fast support for StringCompare. | 5228 // Fast support for StringCompare. |
| 5092 void HGraphBuilder::GenerateStringCompare(int argument_count, int ast_id) { | 5229 void HGraphBuilder::GenerateStringCompare(CallRuntime* call) { |
| 5093 ASSERT_EQ(2, argument_count); | 5230 const int kArgumentCount = 2; |
| 5094 PushArgumentsForStubCall(argument_count); | 5231 ASSERT(call->arguments()->length() == kArgumentCount); |
| 5095 HCallStub* result = new HCallStub(CodeStub::StringCompare, argument_count); | 5232 VisitArgumentList(call->arguments()); |
| 5096 ast_context()->ReturnInstruction(result, ast_id); | 5233 if (HasStackOverflow() || !subgraph()->HasExit()) return; |
| 5234 HCallStub* result = new HCallStub(CodeStub::StringCompare, kArgumentCount); | |
| 5235 Drop(kArgumentCount); | |
| 5236 ast_context()->ReturnInstruction(result, call->id()); | |
| 5097 } | 5237 } |
| 5098 | 5238 |
| 5099 | 5239 |
| 5100 // Support for direct calls from JavaScript to native RegExp code. | 5240 // Support for direct calls from JavaScript to native RegExp code. |
| 5101 void HGraphBuilder::GenerateRegExpExec(int argument_count, int ast_id) { | 5241 void HGraphBuilder::GenerateRegExpExec(CallRuntime* call) { |
| 5102 ASSERT_EQ(4, argument_count); | 5242 const int kArgumentCount = 4; |
| 5103 PushArgumentsForStubCall(argument_count); | 5243 ASSERT(call->arguments()->length() == kArgumentCount); |
| 5104 HCallStub* result = new HCallStub(CodeStub::RegExpExec, argument_count); | 5244 VisitArgumentList(call->arguments()); |
| 5105 ast_context()->ReturnInstruction(result, ast_id); | 5245 if (HasStackOverflow() || !subgraph()->HasExit()) return; |
| 5246 HCallStub* result = new HCallStub(CodeStub::RegExpExec, kArgumentCount); | |
| 5247 Drop(kArgumentCount); | |
| 5248 ast_context()->ReturnInstruction(result, call->id()); | |
| 5106 } | 5249 } |
| 5107 | 5250 |
| 5108 | 5251 |
| 5109 // Construct a RegExp exec result with two in-object properties. | 5252 // Construct a RegExp exec result with two in-object properties. |
| 5110 void HGraphBuilder::GenerateRegExpConstructResult(int argument_count, | 5253 void HGraphBuilder::GenerateRegExpConstructResult(CallRuntime* call) { |
| 5111 int ast_id) { | 5254 const int kArgumentCount = 3; |
| 5112 ASSERT_EQ(3, argument_count); | 5255 ASSERT(call->arguments()->length() == kArgumentCount); |
| 5113 PushArgumentsForStubCall(argument_count); | 5256 VisitArgumentList(call->arguments()); |
| 5257 if (HasStackOverflow() || !subgraph()->HasExit()) return; | |
| 5114 HCallStub* result = | 5258 HCallStub* result = |
| 5115 new HCallStub(CodeStub::RegExpConstructResult, argument_count); | 5259 new HCallStub(CodeStub::RegExpConstructResult, kArgumentCount); |
| 5116 ast_context()->ReturnInstruction(result, ast_id); | 5260 Drop(kArgumentCount); |
| 5261 ast_context()->ReturnInstruction(result, call->id()); | |
| 5117 } | 5262 } |
| 5118 | 5263 |
| 5119 | 5264 |
| 5120 // Support for fast native caches. | 5265 // Support for fast native caches. |
| 5121 void HGraphBuilder::GenerateGetFromCache(int argument_count, int ast_id) { | 5266 void HGraphBuilder::GenerateGetFromCache(CallRuntime* call) { |
| 5122 BAILOUT("inlined runtime function: GetFromCache"); | 5267 BAILOUT("inlined runtime function: GetFromCache"); |
| 5123 } | 5268 } |
| 5124 | 5269 |
| 5125 | 5270 |
| 5126 // Fast support for number to string. | 5271 // Fast support for number to string. |
| 5127 void HGraphBuilder::GenerateNumberToString(int argument_count, int ast_id) { | 5272 void HGraphBuilder::GenerateNumberToString(CallRuntime* call) { |
| 5128 ASSERT_EQ(1, argument_count); | 5273 const int kArgumentCount = 1; |
| 5129 PushArgumentsForStubCall(argument_count); | 5274 ASSERT(call->arguments()->length() == kArgumentCount); |
| 5130 HCallStub* result = new HCallStub(CodeStub::NumberToString, argument_count); | 5275 VisitArgumentList(call->arguments()); |
| 5131 ast_context()->ReturnInstruction(result, ast_id); | 5276 if (HasStackOverflow() || !subgraph()->HasExit()) return; |
| 5277 HCallStub* result = new HCallStub(CodeStub::NumberToString, kArgumentCount); | |
| 5278 Drop(kArgumentCount); | |
| 5279 ast_context()->ReturnInstruction(result, call->id()); | |
| 5132 } | 5280 } |
| 5133 | 5281 |
| 5134 | 5282 |
| 5135 // Fast swapping of elements. Takes three expressions, the object and two | 5283 // Fast swapping of elements. Takes three expressions, the object and two |
| 5136 // indices. This should only be used if the indices are known to be | 5284 // indices. This should only be used if the indices are known to be |
| 5137 // non-negative and within bounds of the elements array at the call site. | 5285 // non-negative and within bounds of the elements array at the call site. |
| 5138 void HGraphBuilder::GenerateSwapElements(int argument_count, int ast_id) { | 5286 void HGraphBuilder::GenerateSwapElements(CallRuntime* call) { |
| 5139 BAILOUT("inlined runtime function: SwapElements"); | 5287 BAILOUT("inlined runtime function: SwapElements"); |
| 5140 } | 5288 } |
| 5141 | 5289 |
| 5142 | 5290 |
| 5143 // Fast call for custom callbacks. | 5291 // Fast call for custom callbacks. |
| 5144 void HGraphBuilder::GenerateCallFunction(int argument_count, int ast_id) { | 5292 void HGraphBuilder::GenerateCallFunction(CallRuntime* call) { |
| 5145 BAILOUT("inlined runtime function: CallFunction"); | 5293 BAILOUT("inlined runtime function: CallFunction"); |
| 5146 } | 5294 } |
| 5147 | 5295 |
| 5148 | 5296 |
| 5149 // Fast call to math functions. | 5297 // Fast call to math functions. |
| 5150 void HGraphBuilder::GenerateMathPow(int argument_count, int ast_id) { | 5298 void HGraphBuilder::GenerateMathPow(CallRuntime* call) { |
| 5151 ASSERT_EQ(2, argument_count); | 5299 ASSERT(call->arguments()->length() == 2); |
| 5300 VISIT_FOR_VALUE(call->arguments()->at(0)); | |
| 5301 VISIT_FOR_VALUE(call->arguments()->at(1)); | |
| 5152 HValue* right = Pop(); | 5302 HValue* right = Pop(); |
| 5153 HValue* left = Pop(); | 5303 HValue* left = Pop(); |
| 5154 HPower* result = new HPower(left, right); | 5304 HPower* result = new HPower(left, right); |
| 5155 ast_context()->ReturnInstruction(result, ast_id); | 5305 ast_context()->ReturnInstruction(result, call->id()); |
| 5156 } | 5306 } |
| 5157 | 5307 |
| 5158 | 5308 |
| 5159 void HGraphBuilder::GenerateMathSin(int argument_count, int ast_id) { | 5309 void HGraphBuilder::GenerateMathSin(CallRuntime* call) { |
| 5160 ASSERT_EQ(1, argument_count); | 5310 const int kArgumentCount = 1; |
| 5161 PushArgumentsForStubCall(argument_count); | 5311 ASSERT(call->arguments()->length() == kArgumentCount); |
| 5312 VisitArgumentList(call->arguments()); | |
| 5313 if (HasStackOverflow() || !subgraph()->HasExit()) return; | |
| 5162 HCallStub* result = | 5314 HCallStub* result = |
| 5163 new HCallStub(CodeStub::TranscendentalCache, argument_count); | 5315 new HCallStub(CodeStub::TranscendentalCache, kArgumentCount); |
| 5164 result->set_transcendental_type(TranscendentalCache::SIN); | 5316 result->set_transcendental_type(TranscendentalCache::SIN); |
| 5165 ast_context()->ReturnInstruction(result, ast_id); | 5317 Drop(kArgumentCount); |
| 5166 } | 5318 ast_context()->ReturnInstruction(result, call->id()); |
| 5167 | 5319 } |
| 5168 | 5320 |
| 5169 void HGraphBuilder::GenerateMathCos(int argument_count, int ast_id) { | 5321 |
| 5170 ASSERT_EQ(1, argument_count); | 5322 void HGraphBuilder::GenerateMathCos(CallRuntime* call) { |
| 5171 PushArgumentsForStubCall(argument_count); | 5323 const int kArgumentCount = 1; |
| 5324 ASSERT(call->arguments()->length() == kArgumentCount); | |
| 5325 VisitArgumentList(call->arguments()); | |
| 5326 if (HasStackOverflow() || !subgraph()->HasExit()) return; | |
| 5172 HCallStub* result = | 5327 HCallStub* result = |
| 5173 new HCallStub(CodeStub::TranscendentalCache, argument_count); | 5328 new HCallStub(CodeStub::TranscendentalCache, kArgumentCount); |
| 5174 result->set_transcendental_type(TranscendentalCache::COS); | 5329 result->set_transcendental_type(TranscendentalCache::COS); |
| 5175 ast_context()->ReturnInstruction(result, ast_id); | 5330 Drop(kArgumentCount); |
| 5176 } | 5331 ast_context()->ReturnInstruction(result, call->id()); |
| 5177 | 5332 } |
| 5178 | 5333 |
| 5179 void HGraphBuilder::GenerateMathLog(int argument_count, int ast_id) { | 5334 |
| 5180 ASSERT_EQ(1, argument_count); | 5335 void HGraphBuilder::GenerateMathLog(CallRuntime* call) { |
| 5181 PushArgumentsForStubCall(argument_count); | 5336 const int kArgumentCount = 1; |
| 5337 ASSERT(call->arguments()->length() == kArgumentCount); | |
| 5338 VisitArgumentList(call->arguments()); | |
| 5339 if (HasStackOverflow() || !subgraph()->HasExit()) return; | |
| 5182 HCallStub* result = | 5340 HCallStub* result = |
| 5183 new HCallStub(CodeStub::TranscendentalCache, argument_count); | 5341 new HCallStub(CodeStub::TranscendentalCache, kArgumentCount); |
| 5184 result->set_transcendental_type(TranscendentalCache::LOG); | 5342 result->set_transcendental_type(TranscendentalCache::LOG); |
| 5185 ast_context()->ReturnInstruction(result, ast_id); | 5343 Drop(kArgumentCount); |
| 5186 } | 5344 ast_context()->ReturnInstruction(result, call->id()); |
| 5187 | 5345 } |
| 5188 | 5346 |
| 5189 void HGraphBuilder::GenerateMathSqrt(int argument_count, int ast_id) { | 5347 |
| 5348 void HGraphBuilder::GenerateMathSqrt(CallRuntime* call) { | |
| 5190 BAILOUT("inlined runtime function: MathSqrt"); | 5349 BAILOUT("inlined runtime function: MathSqrt"); |
| 5191 } | 5350 } |
| 5192 | 5351 |
| 5193 | 5352 |
| 5194 // Check whether two RegExps are equivalent | 5353 // Check whether two RegExps are equivalent |
| 5195 void HGraphBuilder::GenerateIsRegExpEquivalent(int argument_count, | 5354 void HGraphBuilder::GenerateIsRegExpEquivalent(CallRuntime* call) { |
| 5196 int ast_id) { | |
| 5197 BAILOUT("inlined runtime function: IsRegExpEquivalent"); | 5355 BAILOUT("inlined runtime function: IsRegExpEquivalent"); |
| 5198 } | 5356 } |
| 5199 | 5357 |
| 5200 | 5358 |
| 5201 void HGraphBuilder::GenerateGetCachedArrayIndex(int argument_count, | 5359 void HGraphBuilder::GenerateGetCachedArrayIndex(CallRuntime* call) { |
| 5202 int ast_id) { | |
| 5203 BAILOUT("inlined runtime function: GetCachedArrayIndex"); | 5360 BAILOUT("inlined runtime function: GetCachedArrayIndex"); |
| 5204 } | 5361 } |
| 5205 | 5362 |
| 5206 | 5363 |
| 5207 void HGraphBuilder::GenerateFastAsciiArrayJoin(int argument_count, | 5364 void HGraphBuilder::GenerateFastAsciiArrayJoin(CallRuntime* call) { |
| 5208 int ast_id) { | |
| 5209 BAILOUT("inlined runtime function: FastAsciiArrayJoin"); | 5365 BAILOUT("inlined runtime function: FastAsciiArrayJoin"); |
| 5210 } | 5366 } |
| 5211 | 5367 |
| 5212 | 5368 |
| 5213 #undef BAILOUT | 5369 #undef BAILOUT |
| 5214 #undef CHECK_BAILOUT | 5370 #undef CHECK_BAILOUT |
| 5215 #undef VISIT_FOR_EFFECT | 5371 #undef VISIT_FOR_EFFECT |
| 5216 #undef VISIT_FOR_VALUE | 5372 #undef VISIT_FOR_VALUE |
| 5373 #undef VISIT_FOR_CONTROL | |
| 5217 #undef ADD_TO_SUBGRAPH | 5374 #undef ADD_TO_SUBGRAPH |
| 5218 | 5375 |
| 5219 | 5376 |
| 5220 HEnvironment::HEnvironment(HEnvironment* outer, | 5377 HEnvironment::HEnvironment(HEnvironment* outer, |
| 5221 Scope* scope, | 5378 Scope* scope, |
| 5222 Handle<JSFunction> closure) | 5379 Handle<JSFunction> closure) |
| 5223 : closure_(closure), | 5380 : closure_(closure), |
| 5224 values_(0), | 5381 values_(0), |
| 5225 assigned_variables_(4), | 5382 assigned_variables_(4), |
| 5226 parameter_count_(0), | 5383 parameter_count_(0), |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5334 loop_header->AddPhi(phi); | 5491 loop_header->AddPhi(phi); |
| 5335 } | 5492 } |
| 5336 new_env->ClearHistory(); | 5493 new_env->ClearHistory(); |
| 5337 return new_env; | 5494 return new_env; |
| 5338 } | 5495 } |
| 5339 | 5496 |
| 5340 | 5497 |
| 5341 HEnvironment* HEnvironment::CopyForInlining(Handle<JSFunction> target, | 5498 HEnvironment* HEnvironment::CopyForInlining(Handle<JSFunction> target, |
| 5342 FunctionLiteral* function, | 5499 FunctionLiteral* function, |
| 5343 bool is_speculative, | 5500 bool is_speculative, |
| 5344 HConstant* undefined) const { | 5501 HConstant* undefined, |
| 5502 HGlobalReceiver* receiver) const { | |
| 5345 // Outer environment is a copy of this one without the arguments. | 5503 // Outer environment is a copy of this one without the arguments. |
| 5346 int arity = function->scope()->num_parameters(); | 5504 int arity = function->scope()->num_parameters(); |
| 5347 HEnvironment* outer = Copy(); | 5505 HEnvironment* outer = Copy(); |
| 5348 outer->Drop(arity + 1); // Including receiver. | 5506 outer->Drop(arity + 1); // Including receiver. |
| 5349 outer->ClearHistory(); | 5507 outer->ClearHistory(); |
| 5350 HEnvironment* inner = new HEnvironment(outer, function->scope(), target); | 5508 HEnvironment* inner = new HEnvironment(outer, function->scope(), target); |
| 5351 // Get the argument values from the original environment. | 5509 // Get the argument values from the original environment. |
| 5352 if (is_speculative) { | 5510 if (is_speculative) { |
| 5353 for (int i = 0; i <= arity; ++i) { // Include receiver. | 5511 for (int i = 0; i <= arity; ++i) { // Include receiver. |
| 5354 HValue* push = ExpressionStackAt(arity - i); | 5512 HPushArgument* push = HPushArgument::cast(ExpressionStackAt(arity - i)); |
| 5355 inner->SetValueAt(i, push); | 5513 if (i == 0 && receiver != NULL) { |
| 5514 inner->SetValueAt(i, receiver); | |
| 5515 } else { | |
| 5516 inner->SetValueAt(i, push->argument()); | |
| 5517 } | |
| 5356 } | 5518 } |
| 5357 } else { | 5519 } else { |
| 5358 for (int i = 0; i <= arity; ++i) { // Include receiver. | 5520 for (int i = 0; i <= arity; ++i) { // Include receiver. |
| 5359 inner->SetValueAt(i, ExpressionStackAt(arity - i)); | 5521 inner->SetValueAt(i, ExpressionStackAt(arity - i)); |
| 5360 } | 5522 } |
| 5361 } | 5523 } |
| 5362 | 5524 |
| 5363 // Initialize the stack-allocated locals to undefined. | 5525 // Initialize the stack-allocated locals to undefined. |
| 5364 int local_base = arity + 1; | 5526 int local_base = arity + 1; |
| 5365 int local_count = function->scope()->num_stack_slots(); | 5527 int local_count = function->scope()->num_stack_slots(); |
| (...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5674 } | 5836 } |
| 5675 | 5837 |
| 5676 #ifdef DEBUG | 5838 #ifdef DEBUG |
| 5677 if (graph_ != NULL) graph_->Verify(); | 5839 if (graph_ != NULL) graph_->Verify(); |
| 5678 if (chunk_ != NULL) chunk_->Verify(); | 5840 if (chunk_ != NULL) chunk_->Verify(); |
| 5679 if (allocator_ != NULL) allocator_->Verify(); | 5841 if (allocator_ != NULL) allocator_->Verify(); |
| 5680 #endif | 5842 #endif |
| 5681 } | 5843 } |
| 5682 | 5844 |
| 5683 } } // namespace v8::internal | 5845 } } // namespace v8::internal |
| OLD | NEW |