Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(30)

Side by Side Diff: src/hydrogen.cc

Issue 5964005: Shorten live ranges of argument subexpressions. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 10 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/hydrogen.h ('k') | src/hydrogen-instructions.h » ('j') | src/hydrogen-instructions.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698