| 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 397 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 927 | 924 |
| 928 class HRangeAnalysis BASE_EMBEDDED { | 925 class HRangeAnalysis BASE_EMBEDDED { |
| 929 public: | 926 public: |
| 930 explicit HRangeAnalysis(HGraph* graph) : graph_(graph), changed_ranges_(16) {} | 927 explicit HRangeAnalysis(HGraph* graph) : graph_(graph), changed_ranges_(16) {} |
| 931 | 928 |
| 932 void Analyze(); | 929 void Analyze(); |
| 933 | 930 |
| 934 private: | 931 private: |
| 935 void TraceRange(const char* msg, ...); | 932 void TraceRange(const char* msg, ...); |
| 936 void Analyze(HBasicBlock* block); | 933 void Analyze(HBasicBlock* block); |
| 937 void InferControlFlowRange(HBranch* branch, HBasicBlock* dest); | 934 void InferControlFlowRange(HTest* test, HBasicBlock* dest); |
| 938 void InferControlFlowRange(Token::Value op, HValue* value, HValue* other); | 935 void InferControlFlowRange(Token::Value op, HValue* value, HValue* other); |
| 939 void InferPhiRange(HPhi* phi); | 936 void InferPhiRange(HPhi* phi); |
| 940 void InferRange(HValue* value); | 937 void InferRange(HValue* value); |
| 941 void RollBackTo(int index); | 938 void RollBackTo(int index); |
| 942 void AddRange(HValue* value, Range* range); | 939 void AddRange(HValue* value, Range* range); |
| 943 | 940 |
| 944 HGraph* graph_; | 941 HGraph* graph_; |
| 945 ZoneList<HValue*> changed_ranges_; | 942 ZoneList<HValue*> changed_ranges_; |
| 946 }; | 943 }; |
| 947 | 944 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 963 | 960 |
| 964 | 961 |
| 965 void HRangeAnalysis::Analyze(HBasicBlock* block) { | 962 void HRangeAnalysis::Analyze(HBasicBlock* block) { |
| 966 TraceRange("Analyzing block B%d\n", block->block_id()); | 963 TraceRange("Analyzing block B%d\n", block->block_id()); |
| 967 | 964 |
| 968 int last_changed_range = changed_ranges_.length() - 1; | 965 int last_changed_range = changed_ranges_.length() - 1; |
| 969 | 966 |
| 970 // Infer range based on control flow. | 967 // Infer range based on control flow. |
| 971 if (block->predecessors()->length() == 1) { | 968 if (block->predecessors()->length() == 1) { |
| 972 HBasicBlock* pred = block->predecessors()->first(); | 969 HBasicBlock* pred = block->predecessors()->first(); |
| 973 if (pred->end()->IsBranch()) { | 970 if (pred->end()->IsTest()) { |
| 974 InferControlFlowRange(HBranch::cast(pred->end()), block); | 971 InferControlFlowRange(HTest::cast(pred->end()), block); |
| 975 } | 972 } |
| 976 } | 973 } |
| 977 | 974 |
| 978 // Process phi instructions. | 975 // Process phi instructions. |
| 979 for (int i = 0; i < block->phis()->length(); ++i) { | 976 for (int i = 0; i < block->phis()->length(); ++i) { |
| 980 HPhi* phi = block->phis()->at(i); | 977 HPhi* phi = block->phis()->at(i); |
| 981 InferPhiRange(phi); | 978 InferPhiRange(phi); |
| 982 } | 979 } |
| 983 | 980 |
| 984 // Go through all instructions of the current block. | 981 // Go through all instructions of the current block. |
| 985 HInstruction* instr = block->first(); | 982 HInstruction* instr = block->first(); |
| 986 while (instr != block->end()) { | 983 while (instr != block->end()) { |
| 987 InferRange(instr); | 984 InferRange(instr); |
| 988 instr = instr->next(); | 985 instr = instr->next(); |
| 989 } | 986 } |
| 990 | 987 |
| 991 // Continue analysis in all dominated blocks. | 988 // Continue analysis in all dominated blocks. |
| 992 for (int i = 0; i < block->dominated_blocks()->length(); ++i) { | 989 for (int i = 0; i < block->dominated_blocks()->length(); ++i) { |
| 993 Analyze(block->dominated_blocks()->at(i)); | 990 Analyze(block->dominated_blocks()->at(i)); |
| 994 } | 991 } |
| 995 | 992 |
| 996 RollBackTo(last_changed_range); | 993 RollBackTo(last_changed_range); |
| 997 } | 994 } |
| 998 | 995 |
| 999 | 996 |
| 1000 void HRangeAnalysis::InferControlFlowRange(HBranch* branch, HBasicBlock* dest) { | 997 void HRangeAnalysis::InferControlFlowRange(HTest* test, HBasicBlock* dest) { |
| 1001 ASSERT(branch->FirstSuccessor() == dest || branch->SecondSuccessor() == dest); | 998 ASSERT((test->FirstSuccessor() == dest) == (test->SecondSuccessor() != dest)); |
| 1002 ASSERT(branch->FirstSuccessor() != dest || branch->SecondSuccessor() != dest); | 999 if (test->value()->IsCompare()) { |
| 1003 | 1000 HCompare* compare = HCompare::cast(test->value()); |
| 1004 if (branch->value()->IsCompare()) { | |
| 1005 HCompare* compare = HCompare::cast(branch->value()); | |
| 1006 Token::Value op = compare->token(); | 1001 Token::Value op = compare->token(); |
| 1007 if (branch->SecondSuccessor() == dest) { | 1002 if (test->SecondSuccessor() == dest) { |
| 1008 op = Token::NegateCompareOp(op); | 1003 op = Token::NegateCompareOp(op); |
| 1009 } | 1004 } |
| 1010 Token::Value inverted_op = Token::InvertCompareOp(op); | 1005 Token::Value inverted_op = Token::InvertCompareOp(op); |
| 1011 InferControlFlowRange(op, compare->left(), compare->right()); | 1006 InferControlFlowRange(op, compare->left(), compare->right()); |
| 1012 InferControlFlowRange(inverted_op, compare->right(), compare->left()); | 1007 InferControlFlowRange(inverted_op, compare->right(), compare->left()); |
| 1013 } | 1008 } |
| 1014 } | 1009 } |
| 1015 | 1010 |
| 1016 | 1011 |
| 1017 // 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 1042 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2060 | 2055 |
| 2061 | 2056 |
| 2062 void TestContext::BuildBranch(HValue* value) { | 2057 void TestContext::BuildBranch(HValue* value) { |
| 2063 // We expect the graph to be in edge-split form: there is no edge that | 2058 // We expect the graph to be in edge-split form: there is no edge that |
| 2064 // connects a branch node to a join node. We conservatively ensure that | 2059 // connects a branch node to a join node. We conservatively ensure that |
| 2065 // property by always adding an empty block on the outgoing edges of this | 2060 // property by always adding an empty block on the outgoing edges of this |
| 2066 // branch. | 2061 // branch. |
| 2067 HGraphBuilder* builder = owner(); | 2062 HGraphBuilder* builder = owner(); |
| 2068 HBasicBlock* empty_true = builder->graph()->CreateBasicBlock(); | 2063 HBasicBlock* empty_true = builder->graph()->CreateBasicBlock(); |
| 2069 HBasicBlock* empty_false = builder->graph()->CreateBasicBlock(); | 2064 HBasicBlock* empty_false = builder->graph()->CreateBasicBlock(); |
| 2070 HBranch* branch = new HBranch(empty_true, empty_false, value); | 2065 HTest* test = new HTest(value, empty_true, empty_false); |
| 2071 builder->CurrentBlock()->Finish(branch); | 2066 builder->CurrentBlock()->Finish(test); |
| 2072 | 2067 |
| 2073 HValue* const no_return_value = NULL; | 2068 HValue* const no_return_value = NULL; |
| 2074 HBasicBlock* true_target = if_true(); | 2069 HBasicBlock* true_target = if_true(); |
| 2075 if (true_target->IsInlineReturnTarget()) { | 2070 if (true_target->IsInlineReturnTarget()) { |
| 2076 empty_true->AddLeaveInlined(no_return_value, true_target); | 2071 empty_true->AddLeaveInlined(no_return_value, true_target); |
| 2077 } else { | 2072 } else { |
| 2078 empty_true->Goto(true_target); | 2073 empty_true->Goto(true_target); |
| 2079 } | 2074 } |
| 2080 | 2075 |
| 2081 HBasicBlock* false_target = if_false(); | 2076 HBasicBlock* false_target = if_false(); |
| (...skipping 507 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2589 CaseClause* clause = clauses->at(i); | 2584 CaseClause* clause = clauses->at(i); |
| 2590 if (clause->is_default()) continue; | 2585 if (clause->is_default()) continue; |
| 2591 | 2586 |
| 2592 // Finish the previous graph by connecting it to the current. | 2587 // Finish the previous graph by connecting it to the current. |
| 2593 HSubgraph* subgraph = compare_graphs.at(i); | 2588 HSubgraph* subgraph = compare_graphs.at(i); |
| 2594 if (prev_compare_inst == NULL) { | 2589 if (prev_compare_inst == NULL) { |
| 2595 ASSERT(prev_graph == current_subgraph_); | 2590 ASSERT(prev_graph == current_subgraph_); |
| 2596 prev_graph->exit_block()->Finish(new HGoto(subgraph->entry_block())); | 2591 prev_graph->exit_block()->Finish(new HGoto(subgraph->entry_block())); |
| 2597 } else { | 2592 } else { |
| 2598 HBasicBlock* empty = graph()->CreateBasicBlock(); | 2593 HBasicBlock* empty = graph()->CreateBasicBlock(); |
| 2599 prev_graph->exit_block()->Finish(new HBranch(empty, | 2594 prev_graph->exit_block()->Finish(new HTest(prev_compare_inst, |
| 2600 subgraph->entry_block(), | 2595 empty, |
| 2601 prev_compare_inst)); | 2596 subgraph->entry_block())); |
| 2602 } | 2597 } |
| 2603 | 2598 |
| 2604 // Build instructions for current subgraph. | 2599 // Build instructions for current subgraph. |
| 2605 ASSERT(clause->IsSmiCompare()); | 2600 ASSERT(clause->IsSmiCompare()); |
| 2606 prev_compare_inst = BuildSwitchCompare(subgraph, switch_value, clause); | 2601 prev_compare_inst = BuildSwitchCompare(subgraph, switch_value, clause); |
| 2607 if (HasStackOverflow()) return; | 2602 if (HasStackOverflow()) return; |
| 2608 | 2603 |
| 2609 prev_graph = subgraph; | 2604 prev_graph = subgraph; |
| 2610 } | 2605 } |
| 2611 | 2606 |
| 2612 // Finish last comparison if there was at least one comparison. | 2607 // Finish last comparison if there was at least one comparison. |
| 2613 // last_false_block is the (empty) false-block of the last comparison. If | 2608 // last_false_block is the (empty) false-block of the last comparison. If |
| 2614 // there are no comparisons at all (a single default clause), it is just | 2609 // there are no comparisons at all (a single default clause), it is just |
| 2615 // the last block of the current subgraph. | 2610 // the last block of the current subgraph. |
| 2616 HBasicBlock* last_false_block = current_subgraph_->exit_block(); | 2611 HBasicBlock* last_false_block = current_subgraph_->exit_block(); |
| 2617 if (prev_graph != current_subgraph_) { | 2612 if (prev_graph != current_subgraph_) { |
| 2618 last_false_block = graph()->CreateBasicBlock(); | 2613 last_false_block = graph()->CreateBasicBlock(); |
| 2619 HBasicBlock* empty = graph()->CreateBasicBlock(); | 2614 HBasicBlock* empty = graph()->CreateBasicBlock(); |
| 2620 prev_graph->exit_block()->Finish(new HBranch(empty, | 2615 prev_graph->exit_block()->Finish(new HTest(prev_compare_inst, |
| 2621 last_false_block, | 2616 empty, |
| 2622 prev_compare_inst)); | 2617 last_false_block)); |
| 2623 } | 2618 } |
| 2624 | 2619 |
| 2625 // If we have a non-smi compare clause, we deoptimize after trying | 2620 // If we have a non-smi compare clause, we deoptimize after trying |
| 2626 // all the previous compares. | 2621 // all the previous compares. |
| 2627 if (num_smi_clauses < num_clauses) { | 2622 if (num_smi_clauses < num_clauses) { |
| 2628 last_false_block->Finish(new HDeoptimize); | 2623 last_false_block->Finish(new HDeoptimize); |
| 2629 } | 2624 } |
| 2630 | 2625 |
| 2631 // Build statement blocks, connect them to their comparison block and | 2626 // Build statement blocks, connect them to their comparison block and |
| 2632 // to the previous statement block, if there is a fall-through. | 2627 // to the previous statement block, if there is a fall-through. |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2695 return statement->OsrEntryId() == info()->osr_ast_id(); | 2690 return statement->OsrEntryId() == info()->osr_ast_id(); |
| 2696 } | 2691 } |
| 2697 | 2692 |
| 2698 | 2693 |
| 2699 void HSubgraph::PreProcessOsrEntry(IterationStatement* statement) { | 2694 void HSubgraph::PreProcessOsrEntry(IterationStatement* statement) { |
| 2700 if (!graph()->HasOsrEntryAt(statement)) return; | 2695 if (!graph()->HasOsrEntryAt(statement)) return; |
| 2701 | 2696 |
| 2702 HBasicBlock* non_osr_entry = graph()->CreateBasicBlock(); | 2697 HBasicBlock* non_osr_entry = graph()->CreateBasicBlock(); |
| 2703 HBasicBlock* osr_entry = graph()->CreateBasicBlock(); | 2698 HBasicBlock* osr_entry = graph()->CreateBasicBlock(); |
| 2704 HValue* true_value = graph()->GetConstantTrue(); | 2699 HValue* true_value = graph()->GetConstantTrue(); |
| 2705 HBranch* branch = new HBranch(non_osr_entry, osr_entry, true_value); | 2700 HTest* test = new HTest(true_value, non_osr_entry, osr_entry); |
| 2706 exit_block()->Finish(branch); | 2701 exit_block()->Finish(test); |
| 2707 | 2702 |
| 2708 HBasicBlock* loop_predecessor = graph()->CreateBasicBlock(); | 2703 HBasicBlock* loop_predecessor = graph()->CreateBasicBlock(); |
| 2709 non_osr_entry->Goto(loop_predecessor); | 2704 non_osr_entry->Goto(loop_predecessor); |
| 2710 | 2705 |
| 2711 int osr_entry_id = statement->OsrEntryId(); | 2706 int osr_entry_id = statement->OsrEntryId(); |
| 2712 // We want the correct environment at the OsrEntry instruction. Build | 2707 // We want the correct environment at the OsrEntry instruction. Build |
| 2713 // it explicitly. The expression stack should be empty. | 2708 // it explicitly. The expression stack should be empty. |
| 2714 int count = osr_entry->last_environment()->length(); | 2709 int count = osr_entry->last_environment()->length(); |
| 2715 ASSERT(count == (osr_entry->last_environment()->parameter_count() + | 2710 ASSERT(count == (osr_entry->last_environment()->parameter_count() + |
| 2716 osr_entry->last_environment()->local_count())); | 2711 osr_entry->last_environment()->local_count())); |
| (...skipping 381 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3098 | 3093 |
| 3099 // Build map compare subgraphs for all but the first map. | 3094 // Build map compare subgraphs for all but the first map. |
| 3100 ZoneList<HSubgraph*> map_compare_subgraphs(maps->length() - 1); | 3095 ZoneList<HSubgraph*> map_compare_subgraphs(maps->length() - 1); |
| 3101 for (int i = maps->length() - 1; i > 0; --i) { | 3096 for (int i = maps->length() - 1; i > 0; --i) { |
| 3102 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3097 HSubgraph* subgraph = CreateBranchSubgraph(environment()); |
| 3103 SubgraphScope scope(this, subgraph); | 3098 SubgraphScope scope(this, subgraph); |
| 3104 HSubgraph* else_subgraph = | 3099 HSubgraph* else_subgraph = |
| 3105 (i == (maps->length() - 1)) | 3100 (i == (maps->length() - 1)) |
| 3106 ? subgraphs->last() | 3101 ? subgraphs->last() |
| 3107 : map_compare_subgraphs.last(); | 3102 : map_compare_subgraphs.last(); |
| 3108 current_subgraph_->exit_block()->Finish( | 3103 HCompareMap* compare = new HCompareMap(receiver, |
| 3109 new HCompareMapAndBranch(receiver, | 3104 maps->at(i), |
| 3110 maps->at(i), | 3105 subgraphs->at(i)->entry_block(), |
| 3111 subgraphs->at(i)->entry_block(), | 3106 else_subgraph->entry_block()); |
| 3112 else_subgraph->entry_block())); | 3107 current_subgraph_->exit_block()->Finish(compare); |
| 3113 map_compare_subgraphs.Add(subgraph); | 3108 map_compare_subgraphs.Add(subgraph); |
| 3114 } | 3109 } |
| 3115 | 3110 |
| 3116 // Generate first map check to end the current block. | 3111 // Generate first map check to end the current block. |
| 3117 AddInstruction(new HCheckNonSmi(receiver)); | 3112 AddInstruction(new HCheckNonSmi(receiver)); |
| 3118 HSubgraph* else_subgraph = | 3113 HSubgraph* else_subgraph = |
| 3119 (maps->length() == 1) ? subgraphs->at(1) : map_compare_subgraphs.last(); | 3114 (maps->length() == 1) ? subgraphs->at(1) : map_compare_subgraphs.last(); |
| 3120 current_subgraph_->exit_block()->Finish( | 3115 HCompareMap* compare = new HCompareMap(receiver, |
| 3121 new HCompareMapAndBranch(receiver, | 3116 Handle<Map>(maps->first()), |
| 3122 Handle<Map>(maps->first()), | 3117 subgraphs->first()->entry_block(), |
| 3123 subgraphs->first()->entry_block(), | 3118 else_subgraph->entry_block()); |
| 3124 else_subgraph->entry_block())); | 3119 current_subgraph_->exit_block()->Finish(compare); |
| 3125 | 3120 |
| 3126 // Join all the call subgraphs in a new basic block and make | 3121 // Join all the call subgraphs in a new basic block and make |
| 3127 // this basic block the current basic block. | 3122 // this basic block the current basic block. |
| 3128 HBasicBlock* join_block = graph_->CreateBasicBlock(); | 3123 HBasicBlock* join_block = graph_->CreateBasicBlock(); |
| 3129 for (int i = 0; i < subgraphs->length(); ++i) { | 3124 for (int i = 0; i < subgraphs->length(); ++i) { |
| 3130 HSubgraph* subgraph = subgraphs->at(i); | 3125 HSubgraph* subgraph = subgraphs->at(i); |
| 3131 if (subgraph->HasExit()) { | 3126 if (subgraph->HasExit()) { |
| 3132 // In an effect context the value of the type switch is not needed. | 3127 // In an effect context the value of the type switch is not needed. |
| 3133 // There is no need to merge it at the join block only to discard it. | 3128 // There is no need to merge it at the join block only to discard it. |
| 3134 HBasicBlock* subgraph_exit = subgraph->exit_block(); | 3129 HBasicBlock* subgraph_exit = subgraph->exit_block(); |
| (...skipping 933 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4068 ASSERT(function_return_ != NULL); | 4063 ASSERT(function_return_ != NULL); |
| 4069 body->exit_block()->AddLeaveInlined(return_value, function_return_); | 4064 body->exit_block()->AddLeaveInlined(return_value, function_return_); |
| 4070 } else { | 4065 } else { |
| 4071 // The graph builder assumes control can reach both branches of a | 4066 // The graph builder assumes control can reach both branches of a |
| 4072 // test, so we materialize the undefined value and test it rather than | 4067 // test, so we materialize the undefined value and test it rather than |
| 4073 // simply jumping to the false target. | 4068 // simply jumping to the false target. |
| 4074 // | 4069 // |
| 4075 // TODO(3168478): refactor to avoid this. | 4070 // TODO(3168478): refactor to avoid this. |
| 4076 HBasicBlock* empty_true = graph()->CreateBasicBlock(); | 4071 HBasicBlock* empty_true = graph()->CreateBasicBlock(); |
| 4077 HBasicBlock* empty_false = graph()->CreateBasicBlock(); | 4072 HBasicBlock* empty_false = graph()->CreateBasicBlock(); |
| 4078 HBranch* branch = | 4073 HTest* test = new HTest(return_value, empty_true, empty_false); |
| 4079 new HBranch(empty_true, empty_false, return_value); | 4074 body->exit_block()->Finish(test); |
| 4080 body->exit_block()->Finish(branch); | |
| 4081 | 4075 |
| 4082 HValue* const no_return_value = NULL; | 4076 HValue* const no_return_value = NULL; |
| 4083 empty_true->AddLeaveInlined(no_return_value, test_context->if_true()); | 4077 empty_true->AddLeaveInlined(no_return_value, test_context->if_true()); |
| 4084 empty_false->AddLeaveInlined(no_return_value, test_context->if_false()); | 4078 empty_false->AddLeaveInlined(no_return_value, test_context->if_false()); |
| 4085 } | 4079 } |
| 4086 body->set_exit_block(NULL); | 4080 body->set_exit_block(NULL); |
| 4087 } | 4081 } |
| 4088 | 4082 |
| 4089 // Record the environment at the inlined function call. | 4083 // Record the environment at the inlined function call. |
| 4090 AddSimulate(expr->ReturnId()); | 4084 AddSimulate(expr->ReturnId()); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4139 void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) { | 4133 void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) { |
| 4140 ASSERT(target->IsInlineReturnTarget()); | 4134 ASSERT(target->IsInlineReturnTarget()); |
| 4141 AddInstruction(new HLeaveInlined); | 4135 AddInstruction(new HLeaveInlined); |
| 4142 HEnvironment* outer = last_environment()->outer(); | 4136 HEnvironment* outer = last_environment()->outer(); |
| 4143 if (return_value != NULL) outer->Push(return_value); | 4137 if (return_value != NULL) outer->Push(return_value); |
| 4144 UpdateEnvironment(outer); | 4138 UpdateEnvironment(outer); |
| 4145 Goto(target); | 4139 Goto(target); |
| 4146 } | 4140 } |
| 4147 | 4141 |
| 4148 | 4142 |
| 4149 bool HGraphBuilder::TryMathFunctionInline(Call* expr) { | 4143 bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr, |
| 4144 HValue* receiver, |
| 4145 Handle<Map> receiver_map, |
| 4146 CheckType check_type) { |
| 4147 ASSERT(check_type != RECEIVER_MAP_CHECK || !receiver_map.is_null()); |
| 4150 // Try to inline calls like Math.* as operations in the calling function. | 4148 // Try to inline calls like Math.* as operations in the calling function. |
| 4151 if (!expr->target()->shared()->IsBuiltinMathFunction()) return false; | 4149 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; |
| 4152 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); | 4150 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); |
| 4153 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 4151 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
| 4154 switch (id) { | 4152 switch (id) { |
| 4153 case kStringCharCodeAt: |
| 4154 if (argument_count == 2 && check_type == STRING_CHECK) { |
| 4155 HValue* index = Pop(); |
| 4156 HValue* string = Pop(); |
| 4157 ASSERT(!expr->holder().is_null()); |
| 4158 AddInstruction(new HCheckPrototypeMaps( |
| 4159 oracle()->GetPrototypeForPrimitiveCheck(STRING_CHECK), |
| 4160 expr->holder())); |
| 4161 HStringCharCodeAt* result = BuildStringCharCodeAt(string, index); |
| 4162 ast_context()->ReturnInstruction(result, expr->id()); |
| 4163 return true; |
| 4164 } |
| 4165 break; |
| 4155 case kMathRound: | 4166 case kMathRound: |
| 4156 case kMathFloor: | 4167 case kMathFloor: |
| 4157 case kMathAbs: | 4168 case kMathAbs: |
| 4158 case kMathSqrt: | 4169 case kMathSqrt: |
| 4159 case kMathLog: | 4170 case kMathLog: |
| 4160 case kMathSin: | 4171 case kMathSin: |
| 4161 case kMathCos: | 4172 case kMathCos: |
| 4162 if (argument_count == 2) { | 4173 if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) { |
| 4174 AddCheckConstantFunction(expr, receiver, receiver_map, true); |
| 4163 HValue* argument = Pop(); | 4175 HValue* argument = Pop(); |
| 4164 Drop(1); // Receiver. | 4176 Drop(1); // Receiver. |
| 4165 HUnaryMathOperation* op = new HUnaryMathOperation(argument, id); | 4177 HUnaryMathOperation* op = new HUnaryMathOperation(argument, id); |
| 4166 op->set_position(expr->position()); | 4178 op->set_position(expr->position()); |
| 4167 ast_context()->ReturnInstruction(op, expr->id()); | 4179 ast_context()->ReturnInstruction(op, expr->id()); |
| 4168 return true; | 4180 return true; |
| 4169 } | 4181 } |
| 4170 break; | 4182 break; |
| 4171 case kMathPow: | 4183 case kMathPow: |
| 4172 if (argument_count == 3) { | 4184 if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) { |
| 4185 AddCheckConstantFunction(expr, receiver, receiver_map, true); |
| 4173 HValue* right = Pop(); | 4186 HValue* right = Pop(); |
| 4174 HValue* left = Pop(); | 4187 HValue* left = Pop(); |
| 4175 Pop(); // Pop receiver. | 4188 Pop(); // Pop receiver. |
| 4176 HInstruction* result = NULL; | 4189 HInstruction* result = NULL; |
| 4177 // Use sqrt() if exponent is 0.5 or -0.5. | 4190 // Use sqrt() if exponent is 0.5 or -0.5. |
| 4178 if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) { | 4191 if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) { |
| 4179 double exponent = HConstant::cast(right)->DoubleValue(); | 4192 double exponent = HConstant::cast(right)->DoubleValue(); |
| 4180 if (exponent == 0.5) { | 4193 if (exponent == 0.5) { |
| 4181 result = new HUnaryMathOperation(left, kMathPowHalf); | 4194 result = new HUnaryMathOperation(left, kMathPowHalf); |
| 4182 ast_context()->ReturnInstruction(result, expr->id()); | |
| 4183 return true; | |
| 4184 } else if (exponent == -0.5) { | 4195 } else if (exponent == -0.5) { |
| 4185 HConstant* double_one = | 4196 HConstant* double_one = |
| 4186 new HConstant(Handle<Object>(Smi::FromInt(1)), | 4197 new HConstant(Handle<Object>(Smi::FromInt(1)), |
| 4187 Representation::Double()); | 4198 Representation::Double()); |
| 4188 AddInstruction(double_one); | 4199 AddInstruction(double_one); |
| 4189 HUnaryMathOperation* square_root = | 4200 HUnaryMathOperation* square_root = |
| 4190 new HUnaryMathOperation(left, kMathPowHalf); | 4201 new HUnaryMathOperation(left, kMathPowHalf); |
| 4191 AddInstruction(square_root); | 4202 AddInstruction(square_root); |
| 4192 // MathPowHalf doesn't have side effects so there's no need for | 4203 // MathPowHalf doesn't have side effects so there's no need for |
| 4193 // an environment simulation here. | 4204 // an environment simulation here. |
| 4194 ASSERT(!square_root->HasSideEffects()); | 4205 ASSERT(!square_root->HasSideEffects()); |
| 4195 result = new HDiv(double_one, square_root); | 4206 result = new HDiv(double_one, square_root); |
| 4196 ast_context()->ReturnInstruction(result, expr->id()); | |
| 4197 return true; | |
| 4198 } else if (exponent == 2.0) { | 4207 } else if (exponent == 2.0) { |
| 4199 result = new HMul(left, left); | 4208 result = new HMul(left, left); |
| 4200 ast_context()->ReturnInstruction(result, expr->id()); | |
| 4201 return true; | |
| 4202 } | 4209 } |
| 4203 } else if (right->IsConstant() && | 4210 } else if (right->IsConstant() && |
| 4204 HConstant::cast(right)->HasInteger32Value() && | 4211 HConstant::cast(right)->HasInteger32Value() && |
| 4205 HConstant::cast(right)->Integer32Value() == 2) { | 4212 HConstant::cast(right)->Integer32Value() == 2) { |
| 4206 result = new HMul(left, left); | 4213 result = new HMul(left, left); |
| 4207 ast_context()->ReturnInstruction(result, expr->id()); | |
| 4208 return true; | |
| 4209 } | 4214 } |
| 4210 | 4215 |
| 4211 result = new HPower(left, right); | 4216 if (result == NULL) { |
| 4217 result = new HPower(left, right); |
| 4218 } |
| 4212 ast_context()->ReturnInstruction(result, expr->id()); | 4219 ast_context()->ReturnInstruction(result, expr->id()); |
| 4213 return true; | 4220 return true; |
| 4214 } | 4221 } |
| 4215 break; | 4222 break; |
| 4216 default: | 4223 default: |
| 4217 // Not yet supported for inlining. | 4224 // Not yet supported for inlining. |
| 4218 break; | 4225 break; |
| 4219 } | 4226 } |
| 4220 return false; | 4227 return false; |
| 4221 } | 4228 } |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4256 expr->GetReceiverTypes()->first(), | 4263 expr->GetReceiverTypes()->first(), |
| 4257 true); | 4264 true); |
| 4258 HInstruction* result = | 4265 HInstruction* result = |
| 4259 new HApplyArguments(function, receiver, length, elements); | 4266 new HApplyArguments(function, receiver, length, elements); |
| 4260 result->set_position(expr->position()); | 4267 result->set_position(expr->position()); |
| 4261 ast_context()->ReturnInstruction(result, expr->id()); | 4268 ast_context()->ReturnInstruction(result, expr->id()); |
| 4262 return true; | 4269 return true; |
| 4263 } | 4270 } |
| 4264 | 4271 |
| 4265 | 4272 |
| 4273 static bool HasCustomCallGenerator(Handle<JSFunction> function) { |
| 4274 SharedFunctionInfo* info = function->shared(); |
| 4275 return info->HasBuiltinFunctionId() && |
| 4276 CallStubCompiler::HasCustomCallGenerator(info->builtin_function_id()); |
| 4277 } |
| 4278 |
| 4279 |
| 4266 void HGraphBuilder::VisitCall(Call* expr) { | 4280 void HGraphBuilder::VisitCall(Call* expr) { |
| 4267 Expression* callee = expr->expression(); | 4281 Expression* callee = expr->expression(); |
| 4268 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 4282 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
| 4269 HCall* call = NULL; | 4283 HCall* call = NULL; |
| 4270 | 4284 |
| 4271 Property* prop = callee->AsProperty(); | 4285 Property* prop = callee->AsProperty(); |
| 4272 if (prop != NULL) { | 4286 if (prop != NULL) { |
| 4273 if (!prop->key()->IsPropertyName()) { | 4287 if (!prop->key()->IsPropertyName()) { |
| 4274 // Keyed function call. | 4288 // Keyed function call. |
| 4275 VisitArgument(prop->obj()); | 4289 VisitArgument(prop->obj()); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 4302 HValue* receiver = VisitArgument(prop->obj()); | 4316 HValue* receiver = VisitArgument(prop->obj()); |
| 4303 CHECK_BAILOUT; | 4317 CHECK_BAILOUT; |
| 4304 VisitArgumentList(expr->arguments()); | 4318 VisitArgumentList(expr->arguments()); |
| 4305 CHECK_BAILOUT; | 4319 CHECK_BAILOUT; |
| 4306 | 4320 |
| 4307 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); | 4321 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); |
| 4308 | 4322 |
| 4309 expr->RecordTypeFeedback(oracle()); | 4323 expr->RecordTypeFeedback(oracle()); |
| 4310 ZoneMapList* types = expr->GetReceiverTypes(); | 4324 ZoneMapList* types = expr->GetReceiverTypes(); |
| 4311 | 4325 |
| 4312 if (expr->IsMonomorphic() && expr->check_type() == RECEIVER_MAP_CHECK) { | 4326 if (expr->IsMonomorphic()) { |
| 4313 AddCheckConstantFunction(expr, receiver, types->first(), true); | 4327 Handle<Map> receiver_map = |
| 4314 | 4328 (types == NULL) ? Handle<Map>::null() : types->first(); |
| 4315 if (TryMathFunctionInline(expr)) { | 4329 if (TryInlineBuiltinFunction(expr, |
| 4330 receiver, |
| 4331 receiver_map, |
| 4332 expr->check_type())) { |
| 4316 return; | 4333 return; |
| 4317 } else if (TryInline(expr)) { | |
| 4318 if (subgraph()->HasExit()) { | |
| 4319 HValue* return_value = Pop(); | |
| 4320 // If we inlined a function in a test context then we need to emit | |
| 4321 // a simulate here to shadow the ones at the end of the | |
| 4322 // predecessor blocks. Those environments contain the return | |
| 4323 // value on top and do not correspond to any actual state of the | |
| 4324 // unoptimized code. | |
| 4325 if (ast_context()->IsEffect()) AddSimulate(expr->id()); | |
| 4326 ast_context()->ReturnValue(return_value); | |
| 4327 } | |
| 4328 return; | |
| 4329 } else { | |
| 4330 // Check for bailout, as the TryInline call in the if condition above | |
| 4331 // might return false due to bailout during hydrogen processing. | |
| 4332 CHECK_BAILOUT; | |
| 4333 call = new HCallConstantFunction(expr->target(), argument_count); | |
| 4334 } | 4334 } |
| 4335 | 4335 |
| 4336 if (HasCustomCallGenerator(expr->target()) || |
| 4337 expr->check_type() != RECEIVER_MAP_CHECK) { |
| 4338 // When the target has a custom call IC generator, use the IC, |
| 4339 // because it is likely to generate better code. Also use the |
| 4340 // IC when a primitive receiver check is required. |
| 4341 call = new HCallNamed(name, argument_count); |
| 4342 } else { |
| 4343 AddCheckConstantFunction(expr, receiver, receiver_map, true); |
| 4344 |
| 4345 if (TryInline(expr)) { |
| 4346 if (subgraph()->HasExit()) { |
| 4347 HValue* return_value = Pop(); |
| 4348 // If we inlined a function in a test context then we need to emit |
| 4349 // a simulate here to shadow the ones at the end of the |
| 4350 // predecessor blocks. Those environments contain the return |
| 4351 // value on top and do not correspond to any actual state of the |
| 4352 // unoptimized code. |
| 4353 if (ast_context()->IsEffect()) AddSimulate(expr->id()); |
| 4354 ast_context()->ReturnValue(return_value); |
| 4355 } |
| 4356 return; |
| 4357 } else { |
| 4358 // Check for bailout, as the TryInline call in the if condition above |
| 4359 // might return false due to bailout during hydrogen processing. |
| 4360 CHECK_BAILOUT; |
| 4361 call = new HCallConstantFunction(expr->target(), argument_count); |
| 4362 } |
| 4363 } |
| 4336 } else if (types != NULL && types->length() > 1) { | 4364 } else if (types != NULL && types->length() > 1) { |
| 4337 ASSERT(expr->check_type() == RECEIVER_MAP_CHECK); | 4365 ASSERT(expr->check_type() == RECEIVER_MAP_CHECK); |
| 4338 HandlePolymorphicCallNamed(expr, receiver, types, name); | 4366 HandlePolymorphicCallNamed(expr, receiver, types, name); |
| 4339 return; | 4367 return; |
| 4340 | 4368 |
| 4341 } else { | 4369 } else { |
| 4342 call = new HCallNamed(name, argument_count); | 4370 call = new HCallNamed(name, argument_count); |
| 4343 } | 4371 } |
| 4344 | 4372 |
| 4345 } else { | 4373 } else { |
| (...skipping 367 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4713 | 4741 |
| 4714 ast_context()->ReturnValue(expr->is_postfix() ? before : after); | 4742 ast_context()->ReturnValue(expr->is_postfix() ? before : after); |
| 4715 } | 4743 } |
| 4716 | 4744 |
| 4717 } else { | 4745 } else { |
| 4718 BAILOUT("invalid lhs in count operation"); | 4746 BAILOUT("invalid lhs in count operation"); |
| 4719 } | 4747 } |
| 4720 } | 4748 } |
| 4721 | 4749 |
| 4722 | 4750 |
| 4751 HStringCharCodeAt* HGraphBuilder::BuildStringCharCodeAt(HValue* string, |
| 4752 HValue* index) { |
| 4753 AddInstruction(new HCheckNonSmi(string)); |
| 4754 AddInstruction(new HCheckInstanceType( |
| 4755 string, FIRST_STRING_TYPE, LAST_STRING_TYPE)); |
| 4756 HStringLength* length = new HStringLength(string); |
| 4757 AddInstruction(length); |
| 4758 AddInstruction(new HBoundsCheck(index, length)); |
| 4759 return new HStringCharCodeAt(string, index); |
| 4760 } |
| 4761 |
| 4762 |
| 4723 HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr, | 4763 HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr, |
| 4724 HValue* left, | 4764 HValue* left, |
| 4725 HValue* right) { | 4765 HValue* right) { |
| 4726 HInstruction* instr = NULL; | 4766 HInstruction* instr = NULL; |
| 4727 switch (expr->op()) { | 4767 switch (expr->op()) { |
| 4728 case Token::ADD: | 4768 case Token::ADD: |
| 4729 instr = new HAdd(left, right); | 4769 instr = new HAdd(left, right); |
| 4730 break; | 4770 break; |
| 4731 case Token::SUB: | 4771 case Token::SUB: |
| 4732 instr = new HSub(left, right); | 4772 instr = new HSub(left, right); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4766 // for a smi operation. If one of the operands is a constant string | 4806 // for a smi operation. If one of the operands is a constant string |
| 4767 // do not generate code assuming it is a smi operation. | 4807 // do not generate code assuming it is a smi operation. |
| 4768 if (info.IsSmi() && | 4808 if (info.IsSmi() && |
| 4769 ((left->IsConstant() && HConstant::cast(left)->HasStringValue()) || | 4809 ((left->IsConstant() && HConstant::cast(left)->HasStringValue()) || |
| 4770 (right->IsConstant() && HConstant::cast(right)->HasStringValue()))) { | 4810 (right->IsConstant() && HConstant::cast(right)->HasStringValue()))) { |
| 4771 return instr; | 4811 return instr; |
| 4772 } | 4812 } |
| 4773 if (FLAG_trace_representation) { | 4813 if (FLAG_trace_representation) { |
| 4774 PrintF("Info: %s/%s\n", info.ToString(), ToRepresentation(info).Mnemonic()); | 4814 PrintF("Info: %s/%s\n", info.ToString(), ToRepresentation(info).Mnemonic()); |
| 4775 } | 4815 } |
| 4776 AssumeRepresentation(instr, ToRepresentation(info)); | 4816 Representation rep = ToRepresentation(info); |
| 4817 // We only generate either int32 or generic tagged bitwise operations. |
| 4818 if (instr->IsBitwiseBinaryOperation() && rep.IsDouble()) { |
| 4819 rep = Representation::Integer32(); |
| 4820 } |
| 4821 AssumeRepresentation(instr, rep); |
| 4777 return instr; | 4822 return instr; |
| 4778 } | 4823 } |
| 4779 | 4824 |
| 4780 | 4825 |
| 4781 // Check for the form (%_ClassOf(foo) === 'BarClass'). | 4826 // Check for the form (%_ClassOf(foo) === 'BarClass'). |
| 4782 static bool IsClassOfTest(CompareOperation* expr) { | 4827 static bool IsClassOfTest(CompareOperation* expr) { |
| 4783 if (expr->op() != Token::EQ_STRICT) return false; | 4828 if (expr->op() != Token::EQ_STRICT) return false; |
| 4784 CallRuntime* call = expr->left()->AsCallRuntime(); | 4829 CallRuntime* call = expr->left()->AsCallRuntime(); |
| 4785 if (call == NULL) return false; | 4830 if (call == NULL) return false; |
| 4786 Literal* literal = expr->right()->AsLiteral(); | 4831 Literal* literal = expr->right()->AsLiteral(); |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4847 | 4892 |
| 4848 void HGraphBuilder::AssumeRepresentation(HValue* value, Representation r) { | 4893 void HGraphBuilder::AssumeRepresentation(HValue* value, Representation r) { |
| 4849 if (value->CheckFlag(HValue::kFlexibleRepresentation)) { | 4894 if (value->CheckFlag(HValue::kFlexibleRepresentation)) { |
| 4850 if (FLAG_trace_representation) { | 4895 if (FLAG_trace_representation) { |
| 4851 PrintF("Assume representation for %s to be %s (%d)\n", | 4896 PrintF("Assume representation for %s to be %s (%d)\n", |
| 4852 value->Mnemonic(), | 4897 value->Mnemonic(), |
| 4853 r.Mnemonic(), | 4898 r.Mnemonic(), |
| 4854 graph_->GetMaximumValueID()); | 4899 graph_->GetMaximumValueID()); |
| 4855 } | 4900 } |
| 4856 value->ChangeRepresentation(r); | 4901 value->ChangeRepresentation(r); |
| 4857 // The representation of the value is dictated by type feedback. | 4902 // The representation of the value is dictated by type feedback and |
| 4903 // will not be changed later. |
| 4858 value->ClearFlag(HValue::kFlexibleRepresentation); | 4904 value->ClearFlag(HValue::kFlexibleRepresentation); |
| 4859 } else if (FLAG_trace_representation) { | 4905 } else if (FLAG_trace_representation) { |
| 4860 PrintF("No representation assumed\n"); | 4906 PrintF("No representation assumed\n"); |
| 4861 } | 4907 } |
| 4862 } | 4908 } |
| 4863 | 4909 |
| 4864 | 4910 |
| 4865 Representation HGraphBuilder::ToRepresentation(TypeInfo info) { | 4911 Representation HGraphBuilder::ToRepresentation(TypeInfo info) { |
| 4866 if (info.IsSmi()) return Representation::Integer32(); | 4912 if (info.IsSmi()) return Representation::Integer32(); |
| 4867 if (info.IsInteger32()) return Representation::Integer32(); | 4913 if (info.IsInteger32()) return Representation::Integer32(); |
| (...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5122 } | 5168 } |
| 5123 | 5169 |
| 5124 | 5170 |
| 5125 void HGraphBuilder::GenerateSetValueOf(int argument_count, int ast_id) { | 5171 void HGraphBuilder::GenerateSetValueOf(int argument_count, int ast_id) { |
| 5126 BAILOUT("inlined runtime function: SetValueOf"); | 5172 BAILOUT("inlined runtime function: SetValueOf"); |
| 5127 } | 5173 } |
| 5128 | 5174 |
| 5129 | 5175 |
| 5130 // Fast support for charCodeAt(n). | 5176 // Fast support for charCodeAt(n). |
| 5131 void HGraphBuilder::GenerateStringCharCodeAt(int argument_count, int ast_id) { | 5177 void HGraphBuilder::GenerateStringCharCodeAt(int argument_count, int ast_id) { |
| 5132 BAILOUT("inlined runtime function: StringCharCodeAt"); | 5178 ASSERT(argument_count == 2); |
| 5179 HValue* index = Pop(); |
| 5180 HValue* string = Pop(); |
| 5181 HStringCharCodeAt* result = BuildStringCharCodeAt(string, index); |
| 5182 ast_context()->ReturnInstruction(result, ast_id); |
| 5133 } | 5183 } |
| 5134 | 5184 |
| 5135 | 5185 |
| 5136 // Fast support for string.charAt(n) and string[n]. | 5186 // Fast support for string.charAt(n) and string[n]. |
| 5137 void HGraphBuilder::GenerateStringCharFromCode(int argument_count, | 5187 void HGraphBuilder::GenerateStringCharFromCode(int argument_count, |
| 5138 int ast_id) { | 5188 int ast_id) { |
| 5139 BAILOUT("inlined runtime function: StringCharFromCode"); | 5189 BAILOUT("inlined runtime function: StringCharFromCode"); |
| 5140 } | 5190 } |
| 5141 | 5191 |
| 5142 | 5192 |
| (...skipping 673 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5816 } | 5866 } |
| 5817 } | 5867 } |
| 5818 | 5868 |
| 5819 #ifdef DEBUG | 5869 #ifdef DEBUG |
| 5820 if (graph_ != NULL) graph_->Verify(); | 5870 if (graph_ != NULL) graph_->Verify(); |
| 5821 if (allocator_ != NULL) allocator_->Verify(); | 5871 if (allocator_ != NULL) allocator_->Verify(); |
| 5822 #endif | 5872 #endif |
| 5823 } | 5873 } |
| 5824 | 5874 |
| 5825 } } // namespace v8::internal | 5875 } } // namespace v8::internal |
| OLD | NEW |