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