| 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 16 matching lines...) Expand all Loading... |
| 27 | 27 |
| 28 #include "hydrogen.h" | 28 #include "hydrogen.h" |
| 29 | 29 |
| 30 #include "codegen.h" | 30 #include "codegen.h" |
| 31 #include "data-flow.h" | 31 #include "data-flow.h" |
| 32 #include "full-codegen.h" | 32 #include "full-codegen.h" |
| 33 #include "hashmap.h" | 33 #include "hashmap.h" |
| 34 #include "lithium-allocator.h" | 34 #include "lithium-allocator.h" |
| 35 #include "parser.h" | 35 #include "parser.h" |
| 36 #include "scopes.h" | 36 #include "scopes.h" |
| 37 #include "stub-cache.h" |
| 37 | 38 |
| 38 #if V8_TARGET_ARCH_IA32 | 39 #if V8_TARGET_ARCH_IA32 |
| 39 #include "ia32/lithium-codegen-ia32.h" | 40 #include "ia32/lithium-codegen-ia32.h" |
| 40 #elif V8_TARGET_ARCH_X64 | 41 #elif V8_TARGET_ARCH_X64 |
| 41 #include "x64/lithium-codegen-x64.h" | 42 #include "x64/lithium-codegen-x64.h" |
| 42 #elif V8_TARGET_ARCH_ARM | 43 #elif V8_TARGET_ARCH_ARM |
| 43 #include "arm/lithium-codegen-arm.h" | 44 #include "arm/lithium-codegen-arm.h" |
| 44 #else | 45 #else |
| 45 #error Unsupported target architecture. | 46 #error Unsupported target architecture. |
| 46 #endif | 47 #endif |
| (...skipping 450 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 497 } | 498 } |
| 498 | 499 |
| 499 | 500 |
| 500 HConstant* HGraph::GetConstantFalse() { | 501 HConstant* HGraph::GetConstantFalse() { |
| 501 return GetConstant(&constant_false_, HEAP->false_value()); | 502 return GetConstant(&constant_false_, HEAP->false_value()); |
| 502 } | 503 } |
| 503 | 504 |
| 504 | 505 |
| 505 void HSubgraph::AppendOptional(HSubgraph* graph, | 506 void HSubgraph::AppendOptional(HSubgraph* graph, |
| 506 bool on_true_branch, | 507 bool on_true_branch, |
| 507 HValue* boolean_value) { | 508 HValue* value) { |
| 508 ASSERT(HasExit() && graph->HasExit()); | 509 ASSERT(HasExit() && graph->HasExit()); |
| 509 HBasicBlock* other_block = graph_->CreateBasicBlock(); | 510 HBasicBlock* other_block = graph_->CreateBasicBlock(); |
| 510 HBasicBlock* join_block = graph_->CreateBasicBlock(); | 511 HBasicBlock* join_block = graph_->CreateBasicBlock(); |
| 511 | 512 |
| 512 HBasicBlock* true_branch = other_block; | 513 HTest* test = on_true_branch |
| 513 HBasicBlock* false_branch = graph->entry_block(); | 514 ? new HTest(value, graph->entry_block(), other_block) |
| 514 if (on_true_branch) { | 515 : new HTest(value, other_block, graph->entry_block()); |
| 515 true_branch = graph->entry_block(); | 516 exit_block_->Finish(test); |
| 516 false_branch = other_block; | |
| 517 } | |
| 518 | |
| 519 exit_block_->Finish(new HBranch(true_branch, false_branch, boolean_value)); | |
| 520 other_block->Goto(join_block); | 517 other_block->Goto(join_block); |
| 521 graph->exit_block()->Goto(join_block); | 518 graph->exit_block()->Goto(join_block); |
| 522 exit_block_ = join_block; | 519 exit_block_ = join_block; |
| 523 } | 520 } |
| 524 | 521 |
| 525 | 522 |
| 526 void HSubgraph::AppendJoin(HSubgraph* then_graph, | 523 void HSubgraph::AppendJoin(HSubgraph* then_graph, |
| 527 HSubgraph* else_graph, | 524 HSubgraph* else_graph, |
| 528 AstNode* node) { | 525 AstNode* node) { |
| 529 if (then_graph->HasExit() && else_graph->HasExit()) { | 526 if (then_graph->HasExit() && else_graph->HasExit()) { |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 680 next_block_id_(0), | 677 next_block_id_(0), |
| 681 info_(info), | 678 info_(info), |
| 682 blocks_(8), | 679 blocks_(8), |
| 683 values_(16), | 680 values_(16), |
| 684 phi_list_(NULL) { | 681 phi_list_(NULL) { |
| 685 start_environment_ = new HEnvironment(NULL, info->scope(), info->closure()); | 682 start_environment_ = new HEnvironment(NULL, info->scope(), info->closure()); |
| 686 start_environment_->set_ast_id(info->function()->id()); | 683 start_environment_->set_ast_id(info->function()->id()); |
| 687 } | 684 } |
| 688 | 685 |
| 689 | 686 |
| 687 bool HGraph::AllowCodeMotion() const { |
| 688 return info()->shared_info()->opt_count() + 1 < Compiler::kDefaultMaxOptCount; |
| 689 } |
| 690 |
| 691 |
| 690 Handle<Code> HGraph::Compile() { | 692 Handle<Code> HGraph::Compile() { |
| 691 int values = GetMaximumValueID(); | 693 int values = GetMaximumValueID(); |
| 692 if (values > LAllocator::max_initial_value_ids()) { | 694 if (values > LAllocator::max_initial_value_ids()) { |
| 693 if (FLAG_trace_bailout) PrintF("Function is too big\n"); | 695 if (FLAG_trace_bailout) PrintF("Function is too big\n"); |
| 694 return Handle<Code>::null(); | 696 return Handle<Code>::null(); |
| 695 } | 697 } |
| 696 | 698 |
| 697 LAllocator allocator(values, this); | 699 LAllocator allocator(values, this); |
| 698 LChunkBuilder builder(this, &allocator); | 700 LChunkBuilder builder(this, &allocator); |
| 699 LChunk* chunk = builder.Build(); | 701 LChunk* chunk = builder.Build(); |
| (...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 922 | 924 |
| 923 class HRangeAnalysis BASE_EMBEDDED { | 925 class HRangeAnalysis BASE_EMBEDDED { |
| 924 public: | 926 public: |
| 925 explicit HRangeAnalysis(HGraph* graph) : graph_(graph), changed_ranges_(16) {} | 927 explicit HRangeAnalysis(HGraph* graph) : graph_(graph), changed_ranges_(16) {} |
| 926 | 928 |
| 927 void Analyze(); | 929 void Analyze(); |
| 928 | 930 |
| 929 private: | 931 private: |
| 930 void TraceRange(const char* msg, ...); | 932 void TraceRange(const char* msg, ...); |
| 931 void Analyze(HBasicBlock* block); | 933 void Analyze(HBasicBlock* block); |
| 932 void InferControlFlowRange(HBranch* branch, HBasicBlock* dest); | 934 void InferControlFlowRange(HTest* test, HBasicBlock* dest); |
| 933 void InferControlFlowRange(Token::Value op, HValue* value, HValue* other); | 935 void InferControlFlowRange(Token::Value op, HValue* value, HValue* other); |
| 934 void InferPhiRange(HPhi* phi); | 936 void InferPhiRange(HPhi* phi); |
| 935 void InferRange(HValue* value); | 937 void InferRange(HValue* value); |
| 936 void RollBackTo(int index); | 938 void RollBackTo(int index); |
| 937 void AddRange(HValue* value, Range* range); | 939 void AddRange(HValue* value, Range* range); |
| 938 | 940 |
| 939 HGraph* graph_; | 941 HGraph* graph_; |
| 940 ZoneList<HValue*> changed_ranges_; | 942 ZoneList<HValue*> changed_ranges_; |
| 941 }; | 943 }; |
| 942 | 944 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 958 | 960 |
| 959 | 961 |
| 960 void HRangeAnalysis::Analyze(HBasicBlock* block) { | 962 void HRangeAnalysis::Analyze(HBasicBlock* block) { |
| 961 TraceRange("Analyzing block B%d\n", block->block_id()); | 963 TraceRange("Analyzing block B%d\n", block->block_id()); |
| 962 | 964 |
| 963 int last_changed_range = changed_ranges_.length() - 1; | 965 int last_changed_range = changed_ranges_.length() - 1; |
| 964 | 966 |
| 965 // Infer range based on control flow. | 967 // Infer range based on control flow. |
| 966 if (block->predecessors()->length() == 1) { | 968 if (block->predecessors()->length() == 1) { |
| 967 HBasicBlock* pred = block->predecessors()->first(); | 969 HBasicBlock* pred = block->predecessors()->first(); |
| 968 if (pred->end()->IsBranch()) { | 970 if (pred->end()->IsTest()) { |
| 969 InferControlFlowRange(HBranch::cast(pred->end()), block); | 971 InferControlFlowRange(HTest::cast(pred->end()), block); |
| 970 } | 972 } |
| 971 } | 973 } |
| 972 | 974 |
| 973 // Process phi instructions. | 975 // Process phi instructions. |
| 974 for (int i = 0; i < block->phis()->length(); ++i) { | 976 for (int i = 0; i < block->phis()->length(); ++i) { |
| 975 HPhi* phi = block->phis()->at(i); | 977 HPhi* phi = block->phis()->at(i); |
| 976 InferPhiRange(phi); | 978 InferPhiRange(phi); |
| 977 } | 979 } |
| 978 | 980 |
| 979 // Go through all instructions of the current block. | 981 // Go through all instructions of the current block. |
| 980 HInstruction* instr = block->first(); | 982 HInstruction* instr = block->first(); |
| 981 while (instr != block->end()) { | 983 while (instr != block->end()) { |
| 982 InferRange(instr); | 984 InferRange(instr); |
| 983 instr = instr->next(); | 985 instr = instr->next(); |
| 984 } | 986 } |
| 985 | 987 |
| 986 // Continue analysis in all dominated blocks. | 988 // Continue analysis in all dominated blocks. |
| 987 for (int i = 0; i < block->dominated_blocks()->length(); ++i) { | 989 for (int i = 0; i < block->dominated_blocks()->length(); ++i) { |
| 988 Analyze(block->dominated_blocks()->at(i)); | 990 Analyze(block->dominated_blocks()->at(i)); |
| 989 } | 991 } |
| 990 | 992 |
| 991 RollBackTo(last_changed_range); | 993 RollBackTo(last_changed_range); |
| 992 } | 994 } |
| 993 | 995 |
| 994 | 996 |
| 995 void HRangeAnalysis::InferControlFlowRange(HBranch* branch, HBasicBlock* dest) { | 997 void HRangeAnalysis::InferControlFlowRange(HTest* test, HBasicBlock* dest) { |
| 996 ASSERT(branch->FirstSuccessor() == dest || branch->SecondSuccessor() == dest); | 998 ASSERT((test->FirstSuccessor() == dest) == (test->SecondSuccessor() != dest)); |
| 997 ASSERT(branch->FirstSuccessor() != dest || branch->SecondSuccessor() != dest); | 999 if (test->value()->IsCompare()) { |
| 998 | 1000 HCompare* compare = HCompare::cast(test->value()); |
| 999 if (branch->value()->IsCompare()) { | |
| 1000 HCompare* compare = HCompare::cast(branch->value()); | |
| 1001 Token::Value op = compare->token(); | 1001 Token::Value op = compare->token(); |
| 1002 if (branch->SecondSuccessor() == dest) { | 1002 if (test->SecondSuccessor() == dest) { |
| 1003 op = Token::NegateCompareOp(op); | 1003 op = Token::NegateCompareOp(op); |
| 1004 } | 1004 } |
| 1005 Token::Value inverted_op = Token::InvertCompareOp(op); | 1005 Token::Value inverted_op = Token::InvertCompareOp(op); |
| 1006 InferControlFlowRange(op, compare->left(), compare->right()); | 1006 InferControlFlowRange(op, compare->left(), compare->right()); |
| 1007 InferControlFlowRange(inverted_op, compare->right(), compare->left()); | 1007 InferControlFlowRange(inverted_op, compare->right(), compare->left()); |
| 1008 } | 1008 } |
| 1009 } | 1009 } |
| 1010 | 1010 |
| 1011 | 1011 |
| 1012 // We know that value [op] other. Use this information to update the range on | 1012 // We know that value [op] other. Use this information to update the range on |
| (...skipping 426 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1439 TraceGVN("Found loop invariant instruction %d\n", instr->id()); | 1439 TraceGVN("Found loop invariant instruction %d\n", instr->id()); |
| 1440 // Move the instruction out of the loop. | 1440 // Move the instruction out of the loop. |
| 1441 instr->Unlink(); | 1441 instr->Unlink(); |
| 1442 instr->InsertBefore(pre_header->end()); | 1442 instr->InsertBefore(pre_header->end()); |
| 1443 } | 1443 } |
| 1444 } | 1444 } |
| 1445 instr = next; | 1445 instr = next; |
| 1446 } | 1446 } |
| 1447 } | 1447 } |
| 1448 | 1448 |
| 1449 // Only move instructions that postdominate the loop header (i.e. are | 1449 |
| 1450 // always executed inside the loop). This is to avoid unnecessary | |
| 1451 // deoptimizations assuming the loop is executed at least once. | |
| 1452 // TODO(fschneider): Better type feedback should give us information | |
| 1453 // about code that was never executed. | |
| 1454 bool HGlobalValueNumberer::ShouldMove(HInstruction* instr, | 1450 bool HGlobalValueNumberer::ShouldMove(HInstruction* instr, |
| 1455 HBasicBlock* loop_header) { | 1451 HBasicBlock* loop_header) { |
| 1456 if (!instr->IsChange() && | 1452 // If we've disabled code motion, don't move any instructions. |
| 1457 FLAG_aggressive_loop_invariant_motion) return true; | 1453 if (!graph_->AllowCodeMotion()) return false; |
| 1454 |
| 1455 // If --aggressive-loop-invariant-motion, move everything except change |
| 1456 // instructions. |
| 1457 if (FLAG_aggressive_loop_invariant_motion && !instr->IsChange()) { |
| 1458 return true; |
| 1459 } |
| 1460 |
| 1461 // Otherwise only move instructions that postdominate the loop header |
| 1462 // (i.e. are always executed inside the loop). This is to avoid |
| 1463 // unnecessary deoptimizations assuming the loop is executed at least |
| 1464 // once. TODO(fschneider): Better type feedback should give us |
| 1465 // information about code that was never executed. |
| 1458 HBasicBlock* block = instr->block(); | 1466 HBasicBlock* block = instr->block(); |
| 1459 bool result = true; | 1467 bool result = true; |
| 1460 if (block != loop_header) { | 1468 if (block != loop_header) { |
| 1461 for (int i = 1; i < loop_header->predecessors()->length(); ++i) { | 1469 for (int i = 1; i < loop_header->predecessors()->length(); ++i) { |
| 1462 bool found = false; | 1470 bool found = false; |
| 1463 HBasicBlock* pred = loop_header->predecessors()->at(i); | 1471 HBasicBlock* pred = loop_header->predecessors()->at(i); |
| 1464 while (pred != loop_header) { | 1472 while (pred != loop_header) { |
| 1465 if (pred == block) found = true; | 1473 if (pred == block) found = true; |
| 1466 pred = pred->dominator(); | 1474 pred = pred->dominator(); |
| 1467 } | 1475 } |
| (...skipping 583 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2051 | 2059 |
| 2052 | 2060 |
| 2053 void TestContext::BuildBranch(HValue* value) { | 2061 void TestContext::BuildBranch(HValue* value) { |
| 2054 // We expect the graph to be in edge-split form: there is no edge that | 2062 // We expect the graph to be in edge-split form: there is no edge that |
| 2055 // connects a branch node to a join node. We conservatively ensure that | 2063 // connects a branch node to a join node. We conservatively ensure that |
| 2056 // property by always adding an empty block on the outgoing edges of this | 2064 // property by always adding an empty block on the outgoing edges of this |
| 2057 // branch. | 2065 // branch. |
| 2058 HGraphBuilder* builder = owner(); | 2066 HGraphBuilder* builder = owner(); |
| 2059 HBasicBlock* empty_true = builder->graph()->CreateBasicBlock(); | 2067 HBasicBlock* empty_true = builder->graph()->CreateBasicBlock(); |
| 2060 HBasicBlock* empty_false = builder->graph()->CreateBasicBlock(); | 2068 HBasicBlock* empty_false = builder->graph()->CreateBasicBlock(); |
| 2061 HBranch* branch = new HBranch(empty_true, empty_false, value); | 2069 HTest* test = new HTest(value, empty_true, empty_false); |
| 2062 builder->CurrentBlock()->Finish(branch); | 2070 builder->CurrentBlock()->Finish(test); |
| 2063 | 2071 |
| 2064 HValue* const no_return_value = NULL; | 2072 HValue* const no_return_value = NULL; |
| 2065 HBasicBlock* true_target = if_true(); | 2073 HBasicBlock* true_target = if_true(); |
| 2066 if (true_target->IsInlineReturnTarget()) { | 2074 if (true_target->IsInlineReturnTarget()) { |
| 2067 empty_true->AddLeaveInlined(no_return_value, true_target); | 2075 empty_true->AddLeaveInlined(no_return_value, true_target); |
| 2068 } else { | 2076 } else { |
| 2069 empty_true->Goto(true_target); | 2077 empty_true->Goto(true_target); |
| 2070 } | 2078 } |
| 2071 | 2079 |
| 2072 HBasicBlock* false_target = if_false(); | 2080 HBasicBlock* false_target = if_false(); |
| (...skipping 507 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2580 CaseClause* clause = clauses->at(i); | 2588 CaseClause* clause = clauses->at(i); |
| 2581 if (clause->is_default()) continue; | 2589 if (clause->is_default()) continue; |
| 2582 | 2590 |
| 2583 // Finish the previous graph by connecting it to the current. | 2591 // Finish the previous graph by connecting it to the current. |
| 2584 HSubgraph* subgraph = compare_graphs.at(i); | 2592 HSubgraph* subgraph = compare_graphs.at(i); |
| 2585 if (prev_compare_inst == NULL) { | 2593 if (prev_compare_inst == NULL) { |
| 2586 ASSERT(prev_graph == current_subgraph_); | 2594 ASSERT(prev_graph == current_subgraph_); |
| 2587 prev_graph->exit_block()->Finish(new HGoto(subgraph->entry_block())); | 2595 prev_graph->exit_block()->Finish(new HGoto(subgraph->entry_block())); |
| 2588 } else { | 2596 } else { |
| 2589 HBasicBlock* empty = graph()->CreateBasicBlock(); | 2597 HBasicBlock* empty = graph()->CreateBasicBlock(); |
| 2590 prev_graph->exit_block()->Finish(new HBranch(empty, | 2598 prev_graph->exit_block()->Finish(new HTest(prev_compare_inst, |
| 2591 subgraph->entry_block(), | 2599 empty, |
| 2592 prev_compare_inst)); | 2600 subgraph->entry_block())); |
| 2593 } | 2601 } |
| 2594 | 2602 |
| 2595 // Build instructions for current subgraph. | 2603 // Build instructions for current subgraph. |
| 2596 ASSERT(clause->IsSmiCompare()); | 2604 ASSERT(clause->IsSmiCompare()); |
| 2597 prev_compare_inst = BuildSwitchCompare(subgraph, switch_value, clause); | 2605 prev_compare_inst = BuildSwitchCompare(subgraph, switch_value, clause); |
| 2598 if (HasStackOverflow()) return; | 2606 if (HasStackOverflow()) return; |
| 2599 | 2607 |
| 2600 prev_graph = subgraph; | 2608 prev_graph = subgraph; |
| 2601 } | 2609 } |
| 2602 | 2610 |
| 2603 // Finish last comparison if there was at least one comparison. | 2611 // Finish last comparison if there was at least one comparison. |
| 2604 // last_false_block is the (empty) false-block of the last comparison. If | 2612 // last_false_block is the (empty) false-block of the last comparison. If |
| 2605 // there are no comparisons at all (a single default clause), it is just | 2613 // there are no comparisons at all (a single default clause), it is just |
| 2606 // the last block of the current subgraph. | 2614 // the last block of the current subgraph. |
| 2607 HBasicBlock* last_false_block = current_subgraph_->exit_block(); | 2615 HBasicBlock* last_false_block = current_subgraph_->exit_block(); |
| 2608 if (prev_graph != current_subgraph_) { | 2616 if (prev_graph != current_subgraph_) { |
| 2609 last_false_block = graph()->CreateBasicBlock(); | 2617 last_false_block = graph()->CreateBasicBlock(); |
| 2610 HBasicBlock* empty = graph()->CreateBasicBlock(); | 2618 HBasicBlock* empty = graph()->CreateBasicBlock(); |
| 2611 prev_graph->exit_block()->Finish(new HBranch(empty, | 2619 prev_graph->exit_block()->Finish(new HTest(prev_compare_inst, |
| 2612 last_false_block, | 2620 empty, |
| 2613 prev_compare_inst)); | 2621 last_false_block)); |
| 2614 } | 2622 } |
| 2615 | 2623 |
| 2616 // If we have a non-smi compare clause, we deoptimize after trying | 2624 // If we have a non-smi compare clause, we deoptimize after trying |
| 2617 // all the previous compares. | 2625 // all the previous compares. |
| 2618 if (num_smi_clauses < num_clauses) { | 2626 if (num_smi_clauses < num_clauses) { |
| 2619 last_false_block->Finish(new HDeoptimize); | 2627 last_false_block->Finish(new HDeoptimize); |
| 2620 } | 2628 } |
| 2621 | 2629 |
| 2622 // Build statement blocks, connect them to their comparison block and | 2630 // Build statement blocks, connect them to their comparison block and |
| 2623 // to the previous statement block, if there is a fall-through. | 2631 // to the previous statement block, if there is a fall-through. |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2686 return statement->OsrEntryId() == info()->osr_ast_id(); | 2694 return statement->OsrEntryId() == info()->osr_ast_id(); |
| 2687 } | 2695 } |
| 2688 | 2696 |
| 2689 | 2697 |
| 2690 void HSubgraph::PreProcessOsrEntry(IterationStatement* statement) { | 2698 void HSubgraph::PreProcessOsrEntry(IterationStatement* statement) { |
| 2691 if (!graph()->HasOsrEntryAt(statement)) return; | 2699 if (!graph()->HasOsrEntryAt(statement)) return; |
| 2692 | 2700 |
| 2693 HBasicBlock* non_osr_entry = graph()->CreateBasicBlock(); | 2701 HBasicBlock* non_osr_entry = graph()->CreateBasicBlock(); |
| 2694 HBasicBlock* osr_entry = graph()->CreateBasicBlock(); | 2702 HBasicBlock* osr_entry = graph()->CreateBasicBlock(); |
| 2695 HValue* true_value = graph()->GetConstantTrue(); | 2703 HValue* true_value = graph()->GetConstantTrue(); |
| 2696 HBranch* branch = new HBranch(non_osr_entry, osr_entry, true_value); | 2704 HTest* test = new HTest(true_value, non_osr_entry, osr_entry); |
| 2697 exit_block()->Finish(branch); | 2705 exit_block()->Finish(test); |
| 2698 | 2706 |
| 2699 HBasicBlock* loop_predecessor = graph()->CreateBasicBlock(); | 2707 HBasicBlock* loop_predecessor = graph()->CreateBasicBlock(); |
| 2700 non_osr_entry->Goto(loop_predecessor); | 2708 non_osr_entry->Goto(loop_predecessor); |
| 2701 | 2709 |
| 2702 int osr_entry_id = statement->OsrEntryId(); | 2710 int osr_entry_id = statement->OsrEntryId(); |
| 2703 // We want the correct environment at the OsrEntry instruction. Build | 2711 // We want the correct environment at the OsrEntry instruction. Build |
| 2704 // it explicitly. The expression stack should be empty. | 2712 // it explicitly. The expression stack should be empty. |
| 2705 int count = osr_entry->last_environment()->length(); | 2713 int count = osr_entry->last_environment()->length(); |
| 2706 ASSERT(count == (osr_entry->last_environment()->parameter_count() + | 2714 ASSERT(count == (osr_entry->last_environment()->parameter_count() + |
| 2707 osr_entry->last_environment()->local_count())); | 2715 osr_entry->last_environment()->local_count())); |
| (...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2933 | 2941 |
| 2934 void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { | 2942 void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { |
| 2935 Variable* variable = expr->AsVariable(); | 2943 Variable* variable = expr->AsVariable(); |
| 2936 if (variable == NULL) { | 2944 if (variable == NULL) { |
| 2937 BAILOUT("reference to rewritten variable"); | 2945 BAILOUT("reference to rewritten variable"); |
| 2938 } else if (variable->IsStackAllocated()) { | 2946 } else if (variable->IsStackAllocated()) { |
| 2939 if (environment()->Lookup(variable)->CheckFlag(HValue::kIsArguments)) { | 2947 if (environment()->Lookup(variable)->CheckFlag(HValue::kIsArguments)) { |
| 2940 BAILOUT("unsupported context for arguments object"); | 2948 BAILOUT("unsupported context for arguments object"); |
| 2941 } | 2949 } |
| 2942 ast_context()->ReturnValue(environment()->Lookup(variable)); | 2950 ast_context()->ReturnValue(environment()->Lookup(variable)); |
| 2951 } else if (variable->IsContextSlot()) { |
| 2952 if (variable->mode() == Variable::CONST) { |
| 2953 BAILOUT("reference to const context slot"); |
| 2954 } |
| 2955 Slot* slot = variable->AsSlot(); |
| 2956 CompilationInfo* info = graph()->info(); |
| 2957 int context_chain_length = info->function()->scope()-> |
| 2958 ContextChainLength(slot->var()->scope()); |
| 2959 ASSERT(context_chain_length >= 0); |
| 2960 // TODO(antonm): if slot's value is not modified by closures, instead |
| 2961 // of reading it out of context, we could just embed the value as |
| 2962 // a constant. |
| 2963 HLoadContextSlot* instr = |
| 2964 new HLoadContextSlot(context_chain_length, slot->index()); |
| 2965 ast_context()->ReturnInstruction(instr, expr->id()); |
| 2943 } else if (variable->is_global()) { | 2966 } else if (variable->is_global()) { |
| 2944 LookupResult lookup; | 2967 LookupResult lookup; |
| 2945 LookupGlobalPropertyCell(variable, &lookup, false); | 2968 LookupGlobalPropertyCell(variable, &lookup, false); |
| 2946 CHECK_BAILOUT; | 2969 CHECK_BAILOUT; |
| 2947 | 2970 |
| 2948 Handle<GlobalObject> global(graph()->info()->global_object()); | 2971 Handle<GlobalObject> global(graph()->info()->global_object()); |
| 2949 // TODO(3039103): Handle global property load through an IC call when access | 2972 // TODO(3039103): Handle global property load through an IC call when access |
| 2950 // checks are enabled. | 2973 // checks are enabled. |
| 2951 if (global->IsAccessCheckNeeded()) { | 2974 if (global->IsAccessCheckNeeded()) { |
| 2952 BAILOUT("global object requires access check"); | 2975 BAILOUT("global object requires access check"); |
| 2953 } | 2976 } |
| 2954 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); | 2977 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); |
| 2955 bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); | 2978 bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); |
| 2956 HLoadGlobal* instr = new HLoadGlobal(cell, check_hole); | 2979 HLoadGlobal* instr = new HLoadGlobal(cell, check_hole); |
| 2957 ast_context()->ReturnInstruction(instr, expr->id()); | 2980 ast_context()->ReturnInstruction(instr, expr->id()); |
| 2958 } else { | 2981 } else { |
| 2959 BAILOUT("reference to non-stack-allocated/non-global variable"); | 2982 BAILOUT("reference to a variable which requires dynamic lookup"); |
| 2960 } | 2983 } |
| 2961 } | 2984 } |
| 2962 | 2985 |
| 2963 | 2986 |
| 2964 void HGraphBuilder::VisitLiteral(Literal* expr) { | 2987 void HGraphBuilder::VisitLiteral(Literal* expr) { |
| 2965 HConstant* instr = new HConstant(expr->handle(), Representation::Tagged()); | 2988 HConstant* instr = new HConstant(expr->handle(), Representation::Tagged()); |
| 2966 ast_context()->ReturnInstruction(instr, expr->id()); | 2989 ast_context()->ReturnInstruction(instr, expr->id()); |
| 2967 } | 2990 } |
| 2968 | 2991 |
| 2969 | 2992 |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3074 | 3097 |
| 3075 // Build map compare subgraphs for all but the first map. | 3098 // Build map compare subgraphs for all but the first map. |
| 3076 ZoneList<HSubgraph*> map_compare_subgraphs(maps->length() - 1); | 3099 ZoneList<HSubgraph*> map_compare_subgraphs(maps->length() - 1); |
| 3077 for (int i = maps->length() - 1; i > 0; --i) { | 3100 for (int i = maps->length() - 1; i > 0; --i) { |
| 3078 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3101 HSubgraph* subgraph = CreateBranchSubgraph(environment()); |
| 3079 SubgraphScope scope(this, subgraph); | 3102 SubgraphScope scope(this, subgraph); |
| 3080 HSubgraph* else_subgraph = | 3103 HSubgraph* else_subgraph = |
| 3081 (i == (maps->length() - 1)) | 3104 (i == (maps->length() - 1)) |
| 3082 ? subgraphs->last() | 3105 ? subgraphs->last() |
| 3083 : map_compare_subgraphs.last(); | 3106 : map_compare_subgraphs.last(); |
| 3084 current_subgraph_->exit_block()->Finish( | 3107 HCompareMap* compare = new HCompareMap(receiver, |
| 3085 new HCompareMapAndBranch(receiver, | 3108 maps->at(i), |
| 3086 maps->at(i), | 3109 subgraphs->at(i)->entry_block(), |
| 3087 subgraphs->at(i)->entry_block(), | 3110 else_subgraph->entry_block()); |
| 3088 else_subgraph->entry_block())); | 3111 current_subgraph_->exit_block()->Finish(compare); |
| 3089 map_compare_subgraphs.Add(subgraph); | 3112 map_compare_subgraphs.Add(subgraph); |
| 3090 } | 3113 } |
| 3091 | 3114 |
| 3092 // Generate first map check to end the current block. | 3115 // Generate first map check to end the current block. |
| 3093 AddInstruction(new HCheckNonSmi(receiver)); | 3116 AddInstruction(new HCheckNonSmi(receiver)); |
| 3094 HSubgraph* else_subgraph = | 3117 HSubgraph* else_subgraph = |
| 3095 (maps->length() == 1) ? subgraphs->at(1) : map_compare_subgraphs.last(); | 3118 (maps->length() == 1) ? subgraphs->at(1) : map_compare_subgraphs.last(); |
| 3096 current_subgraph_->exit_block()->Finish( | 3119 HCompareMap* compare = new HCompareMap(receiver, |
| 3097 new HCompareMapAndBranch(receiver, | 3120 Handle<Map>(maps->first()), |
| 3098 Handle<Map>(maps->first()), | 3121 subgraphs->first()->entry_block(), |
| 3099 subgraphs->first()->entry_block(), | 3122 else_subgraph->entry_block()); |
| 3100 else_subgraph->entry_block())); | 3123 current_subgraph_->exit_block()->Finish(compare); |
| 3101 | 3124 |
| 3102 // Join all the call subgraphs in a new basic block and make | 3125 // Join all the call subgraphs in a new basic block and make |
| 3103 // this basic block the current basic block. | 3126 // this basic block the current basic block. |
| 3104 HBasicBlock* join_block = graph_->CreateBasicBlock(); | 3127 HBasicBlock* join_block = graph_->CreateBasicBlock(); |
| 3105 for (int i = 0; i < subgraphs->length(); ++i) { | 3128 for (int i = 0; i < subgraphs->length(); ++i) { |
| 3106 HSubgraph* subgraph = subgraphs->at(i); | 3129 HSubgraph* subgraph = subgraphs->at(i); |
| 3107 if (subgraph->HasExit()) { | 3130 if (subgraph->HasExit()) { |
| 3108 // In an effect context the value of the type switch is not needed. | 3131 // In an effect context the value of the type switch is not needed. |
| 3109 // There is no need to merge it at the join block only to discard it. | 3132 // There is no need to merge it at the join block only to discard it. |
| 3110 HBasicBlock* subgraph_exit = subgraph->exit_block(); | 3133 HBasicBlock* subgraph_exit = subgraph->exit_block(); |
| (...skipping 364 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3475 if (var != NULL) { | 3498 if (var != NULL) { |
| 3476 if (proxy->IsArguments()) BAILOUT("assignment to arguments"); | 3499 if (proxy->IsArguments()) BAILOUT("assignment to arguments"); |
| 3477 | 3500 |
| 3478 // Handle the assignment. | 3501 // Handle the assignment. |
| 3479 if (var->is_global()) { | 3502 if (var->is_global()) { |
| 3480 VISIT_FOR_VALUE(expr->value()); | 3503 VISIT_FOR_VALUE(expr->value()); |
| 3481 HandleGlobalVariableAssignment(var, | 3504 HandleGlobalVariableAssignment(var, |
| 3482 Top(), | 3505 Top(), |
| 3483 expr->position(), | 3506 expr->position(), |
| 3484 expr->AssignmentId()); | 3507 expr->AssignmentId()); |
| 3485 } else { | 3508 } else if (var->IsStackAllocated()) { |
| 3486 // We allow reference to the arguments object only in assignemtns | 3509 // We allow reference to the arguments object only in assignemtns |
| 3487 // to local variables to make sure that the arguments object does | 3510 // to local variables to make sure that the arguments object does |
| 3488 // not escape and is not modified. | 3511 // not escape and is not modified. |
| 3489 VariableProxy* rhs = expr->value()->AsVariableProxy(); | 3512 VariableProxy* rhs = expr->value()->AsVariableProxy(); |
| 3490 if (rhs != NULL && | 3513 if (rhs != NULL && |
| 3491 rhs->var()->IsStackAllocated() && | 3514 rhs->var()->IsStackAllocated() && |
| 3492 environment()->Lookup(rhs->var())->CheckFlag(HValue::kIsArguments)) { | 3515 environment()->Lookup(rhs->var())->CheckFlag(HValue::kIsArguments)) { |
| 3493 Push(environment()->Lookup(rhs->var())); | 3516 Push(environment()->Lookup(rhs->var())); |
| 3494 } else { | 3517 } else { |
| 3495 VISIT_FOR_VALUE(expr->value()); | 3518 VISIT_FOR_VALUE(expr->value()); |
| 3496 } | 3519 } |
| 3497 Bind(proxy->var(), Top()); | 3520 Bind(proxy->var(), Top()); |
| 3521 } else { |
| 3522 BAILOUT("Assigning to no non-stack-allocated/non-global variable"); |
| 3498 } | 3523 } |
| 3499 // Return the value. | 3524 // Return the value. |
| 3500 ast_context()->ReturnValue(Pop()); | 3525 ast_context()->ReturnValue(Pop()); |
| 3501 | 3526 |
| 3502 } else if (prop != NULL) { | 3527 } else if (prop != NULL) { |
| 3503 HandlePropertyAssignment(expr); | 3528 HandlePropertyAssignment(expr); |
| 3504 } else { | 3529 } else { |
| 3505 BAILOUT("unsupported invalid lhs"); | 3530 BAILOUT("unsupported invalid lhs"); |
| 3506 } | 3531 } |
| 3507 } | 3532 } |
| (...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3738 | 3763 |
| 3739 VISIT_FOR_VALUE(expr->obj()); | 3764 VISIT_FOR_VALUE(expr->obj()); |
| 3740 | 3765 |
| 3741 HInstruction* instr = NULL; | 3766 HInstruction* instr = NULL; |
| 3742 if (expr->IsArrayLength()) { | 3767 if (expr->IsArrayLength()) { |
| 3743 HValue* array = Pop(); | 3768 HValue* array = Pop(); |
| 3744 AddInstruction(new HCheckNonSmi(array)); | 3769 AddInstruction(new HCheckNonSmi(array)); |
| 3745 AddInstruction(new HCheckInstanceType(array, JS_ARRAY_TYPE, JS_ARRAY_TYPE)); | 3770 AddInstruction(new HCheckInstanceType(array, JS_ARRAY_TYPE, JS_ARRAY_TYPE)); |
| 3746 instr = new HJSArrayLength(array); | 3771 instr = new HJSArrayLength(array); |
| 3747 | 3772 |
| 3773 } else if (expr->IsStringLength()) { |
| 3774 HValue* string = Pop(); |
| 3775 AddInstruction(new HCheckNonSmi(string)); |
| 3776 AddInstruction(new HCheckInstanceType(string, |
| 3777 FIRST_STRING_TYPE, |
| 3778 LAST_STRING_TYPE)); |
| 3779 instr = new HStringLength(string); |
| 3780 |
| 3748 } else if (expr->IsFunctionPrototype()) { | 3781 } else if (expr->IsFunctionPrototype()) { |
| 3749 HValue* function = Pop(); | 3782 HValue* function = Pop(); |
| 3750 AddInstruction(new HCheckNonSmi(function)); | 3783 AddInstruction(new HCheckNonSmi(function)); |
| 3751 instr = new HLoadFunctionPrototype(function); | 3784 instr = new HLoadFunctionPrototype(function); |
| 3752 | 3785 |
| 3753 } else if (expr->key()->IsPropertyName()) { | 3786 } else if (expr->key()->IsPropertyName()) { |
| 3754 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); | 3787 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); |
| 3755 ZoneMapList* types = expr->GetReceiverTypes(); | 3788 ZoneMapList* types = expr->GetReceiverTypes(); |
| 3756 | 3789 |
| 3757 HValue* obj = Pop(); | 3790 HValue* obj = Pop(); |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3924 | 3957 |
| 3925 // We don't want to add more than a certain number of nodes from inlining. | 3958 // We don't want to add more than a certain number of nodes from inlining. |
| 3926 if (FLAG_limit_inlining && inlined_count_ > kMaxInlinedNodes) { | 3959 if (FLAG_limit_inlining && inlined_count_ > kMaxInlinedNodes) { |
| 3927 if (FLAG_trace_inlining) TraceInline(target, false); | 3960 if (FLAG_trace_inlining) TraceInline(target, false); |
| 3928 return false; | 3961 return false; |
| 3929 } | 3962 } |
| 3930 | 3963 |
| 3931 int count_before = AstNode::Count(); | 3964 int count_before = AstNode::Count(); |
| 3932 | 3965 |
| 3933 // Parse and allocate variables. | 3966 // Parse and allocate variables. |
| 3934 Handle<SharedFunctionInfo> shared(target->shared()); | 3967 CompilationInfo inner_info(target); |
| 3935 CompilationInfo inner_info(shared); | |
| 3936 if (!ParserApi::Parse(&inner_info) || | 3968 if (!ParserApi::Parse(&inner_info) || |
| 3937 !Scope::Analyze(&inner_info)) { | 3969 !Scope::Analyze(&inner_info)) { |
| 3938 return false; | 3970 return false; |
| 3939 } | 3971 } |
| 3940 FunctionLiteral* function = inner_info.function(); | 3972 FunctionLiteral* function = inner_info.function(); |
| 3941 | 3973 |
| 3942 // Count the number of AST nodes added by inlining this call. | 3974 // Count the number of AST nodes added by inlining this call. |
| 3943 int nodes_added = AstNode::Count() - count_before; | 3975 int nodes_added = AstNode::Count() - count_before; |
| 3944 if (FLAG_limit_inlining && nodes_added > kMaxInlinedSize) { | 3976 if (FLAG_limit_inlining && nodes_added > kMaxInlinedSize) { |
| 3945 if (FLAG_trace_inlining) TraceInline(target, false); | 3977 if (FLAG_trace_inlining) TraceInline(target, false); |
| 3946 return false; | 3978 return false; |
| 3947 } | 3979 } |
| 3948 | 3980 |
| 3949 // Check if we can handle all declarations in the inlined functions. | 3981 // Check if we can handle all declarations in the inlined functions. |
| 3950 VisitDeclarations(inner_info.scope()->declarations()); | 3982 VisitDeclarations(inner_info.scope()->declarations()); |
| 3951 if (HasStackOverflow()) { | 3983 if (HasStackOverflow()) { |
| 3952 ClearStackOverflow(); | 3984 ClearStackOverflow(); |
| 3953 return false; | 3985 return false; |
| 3954 } | 3986 } |
| 3955 | 3987 |
| 3956 // Don't inline functions that uses the arguments object or that | 3988 // Don't inline functions that uses the arguments object or that |
| 3957 // have a mismatching number of parameters. | 3989 // have a mismatching number of parameters. |
| 3990 Handle<SharedFunctionInfo> shared(target->shared()); |
| 3958 int arity = expr->arguments()->length(); | 3991 int arity = expr->arguments()->length(); |
| 3959 if (function->scope()->arguments() != NULL || | 3992 if (function->scope()->arguments() != NULL || |
| 3960 arity != target->shared()->formal_parameter_count()) { | 3993 arity != shared->formal_parameter_count()) { |
| 3961 return false; | 3994 return false; |
| 3962 } | 3995 } |
| 3963 | 3996 |
| 3964 // All statements in the body must be inlineable. | 3997 // All statements in the body must be inlineable. |
| 3965 for (int i = 0, count = function->body()->length(); i < count; ++i) { | 3998 for (int i = 0, count = function->body()->length(); i < count; ++i) { |
| 3966 if (!function->body()->at(i)->IsInlineable()) return false; | 3999 if (!function->body()->at(i)->IsInlineable()) return false; |
| 3967 } | 4000 } |
| 3968 | 4001 |
| 3969 // Generate the deoptimization data for the unoptimized version of | 4002 // Generate the deoptimization data for the unoptimized version of |
| 3970 // the target function if we don't already have it. | 4003 // the target function if we don't already have it. |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4042 ASSERT(function_return_ != NULL); | 4075 ASSERT(function_return_ != NULL); |
| 4043 body->exit_block()->AddLeaveInlined(return_value, function_return_); | 4076 body->exit_block()->AddLeaveInlined(return_value, function_return_); |
| 4044 } else { | 4077 } else { |
| 4045 // The graph builder assumes control can reach both branches of a | 4078 // The graph builder assumes control can reach both branches of a |
| 4046 // test, so we materialize the undefined value and test it rather than | 4079 // test, so we materialize the undefined value and test it rather than |
| 4047 // simply jumping to the false target. | 4080 // simply jumping to the false target. |
| 4048 // | 4081 // |
| 4049 // TODO(3168478): refactor to avoid this. | 4082 // TODO(3168478): refactor to avoid this. |
| 4050 HBasicBlock* empty_true = graph()->CreateBasicBlock(); | 4083 HBasicBlock* empty_true = graph()->CreateBasicBlock(); |
| 4051 HBasicBlock* empty_false = graph()->CreateBasicBlock(); | 4084 HBasicBlock* empty_false = graph()->CreateBasicBlock(); |
| 4052 HBranch* branch = | 4085 HTest* test = new HTest(return_value, empty_true, empty_false); |
| 4053 new HBranch(empty_true, empty_false, return_value); | 4086 body->exit_block()->Finish(test); |
| 4054 body->exit_block()->Finish(branch); | |
| 4055 | 4087 |
| 4056 HValue* const no_return_value = NULL; | 4088 HValue* const no_return_value = NULL; |
| 4057 empty_true->AddLeaveInlined(no_return_value, test_context->if_true()); | 4089 empty_true->AddLeaveInlined(no_return_value, test_context->if_true()); |
| 4058 empty_false->AddLeaveInlined(no_return_value, test_context->if_false()); | 4090 empty_false->AddLeaveInlined(no_return_value, test_context->if_false()); |
| 4059 } | 4091 } |
| 4060 body->set_exit_block(NULL); | 4092 body->set_exit_block(NULL); |
| 4061 } | 4093 } |
| 4062 | 4094 |
| 4063 // Record the environment at the inlined function call. | 4095 // Record the environment at the inlined function call. |
| 4064 AddSimulate(expr->ReturnId()); | 4096 AddSimulate(expr->ReturnId()); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4113 void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) { | 4145 void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) { |
| 4114 ASSERT(target->IsInlineReturnTarget()); | 4146 ASSERT(target->IsInlineReturnTarget()); |
| 4115 AddInstruction(new HLeaveInlined); | 4147 AddInstruction(new HLeaveInlined); |
| 4116 HEnvironment* outer = last_environment()->outer(); | 4148 HEnvironment* outer = last_environment()->outer(); |
| 4117 if (return_value != NULL) outer->Push(return_value); | 4149 if (return_value != NULL) outer->Push(return_value); |
| 4118 UpdateEnvironment(outer); | 4150 UpdateEnvironment(outer); |
| 4119 Goto(target); | 4151 Goto(target); |
| 4120 } | 4152 } |
| 4121 | 4153 |
| 4122 | 4154 |
| 4123 bool HGraphBuilder::TryMathFunctionInline(Call* expr) { | 4155 bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr, |
| 4156 HValue* receiver, |
| 4157 Handle<Map> receiver_map, |
| 4158 CheckType check_type) { |
| 4159 ASSERT(check_type != RECEIVER_MAP_CHECK || !receiver_map.is_null()); |
| 4124 // Try to inline calls like Math.* as operations in the calling function. | 4160 // Try to inline calls like Math.* as operations in the calling function. |
| 4125 if (!expr->target()->shared()->IsBuiltinMathFunction()) return false; | 4161 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; |
| 4126 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); | 4162 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); |
| 4127 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 4163 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
| 4128 switch (id) { | 4164 switch (id) { |
| 4165 case kStringCharCodeAt: |
| 4166 if (argument_count == 2 && check_type == STRING_CHECK) { |
| 4167 HValue* index = Pop(); |
| 4168 HValue* string = Pop(); |
| 4169 ASSERT(!expr->holder().is_null()); |
| 4170 AddInstruction(new HCheckPrototypeMaps( |
| 4171 oracle()->GetPrototypeForPrimitiveCheck(STRING_CHECK), |
| 4172 expr->holder())); |
| 4173 HStringCharCodeAt* result = BuildStringCharCodeAt(string, index); |
| 4174 ast_context()->ReturnInstruction(result, expr->id()); |
| 4175 return true; |
| 4176 } |
| 4177 break; |
| 4129 case kMathRound: | 4178 case kMathRound: |
| 4130 case kMathFloor: | 4179 case kMathFloor: |
| 4131 case kMathAbs: | 4180 case kMathAbs: |
| 4132 case kMathSqrt: | 4181 case kMathSqrt: |
| 4133 case kMathLog: | 4182 case kMathLog: |
| 4134 case kMathSin: | 4183 case kMathSin: |
| 4135 case kMathCos: | 4184 case kMathCos: |
| 4136 if (argument_count == 2) { | 4185 if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) { |
| 4186 AddCheckConstantFunction(expr, receiver, receiver_map, true); |
| 4137 HValue* argument = Pop(); | 4187 HValue* argument = Pop(); |
| 4138 Drop(1); // Receiver. | 4188 Drop(1); // Receiver. |
| 4139 HUnaryMathOperation* op = new HUnaryMathOperation(argument, id); | 4189 HUnaryMathOperation* op = new HUnaryMathOperation(argument, id); |
| 4140 op->set_position(expr->position()); | 4190 op->set_position(expr->position()); |
| 4141 ast_context()->ReturnInstruction(op, expr->id()); | 4191 ast_context()->ReturnInstruction(op, expr->id()); |
| 4142 return true; | 4192 return true; |
| 4143 } | 4193 } |
| 4144 break; | 4194 break; |
| 4145 case kMathPow: | 4195 case kMathPow: |
| 4146 if (argument_count == 3) { | 4196 if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) { |
| 4197 AddCheckConstantFunction(expr, receiver, receiver_map, true); |
| 4147 HValue* right = Pop(); | 4198 HValue* right = Pop(); |
| 4148 HValue* left = Pop(); | 4199 HValue* left = Pop(); |
| 4149 Pop(); // Pop receiver. | 4200 Pop(); // Pop receiver. |
| 4150 HInstruction* result = NULL; | 4201 HInstruction* result = NULL; |
| 4151 // Use sqrt() if exponent is 0.5 or -0.5. | 4202 // Use sqrt() if exponent is 0.5 or -0.5. |
| 4152 if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) { | 4203 if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) { |
| 4153 double exponent = HConstant::cast(right)->DoubleValue(); | 4204 double exponent = HConstant::cast(right)->DoubleValue(); |
| 4154 if (exponent == 0.5) { | 4205 if (exponent == 0.5) { |
| 4155 result = new HUnaryMathOperation(left, kMathPowHalf); | 4206 result = new HUnaryMathOperation(left, kMathPowHalf); |
| 4156 ast_context()->ReturnInstruction(result, expr->id()); | |
| 4157 return true; | |
| 4158 } else if (exponent == -0.5) { | 4207 } else if (exponent == -0.5) { |
| 4159 HConstant* double_one = | 4208 HConstant* double_one = |
| 4160 new HConstant(Handle<Object>(Smi::FromInt(1)), | 4209 new HConstant(Handle<Object>(Smi::FromInt(1)), |
| 4161 Representation::Double()); | 4210 Representation::Double()); |
| 4162 AddInstruction(double_one); | 4211 AddInstruction(double_one); |
| 4163 HUnaryMathOperation* square_root = | 4212 HUnaryMathOperation* square_root = |
| 4164 new HUnaryMathOperation(left, kMathPowHalf); | 4213 new HUnaryMathOperation(left, kMathPowHalf); |
| 4165 AddInstruction(square_root); | 4214 AddInstruction(square_root); |
| 4166 // MathPowHalf doesn't have side effects so there's no need for | 4215 // MathPowHalf doesn't have side effects so there's no need for |
| 4167 // an environment simulation here. | 4216 // an environment simulation here. |
| 4168 ASSERT(!square_root->HasSideEffects()); | 4217 ASSERT(!square_root->HasSideEffects()); |
| 4169 result = new HDiv(double_one, square_root); | 4218 result = new HDiv(double_one, square_root); |
| 4170 ast_context()->ReturnInstruction(result, expr->id()); | |
| 4171 return true; | |
| 4172 } else if (exponent == 2.0) { | 4219 } else if (exponent == 2.0) { |
| 4173 result = new HMul(left, left); | 4220 result = new HMul(left, left); |
| 4174 ast_context()->ReturnInstruction(result, expr->id()); | |
| 4175 return true; | |
| 4176 } | 4221 } |
| 4177 } else if (right->IsConstant() && | 4222 } else if (right->IsConstant() && |
| 4178 HConstant::cast(right)->HasInteger32Value() && | 4223 HConstant::cast(right)->HasInteger32Value() && |
| 4179 HConstant::cast(right)->Integer32Value() == 2) { | 4224 HConstant::cast(right)->Integer32Value() == 2) { |
| 4180 result = new HMul(left, left); | 4225 result = new HMul(left, left); |
| 4181 ast_context()->ReturnInstruction(result, expr->id()); | |
| 4182 return true; | |
| 4183 } | 4226 } |
| 4184 | 4227 |
| 4185 result = new HPower(left, right); | 4228 if (result == NULL) { |
| 4229 result = new HPower(left, right); |
| 4230 } |
| 4186 ast_context()->ReturnInstruction(result, expr->id()); | 4231 ast_context()->ReturnInstruction(result, expr->id()); |
| 4187 return true; | 4232 return true; |
| 4188 } | 4233 } |
| 4189 break; | 4234 break; |
| 4190 default: | 4235 default: |
| 4191 // Not yet supported for inlining. | 4236 // Not yet supported for inlining. |
| 4192 break; | 4237 break; |
| 4193 } | 4238 } |
| 4194 return false; | 4239 return false; |
| 4195 } | 4240 } |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4230 expr->GetReceiverTypes()->first(), | 4275 expr->GetReceiverTypes()->first(), |
| 4231 true); | 4276 true); |
| 4232 HInstruction* result = | 4277 HInstruction* result = |
| 4233 new HApplyArguments(function, receiver, length, elements); | 4278 new HApplyArguments(function, receiver, length, elements); |
| 4234 result->set_position(expr->position()); | 4279 result->set_position(expr->position()); |
| 4235 ast_context()->ReturnInstruction(result, expr->id()); | 4280 ast_context()->ReturnInstruction(result, expr->id()); |
| 4236 return true; | 4281 return true; |
| 4237 } | 4282 } |
| 4238 | 4283 |
| 4239 | 4284 |
| 4285 static bool HasCustomCallGenerator(Handle<JSFunction> function) { |
| 4286 SharedFunctionInfo* info = function->shared(); |
| 4287 return info->HasBuiltinFunctionId() && |
| 4288 CallStubCompiler::HasCustomCallGenerator(info->builtin_function_id()); |
| 4289 } |
| 4290 |
| 4291 |
| 4240 void HGraphBuilder::VisitCall(Call* expr) { | 4292 void HGraphBuilder::VisitCall(Call* expr) { |
| 4241 Expression* callee = expr->expression(); | 4293 Expression* callee = expr->expression(); |
| 4242 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 4294 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
| 4243 HCall* call = NULL; | 4295 HCall* call = NULL; |
| 4244 | 4296 |
| 4245 Property* prop = callee->AsProperty(); | 4297 Property* prop = callee->AsProperty(); |
| 4246 if (prop != NULL) { | 4298 if (prop != NULL) { |
| 4247 if (!prop->key()->IsPropertyName()) { | 4299 if (!prop->key()->IsPropertyName()) { |
| 4248 // Keyed function call. | 4300 // Keyed function call. |
| 4249 VisitArgument(prop->obj()); | 4301 VisitArgument(prop->obj()); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 4276 HValue* receiver = VisitArgument(prop->obj()); | 4328 HValue* receiver = VisitArgument(prop->obj()); |
| 4277 CHECK_BAILOUT; | 4329 CHECK_BAILOUT; |
| 4278 VisitArgumentList(expr->arguments()); | 4330 VisitArgumentList(expr->arguments()); |
| 4279 CHECK_BAILOUT; | 4331 CHECK_BAILOUT; |
| 4280 | 4332 |
| 4281 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); | 4333 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); |
| 4282 | 4334 |
| 4283 expr->RecordTypeFeedback(oracle()); | 4335 expr->RecordTypeFeedback(oracle()); |
| 4284 ZoneMapList* types = expr->GetReceiverTypes(); | 4336 ZoneMapList* types = expr->GetReceiverTypes(); |
| 4285 | 4337 |
| 4286 if (expr->IsMonomorphic() && expr->check_type() == RECEIVER_MAP_CHECK) { | 4338 if (expr->IsMonomorphic()) { |
| 4287 AddCheckConstantFunction(expr, receiver, types->first(), true); | 4339 Handle<Map> receiver_map = |
| 4288 | 4340 (types == NULL) ? Handle<Map>::null() : types->first(); |
| 4289 if (TryMathFunctionInline(expr)) { | 4341 if (TryInlineBuiltinFunction(expr, |
| 4342 receiver, |
| 4343 receiver_map, |
| 4344 expr->check_type())) { |
| 4290 return; | 4345 return; |
| 4291 } else if (TryInline(expr)) { | |
| 4292 if (subgraph()->HasExit()) { | |
| 4293 HValue* return_value = Pop(); | |
| 4294 // If we inlined a function in a test context then we need to emit | |
| 4295 // a simulate here to shadow the ones at the end of the | |
| 4296 // predecessor blocks. Those environments contain the return | |
| 4297 // value on top and do not correspond to any actual state of the | |
| 4298 // unoptimized code. | |
| 4299 if (ast_context()->IsEffect()) AddSimulate(expr->id()); | |
| 4300 ast_context()->ReturnValue(return_value); | |
| 4301 } | |
| 4302 return; | |
| 4303 } else { | |
| 4304 // Check for bailout, as the TryInline call in the if condition above | |
| 4305 // might return false due to bailout during hydrogen processing. | |
| 4306 CHECK_BAILOUT; | |
| 4307 call = new HCallConstantFunction(expr->target(), argument_count); | |
| 4308 } | 4346 } |
| 4309 | 4347 |
| 4348 if (HasCustomCallGenerator(expr->target()) || |
| 4349 expr->check_type() != RECEIVER_MAP_CHECK) { |
| 4350 // When the target has a custom call IC generator, use the IC, |
| 4351 // because it is likely to generate better code. Also use the |
| 4352 // IC when a primitive receiver check is required. |
| 4353 call = new HCallNamed(name, argument_count); |
| 4354 } else { |
| 4355 AddCheckConstantFunction(expr, receiver, receiver_map, true); |
| 4356 |
| 4357 if (TryInline(expr)) { |
| 4358 if (subgraph()->HasExit()) { |
| 4359 HValue* return_value = Pop(); |
| 4360 // If we inlined a function in a test context then we need to emit |
| 4361 // a simulate here to shadow the ones at the end of the |
| 4362 // predecessor blocks. Those environments contain the return |
| 4363 // value on top and do not correspond to any actual state of the |
| 4364 // unoptimized code. |
| 4365 if (ast_context()->IsEffect()) AddSimulate(expr->id()); |
| 4366 ast_context()->ReturnValue(return_value); |
| 4367 } |
| 4368 return; |
| 4369 } else { |
| 4370 // Check for bailout, as the TryInline call in the if condition above |
| 4371 // might return false due to bailout during hydrogen processing. |
| 4372 CHECK_BAILOUT; |
| 4373 call = new HCallConstantFunction(expr->target(), argument_count); |
| 4374 } |
| 4375 } |
| 4310 } else if (types != NULL && types->length() > 1) { | 4376 } else if (types != NULL && types->length() > 1) { |
| 4311 ASSERT(expr->check_type() == RECEIVER_MAP_CHECK); | 4377 ASSERT(expr->check_type() == RECEIVER_MAP_CHECK); |
| 4312 HandlePolymorphicCallNamed(expr, receiver, types, name); | 4378 HandlePolymorphicCallNamed(expr, receiver, types, name); |
| 4313 return; | 4379 return; |
| 4314 | 4380 |
| 4315 } else { | 4381 } else { |
| 4316 call = new HCallNamed(name, argument_count); | 4382 call = new HCallNamed(name, argument_count); |
| 4317 } | 4383 } |
| 4318 | 4384 |
| 4319 } else { | 4385 } else { |
| (...skipping 367 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4687 | 4753 |
| 4688 ast_context()->ReturnValue(expr->is_postfix() ? before : after); | 4754 ast_context()->ReturnValue(expr->is_postfix() ? before : after); |
| 4689 } | 4755 } |
| 4690 | 4756 |
| 4691 } else { | 4757 } else { |
| 4692 BAILOUT("invalid lhs in count operation"); | 4758 BAILOUT("invalid lhs in count operation"); |
| 4693 } | 4759 } |
| 4694 } | 4760 } |
| 4695 | 4761 |
| 4696 | 4762 |
| 4763 HStringCharCodeAt* HGraphBuilder::BuildStringCharCodeAt(HValue* string, |
| 4764 HValue* index) { |
| 4765 AddInstruction(new HCheckNonSmi(string)); |
| 4766 AddInstruction(new HCheckInstanceType( |
| 4767 string, FIRST_STRING_TYPE, LAST_STRING_TYPE)); |
| 4768 HStringLength* length = new HStringLength(string); |
| 4769 AddInstruction(length); |
| 4770 AddInstruction(new HBoundsCheck(index, length)); |
| 4771 return new HStringCharCodeAt(string, index); |
| 4772 } |
| 4773 |
| 4774 |
| 4697 HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr, | 4775 HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr, |
| 4698 HValue* left, | 4776 HValue* left, |
| 4699 HValue* right) { | 4777 HValue* right) { |
| 4700 HInstruction* instr = NULL; | 4778 HInstruction* instr = NULL; |
| 4701 switch (expr->op()) { | 4779 switch (expr->op()) { |
| 4702 case Token::ADD: | 4780 case Token::ADD: |
| 4703 instr = new HAdd(left, right); | 4781 instr = new HAdd(left, right); |
| 4704 break; | 4782 break; |
| 4705 case Token::SUB: | 4783 case Token::SUB: |
| 4706 instr = new HSub(left, right); | 4784 instr = new HSub(left, right); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4740 // for a smi operation. If one of the operands is a constant string | 4818 // for a smi operation. If one of the operands is a constant string |
| 4741 // do not generate code assuming it is a smi operation. | 4819 // do not generate code assuming it is a smi operation. |
| 4742 if (info.IsSmi() && | 4820 if (info.IsSmi() && |
| 4743 ((left->IsConstant() && HConstant::cast(left)->HasStringValue()) || | 4821 ((left->IsConstant() && HConstant::cast(left)->HasStringValue()) || |
| 4744 (right->IsConstant() && HConstant::cast(right)->HasStringValue()))) { | 4822 (right->IsConstant() && HConstant::cast(right)->HasStringValue()))) { |
| 4745 return instr; | 4823 return instr; |
| 4746 } | 4824 } |
| 4747 if (FLAG_trace_representation) { | 4825 if (FLAG_trace_representation) { |
| 4748 PrintF("Info: %s/%s\n", info.ToString(), ToRepresentation(info).Mnemonic()); | 4826 PrintF("Info: %s/%s\n", info.ToString(), ToRepresentation(info).Mnemonic()); |
| 4749 } | 4827 } |
| 4750 AssumeRepresentation(instr, ToRepresentation(info)); | 4828 Representation rep = ToRepresentation(info); |
| 4829 // We only generate either int32 or generic tagged bitwise operations. |
| 4830 if (instr->IsBitwiseBinaryOperation() && rep.IsDouble()) { |
| 4831 rep = Representation::Integer32(); |
| 4832 } |
| 4833 AssumeRepresentation(instr, rep); |
| 4751 return instr; | 4834 return instr; |
| 4752 } | 4835 } |
| 4753 | 4836 |
| 4754 | 4837 |
| 4755 // Check for the form (%_ClassOf(foo) === 'BarClass'). | 4838 // Check for the form (%_ClassOf(foo) === 'BarClass'). |
| 4756 static bool IsClassOfTest(CompareOperation* expr) { | 4839 static bool IsClassOfTest(CompareOperation* expr) { |
| 4757 if (expr->op() != Token::EQ_STRICT) return false; | 4840 if (expr->op() != Token::EQ_STRICT) return false; |
| 4758 CallRuntime* call = expr->left()->AsCallRuntime(); | 4841 CallRuntime* call = expr->left()->AsCallRuntime(); |
| 4759 if (call == NULL) return false; | 4842 if (call == NULL) return false; |
| 4760 Literal* literal = expr->right()->AsLiteral(); | 4843 Literal* literal = expr->right()->AsLiteral(); |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4821 | 4904 |
| 4822 void HGraphBuilder::AssumeRepresentation(HValue* value, Representation r) { | 4905 void HGraphBuilder::AssumeRepresentation(HValue* value, Representation r) { |
| 4823 if (value->CheckFlag(HValue::kFlexibleRepresentation)) { | 4906 if (value->CheckFlag(HValue::kFlexibleRepresentation)) { |
| 4824 if (FLAG_trace_representation) { | 4907 if (FLAG_trace_representation) { |
| 4825 PrintF("Assume representation for %s to be %s (%d)\n", | 4908 PrintF("Assume representation for %s to be %s (%d)\n", |
| 4826 value->Mnemonic(), | 4909 value->Mnemonic(), |
| 4827 r.Mnemonic(), | 4910 r.Mnemonic(), |
| 4828 graph_->GetMaximumValueID()); | 4911 graph_->GetMaximumValueID()); |
| 4829 } | 4912 } |
| 4830 value->ChangeRepresentation(r); | 4913 value->ChangeRepresentation(r); |
| 4831 // The representation of the value is dictated by type feedback. | 4914 // The representation of the value is dictated by type feedback and |
| 4915 // will not be changed later. |
| 4832 value->ClearFlag(HValue::kFlexibleRepresentation); | 4916 value->ClearFlag(HValue::kFlexibleRepresentation); |
| 4833 } else if (FLAG_trace_representation) { | 4917 } else if (FLAG_trace_representation) { |
| 4834 PrintF("No representation assumed\n"); | 4918 PrintF("No representation assumed\n"); |
| 4835 } | 4919 } |
| 4836 } | 4920 } |
| 4837 | 4921 |
| 4838 | 4922 |
| 4839 Representation HGraphBuilder::ToRepresentation(TypeInfo info) { | 4923 Representation HGraphBuilder::ToRepresentation(TypeInfo info) { |
| 4840 if (info.IsSmi()) return Representation::Integer32(); | 4924 if (info.IsSmi()) return Representation::Integer32(); |
| 4841 if (info.IsInteger32()) return Representation::Integer32(); | 4925 if (info.IsInteger32()) return Representation::Integer32(); |
| (...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5096 } | 5180 } |
| 5097 | 5181 |
| 5098 | 5182 |
| 5099 void HGraphBuilder::GenerateSetValueOf(int argument_count, int ast_id) { | 5183 void HGraphBuilder::GenerateSetValueOf(int argument_count, int ast_id) { |
| 5100 BAILOUT("inlined runtime function: SetValueOf"); | 5184 BAILOUT("inlined runtime function: SetValueOf"); |
| 5101 } | 5185 } |
| 5102 | 5186 |
| 5103 | 5187 |
| 5104 // Fast support for charCodeAt(n). | 5188 // Fast support for charCodeAt(n). |
| 5105 void HGraphBuilder::GenerateStringCharCodeAt(int argument_count, int ast_id) { | 5189 void HGraphBuilder::GenerateStringCharCodeAt(int argument_count, int ast_id) { |
| 5106 BAILOUT("inlined runtime function: StringCharCodeAt"); | 5190 ASSERT(argument_count == 2); |
| 5191 HValue* index = Pop(); |
| 5192 HValue* string = Pop(); |
| 5193 HStringCharCodeAt* result = BuildStringCharCodeAt(string, index); |
| 5194 ast_context()->ReturnInstruction(result, ast_id); |
| 5107 } | 5195 } |
| 5108 | 5196 |
| 5109 | 5197 |
| 5110 // Fast support for string.charAt(n) and string[n]. | 5198 // Fast support for string.charAt(n) and string[n]. |
| 5111 void HGraphBuilder::GenerateStringCharFromCode(int argument_count, | 5199 void HGraphBuilder::GenerateStringCharFromCode(int argument_count, |
| 5112 int ast_id) { | 5200 int ast_id) { |
| 5113 BAILOUT("inlined runtime function: StringCharFromCode"); | 5201 BAILOUT("inlined runtime function: StringCharFromCode"); |
| 5114 } | 5202 } |
| 5115 | 5203 |
| 5116 | 5204 |
| (...skipping 673 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5790 } | 5878 } |
| 5791 } | 5879 } |
| 5792 | 5880 |
| 5793 #ifdef DEBUG | 5881 #ifdef DEBUG |
| 5794 if (graph_ != NULL) graph_->Verify(); | 5882 if (graph_ != NULL) graph_->Verify(); |
| 5795 if (allocator_ != NULL) allocator_->Verify(); | 5883 if (allocator_ != NULL) allocator_->Verify(); |
| 5796 #endif | 5884 #endif |
| 5797 } | 5885 } |
| 5798 | 5886 |
| 5799 } } // namespace v8::internal | 5887 } } // namespace v8::internal |
| OLD | NEW |