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

Side by Side Diff: src/hydrogen.cc

Issue 6597029: [Isolates] Merge r 6300:6500 from bleeding_edge to isolates. (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/isolates/
Patch Set: Created 9 years, 10 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 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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