Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(579)

Side by Side Diff: src/hydrogen.cc

Issue 6322008: Version 3.0.10... (Closed) Base URL: http://v8.googlecode.com/svn/trunk/
Patch Set: Created 9 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/hydrogen.h ('k') | src/hydrogen-instructions.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/hydrogen.h ('k') | src/hydrogen-instructions.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698