| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 16 matching lines...) Expand all Loading... |
| 27 | 27 |
| 28 #include "hydrogen.h" | 28 #include "hydrogen.h" |
| 29 | 29 |
| 30 #include <algorithm> | 30 #include <algorithm> |
| 31 | 31 |
| 32 #include "v8.h" | 32 #include "v8.h" |
| 33 #include "codegen.h" | 33 #include "codegen.h" |
| 34 #include "full-codegen.h" | 34 #include "full-codegen.h" |
| 35 #include "hashmap.h" | 35 #include "hashmap.h" |
| 36 #include "hydrogen-bce.h" | 36 #include "hydrogen-bce.h" |
| 37 #include "hydrogen-canonicalize.h" |
| 37 #include "hydrogen-dce.h" | 38 #include "hydrogen-dce.h" |
| 39 #include "hydrogen-dehoist.h" |
| 40 #include "hydrogen-deoptimizing-mark.h" |
| 38 #include "hydrogen-environment-liveness.h" | 41 #include "hydrogen-environment-liveness.h" |
| 39 #include "hydrogen-escape-analysis.h" | 42 #include "hydrogen-escape-analysis.h" |
| 40 #include "hydrogen-infer-representation.h" | 43 #include "hydrogen-infer-representation.h" |
| 41 #include "hydrogen-infer-types.h" | 44 #include "hydrogen-infer-types.h" |
| 42 #include "hydrogen-gvn.h" | 45 #include "hydrogen-gvn.h" |
| 46 #include "hydrogen-minus-zero.h" |
| 43 #include "hydrogen-osr.h" | 47 #include "hydrogen-osr.h" |
| 44 #include "hydrogen-range-analysis.h" | 48 #include "hydrogen-range-analysis.h" |
| 45 #include "hydrogen-redundant-phi.h" | 49 #include "hydrogen-redundant-phi.h" |
| 50 #include "hydrogen-removable-simulates.h" |
| 46 #include "hydrogen-representation-changes.h" | 51 #include "hydrogen-representation-changes.h" |
| 47 #include "hydrogen-sce.h" | 52 #include "hydrogen-sce.h" |
| 48 #include "hydrogen-uint32-analysis.h" | 53 #include "hydrogen-uint32-analysis.h" |
| 49 #include "lithium-allocator.h" | 54 #include "lithium-allocator.h" |
| 50 #include "parser.h" | 55 #include "parser.h" |
| 51 #include "scopeinfo.h" | 56 #include "scopeinfo.h" |
| 52 #include "scopes.h" | 57 #include "scopes.h" |
| 53 #include "stub-cache.h" | 58 #include "stub-cache.h" |
| 54 #include "typing.h" | 59 #include "typing.h" |
| 55 | 60 |
| (...skipping 1081 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1137 | 1142 |
| 1138 HValue* HGraphBuilder::BuildCheckForCapacityGrow(HValue* object, | 1143 HValue* HGraphBuilder::BuildCheckForCapacityGrow(HValue* object, |
| 1139 HValue* elements, | 1144 HValue* elements, |
| 1140 ElementsKind kind, | 1145 ElementsKind kind, |
| 1141 HValue* length, | 1146 HValue* length, |
| 1142 HValue* key, | 1147 HValue* key, |
| 1143 bool is_js_array) { | 1148 bool is_js_array) { |
| 1144 Zone* zone = this->zone(); | 1149 Zone* zone = this->zone(); |
| 1145 IfBuilder length_checker(this); | 1150 IfBuilder length_checker(this); |
| 1146 | 1151 |
| 1147 length_checker.If<HCompareNumericAndBranch>(length, key, Token::EQ); | 1152 Token::Value token = IsHoleyElementsKind(kind) ? Token::GTE : Token::EQ; |
| 1153 length_checker.If<HCompareNumericAndBranch>(key, length, token); |
| 1154 |
| 1148 length_checker.Then(); | 1155 length_checker.Then(); |
| 1149 | 1156 |
| 1150 HValue* current_capacity = AddLoadFixedArrayLength(elements); | 1157 HValue* current_capacity = AddLoadFixedArrayLength(elements); |
| 1151 | 1158 |
| 1152 IfBuilder capacity_checker(this); | 1159 IfBuilder capacity_checker(this); |
| 1153 | 1160 |
| 1154 capacity_checker.If<HCompareNumericAndBranch>(length, current_capacity, | 1161 capacity_checker.If<HCompareNumericAndBranch>(key, current_capacity, |
| 1155 Token::EQ); | 1162 Token::GTE); |
| 1156 capacity_checker.Then(); | 1163 capacity_checker.Then(); |
| 1157 | 1164 |
| 1158 HValue* context = environment()->LookupContext(); | 1165 HValue* context = environment()->LookupContext(); |
| 1159 | 1166 |
| 1160 HValue* new_capacity = | 1167 HValue* new_capacity = BuildNewElementsCapacity(context, key); |
| 1161 BuildNewElementsCapacity(context, current_capacity); | |
| 1162 | 1168 |
| 1163 HValue* new_elements = BuildGrowElementsCapacity(object, elements, | 1169 HValue* new_elements = BuildGrowElementsCapacity(object, elements, |
| 1164 kind, kind, length, | 1170 kind, kind, length, |
| 1165 new_capacity); | 1171 new_capacity); |
| 1166 | 1172 |
| 1167 environment()->Push(new_elements); | 1173 environment()->Push(new_elements); |
| 1168 capacity_checker.Else(); | 1174 capacity_checker.Else(); |
| 1169 | 1175 |
| 1170 environment()->Push(elements); | 1176 environment()->Push(elements); |
| 1171 capacity_checker.End(); | 1177 capacity_checker.End(); |
| 1172 | 1178 |
| 1173 if (is_js_array) { | 1179 if (is_js_array) { |
| 1174 HValue* new_length = AddInstruction( | 1180 HValue* new_length = AddInstruction( |
| 1175 HAdd::New(zone, context, length, graph_->GetConstant1())); | 1181 HAdd::New(zone, context, key, graph_->GetConstant1())); |
| 1176 new_length->ClearFlag(HValue::kCanOverflow); | 1182 new_length->ClearFlag(HValue::kCanOverflow); |
| 1177 | 1183 |
| 1178 Representation representation = IsFastElementsKind(kind) | 1184 Representation representation = IsFastElementsKind(kind) |
| 1179 ? Representation::Smi() : Representation::Tagged(); | 1185 ? Representation::Smi() : Representation::Tagged(); |
| 1180 AddStore(object, HObjectAccess::ForArrayLength(), new_length, | 1186 AddStore(object, HObjectAccess::ForArrayLength(), new_length, |
| 1181 representation); | 1187 representation); |
| 1182 } | 1188 } |
| 1183 | 1189 |
| 1184 length_checker.Else(); | 1190 length_checker.Else(); |
| 1191 Add<HBoundsCheck>(key, length); |
| 1185 | 1192 |
| 1186 Add<HBoundsCheck>(key, length); | |
| 1187 environment()->Push(elements); | 1193 environment()->Push(elements); |
| 1188 | |
| 1189 length_checker.End(); | 1194 length_checker.End(); |
| 1190 | 1195 |
| 1191 return environment()->Pop(); | 1196 return environment()->Pop(); |
| 1192 } | 1197 } |
| 1193 | 1198 |
| 1194 | 1199 |
| 1195 HValue* HGraphBuilder::BuildCopyElementsOnWrite(HValue* object, | 1200 HValue* HGraphBuilder::BuildCopyElementsOnWrite(HValue* object, |
| 1196 HValue* elements, | 1201 HValue* elements, |
| 1197 ElementsKind kind, | 1202 ElementsKind kind, |
| 1198 HValue* length) { | 1203 HValue* length) { |
| (...skipping 885 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2084 DisallowHeapAllocation no_gc; | 2089 DisallowHeapAllocation no_gc; |
| 2085 ASSERT(!isolate()->optimizing_compiler_thread()->IsOptimizerThread()); | 2090 ASSERT(!isolate()->optimizing_compiler_thread()->IsOptimizerThread()); |
| 2086 for (int i = 0; i < blocks()->length(); ++i) { | 2091 for (int i = 0; i < blocks()->length(); ++i) { |
| 2087 for (HInstructionIterator it(blocks()->at(i)); !it.Done(); it.Advance()) { | 2092 for (HInstructionIterator it(blocks()->at(i)); !it.Done(); it.Advance()) { |
| 2088 it.Current()->FinalizeUniqueValueId(); | 2093 it.Current()->FinalizeUniqueValueId(); |
| 2089 } | 2094 } |
| 2090 } | 2095 } |
| 2091 } | 2096 } |
| 2092 | 2097 |
| 2093 | 2098 |
| 2094 void HGraph::Canonicalize() { | |
| 2095 HPhase phase("H_Canonicalize", this); | |
| 2096 // Before removing no-op instructions, save their semantic value. | |
| 2097 // We must be careful not to set the flag unnecessarily, because GVN | |
| 2098 // cannot identify two instructions when their flag value differs. | |
| 2099 for (int i = 0; i < blocks()->length(); ++i) { | |
| 2100 for (HInstructionIterator it(blocks()->at(i)); !it.Done(); it.Advance()) { | |
| 2101 HInstruction* instr = it.Current(); | |
| 2102 if (instr->IsArithmeticBinaryOperation() && | |
| 2103 instr->representation().IsInteger32() && | |
| 2104 instr->HasAtLeastOneUseWithFlagAndNoneWithout( | |
| 2105 HInstruction::kTruncatingToInt32)) { | |
| 2106 instr->SetFlag(HInstruction::kAllUsesTruncatingToInt32); | |
| 2107 } | |
| 2108 } | |
| 2109 } | |
| 2110 // Perform actual Canonicalization pass. | |
| 2111 for (int i = 0; i < blocks()->length(); ++i) { | |
| 2112 for (HInstructionIterator it(blocks()->at(i)); !it.Done(); it.Advance()) { | |
| 2113 HInstruction* instr = it.Current(); | |
| 2114 HValue* value = instr->Canonicalize(); | |
| 2115 if (value != instr) instr->DeleteAndReplaceWith(value); | |
| 2116 } | |
| 2117 } | |
| 2118 } | |
| 2119 | |
| 2120 | |
| 2121 // Block ordering was implemented with two mutually recursive methods, | 2099 // Block ordering was implemented with two mutually recursive methods, |
| 2122 // HGraph::Postorder and HGraph::PostorderLoopBlocks. | 2100 // HGraph::Postorder and HGraph::PostorderLoopBlocks. |
| 2123 // The recursion could lead to stack overflow so the algorithm has been | 2101 // The recursion could lead to stack overflow so the algorithm has been |
| 2124 // implemented iteratively. | 2102 // implemented iteratively. |
| 2125 // At a high level the algorithm looks like this: | 2103 // At a high level the algorithm looks like this: |
| 2126 // | 2104 // |
| 2127 // Postorder(block, loop_header) : { | 2105 // Postorder(block, loop_header) : { |
| 2128 // if (block has already been visited or is of another loop) return; | 2106 // if (block has already been visited or is of another loop) return; |
| 2129 // mark block as visited; | 2107 // mark block as visited; |
| 2130 // if (block is a loop header) { | 2108 // if (block is a loop header) { |
| (...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2445 block->AssignLoopSuccessorDominators(); | 2423 block->AssignLoopSuccessorDominators(); |
| 2446 } else { | 2424 } else { |
| 2447 for (int j = blocks_[i]->predecessors()->length() - 1; j >= 0; --j) { | 2425 for (int j = blocks_[i]->predecessors()->length() - 1; j >= 0; --j) { |
| 2448 blocks_[i]->AssignCommonDominator(blocks_[i]->predecessors()->at(j)); | 2426 blocks_[i]->AssignCommonDominator(blocks_[i]->predecessors()->at(j)); |
| 2449 } | 2427 } |
| 2450 } | 2428 } |
| 2451 } | 2429 } |
| 2452 } | 2430 } |
| 2453 | 2431 |
| 2454 | 2432 |
| 2455 // Mark all blocks that are dominated by an unconditional soft deoptimize to | |
| 2456 // prevent code motion across those blocks. | |
| 2457 void HGraph::PropagateDeoptimizingMark() { | |
| 2458 HPhase phase("H_Propagate deoptimizing mark", this); | |
| 2459 // Skip this phase if there is nothing to be done anyway. | |
| 2460 if (!has_soft_deoptimize()) return; | |
| 2461 MarkAsDeoptimizingRecursively(entry_block()); | |
| 2462 NullifyUnreachableInstructions(); | |
| 2463 } | |
| 2464 | |
| 2465 | |
| 2466 void HGraph::MarkAsDeoptimizingRecursively(HBasicBlock* block) { | |
| 2467 for (int i = 0; i < block->dominated_blocks()->length(); ++i) { | |
| 2468 HBasicBlock* dominated = block->dominated_blocks()->at(i); | |
| 2469 if (block->IsDeoptimizing()) dominated->MarkAsDeoptimizing(); | |
| 2470 MarkAsDeoptimizingRecursively(dominated); | |
| 2471 } | |
| 2472 } | |
| 2473 | |
| 2474 | |
| 2475 void HGraph::NullifyUnreachableInstructions() { | |
| 2476 if (!FLAG_unreachable_code_elimination) return; | |
| 2477 int block_count = blocks_.length(); | |
| 2478 for (int i = 0; i < block_count; ++i) { | |
| 2479 HBasicBlock* block = blocks_.at(i); | |
| 2480 bool nullify = false; | |
| 2481 const ZoneList<HBasicBlock*>* predecessors = block->predecessors(); | |
| 2482 int predecessors_length = predecessors->length(); | |
| 2483 bool all_predecessors_deoptimizing = (predecessors_length > 0); | |
| 2484 for (int j = 0; j < predecessors_length; ++j) { | |
| 2485 if (!predecessors->at(j)->IsDeoptimizing()) { | |
| 2486 all_predecessors_deoptimizing = false; | |
| 2487 break; | |
| 2488 } | |
| 2489 } | |
| 2490 if (all_predecessors_deoptimizing) nullify = true; | |
| 2491 for (HInstructionIterator it(block); !it.Done(); it.Advance()) { | |
| 2492 HInstruction* instr = it.Current(); | |
| 2493 // Leave the basic structure of the graph intact. | |
| 2494 if (instr->IsBlockEntry()) continue; | |
| 2495 if (instr->IsControlInstruction()) continue; | |
| 2496 if (instr->IsSimulate()) continue; | |
| 2497 if (instr->IsEnterInlined()) continue; | |
| 2498 if (instr->IsLeaveInlined()) continue; | |
| 2499 if (nullify) { | |
| 2500 HInstruction* last_dummy = NULL; | |
| 2501 for (int j = 0; j < instr->OperandCount(); ++j) { | |
| 2502 HValue* operand = instr->OperandAt(j); | |
| 2503 // Insert an HDummyUse for each operand, unless the operand | |
| 2504 // is an HDummyUse itself. If it's even from the same block, | |
| 2505 // remember it as a potential replacement for the instruction. | |
| 2506 if (operand->IsDummyUse()) { | |
| 2507 if (operand->block() == instr->block() && | |
| 2508 last_dummy == NULL) { | |
| 2509 last_dummy = HInstruction::cast(operand); | |
| 2510 } | |
| 2511 continue; | |
| 2512 } | |
| 2513 if (operand->IsControlInstruction()) { | |
| 2514 // Inserting a dummy use for a value that's not defined anywhere | |
| 2515 // will fail. Some instructions define fake inputs on such | |
| 2516 // values as control flow dependencies. | |
| 2517 continue; | |
| 2518 } | |
| 2519 HDummyUse* dummy = new(zone()) HDummyUse(operand); | |
| 2520 dummy->InsertBefore(instr); | |
| 2521 last_dummy = dummy; | |
| 2522 } | |
| 2523 if (last_dummy == NULL) last_dummy = GetConstant1(); | |
| 2524 instr->DeleteAndReplaceWith(last_dummy); | |
| 2525 continue; | |
| 2526 } | |
| 2527 if (instr->IsSoftDeoptimize()) { | |
| 2528 ASSERT(block->IsDeoptimizing()); | |
| 2529 nullify = true; | |
| 2530 } | |
| 2531 } | |
| 2532 } | |
| 2533 } | |
| 2534 | |
| 2535 | |
| 2536 bool HGraph::CheckArgumentsPhiUses() { | 2433 bool HGraph::CheckArgumentsPhiUses() { |
| 2537 int block_count = blocks_.length(); | 2434 int block_count = blocks_.length(); |
| 2538 for (int i = 0; i < block_count; ++i) { | 2435 for (int i = 0; i < block_count; ++i) { |
| 2539 for (int j = 0; j < blocks_[i]->phis()->length(); ++j) { | 2436 for (int j = 0; j < blocks_[i]->phis()->length(); ++j) { |
| 2540 HPhi* phi = blocks_[i]->phis()->at(j); | 2437 HPhi* phi = blocks_[i]->phis()->at(j); |
| 2541 // We don't support phi uses of arguments for now. | 2438 // We don't support phi uses of arguments for now. |
| 2542 if (phi->CheckFlag(HValue::kIsArguments)) return false; | 2439 if (phi->CheckFlag(HValue::kIsArguments)) return false; |
| 2543 } | 2440 } |
| 2544 } | 2441 } |
| 2545 return true; | 2442 return true; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 2566 phi_list_ = new(zone()) ZoneList<HPhi*>(block_count, zone()); | 2463 phi_list_ = new(zone()) ZoneList<HPhi*>(block_count, zone()); |
| 2567 for (int i = 0; i < block_count; ++i) { | 2464 for (int i = 0; i < block_count; ++i) { |
| 2568 for (int j = 0; j < blocks_[i]->phis()->length(); ++j) { | 2465 for (int j = 0; j < blocks_[i]->phis()->length(); ++j) { |
| 2569 HPhi* phi = blocks_[i]->phis()->at(j); | 2466 HPhi* phi = blocks_[i]->phis()->at(j); |
| 2570 phi_list_->Add(phi, zone()); | 2467 phi_list_->Add(phi, zone()); |
| 2571 } | 2468 } |
| 2572 } | 2469 } |
| 2573 } | 2470 } |
| 2574 | 2471 |
| 2575 | 2472 |
| 2576 void HGraph::MergeRemovableSimulates() { | |
| 2577 HPhase phase("H_Merge removable simulates", this); | |
| 2578 ZoneList<HSimulate*> mergelist(2, zone()); | |
| 2579 for (int i = 0; i < blocks()->length(); ++i) { | |
| 2580 HBasicBlock* block = blocks()->at(i); | |
| 2581 // Make sure the merge list is empty at the start of a block. | |
| 2582 ASSERT(mergelist.is_empty()); | |
| 2583 // Nasty heuristic: Never remove the first simulate in a block. This | |
| 2584 // just so happens to have a beneficial effect on register allocation. | |
| 2585 bool first = true; | |
| 2586 for (HInstructionIterator it(block); !it.Done(); it.Advance()) { | |
| 2587 HInstruction* current = it.Current(); | |
| 2588 if (current->IsLeaveInlined()) { | |
| 2589 // Never fold simulates from inlined environments into simulates | |
| 2590 // in the outer environment. | |
| 2591 // (Before each HEnterInlined, there is a non-foldable HSimulate | |
| 2592 // anyway, so we get the barrier in the other direction for free.) | |
| 2593 // Simply remove all accumulated simulates without merging. This | |
| 2594 // is safe because simulates after instructions with side effects | |
| 2595 // are never added to the merge list. | |
| 2596 while (!mergelist.is_empty()) { | |
| 2597 mergelist.RemoveLast()->DeleteAndReplaceWith(NULL); | |
| 2598 } | |
| 2599 continue; | |
| 2600 } | |
| 2601 if (current->IsReturn()) { | |
| 2602 // Drop mergeable simulates in the list. This is safe because | |
| 2603 // simulates after instructions with side effects are never added | |
| 2604 // to the merge list. | |
| 2605 while (!mergelist.is_empty()) { | |
| 2606 mergelist.RemoveLast()->DeleteAndReplaceWith(NULL); | |
| 2607 } | |
| 2608 continue; | |
| 2609 } | |
| 2610 // Skip the non-simulates and the first simulate. | |
| 2611 if (!current->IsSimulate()) continue; | |
| 2612 if (first) { | |
| 2613 first = false; | |
| 2614 continue; | |
| 2615 } | |
| 2616 HSimulate* current_simulate = HSimulate::cast(current); | |
| 2617 if ((current_simulate->previous()->HasObservableSideEffects() && | |
| 2618 !current_simulate->next()->IsSimulate()) || | |
| 2619 !current_simulate->is_candidate_for_removal()) { | |
| 2620 // This simulate is not suitable for folding. | |
| 2621 // Fold the ones accumulated so far. | |
| 2622 current_simulate->MergeWith(&mergelist); | |
| 2623 continue; | |
| 2624 } else { | |
| 2625 // Accumulate this simulate for folding later on. | |
| 2626 mergelist.Add(current_simulate, zone()); | |
| 2627 } | |
| 2628 } | |
| 2629 | |
| 2630 if (!mergelist.is_empty()) { | |
| 2631 // Merge the accumulated simulates at the end of the block. | |
| 2632 HSimulate* last = mergelist.RemoveLast(); | |
| 2633 last->MergeWith(&mergelist); | |
| 2634 } | |
| 2635 } | |
| 2636 } | |
| 2637 | |
| 2638 | |
| 2639 void HGraph::PropagateMinusZeroChecks(HValue* value, BitVector* visited) { | |
| 2640 HValue* current = value; | |
| 2641 while (current != NULL) { | |
| 2642 if (visited->Contains(current->id())) return; | |
| 2643 | |
| 2644 // For phis, we must propagate the check to all of its inputs. | |
| 2645 if (current->IsPhi()) { | |
| 2646 visited->Add(current->id()); | |
| 2647 HPhi* phi = HPhi::cast(current); | |
| 2648 for (int i = 0; i < phi->OperandCount(); ++i) { | |
| 2649 PropagateMinusZeroChecks(phi->OperandAt(i), visited); | |
| 2650 } | |
| 2651 break; | |
| 2652 } | |
| 2653 | |
| 2654 // For multiplication, division, and Math.min/max(), we must propagate | |
| 2655 // to the left and the right side. | |
| 2656 if (current->IsMul()) { | |
| 2657 HMul* mul = HMul::cast(current); | |
| 2658 mul->EnsureAndPropagateNotMinusZero(visited); | |
| 2659 PropagateMinusZeroChecks(mul->left(), visited); | |
| 2660 PropagateMinusZeroChecks(mul->right(), visited); | |
| 2661 } else if (current->IsDiv()) { | |
| 2662 HDiv* div = HDiv::cast(current); | |
| 2663 div->EnsureAndPropagateNotMinusZero(visited); | |
| 2664 PropagateMinusZeroChecks(div->left(), visited); | |
| 2665 PropagateMinusZeroChecks(div->right(), visited); | |
| 2666 } else if (current->IsMathMinMax()) { | |
| 2667 HMathMinMax* minmax = HMathMinMax::cast(current); | |
| 2668 visited->Add(minmax->id()); | |
| 2669 PropagateMinusZeroChecks(minmax->left(), visited); | |
| 2670 PropagateMinusZeroChecks(minmax->right(), visited); | |
| 2671 } | |
| 2672 | |
| 2673 current = current->EnsureAndPropagateNotMinusZero(visited); | |
| 2674 } | |
| 2675 } | |
| 2676 | |
| 2677 | |
| 2678 void HGraph::RecursivelyMarkPhiDeoptimizeOnUndefined(HPhi* phi) { | 2473 void HGraph::RecursivelyMarkPhiDeoptimizeOnUndefined(HPhi* phi) { |
| 2679 if (!phi->CheckFlag(HValue::kAllowUndefinedAsNaN)) return; | 2474 if (!phi->CheckFlag(HValue::kAllowUndefinedAsNaN)) return; |
| 2680 phi->ClearFlag(HValue::kAllowUndefinedAsNaN); | 2475 phi->ClearFlag(HValue::kAllowUndefinedAsNaN); |
| 2681 for (int i = 0; i < phi->OperandCount(); ++i) { | 2476 for (int i = 0; i < phi->OperandCount(); ++i) { |
| 2682 HValue* input = phi->OperandAt(i); | 2477 HValue* input = phi->OperandAt(i); |
| 2683 if (input->IsPhi()) { | 2478 if (input->IsPhi()) { |
| 2684 RecursivelyMarkPhiDeoptimizeOnUndefined(HPhi::cast(input)); | 2479 RecursivelyMarkPhiDeoptimizeOnUndefined(HPhi::cast(input)); |
| 2685 } | 2480 } |
| 2686 } | 2481 } |
| 2687 } | 2482 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 2700 HValue* use_value = it.value(); | 2495 HValue* use_value = it.value(); |
| 2701 if (!use_value->CheckFlag(HValue::kAllowUndefinedAsNaN)) { | 2496 if (!use_value->CheckFlag(HValue::kAllowUndefinedAsNaN)) { |
| 2702 RecursivelyMarkPhiDeoptimizeOnUndefined(phi); | 2497 RecursivelyMarkPhiDeoptimizeOnUndefined(phi); |
| 2703 break; | 2498 break; |
| 2704 } | 2499 } |
| 2705 } | 2500 } |
| 2706 } | 2501 } |
| 2707 } | 2502 } |
| 2708 | 2503 |
| 2709 | 2504 |
| 2710 void HGraph::ComputeMinusZeroChecks() { | |
| 2711 HPhase phase("H_Compute minus zero checks", this); | |
| 2712 BitVector visited(GetMaximumValueID(), zone()); | |
| 2713 for (int i = 0; i < blocks_.length(); ++i) { | |
| 2714 for (HInstructionIterator it(blocks_[i]); !it.Done(); it.Advance()) { | |
| 2715 HInstruction* current = it.Current(); | |
| 2716 if (current->IsChange()) { | |
| 2717 HChange* change = HChange::cast(current); | |
| 2718 // Propagate flags for negative zero checks upwards from conversions | |
| 2719 // int32-to-tagged and int32-to-double. | |
| 2720 Representation from = change->value()->representation(); | |
| 2721 ASSERT(from.Equals(change->from())); | |
| 2722 if (from.IsInteger32()) { | |
| 2723 ASSERT(change->to().IsTagged() || | |
| 2724 change->to().IsDouble() || | |
| 2725 change->to().IsSmi()); | |
| 2726 ASSERT(visited.IsEmpty()); | |
| 2727 PropagateMinusZeroChecks(change->value(), &visited); | |
| 2728 visited.Clear(); | |
| 2729 } | |
| 2730 } | |
| 2731 } | |
| 2732 } | |
| 2733 } | |
| 2734 | |
| 2735 | |
| 2736 // Implementation of utility class to encapsulate the translation state for | 2505 // Implementation of utility class to encapsulate the translation state for |
| 2737 // a (possibly inlined) function. | 2506 // a (possibly inlined) function. |
| 2738 FunctionState::FunctionState(HOptimizedGraphBuilder* owner, | 2507 FunctionState::FunctionState(HOptimizedGraphBuilder* owner, |
| 2739 CompilationInfo* info, | 2508 CompilationInfo* info, |
| 2740 InliningKind inlining_kind) | 2509 InliningKind inlining_kind) |
| 2741 : owner_(owner), | 2510 : owner_(owner), |
| 2742 compilation_info_(info), | 2511 compilation_info_(info), |
| 2743 call_context_(NULL), | 2512 call_context_(NULL), |
| 2744 inlining_kind_(inlining_kind), | 2513 inlining_kind_(inlining_kind), |
| 2745 function_return_(NULL), | 2514 function_return_(NULL), |
| (...skipping 426 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3172 | 2941 |
| 3173 #ifdef DEBUG | 2942 #ifdef DEBUG |
| 3174 // Do a full verify after building the graph and computing dominators. | 2943 // Do a full verify after building the graph and computing dominators. |
| 3175 Verify(true); | 2944 Verify(true); |
| 3176 #endif | 2945 #endif |
| 3177 | 2946 |
| 3178 if (FLAG_analyze_environment_liveness && maximum_environment_size() != 0) { | 2947 if (FLAG_analyze_environment_liveness && maximum_environment_size() != 0) { |
| 3179 Run<HEnvironmentLivenessAnalysisPhase>(); | 2948 Run<HEnvironmentLivenessAnalysisPhase>(); |
| 3180 } | 2949 } |
| 3181 | 2950 |
| 3182 PropagateDeoptimizingMark(); | 2951 Run<HPropagateDeoptimizingMarkPhase>(); |
| 3183 if (!CheckConstPhiUses()) { | 2952 if (!CheckConstPhiUses()) { |
| 3184 *bailout_reason = SmartArrayPointer<char>(StrDup( | 2953 *bailout_reason = SmartArrayPointer<char>(StrDup( |
| 3185 "Unsupported phi use of const variable")); | 2954 "Unsupported phi use of const variable")); |
| 3186 return false; | 2955 return false; |
| 3187 } | 2956 } |
| 3188 Run<HRedundantPhiEliminationPhase>(); | 2957 Run<HRedundantPhiEliminationPhase>(); |
| 3189 if (!CheckArgumentsPhiUses()) { | 2958 if (!CheckArgumentsPhiUses()) { |
| 3190 *bailout_reason = SmartArrayPointer<char>(StrDup( | 2959 *bailout_reason = SmartArrayPointer<char>(StrDup( |
| 3191 "Unsupported phi use of arguments")); | 2960 "Unsupported phi use of arguments")); |
| 3192 return false; | 2961 return false; |
| 3193 } | 2962 } |
| 3194 | 2963 |
| 3195 // Remove dead code and phis | 2964 // Remove dead code and phis |
| 3196 if (FLAG_dead_code_elimination) Run<HDeadCodeEliminationPhase>(); | 2965 if (FLAG_dead_code_elimination) Run<HDeadCodeEliminationPhase>(); |
| 3197 CollectPhis(); | 2966 CollectPhis(); |
| 3198 | 2967 |
| 3199 if (has_osr()) osr()->FinishOsrValues(); | 2968 if (has_osr()) osr()->FinishOsrValues(); |
| 3200 | 2969 |
| 3201 Run<HInferRepresentationPhase>(); | 2970 Run<HInferRepresentationPhase>(); |
| 3202 | 2971 |
| 3203 // Remove HSimulate instructions that have turned out not to be needed | 2972 // Remove HSimulate instructions that have turned out not to be needed |
| 3204 // after all by folding them into the following HSimulate. | 2973 // after all by folding them into the following HSimulate. |
| 3205 // This must happen after inferring representations. | 2974 // This must happen after inferring representations. |
| 3206 MergeRemovableSimulates(); | 2975 Run<HMergeRemovableSimulatesPhase>(); |
| 3207 | 2976 |
| 3208 MarkDeoptimizeOnUndefined(); | 2977 MarkDeoptimizeOnUndefined(); |
| 3209 Run<HRepresentationChangesPhase>(); | 2978 Run<HRepresentationChangesPhase>(); |
| 3210 | 2979 |
| 3211 Run<HInferTypesPhase>(); | 2980 Run<HInferTypesPhase>(); |
| 3212 | 2981 |
| 3213 // Must be performed before canonicalization to ensure that Canonicalize | 2982 // Must be performed before canonicalization to ensure that Canonicalize |
| 3214 // will not remove semantically meaningful ToInt32 operations e.g. BIT_OR with | 2983 // will not remove semantically meaningful ToInt32 operations e.g. BIT_OR with |
| 3215 // zero. | 2984 // zero. |
| 3216 if (FLAG_opt_safe_uint32_operations) Run<HUint32AnalysisPhase>(); | 2985 if (FLAG_opt_safe_uint32_operations) Run<HUint32AnalysisPhase>(); |
| 3217 | 2986 |
| 3218 if (FLAG_use_canonicalizing) Canonicalize(); | 2987 if (FLAG_use_canonicalizing) Run<HCanonicalizePhase>(); |
| 3219 | 2988 |
| 3220 if (FLAG_use_escape_analysis) Run<HEscapeAnalysisPhase>(); | 2989 if (FLAG_use_escape_analysis) Run<HEscapeAnalysisPhase>(); |
| 3221 | 2990 |
| 3222 if (FLAG_use_gvn) Run<HGlobalValueNumberingPhase>(); | 2991 if (FLAG_use_gvn) Run<HGlobalValueNumberingPhase>(); |
| 3223 | 2992 |
| 3224 if (FLAG_use_range) Run<HRangeAnalysisPhase>(); | 2993 if (FLAG_use_range) Run<HRangeAnalysisPhase>(); |
| 3225 | 2994 |
| 3226 ComputeMinusZeroChecks(); | 2995 Run<HComputeMinusZeroChecksPhase>(); |
| 3227 | 2996 |
| 3228 // Eliminate redundant stack checks on backwards branches. | 2997 // Eliminate redundant stack checks on backwards branches. |
| 3229 Run<HStackCheckEliminationPhase>(); | 2998 Run<HStackCheckEliminationPhase>(); |
| 3230 | 2999 |
| 3231 if (FLAG_idefs) SetupInformativeDefinitions(); | 3000 if (FLAG_idefs) SetupInformativeDefinitions(); |
| 3232 if (FLAG_array_bounds_checks_elimination && !FLAG_idefs) { | 3001 if (FLAG_array_bounds_checks_elimination && !FLAG_idefs) { |
| 3233 Run<HBoundsCheckEliminationPhase>(); | 3002 Run<HBoundsCheckEliminationPhase>(); |
| 3234 } | 3003 } |
| 3235 if (FLAG_array_index_dehoisting) DehoistSimpleArrayIndexComputations(); | 3004 if (FLAG_array_index_dehoisting) Run<HDehoistIndexComputationsPhase>(); |
| 3236 if (FLAG_dead_code_elimination) Run<HDeadCodeEliminationPhase>(); | 3005 if (FLAG_dead_code_elimination) Run<HDeadCodeEliminationPhase>(); |
| 3237 | 3006 |
| 3238 RestoreActualValues(); | 3007 RestoreActualValues(); |
| 3239 | 3008 |
| 3240 return true; | 3009 return true; |
| 3241 } | 3010 } |
| 3242 | 3011 |
| 3243 | 3012 |
| 3244 void HGraph::SetupInformativeDefinitionsInBlock(HBasicBlock* block) { | 3013 void HGraph::SetupInformativeDefinitionsInBlock(HBasicBlock* block) { |
| 3245 for (int phi_index = 0; phi_index < block->phis()->length(); phi_index++) { | 3014 for (int phi_index = 0; phi_index < block->phis()->length(); phi_index++) { |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3278 } | 3047 } |
| 3279 } | 3048 } |
| 3280 | 3049 |
| 3281 | 3050 |
| 3282 void HGraph::SetupInformativeDefinitions() { | 3051 void HGraph::SetupInformativeDefinitions() { |
| 3283 HPhase phase("H_Setup informative definitions", this); | 3052 HPhase phase("H_Setup informative definitions", this); |
| 3284 SetupInformativeDefinitionsRecursively(entry_block()); | 3053 SetupInformativeDefinitionsRecursively(entry_block()); |
| 3285 } | 3054 } |
| 3286 | 3055 |
| 3287 | 3056 |
| 3288 static void DehoistArrayIndex(ArrayInstructionInterface* array_operation) { | |
| 3289 HValue* index = array_operation->GetKey()->ActualValue(); | |
| 3290 if (!index->representation().IsSmiOrInteger32()) return; | |
| 3291 | |
| 3292 HConstant* constant; | |
| 3293 HValue* subexpression; | |
| 3294 int32_t sign; | |
| 3295 if (index->IsAdd()) { | |
| 3296 sign = 1; | |
| 3297 HAdd* add = HAdd::cast(index); | |
| 3298 if (add->left()->IsConstant()) { | |
| 3299 subexpression = add->right(); | |
| 3300 constant = HConstant::cast(add->left()); | |
| 3301 } else if (add->right()->IsConstant()) { | |
| 3302 subexpression = add->left(); | |
| 3303 constant = HConstant::cast(add->right()); | |
| 3304 } else { | |
| 3305 return; | |
| 3306 } | |
| 3307 } else if (index->IsSub()) { | |
| 3308 sign = -1; | |
| 3309 HSub* sub = HSub::cast(index); | |
| 3310 if (sub->left()->IsConstant()) { | |
| 3311 subexpression = sub->right(); | |
| 3312 constant = HConstant::cast(sub->left()); | |
| 3313 } else if (sub->right()->IsConstant()) { | |
| 3314 subexpression = sub->left(); | |
| 3315 constant = HConstant::cast(sub->right()); | |
| 3316 } else { | |
| 3317 return; | |
| 3318 } | |
| 3319 } else { | |
| 3320 return; | |
| 3321 } | |
| 3322 | |
| 3323 if (!constant->HasInteger32Value()) return; | |
| 3324 int32_t value = constant->Integer32Value() * sign; | |
| 3325 // We limit offset values to 30 bits because we want to avoid the risk of | |
| 3326 // overflows when the offset is added to the object header size. | |
| 3327 if (value >= 1 << 30 || value < 0) return; | |
| 3328 array_operation->SetKey(subexpression); | |
| 3329 if (index->HasNoUses()) { | |
| 3330 index->DeleteAndReplaceWith(NULL); | |
| 3331 } | |
| 3332 ASSERT(value >= 0); | |
| 3333 array_operation->SetIndexOffset(static_cast<uint32_t>(value)); | |
| 3334 array_operation->SetDehoisted(true); | |
| 3335 } | |
| 3336 | |
| 3337 | |
| 3338 void HGraph::DehoistSimpleArrayIndexComputations() { | |
| 3339 HPhase phase("H_Dehoist index computations", this); | |
| 3340 for (int i = 0; i < blocks()->length(); ++i) { | |
| 3341 for (HInstructionIterator it(blocks()->at(i)); !it.Done(); it.Advance()) { | |
| 3342 HInstruction* instr = it.Current(); | |
| 3343 ArrayInstructionInterface* array_instruction = NULL; | |
| 3344 if (instr->IsLoadKeyed()) { | |
| 3345 HLoadKeyed* op = HLoadKeyed::cast(instr); | |
| 3346 array_instruction = static_cast<ArrayInstructionInterface*>(op); | |
| 3347 } else if (instr->IsStoreKeyed()) { | |
| 3348 HStoreKeyed* op = HStoreKeyed::cast(instr); | |
| 3349 array_instruction = static_cast<ArrayInstructionInterface*>(op); | |
| 3350 } else { | |
| 3351 continue; | |
| 3352 } | |
| 3353 DehoistArrayIndex(array_instruction); | |
| 3354 } | |
| 3355 } | |
| 3356 } | |
| 3357 | |
| 3358 | |
| 3359 void HGraph::RestoreActualValues() { | 3057 void HGraph::RestoreActualValues() { |
| 3360 HPhase phase("H_Restore actual values", this); | 3058 HPhase phase("H_Restore actual values", this); |
| 3361 | 3059 |
| 3362 for (int block_index = 0; block_index < blocks()->length(); block_index++) { | 3060 for (int block_index = 0; block_index < blocks()->length(); block_index++) { |
| 3363 HBasicBlock* block = blocks()->at(block_index); | 3061 HBasicBlock* block = blocks()->at(block_index); |
| 3364 | 3062 |
| 3365 #ifdef DEBUG | 3063 #ifdef DEBUG |
| 3366 for (int i = 0; i < block->phis()->length(); i++) { | 3064 for (int i = 0; i < block->phis()->length(); i++) { |
| 3367 HPhi* phi = block->phis()->at(i); | 3065 HPhi* phi = block->phis()->at(i); |
| 3368 ASSERT(phi->ActualValue() == phi); | 3066 ASSERT(phi->ActualValue() == phi); |
| (...skipping 1539 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4908 HValue* context = environment()->LookupContext(); | 4606 HValue* context = environment()->LookupContext(); |
| 4909 return new(zone()) HStoreNamedGeneric( | 4607 return new(zone()) HStoreNamedGeneric( |
| 4910 context, | 4608 context, |
| 4911 object, | 4609 object, |
| 4912 name, | 4610 name, |
| 4913 value, | 4611 value, |
| 4914 function_strict_mode_flag()); | 4612 function_strict_mode_flag()); |
| 4915 } | 4613 } |
| 4916 | 4614 |
| 4917 | 4615 |
| 4918 HInstruction* HOptimizedGraphBuilder::BuildCallSetter( | |
| 4919 HValue* object, | |
| 4920 HValue* value, | |
| 4921 Handle<Map> map, | |
| 4922 Handle<JSFunction> setter, | |
| 4923 Handle<JSObject> holder) { | |
| 4924 AddCheckConstantFunction(holder, object, map); | |
| 4925 Add<HPushArgument>(object); | |
| 4926 Add<HPushArgument>(value); | |
| 4927 return new(zone()) HCallConstantFunction(setter, 2); | |
| 4928 } | |
| 4929 | |
| 4930 | |
| 4931 HInstruction* HOptimizedGraphBuilder::BuildStoreNamedMonomorphic( | 4616 HInstruction* HOptimizedGraphBuilder::BuildStoreNamedMonomorphic( |
| 4932 HValue* object, | 4617 HValue* object, |
| 4933 Handle<String> name, | 4618 Handle<String> name, |
| 4934 HValue* value, | 4619 HValue* value, |
| 4935 Handle<Map> map) { | 4620 Handle<Map> map) { |
| 4936 // Handle a store to a known field. | 4621 // Handle a store to a known field. |
| 4937 LookupResult lookup(isolate()); | 4622 LookupResult lookup(isolate()); |
| 4938 if (ComputeLoadStoreField(map, name, &lookup, true)) { | 4623 if (ComputeLoadStoreField(map, name, &lookup, true)) { |
| 4939 AddCheckMapsWithTransitions(object, map); | 4624 AddCheckMapsWithTransitions(object, map); |
| 4940 return BuildStoreNamedField(object, name, value, map, &lookup); | 4625 return BuildStoreNamedField(object, name, value, map, &lookup); |
| (...skipping 1176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6117 instr = BuildMonomorphicElementAccess( | 5802 instr = BuildMonomorphicElementAccess( |
| 6118 obj, key, val, NULL, map, is_store, expr->GetStoreMode()); | 5803 obj, key, val, NULL, map, is_store, expr->GetStoreMode()); |
| 6119 } | 5804 } |
| 6120 } else if (expr->GetReceiverTypes() != NULL && | 5805 } else if (expr->GetReceiverTypes() != NULL && |
| 6121 !expr->GetReceiverTypes()->is_empty()) { | 5806 !expr->GetReceiverTypes()->is_empty()) { |
| 6122 return HandlePolymorphicElementAccess( | 5807 return HandlePolymorphicElementAccess( |
| 6123 obj, key, val, expr, ast_id, position, is_store, | 5808 obj, key, val, expr, ast_id, position, is_store, |
| 6124 expr->GetStoreMode(), has_side_effects); | 5809 expr->GetStoreMode(), has_side_effects); |
| 6125 } else { | 5810 } else { |
| 6126 if (is_store) { | 5811 if (is_store) { |
| 5812 if (expr->IsAssignment() && expr->AsAssignment()->IsUninitialized()) { |
| 5813 AddSoftDeoptimize(); |
| 5814 } |
| 6127 instr = BuildStoreKeyedGeneric(obj, key, val); | 5815 instr = BuildStoreKeyedGeneric(obj, key, val); |
| 6128 } else { | 5816 } else { |
| 5817 if (expr->AsProperty()->IsUninitialized()) { |
| 5818 AddSoftDeoptimize(); |
| 5819 } |
| 6129 instr = BuildLoadKeyedGeneric(obj, key); | 5820 instr = BuildLoadKeyedGeneric(obj, key); |
| 6130 } | 5821 } |
| 6131 AddInstruction(instr); | 5822 AddInstruction(instr); |
| 6132 } | 5823 } |
| 6133 if (position != RelocInfo::kNoPosition) instr->set_position(position); | 5824 if (position != RelocInfo::kNoPosition) instr->set_position(position); |
| 6134 *has_side_effects = instr->HasObservableSideEffects(); | 5825 *has_side_effects = instr->HasObservableSideEffects(); |
| 6135 return instr; | 5826 return instr; |
| 6136 } | 5827 } |
| 6137 | 5828 |
| 6138 | 5829 |
| (...skipping 1282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7421 return; | 7112 return; |
| 7422 | 7113 |
| 7423 } else { | 7114 } else { |
| 7424 HValue* context = environment()->LookupContext(); | 7115 HValue* context = environment()->LookupContext(); |
| 7425 call = PreProcessCall( | 7116 call = PreProcessCall( |
| 7426 new(zone()) HCallNamed(context, name, argument_count)); | 7117 new(zone()) HCallNamed(context, name, argument_count)); |
| 7427 } | 7118 } |
| 7428 | 7119 |
| 7429 } else { | 7120 } else { |
| 7430 VariableProxy* proxy = expr->expression()->AsVariableProxy(); | 7121 VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
| 7431 bool global_call = proxy != NULL && proxy->var()->IsUnallocated(); | |
| 7432 | |
| 7433 if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) { | 7122 if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) { |
| 7434 return Bailout("possible direct call to eval"); | 7123 return Bailout("possible direct call to eval"); |
| 7435 } | 7124 } |
| 7436 | 7125 |
| 7126 bool global_call = proxy != NULL && proxy->var()->IsUnallocated(); |
| 7437 if (global_call) { | 7127 if (global_call) { |
| 7438 Variable* var = proxy->var(); | 7128 Variable* var = proxy->var(); |
| 7439 bool known_global_function = false; | 7129 bool known_global_function = false; |
| 7440 // If there is a global property cell for the name at compile time and | 7130 // If there is a global property cell for the name at compile time and |
| 7441 // access check is not enabled we assume that the function will not change | 7131 // access check is not enabled we assume that the function will not change |
| 7442 // and generate optimized code for calling the function. | 7132 // and generate optimized code for calling the function. |
| 7443 LookupResult lookup(isolate()); | 7133 LookupResult lookup(isolate()); |
| 7444 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, false); | 7134 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, false); |
| 7445 if (type == kUseCell && | 7135 if (type == kUseCell && |
| 7446 !current_info()->global_object()->IsAccessCheckNeeded()) { | 7136 !current_info()->global_object()->IsAccessCheckNeeded()) { |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7549 | 7239 |
| 7550 call->set_position(expr->position()); | 7240 call->set_position(expr->position()); |
| 7551 return ast_context()->ReturnInstruction(call, expr->id()); | 7241 return ast_context()->ReturnInstruction(call, expr->id()); |
| 7552 } | 7242 } |
| 7553 | 7243 |
| 7554 | 7244 |
| 7555 // Checks whether allocation using the given constructor can be inlined. | 7245 // Checks whether allocation using the given constructor can be inlined. |
| 7556 static bool IsAllocationInlineable(Handle<JSFunction> constructor) { | 7246 static bool IsAllocationInlineable(Handle<JSFunction> constructor) { |
| 7557 return constructor->has_initial_map() && | 7247 return constructor->has_initial_map() && |
| 7558 constructor->initial_map()->instance_type() == JS_OBJECT_TYPE && | 7248 constructor->initial_map()->instance_type() == JS_OBJECT_TYPE && |
| 7559 constructor->initial_map()->instance_size() < HAllocateObject::kMaxSize; | 7249 constructor->initial_map()->instance_size() < HAllocate::kMaxInlineSize && |
| 7250 constructor->initial_map()->InitialPropertiesLength() == 0; |
| 7560 } | 7251 } |
| 7561 | 7252 |
| 7562 | 7253 |
| 7563 void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) { | 7254 void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) { |
| 7564 ASSERT(!HasStackOverflow()); | 7255 ASSERT(!HasStackOverflow()); |
| 7565 ASSERT(current_block() != NULL); | 7256 ASSERT(current_block() != NULL); |
| 7566 ASSERT(current_block()->HasPredecessor()); | 7257 ASSERT(current_block()->HasPredecessor()); |
| 7567 int argument_count = expr->arguments()->length() + 1; // Plus constructor. | 7258 int argument_count = expr->arguments()->length() + 1; // Plus constructor. |
| 7568 HValue* context = environment()->LookupContext(); | 7259 HValue* context = environment()->LookupContext(); |
| 7260 Factory* factory = isolate()->factory(); |
| 7569 | 7261 |
| 7570 if (FLAG_inline_construct && | 7262 if (FLAG_inline_construct && |
| 7571 expr->IsMonomorphic() && | 7263 expr->IsMonomorphic() && |
| 7572 IsAllocationInlineable(expr->target())) { | 7264 IsAllocationInlineable(expr->target())) { |
| 7573 // The constructor function is on the stack in the unoptimized code | 7265 // The constructor function is on the stack in the unoptimized code |
| 7574 // during evaluation of the arguments. | 7266 // during evaluation of the arguments. |
| 7575 CHECK_ALIVE(VisitForValue(expr->expression())); | 7267 CHECK_ALIVE(VisitForValue(expr->expression())); |
| 7576 HValue* function = Top(); | 7268 HValue* function = Top(); |
| 7577 CHECK_ALIVE(VisitExpressions(expr->arguments())); | 7269 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
| 7578 Handle<JSFunction> constructor = expr->target(); | 7270 Handle<JSFunction> constructor = expr->target(); |
| 7579 HValue* check = Add<HCheckFunction>(function, constructor); | 7271 HValue* check = Add<HCheckFunction>(function, constructor); |
| 7580 | 7272 |
| 7581 // Force completion of inobject slack tracking before generating | 7273 // Force completion of inobject slack tracking before generating |
| 7582 // allocation code to finalize instance size. | 7274 // allocation code to finalize instance size. |
| 7583 if (constructor->shared()->IsInobjectSlackTrackingInProgress()) { | 7275 if (constructor->shared()->IsInobjectSlackTrackingInProgress()) { |
| 7584 constructor->shared()->CompleteInobjectSlackTracking(); | 7276 constructor->shared()->CompleteInobjectSlackTracking(); |
| 7585 } | 7277 } |
| 7586 | 7278 |
| 7587 // Replace the constructor function with a newly allocated receiver. | 7279 // Calculate instance size from initial map of constructor. |
| 7588 HInstruction* receiver = Add<HAllocateObject>(context, constructor); | 7280 ASSERT(constructor->has_initial_map()); |
| 7589 // Index of the receiver from the top of the expression stack. | 7281 Handle<Map> initial_map(constructor->initial_map()); |
| 7282 int instance_size = initial_map->instance_size(); |
| 7283 ASSERT(initial_map->InitialPropertiesLength() == 0); |
| 7284 |
| 7285 // Allocate an instance of the implicit receiver object. |
| 7286 HValue* size_in_bytes = Add<HConstant>(instance_size); |
| 7287 HAllocate::Flags flags = HAllocate::DefaultFlags(); |
| 7288 if (FLAG_pretenuring_call_new && |
| 7289 isolate()->heap()->ShouldGloballyPretenure()) { |
| 7290 flags = static_cast<HAllocate::Flags>( |
| 7291 flags | HAllocate::CAN_ALLOCATE_IN_OLD_POINTER_SPACE); |
| 7292 } |
| 7293 HAllocate* receiver = |
| 7294 Add<HAllocate>(context, size_in_bytes, HType::JSObject(), flags); |
| 7295 receiver->set_known_initial_map(initial_map); |
| 7296 |
| 7297 // Load the initial map from the constructor. |
| 7298 HValue* constructor_value = Add<HConstant>(constructor); |
| 7299 HValue* initial_map_value = |
| 7300 AddLoad(constructor_value, HObjectAccess::ForJSObjectOffset( |
| 7301 JSFunction::kPrototypeOrInitialMapOffset)); |
| 7302 |
| 7303 // Initialize map and fields of the newly allocated object. |
| 7304 { NoObservableSideEffectsScope no_effects(this); |
| 7305 ASSERT(initial_map->instance_type() == JS_OBJECT_TYPE); |
| 7306 AddStore(receiver, |
| 7307 HObjectAccess::ForJSObjectOffset(JSObject::kMapOffset), |
| 7308 initial_map_value); |
| 7309 HValue* empty_fixed_array = Add<HConstant>(factory->empty_fixed_array()); |
| 7310 AddStore(receiver, |
| 7311 HObjectAccess::ForJSObjectOffset(JSObject::kPropertiesOffset), |
| 7312 empty_fixed_array); |
| 7313 AddStore(receiver, |
| 7314 HObjectAccess::ForJSObjectOffset(JSObject::kElementsOffset), |
| 7315 empty_fixed_array); |
| 7316 if (initial_map->inobject_properties() != 0) { |
| 7317 HConstant* undefined = graph()->GetConstantUndefined(); |
| 7318 for (int i = 0; i < initial_map->inobject_properties(); i++) { |
| 7319 int property_offset = JSObject::kHeaderSize + i * kPointerSize; |
| 7320 AddStore(receiver, |
| 7321 HObjectAccess::ForJSObjectOffset(property_offset), |
| 7322 undefined); |
| 7323 } |
| 7324 } |
| 7325 } |
| 7326 |
| 7327 // Replace the constructor function with a newly allocated receiver using |
| 7328 // the index of the receiver from the top of the expression stack. |
| 7590 const int receiver_index = argument_count - 1; | 7329 const int receiver_index = argument_count - 1; |
| 7591 ASSERT(environment()->ExpressionStackAt(receiver_index) == function); | 7330 ASSERT(environment()->ExpressionStackAt(receiver_index) == function); |
| 7592 environment()->SetExpressionStackAt(receiver_index, receiver); | 7331 environment()->SetExpressionStackAt(receiver_index, receiver); |
| 7593 | 7332 |
| 7594 if (TryInlineConstruct(expr, receiver)) return; | 7333 if (TryInlineConstruct(expr, receiver)) return; |
| 7595 | 7334 |
| 7596 // TODO(mstarzinger): For now we remove the previous HAllocateObject and | 7335 // TODO(mstarzinger): For now we remove the previous HAllocate and all |
| 7597 // add HPushArgument for the arguments in case inlining failed. What we | 7336 // corresponding instructions and instead add HPushArgument for the |
| 7598 // actually should do is emit HInvokeFunction on the constructor instead | 7337 // arguments in case inlining failed. What we actually should do is for |
| 7599 // of using HCallNew as a fallback. | 7338 // inlining to try to build a subgraph without mutating the parent graph. |
| 7339 HInstruction* instr = current_block()->last(); |
| 7340 while (instr != initial_map_value) { |
| 7341 HInstruction* prev_instr = instr->previous(); |
| 7342 instr->DeleteAndReplaceWith(NULL); |
| 7343 instr = prev_instr; |
| 7344 } |
| 7345 initial_map_value->DeleteAndReplaceWith(NULL); |
| 7600 receiver->DeleteAndReplaceWith(NULL); | 7346 receiver->DeleteAndReplaceWith(NULL); |
| 7601 check->DeleteAndReplaceWith(NULL); | 7347 check->DeleteAndReplaceWith(NULL); |
| 7602 environment()->SetExpressionStackAt(receiver_index, function); | 7348 environment()->SetExpressionStackAt(receiver_index, function); |
| 7603 HInstruction* call = PreProcessCall( | 7349 HInstruction* call = PreProcessCall( |
| 7604 new(zone()) HCallNew(context, function, argument_count)); | 7350 new(zone()) HCallNew(context, function, argument_count)); |
| 7605 call->set_position(expr->position()); | 7351 call->set_position(expr->position()); |
| 7606 return ast_context()->ReturnInstruction(call, expr->id()); | 7352 return ast_context()->ReturnInstruction(call, expr->id()); |
| 7607 } else { | 7353 } else { |
| 7608 // The constructor function is both an operand to the instruction and an | 7354 // The constructor function is both an operand to the instruction and an |
| 7609 // argument to the construct call. | 7355 // argument to the construct call. |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7647 void HOptimizedGraphBuilder::VisitCallRuntime(CallRuntime* expr) { | 7393 void HOptimizedGraphBuilder::VisitCallRuntime(CallRuntime* expr) { |
| 7648 ASSERT(!HasStackOverflow()); | 7394 ASSERT(!HasStackOverflow()); |
| 7649 ASSERT(current_block() != NULL); | 7395 ASSERT(current_block() != NULL); |
| 7650 ASSERT(current_block()->HasPredecessor()); | 7396 ASSERT(current_block()->HasPredecessor()); |
| 7651 if (expr->is_jsruntime()) { | 7397 if (expr->is_jsruntime()) { |
| 7652 return Bailout("call to a JavaScript runtime function"); | 7398 return Bailout("call to a JavaScript runtime function"); |
| 7653 } | 7399 } |
| 7654 | 7400 |
| 7655 const Runtime::Function* function = expr->function(); | 7401 const Runtime::Function* function = expr->function(); |
| 7656 ASSERT(function != NULL); | 7402 ASSERT(function != NULL); |
| 7403 |
| 7404 if (static_cast<int>(function->function_id) |
| 7405 == static_cast<int>(Runtime::kNeverOptimize) |
| 7406 && expr->arguments()->length() == 0) { |
| 7407 // %NeverOptimize() without arguments marks the caller as never optimize. |
| 7408 return Bailout("function marked itself as never optimize"); |
| 7409 } |
| 7410 |
| 7657 if (function->intrinsic_type == Runtime::INLINE) { | 7411 if (function->intrinsic_type == Runtime::INLINE) { |
| 7658 ASSERT(expr->name()->length() > 0); | 7412 ASSERT(expr->name()->length() > 0); |
| 7659 ASSERT(expr->name()->Get(0) == '_'); | 7413 ASSERT(expr->name()->Get(0) == '_'); |
| 7660 // Call to an inline function. | 7414 // Call to an inline function. |
| 7661 int lookup_index = static_cast<int>(function->function_id) - | 7415 int lookup_index = static_cast<int>(function->function_id) - |
| 7662 static_cast<int>(Runtime::kFirstInlineFunction); | 7416 static_cast<int>(Runtime::kFirstInlineFunction); |
| 7663 ASSERT(lookup_index >= 0); | 7417 ASSERT(lookup_index >= 0); |
| 7664 ASSERT(static_cast<size_t>(lookup_index) < | 7418 ASSERT(static_cast<size_t>(lookup_index) < |
| 7665 ARRAY_SIZE(kInlineFunctionGenerators)); | 7419 ARRAY_SIZE(kInlineFunctionGenerators)); |
| 7666 InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index]; | 7420 InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index]; |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7750 HValue* value = Pop(); | 7504 HValue* value = Pop(); |
| 7751 HValue* context = environment()->LookupContext(); | 7505 HValue* context = environment()->LookupContext(); |
| 7752 HInstruction* instr = new(zone()) HTypeof(context, value); | 7506 HInstruction* instr = new(zone()) HTypeof(context, value); |
| 7753 return ast_context()->ReturnInstruction(instr, expr->id()); | 7507 return ast_context()->ReturnInstruction(instr, expr->id()); |
| 7754 } | 7508 } |
| 7755 | 7509 |
| 7756 | 7510 |
| 7757 void HOptimizedGraphBuilder::VisitSub(UnaryOperation* expr) { | 7511 void HOptimizedGraphBuilder::VisitSub(UnaryOperation* expr) { |
| 7758 CHECK_ALIVE(VisitForValue(expr->expression())); | 7512 CHECK_ALIVE(VisitForValue(expr->expression())); |
| 7759 HValue* value = Pop(); | 7513 HValue* value = Pop(); |
| 7760 Handle<Type> operand_type = expr->expression()->lower_type(); | 7514 Handle<Type> operand_type = expr->expression()->bounds().lower; |
| 7761 HInstruction* instr = BuildUnaryMathOp(value, operand_type, Token::SUB); | 7515 HInstruction* instr = BuildUnaryMathOp(value, operand_type, Token::SUB); |
| 7762 return ast_context()->ReturnInstruction(instr, expr->id()); | 7516 return ast_context()->ReturnInstruction(instr, expr->id()); |
| 7763 } | 7517 } |
| 7764 | 7518 |
| 7765 | 7519 |
| 7766 void HOptimizedGraphBuilder::VisitBitNot(UnaryOperation* expr) { | 7520 void HOptimizedGraphBuilder::VisitBitNot(UnaryOperation* expr) { |
| 7767 CHECK_ALIVE(VisitForValue(expr->expression())); | 7521 CHECK_ALIVE(VisitForValue(expr->expression())); |
| 7768 HValue* value = Pop(); | 7522 HValue* value = Pop(); |
| 7769 Handle<Type> operand_type = expr->expression()->lower_type(); | 7523 Handle<Type> operand_type = expr->expression()->bounds().lower; |
| 7770 HInstruction* instr = BuildUnaryMathOp(value, operand_type, Token::BIT_NOT); | 7524 HInstruction* instr = BuildUnaryMathOp(value, operand_type, Token::BIT_NOT); |
| 7771 return ast_context()->ReturnInstruction(instr, expr->id()); | 7525 return ast_context()->ReturnInstruction(instr, expr->id()); |
| 7772 } | 7526 } |
| 7773 | 7527 |
| 7774 | 7528 |
| 7775 void HOptimizedGraphBuilder::VisitNot(UnaryOperation* expr) { | 7529 void HOptimizedGraphBuilder::VisitNot(UnaryOperation* expr) { |
| 7776 if (ast_context()->IsTest()) { | 7530 if (ast_context()->IsTest()) { |
| 7777 TestContext* context = TestContext::cast(ast_context()); | 7531 TestContext* context = TestContext::cast(ast_context()); |
| 7778 VisitForControl(expr->expression(), | 7532 VisitForControl(expr->expression(), |
| 7779 context->if_false(), | 7533 context->if_false(), |
| (...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8095 } | 7849 } |
| 8096 return true; | 7850 return true; |
| 8097 } | 7851 } |
| 8098 | 7852 |
| 8099 | 7853 |
| 8100 HInstruction* HOptimizedGraphBuilder::BuildBinaryOperation( | 7854 HInstruction* HOptimizedGraphBuilder::BuildBinaryOperation( |
| 8101 BinaryOperation* expr, | 7855 BinaryOperation* expr, |
| 8102 HValue* left, | 7856 HValue* left, |
| 8103 HValue* right) { | 7857 HValue* right) { |
| 8104 HValue* context = environment()->LookupContext(); | 7858 HValue* context = environment()->LookupContext(); |
| 8105 Handle<Type> left_type = expr->left()->lower_type(); | 7859 Handle<Type> left_type = expr->left()->bounds().lower; |
| 8106 Handle<Type> right_type = expr->right()->lower_type(); | 7860 Handle<Type> right_type = expr->right()->bounds().lower; |
| 8107 Handle<Type> result_type = expr->lower_type(); | 7861 Handle<Type> result_type = expr->bounds().lower; |
| 8108 Maybe<int> fixed_right_arg = expr->fixed_right_arg(); | 7862 Maybe<int> fixed_right_arg = expr->fixed_right_arg(); |
| 8109 Representation left_rep = Representation::FromType(left_type); | 7863 Representation left_rep = Representation::FromType(left_type); |
| 8110 Representation right_rep = Representation::FromType(right_type); | 7864 Representation right_rep = Representation::FromType(right_type); |
| 8111 Representation result_rep = Representation::FromType(result_type); | 7865 Representation result_rep = Representation::FromType(result_type); |
| 8112 | 7866 |
| 8113 if (left_type->Is(Type::None())) { | 7867 if (left_type->Is(Type::None())) { |
| 8114 AddSoftDeoptimize(); | 7868 AddSoftDeoptimize(); |
| 8115 // TODO(rossberg): we should be able to get rid of non-continuous defaults. | 7869 // TODO(rossberg): we should be able to get rid of non-continuous defaults. |
| 8116 left_type = handle(Type::Any(), isolate()); | 7870 left_type = handle(Type::Any(), isolate()); |
| 8117 } | 7871 } |
| (...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8419 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 8173 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 8420 HValue* value = Pop(); | 8174 HValue* value = Pop(); |
| 8421 Literal* literal = expr->right()->AsLiteral(); | 8175 Literal* literal = expr->right()->AsLiteral(); |
| 8422 Handle<String> rhs = Handle<String>::cast(literal->value()); | 8176 Handle<String> rhs = Handle<String>::cast(literal->value()); |
| 8423 HClassOfTestAndBranch* instr = | 8177 HClassOfTestAndBranch* instr = |
| 8424 new(zone()) HClassOfTestAndBranch(value, rhs); | 8178 new(zone()) HClassOfTestAndBranch(value, rhs); |
| 8425 instr->set_position(expr->position()); | 8179 instr->set_position(expr->position()); |
| 8426 return ast_context()->ReturnControl(instr, expr->id()); | 8180 return ast_context()->ReturnControl(instr, expr->id()); |
| 8427 } | 8181 } |
| 8428 | 8182 |
| 8429 Handle<Type> left_type = expr->left()->lower_type(); | 8183 Handle<Type> left_type = expr->left()->bounds().lower; |
| 8430 Handle<Type> right_type = expr->right()->lower_type(); | 8184 Handle<Type> right_type = expr->right()->bounds().lower; |
| 8431 Handle<Type> combined_type = expr->combined_type(); | 8185 Handle<Type> combined_type = expr->combined_type(); |
| 8432 Representation combined_rep = Representation::FromType(combined_type); | 8186 Representation combined_rep = Representation::FromType(combined_type); |
| 8433 Representation left_rep = Representation::FromType(left_type); | 8187 Representation left_rep = Representation::FromType(left_type); |
| 8434 Representation right_rep = Representation::FromType(right_type); | 8188 Representation right_rep = Representation::FromType(right_type); |
| 8435 | 8189 |
| 8436 CHECK_ALIVE(VisitForValue(expr->left())); | 8190 CHECK_ALIVE(VisitForValue(expr->left())); |
| 8437 CHECK_ALIVE(VisitForValue(expr->right())); | 8191 CHECK_ALIVE(VisitForValue(expr->right())); |
| 8438 | 8192 |
| 8439 HValue* context = environment()->LookupContext(); | 8193 HValue* context = environment()->LookupContext(); |
| 8440 HValue* right = Pop(); | 8194 HValue* right = Pop(); |
| (...skipping 1801 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10242 if (ShouldProduceTraceOutput()) { | 9996 if (ShouldProduceTraceOutput()) { |
| 10243 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 9997 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
| 10244 } | 9998 } |
| 10245 | 9999 |
| 10246 #ifdef DEBUG | 10000 #ifdef DEBUG |
| 10247 graph_->Verify(false); // No full verify. | 10001 graph_->Verify(false); // No full verify. |
| 10248 #endif | 10002 #endif |
| 10249 } | 10003 } |
| 10250 | 10004 |
| 10251 } } // namespace v8::internal | 10005 } } // namespace v8::internal |
| OLD | NEW |