| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 106 if (first_ == NULL) { | 106 if (first_ == NULL) { |
| 107 HBlockEntry* entry = new HBlockEntry(); | 107 HBlockEntry* entry = new HBlockEntry(); |
| 108 entry->InitializeAsFirst(this); | 108 entry->InitializeAsFirst(this); |
| 109 first_ = last_ = entry; | 109 first_ = last_ = entry; |
| 110 } | 110 } |
| 111 instr->InsertAfter(last_); | 111 instr->InsertAfter(last_); |
| 112 last_ = instr; | 112 last_ = instr; |
| 113 } | 113 } |
| 114 | 114 |
| 115 | 115 |
| 116 HDeoptimize* HBasicBlock::CreateDeoptimize() { |
| 117 ASSERT(HasEnvironment()); |
| 118 HEnvironment* environment = last_environment(); |
| 119 |
| 120 HDeoptimize* instr = new HDeoptimize(environment->length()); |
| 121 |
| 122 for (int i = 0; i < environment->length(); i++) { |
| 123 HValue* val = environment->values()->at(i); |
| 124 instr->AddEnvironmentValue(val); |
| 125 } |
| 126 |
| 127 return instr; |
| 128 } |
| 129 |
| 130 |
| 116 HSimulate* HBasicBlock::CreateSimulate(int id) { | 131 HSimulate* HBasicBlock::CreateSimulate(int id) { |
| 117 ASSERT(HasEnvironment()); | 132 ASSERT(HasEnvironment()); |
| 118 HEnvironment* environment = last_environment(); | 133 HEnvironment* environment = last_environment(); |
| 119 ASSERT(id == AstNode::kNoNumber || | 134 ASSERT(id == AstNode::kNoNumber || |
| 120 environment->closure()->shared()->VerifyBailoutId(id)); | 135 environment->closure()->shared()->VerifyBailoutId(id)); |
| 121 | 136 |
| 122 int push_count = environment->push_count(); | 137 int push_count = environment->push_count(); |
| 123 int pop_count = environment->pop_count(); | 138 int pop_count = environment->pop_count(); |
| 124 | 139 |
| 125 int length = environment->length(); | 140 int length = environment->length(); |
| (...skipping 2339 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2465 // We only optimize switch statements with smi-literal smi comparisons, | 2480 // We only optimize switch statements with smi-literal smi comparisons, |
| 2466 // with a bounded number of clauses. | 2481 // with a bounded number of clauses. |
| 2467 const int kCaseClauseLimit = 128; | 2482 const int kCaseClauseLimit = 128; |
| 2468 ZoneList<CaseClause*>* clauses = stmt->cases(); | 2483 ZoneList<CaseClause*>* clauses = stmt->cases(); |
| 2469 int clause_count = clauses->length(); | 2484 int clause_count = clauses->length(); |
| 2470 if (clause_count > kCaseClauseLimit) { | 2485 if (clause_count > kCaseClauseLimit) { |
| 2471 BAILOUT("SwitchStatement: too many clauses"); | 2486 BAILOUT("SwitchStatement: too many clauses"); |
| 2472 } | 2487 } |
| 2473 | 2488 |
| 2474 VISIT_FOR_VALUE(stmt->tag()); | 2489 VISIT_FOR_VALUE(stmt->tag()); |
| 2490 AddSimulate(stmt->EntryId()); |
| 2475 HValue* tag_value = Pop(); | 2491 HValue* tag_value = Pop(); |
| 2476 HBasicBlock* first_test_block = current_block(); | 2492 HBasicBlock* first_test_block = current_block(); |
| 2477 | 2493 |
| 2478 // 1. Build all the tests, with dangling true branches. Unconditionally | 2494 // 1. Build all the tests, with dangling true branches. Unconditionally |
| 2479 // deoptimize if we encounter a non-smi comparison. | 2495 // deoptimize if we encounter a non-smi comparison. |
| 2480 for (int i = 0; i < clause_count; ++i) { | 2496 for (int i = 0; i < clause_count; ++i) { |
| 2481 CaseClause* clause = clauses->at(i); | 2497 CaseClause* clause = clauses->at(i); |
| 2482 if (clause->is_default()) continue; | 2498 if (clause->is_default()) continue; |
| 2483 if (!clause->label()->IsSmiLiteral()) { | 2499 if (!clause->label()->IsSmiLiteral()) { |
| 2484 BAILOUT("SwitchStatement: non-literal switch label"); | 2500 BAILOUT("SwitchStatement: non-literal switch label"); |
| 2485 } | 2501 } |
| 2486 | 2502 |
| 2487 // Unconditionally deoptimize on the first non-smi compare. | 2503 // Unconditionally deoptimize on the first non-smi compare. |
| 2488 clause->RecordTypeFeedback(oracle()); | 2504 clause->RecordTypeFeedback(oracle()); |
| 2489 if (!clause->IsSmiCompare()) { | 2505 if (!clause->IsSmiCompare()) { |
| 2490 if (current_block() == first_test_block) { | 2506 current_block()->FinishExitWithDeoptimization(); |
| 2491 // If the first test is the one that deopts and if the tag value is | |
| 2492 // a phi, we need to have some use of that phi to prevent phi | |
| 2493 // elimination from removing it. This HSimulate is such a use. | |
| 2494 Push(tag_value); | |
| 2495 AddSimulate(stmt->EntryId()); | |
| 2496 Drop(1); | |
| 2497 } | |
| 2498 current_block()->Finish(new HDeoptimize()); | |
| 2499 set_current_block(NULL); | 2507 set_current_block(NULL); |
| 2500 break; | 2508 break; |
| 2501 } | 2509 } |
| 2502 | 2510 |
| 2503 // Otherwise generate a compare and branch. | 2511 // Otherwise generate a compare and branch. |
| 2504 VISIT_FOR_VALUE(clause->label()); | 2512 VISIT_FOR_VALUE(clause->label()); |
| 2505 HValue* label_value = Pop(); | 2513 HValue* label_value = Pop(); |
| 2506 HCompare* compare = new HCompare(tag_value, label_value, Token::EQ_STRICT); | 2514 HCompare* compare = new HCompare(tag_value, label_value, Token::EQ_STRICT); |
| 2507 compare->SetInputRepresentation(Representation::Integer32()); | 2515 compare->SetInputRepresentation(Representation::Integer32()); |
| 2508 ASSERT(!compare->HasSideEffects()); | 2516 ASSERT(!compare->HasSideEffects()); |
| (...skipping 599 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3108 current_block()->Goto(join); | 3116 current_block()->Goto(join); |
| 3109 | 3117 |
| 3110 set_current_block(if_false); | 3118 set_current_block(if_false); |
| 3111 } | 3119 } |
| 3112 } | 3120 } |
| 3113 | 3121 |
| 3114 // Finish up. Unconditionally deoptimize if we've handled all the maps we | 3122 // Finish up. Unconditionally deoptimize if we've handled all the maps we |
| 3115 // know about and do not want to handle ones we've never seen. Otherwise | 3123 // know about and do not want to handle ones we've never seen. Otherwise |
| 3116 // use a generic IC. | 3124 // use a generic IC. |
| 3117 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { | 3125 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { |
| 3118 current_block()->FinishExit(new HDeoptimize); | 3126 current_block()->FinishExitWithDeoptimization(); |
| 3119 } else { | 3127 } else { |
| 3120 HInstruction* instr = BuildStoreNamedGeneric(object, name, value); | 3128 HInstruction* instr = BuildStoreNamedGeneric(object, name, value); |
| 3121 instr->set_position(expr->position()); | 3129 instr->set_position(expr->position()); |
| 3122 AddInstruction(instr); | 3130 AddInstruction(instr); |
| 3123 | 3131 |
| 3124 if (join != NULL) { | 3132 if (join != NULL) { |
| 3125 if (!ast_context()->IsEffect()) Push(value); | 3133 if (!ast_context()->IsEffect()) Push(value); |
| 3126 current_block()->Goto(join); | 3134 current_block()->Goto(join); |
| 3127 } else { | 3135 } else { |
| 3128 // The HSimulate for the store should not see the stored value in | 3136 // The HSimulate for the store should not see the stored value in |
| (...skipping 327 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3456 current_block()->Goto(join); | 3464 current_block()->Goto(join); |
| 3457 | 3465 |
| 3458 set_current_block(if_false); | 3466 set_current_block(if_false); |
| 3459 } | 3467 } |
| 3460 } | 3468 } |
| 3461 | 3469 |
| 3462 // Finish up. Unconditionally deoptimize if we've handled all the maps we | 3470 // Finish up. Unconditionally deoptimize if we've handled all the maps we |
| 3463 // know about and do not want to handle ones we've never seen. Otherwise | 3471 // know about and do not want to handle ones we've never seen. Otherwise |
| 3464 // use a generic IC. | 3472 // use a generic IC. |
| 3465 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { | 3473 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { |
| 3466 current_block()->FinishExit(new HDeoptimize); | 3474 current_block()->FinishExitWithDeoptimization(); |
| 3467 } else { | 3475 } else { |
| 3468 HInstruction* instr = BuildLoadNamedGeneric(object, expr); | 3476 HInstruction* instr = BuildLoadNamedGeneric(object, expr); |
| 3469 instr->set_position(expr->position()); | 3477 instr->set_position(expr->position()); |
| 3470 | 3478 |
| 3471 if (join != NULL) { | 3479 if (join != NULL) { |
| 3472 AddInstruction(instr); | 3480 AddInstruction(instr); |
| 3473 if (!ast_context()->IsEffect()) Push(instr); | 3481 if (!ast_context()->IsEffect()) Push(instr); |
| 3474 current_block()->Goto(join); | 3482 current_block()->Goto(join); |
| 3475 } else { | 3483 } else { |
| 3476 ast_context()->ReturnInstruction(instr, expr->id()); | 3484 ast_context()->ReturnInstruction(instr, expr->id()); |
| (...skipping 344 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3821 | 3829 |
| 3822 if (current_block() != NULL) current_block()->Goto(join); | 3830 if (current_block() != NULL) current_block()->Goto(join); |
| 3823 set_current_block(if_false); | 3831 set_current_block(if_false); |
| 3824 } | 3832 } |
| 3825 } | 3833 } |
| 3826 | 3834 |
| 3827 // Finish up. Unconditionally deoptimize if we've handled all the maps we | 3835 // Finish up. Unconditionally deoptimize if we've handled all the maps we |
| 3828 // know about and do not want to handle ones we've never seen. Otherwise | 3836 // know about and do not want to handle ones we've never seen. Otherwise |
| 3829 // use a generic IC. | 3837 // use a generic IC. |
| 3830 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { | 3838 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { |
| 3831 current_block()->FinishExit(new HDeoptimize); | 3839 current_block()->FinishExitWithDeoptimization(); |
| 3832 } else { | 3840 } else { |
| 3833 HContext* context = new HContext; | 3841 HContext* context = new HContext; |
| 3834 AddInstruction(context); | 3842 AddInstruction(context); |
| 3835 HCallNamed* call = new HCallNamed(context, name, argument_count); | 3843 HCallNamed* call = new HCallNamed(context, name, argument_count); |
| 3836 call->set_position(expr->position()); | 3844 call->set_position(expr->position()); |
| 3837 PreProcessCall(call); | 3845 PreProcessCall(call); |
| 3838 | 3846 |
| 3839 if (join != NULL) { | 3847 if (join != NULL) { |
| 3840 AddInstruction(call); | 3848 AddInstruction(call); |
| 3841 if (!ast_context()->IsEffect()) Push(call); | 3849 if (!ast_context()->IsEffect()) Push(call); |
| (...skipping 367 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4209 expr->GetReceiverTypes()->first(), | 4217 expr->GetReceiverTypes()->first(), |
| 4210 true); | 4218 true); |
| 4211 HInstruction* result = | 4219 HInstruction* result = |
| 4212 new HApplyArguments(function, receiver, length, elements); | 4220 new HApplyArguments(function, receiver, length, elements); |
| 4213 result->set_position(expr->position()); | 4221 result->set_position(expr->position()); |
| 4214 ast_context()->ReturnInstruction(result, expr->id()); | 4222 ast_context()->ReturnInstruction(result, expr->id()); |
| 4215 return true; | 4223 return true; |
| 4216 } | 4224 } |
| 4217 | 4225 |
| 4218 | 4226 |
| 4219 static bool HasCustomCallGenerator(Handle<JSFunction> function) { | |
| 4220 SharedFunctionInfo* info = function->shared(); | |
| 4221 return info->HasBuiltinFunctionId() && | |
| 4222 CallStubCompiler::HasCustomCallGenerator(info->builtin_function_id()); | |
| 4223 } | |
| 4224 | |
| 4225 | |
| 4226 void HGraphBuilder::VisitCall(Call* expr) { | 4227 void HGraphBuilder::VisitCall(Call* expr) { |
| 4227 Expression* callee = expr->expression(); | 4228 Expression* callee = expr->expression(); |
| 4228 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 4229 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
| 4229 HInstruction* call = NULL; | 4230 HInstruction* call = NULL; |
| 4230 | 4231 |
| 4231 Property* prop = callee->AsProperty(); | 4232 Property* prop = callee->AsProperty(); |
| 4232 if (prop != NULL) { | 4233 if (prop != NULL) { |
| 4233 if (!prop->key()->IsPropertyName()) { | 4234 if (!prop->key()->IsPropertyName()) { |
| 4234 // Keyed function call. | 4235 // Keyed function call. |
| 4235 VISIT_FOR_VALUE(prop->obj()); | 4236 VISIT_FOR_VALUE(prop->obj()); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4273 if (expr->IsMonomorphic()) { | 4274 if (expr->IsMonomorphic()) { |
| 4274 Handle<Map> receiver_map = | 4275 Handle<Map> receiver_map = |
| 4275 (types == NULL) ? Handle<Map>::null() : types->first(); | 4276 (types == NULL) ? Handle<Map>::null() : types->first(); |
| 4276 if (TryInlineBuiltinFunction(expr, | 4277 if (TryInlineBuiltinFunction(expr, |
| 4277 receiver, | 4278 receiver, |
| 4278 receiver_map, | 4279 receiver_map, |
| 4279 expr->check_type())) { | 4280 expr->check_type())) { |
| 4280 return; | 4281 return; |
| 4281 } | 4282 } |
| 4282 | 4283 |
| 4283 if (HasCustomCallGenerator(expr->target()) || | 4284 if (CallStubCompiler::HasCustomCallGenerator(*expr->target()) || |
| 4284 CallOptimization(*expr->target()).is_simple_api_call() || | |
| 4285 expr->check_type() != RECEIVER_MAP_CHECK) { | 4285 expr->check_type() != RECEIVER_MAP_CHECK) { |
| 4286 // When the target has a custom call IC generator, use the IC, | 4286 // When the target has a custom call IC generator, use the IC, |
| 4287 // because it is likely to generate better code. Similarly, we | 4287 // because it is likely to generate better code. Also use the IC |
| 4288 // generate better call stubs for some API functions. | 4288 // when a primitive receiver check is required. |
| 4289 // Also use the IC when a primitive receiver check is required. | |
| 4290 HContext* context = new HContext; | 4289 HContext* context = new HContext; |
| 4291 AddInstruction(context); | 4290 AddInstruction(context); |
| 4292 call = PreProcessCall(new HCallNamed(context, name, argument_count)); | 4291 call = PreProcessCall(new HCallNamed(context, name, argument_count)); |
| 4293 } else { | 4292 } else { |
| 4294 AddCheckConstantFunction(expr, receiver, receiver_map, true); | 4293 AddCheckConstantFunction(expr, receiver, receiver_map, true); |
| 4295 | 4294 |
| 4296 if (TryInline(expr)) { | 4295 if (TryInline(expr)) { |
| 4297 return; | 4296 return; |
| 4298 } else { | 4297 } else { |
| 4299 // Check for bailout, as the TryInline call in the if condition above | 4298 // Check for bailout, as the TryInline call in the if condition above |
| (...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4526 | 4525 |
| 4527 HBasicBlock* join = | 4526 HBasicBlock* join = |
| 4528 CreateJoin(materialize_false, materialize_true, expr->id()); | 4527 CreateJoin(materialize_false, materialize_true, expr->id()); |
| 4529 set_current_block(join); | 4528 set_current_block(join); |
| 4530 ast_context()->ReturnValue(Pop()); | 4529 ast_context()->ReturnValue(Pop()); |
| 4531 } else { | 4530 } else { |
| 4532 ASSERT(ast_context()->IsEffect()); | 4531 ASSERT(ast_context()->IsEffect()); |
| 4533 VisitForEffect(expr->expression()); | 4532 VisitForEffect(expr->expression()); |
| 4534 } | 4533 } |
| 4535 | 4534 |
| 4536 } else if (op == Token::BIT_NOT || op == Token::SUB) { | 4535 } else if (op == Token::TYPEOF) { |
| 4536 VISIT_FOR_VALUE(expr->expression()); |
| 4537 HValue* value = Pop(); |
| 4538 ast_context()->ReturnInstruction(new HTypeof(value), expr->id()); |
| 4539 |
| 4540 } else { |
| 4537 VISIT_FOR_VALUE(expr->expression()); | 4541 VISIT_FOR_VALUE(expr->expression()); |
| 4538 HValue* value = Pop(); | 4542 HValue* value = Pop(); |
| 4539 HInstruction* instr = NULL; | 4543 HInstruction* instr = NULL; |
| 4540 switch (op) { | 4544 switch (op) { |
| 4541 case Token::BIT_NOT: | 4545 case Token::BIT_NOT: |
| 4542 instr = new HBitNot(value); | 4546 instr = new HBitNot(value); |
| 4543 break; | 4547 break; |
| 4544 case Token::SUB: | 4548 case Token::SUB: |
| 4545 instr = new HMul(graph_->GetConstantMinus1(), value); | 4549 instr = new HMul(value, graph_->GetConstantMinus1()); |
| 4550 break; |
| 4551 case Token::ADD: |
| 4552 instr = new HMul(value, graph_->GetConstant1()); |
| 4546 break; | 4553 break; |
| 4547 default: | 4554 default: |
| 4548 UNREACHABLE(); | 4555 BAILOUT("Value: unsupported unary operation"); |
| 4549 break; | 4556 break; |
| 4550 } | 4557 } |
| 4551 ast_context()->ReturnInstruction(instr, expr->id()); | 4558 ast_context()->ReturnInstruction(instr, expr->id()); |
| 4552 } else if (op == Token::TYPEOF) { | |
| 4553 VISIT_FOR_VALUE(expr->expression()); | |
| 4554 HValue* value = Pop(); | |
| 4555 ast_context()->ReturnInstruction(new HTypeof(value), expr->id()); | |
| 4556 } else { | |
| 4557 BAILOUT("Value: unsupported unary operation"); | |
| 4558 } | 4559 } |
| 4559 } | 4560 } |
| 4560 | 4561 |
| 4561 | 4562 |
| 4562 void HGraphBuilder::VisitIncrementOperation(IncrementOperation* expr) { | 4563 void HGraphBuilder::VisitIncrementOperation(IncrementOperation* expr) { |
| 4563 // IncrementOperation is never visited by the visitor. It only | 4564 // IncrementOperation is never visited by the visitor. It only |
| 4564 // occurs as a subexpression of CountOperation. | 4565 // occurs as a subexpression of CountOperation. |
| 4565 UNREACHABLE(); | 4566 UNREACHABLE(); |
| 4566 } | 4567 } |
| 4567 | 4568 |
| (...skipping 1357 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5925 } | 5926 } |
| 5926 } | 5927 } |
| 5927 | 5928 |
| 5928 #ifdef DEBUG | 5929 #ifdef DEBUG |
| 5929 if (graph_ != NULL) graph_->Verify(); | 5930 if (graph_ != NULL) graph_->Verify(); |
| 5930 if (allocator_ != NULL) allocator_->Verify(); | 5931 if (allocator_ != NULL) allocator_->Verify(); |
| 5931 #endif | 5932 #endif |
| 5932 } | 5933 } |
| 5933 | 5934 |
| 5934 } } // namespace v8::internal | 5935 } } // namespace v8::internal |
| OLD | NEW |