| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 25 matching lines...) Expand all Loading... |
| 36 #include "hydrogen-bce.h" | 36 #include "hydrogen-bce.h" |
| 37 #include "hydrogen-bch.h" | 37 #include "hydrogen-bch.h" |
| 38 #include "hydrogen-canonicalize.h" | 38 #include "hydrogen-canonicalize.h" |
| 39 #include "hydrogen-dce.h" | 39 #include "hydrogen-dce.h" |
| 40 #include "hydrogen-dehoist.h" | 40 #include "hydrogen-dehoist.h" |
| 41 #include "hydrogen-deoptimizing-mark.h" | 41 #include "hydrogen-deoptimizing-mark.h" |
| 42 #include "hydrogen-environment-liveness.h" | 42 #include "hydrogen-environment-liveness.h" |
| 43 #include "hydrogen-escape-analysis.h" | 43 #include "hydrogen-escape-analysis.h" |
| 44 #include "hydrogen-infer-representation.h" | 44 #include "hydrogen-infer-representation.h" |
| 45 #include "hydrogen-infer-types.h" | 45 #include "hydrogen-infer-types.h" |
| 46 #include "hydrogen-load-elimination.h" |
| 46 #include "hydrogen-gvn.h" | 47 #include "hydrogen-gvn.h" |
| 47 #include "hydrogen-mark-deoptimize.h" | 48 #include "hydrogen-mark-deoptimize.h" |
| 48 #include "hydrogen-minus-zero.h" | 49 #include "hydrogen-minus-zero.h" |
| 49 #include "hydrogen-osr.h" | 50 #include "hydrogen-osr.h" |
| 50 #include "hydrogen-range-analysis.h" | 51 #include "hydrogen-range-analysis.h" |
| 51 #include "hydrogen-redundant-phi.h" | 52 #include "hydrogen-redundant-phi.h" |
| 52 #include "hydrogen-removable-simulates.h" | 53 #include "hydrogen-removable-simulates.h" |
| 53 #include "hydrogen-representation-changes.h" | 54 #include "hydrogen-representation-changes.h" |
| 54 #include "hydrogen-sce.h" | 55 #include "hydrogen-sce.h" |
| 55 #include "hydrogen-uint32-analysis.h" | 56 #include "hydrogen-uint32-analysis.h" |
| (...skipping 665 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 721 finished_(false), | 722 finished_(false), |
| 722 deopt_then_(false), | 723 deopt_then_(false), |
| 723 deopt_else_(false), | 724 deopt_else_(false), |
| 724 did_then_(false), | 725 did_then_(false), |
| 725 did_else_(false), | 726 did_else_(false), |
| 726 did_and_(false), | 727 did_and_(false), |
| 727 did_or_(false), | 728 did_or_(false), |
| 728 captured_(false), | 729 captured_(false), |
| 729 needs_compare_(false), | 730 needs_compare_(false), |
| 730 first_true_block_(NULL), | 731 first_true_block_(NULL), |
| 732 last_true_block_(NULL), |
| 731 first_false_block_(NULL), | 733 first_false_block_(NULL), |
| 732 split_edge_merge_block_(NULL), | 734 split_edge_merge_block_(NULL), |
| 733 merge_block_(NULL) { | 735 merge_block_(NULL) { |
| 734 continuation->Continue(&first_true_block_, | 736 continuation->Continue(&first_true_block_, |
| 735 &first_false_block_, | 737 &first_false_block_, |
| 736 &position_); | 738 &position_); |
| 737 } | 739 } |
| 738 | 740 |
| 739 | 741 |
| 740 void HGraphBuilder::IfBuilder::AddCompare(HControlInstruction* compare) { | 742 HControlInstruction* HGraphBuilder::IfBuilder::AddCompare( |
| 743 HControlInstruction* compare) { |
| 741 if (split_edge_merge_block_ != NULL) { | 744 if (split_edge_merge_block_ != NULL) { |
| 742 HEnvironment* env = first_false_block_->last_environment(); | 745 HEnvironment* env = first_false_block_->last_environment(); |
| 743 HBasicBlock* split_edge = | 746 HBasicBlock* split_edge = |
| 744 builder_->CreateBasicBlock(env->Copy()); | 747 builder_->CreateBasicBlock(env->Copy()); |
| 745 if (did_or_) { | 748 if (did_or_) { |
| 746 compare->SetSuccessorAt(0, split_edge); | 749 compare->SetSuccessorAt(0, split_edge); |
| 747 compare->SetSuccessorAt(1, first_false_block_); | 750 compare->SetSuccessorAt(1, first_false_block_); |
| 748 } else { | 751 } else { |
| 749 compare->SetSuccessorAt(0, first_true_block_); | 752 compare->SetSuccessorAt(0, first_true_block_); |
| 750 compare->SetSuccessorAt(1, split_edge); | 753 compare->SetSuccessorAt(1, split_edge); |
| 751 } | 754 } |
| 752 split_edge->GotoNoSimulate(split_edge_merge_block_); | 755 split_edge->GotoNoSimulate(split_edge_merge_block_); |
| 753 } else { | 756 } else { |
| 754 compare->SetSuccessorAt(0, first_true_block_); | 757 compare->SetSuccessorAt(0, first_true_block_); |
| 755 compare->SetSuccessorAt(1, first_false_block_); | 758 compare->SetSuccessorAt(1, first_false_block_); |
| 756 } | 759 } |
| 757 builder_->current_block()->Finish(compare); | 760 builder_->current_block()->Finish(compare); |
| 758 needs_compare_ = false; | 761 needs_compare_ = false; |
| 762 return compare; |
| 759 } | 763 } |
| 760 | 764 |
| 761 | 765 |
| 762 void HGraphBuilder::IfBuilder::Or() { | 766 void HGraphBuilder::IfBuilder::Or() { |
| 763 ASSERT(!did_and_); | 767 ASSERT(!did_and_); |
| 764 did_or_ = true; | 768 did_or_ = true; |
| 765 HEnvironment* env = first_false_block_->last_environment(); | 769 HEnvironment* env = first_false_block_->last_environment(); |
| 766 if (split_edge_merge_block_ == NULL) { | 770 if (split_edge_merge_block_ == NULL) { |
| 767 split_edge_merge_block_ = | 771 split_edge_merge_block_ = |
| 768 builder_->CreateBasicBlock(env->Copy()); | 772 builder_->CreateBasicBlock(env->Copy()); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 809 ASSERT(!finished_); | 813 ASSERT(!finished_); |
| 810 did_then_ = true; | 814 did_then_ = true; |
| 811 if (needs_compare_) { | 815 if (needs_compare_) { |
| 812 // Handle if's without any expressions, they jump directly to the "else" | 816 // Handle if's without any expressions, they jump directly to the "else" |
| 813 // branch. However, we must pretend that the "then" branch is reachable, | 817 // branch. However, we must pretend that the "then" branch is reachable, |
| 814 // so that the graph builder visits it and sees any live range extending | 818 // so that the graph builder visits it and sees any live range extending |
| 815 // constructs within it. | 819 // constructs within it. |
| 816 HConstant* constant_false = builder_->graph()->GetConstantFalse(); | 820 HConstant* constant_false = builder_->graph()->GetConstantFalse(); |
| 817 ToBooleanStub::Types boolean_type = ToBooleanStub::Types(); | 821 ToBooleanStub::Types boolean_type = ToBooleanStub::Types(); |
| 818 boolean_type.Add(ToBooleanStub::BOOLEAN); | 822 boolean_type.Add(ToBooleanStub::BOOLEAN); |
| 819 HBranch* branch = | 823 HBranch* branch = builder()->New<HBranch>( |
| 820 new(zone()) HBranch(constant_false, boolean_type, first_true_block_, | 824 constant_false, boolean_type, first_true_block_, first_false_block_); |
| 821 first_false_block_); | |
| 822 builder_->current_block()->Finish(branch); | 825 builder_->current_block()->Finish(branch); |
| 823 } | 826 } |
| 824 builder_->set_current_block(first_true_block_); | 827 builder_->set_current_block(first_true_block_); |
| 825 } | 828 } |
| 826 | 829 |
| 827 | 830 |
| 828 void HGraphBuilder::IfBuilder::Else() { | 831 void HGraphBuilder::IfBuilder::Else() { |
| 829 ASSERT(did_then_); | 832 ASSERT(did_then_); |
| 830 ASSERT(!captured_); | 833 ASSERT(!captured_); |
| 831 ASSERT(!finished_); | 834 ASSERT(!finished_); |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 943 HEnvironment* body_env = env->Copy(); | 946 HEnvironment* body_env = env->Copy(); |
| 944 HEnvironment* exit_env = env->Copy(); | 947 HEnvironment* exit_env = env->Copy(); |
| 945 // Remove the phi from the expression stack | 948 // Remove the phi from the expression stack |
| 946 body_env->Pop(); | 949 body_env->Pop(); |
| 947 exit_env->Pop(); | 950 exit_env->Pop(); |
| 948 body_block_ = builder_->CreateBasicBlock(body_env); | 951 body_block_ = builder_->CreateBasicBlock(body_env); |
| 949 exit_block_ = builder_->CreateBasicBlock(exit_env); | 952 exit_block_ = builder_->CreateBasicBlock(exit_env); |
| 950 | 953 |
| 951 builder_->set_current_block(header_block_); | 954 builder_->set_current_block(header_block_); |
| 952 env->Pop(); | 955 env->Pop(); |
| 953 HCompareNumericAndBranch* compare = | 956 builder_->current_block()->Finish(builder_->New<HCompareNumericAndBranch>( |
| 954 new(zone()) HCompareNumericAndBranch(phi_, terminating, token); | 957 phi_, terminating, token, body_block_, exit_block_)); |
| 955 compare->SetSuccessorAt(0, body_block_); | |
| 956 compare->SetSuccessorAt(1, exit_block_); | |
| 957 builder_->current_block()->Finish(compare); | |
| 958 | 958 |
| 959 builder_->set_current_block(body_block_); | 959 builder_->set_current_block(body_block_); |
| 960 if (direction_ == kPreIncrement || direction_ == kPreDecrement) { | 960 if (direction_ == kPreIncrement || direction_ == kPreDecrement) { |
| 961 HValue* one = builder_->graph()->GetConstant1(); | 961 HValue* one = builder_->graph()->GetConstant1(); |
| 962 if (direction_ == kPreIncrement) { | 962 if (direction_ == kPreIncrement) { |
| 963 increment_ = HAdd::New(zone(), context_, phi_, one); | 963 increment_ = HAdd::New(zone(), context_, phi_, one); |
| 964 } else { | 964 } else { |
| 965 increment_ = HSub::New(zone(), context_, phi_, one); | 965 increment_ = HSub::New(zone(), context_, phi_, one); |
| 966 } | 966 } |
| 967 increment_->ClearFlag(HValue::kCanOverflow); | 967 increment_->ClearFlag(HValue::kCanOverflow); |
| (...skipping 1798 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2766 // connects a branch node to a join node. We conservatively ensure that | 2766 // connects a branch node to a join node. We conservatively ensure that |
| 2767 // property by always adding an empty block on the outgoing edges of this | 2767 // property by always adding an empty block on the outgoing edges of this |
| 2768 // branch. | 2768 // branch. |
| 2769 HOptimizedGraphBuilder* builder = owner(); | 2769 HOptimizedGraphBuilder* builder = owner(); |
| 2770 if (value != NULL && value->CheckFlag(HValue::kIsArguments)) { | 2770 if (value != NULL && value->CheckFlag(HValue::kIsArguments)) { |
| 2771 builder->Bailout(kArgumentsObjectValueInATestContext); | 2771 builder->Bailout(kArgumentsObjectValueInATestContext); |
| 2772 } | 2772 } |
| 2773 HBasicBlock* empty_true = builder->graph()->CreateBasicBlock(); | 2773 HBasicBlock* empty_true = builder->graph()->CreateBasicBlock(); |
| 2774 HBasicBlock* empty_false = builder->graph()->CreateBasicBlock(); | 2774 HBasicBlock* empty_false = builder->graph()->CreateBasicBlock(); |
| 2775 ToBooleanStub::Types expected(condition()->to_boolean_types()); | 2775 ToBooleanStub::Types expected(condition()->to_boolean_types()); |
| 2776 HBranch* test = new(zone()) HBranch(value, expected, empty_true, empty_false); | 2776 builder->current_block()->Finish(builder->New<HBranch>( |
| 2777 builder->current_block()->Finish(test); | 2777 value, expected, empty_true, empty_false)); |
| 2778 | 2778 |
| 2779 empty_true->Goto(if_true(), builder->function_state()); | 2779 empty_true->Goto(if_true(), builder->function_state()); |
| 2780 empty_false->Goto(if_false(), builder->function_state()); | 2780 empty_false->Goto(if_false(), builder->function_state()); |
| 2781 builder->set_current_block(NULL); | 2781 builder->set_current_block(NULL); |
| 2782 } | 2782 } |
| 2783 | 2783 |
| 2784 | 2784 |
| 2785 // HOptimizedGraphBuilder infrastructure for bailing out and checking bailouts. | 2785 // HOptimizedGraphBuilder infrastructure for bailing out and checking bailouts. |
| 2786 #define CHECK_BAILOUT(call) \ | 2786 #define CHECK_BAILOUT(call) \ |
| 2787 do { \ | 2787 do { \ |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2966 if (!CheckArgumentsPhiUses()) { | 2966 if (!CheckArgumentsPhiUses()) { |
| 2967 *bailout_reason = kUnsupportedPhiUseOfArguments; | 2967 *bailout_reason = kUnsupportedPhiUseOfArguments; |
| 2968 return false; | 2968 return false; |
| 2969 } | 2969 } |
| 2970 | 2970 |
| 2971 // Remove dead code and phis | 2971 // Remove dead code and phis |
| 2972 if (FLAG_dead_code_elimination) Run<HDeadCodeEliminationPhase>(); | 2972 if (FLAG_dead_code_elimination) Run<HDeadCodeEliminationPhase>(); |
| 2973 | 2973 |
| 2974 if (FLAG_use_escape_analysis) Run<HEscapeAnalysisPhase>(); | 2974 if (FLAG_use_escape_analysis) Run<HEscapeAnalysisPhase>(); |
| 2975 | 2975 |
| 2976 if (FLAG_load_elimination) Run<HLoadEliminationPhase>(); |
| 2977 |
| 2976 CollectPhis(); | 2978 CollectPhis(); |
| 2977 | 2979 |
| 2978 if (has_osr()) osr()->FinishOsrValues(); | 2980 if (has_osr()) osr()->FinishOsrValues(); |
| 2979 | 2981 |
| 2980 Run<HInferRepresentationPhase>(); | 2982 Run<HInferRepresentationPhase>(); |
| 2981 | 2983 |
| 2982 // Remove HSimulate instructions that have turned out not to be needed | 2984 // Remove HSimulate instructions that have turned out not to be needed |
| 2983 // after all by folding them into the following HSimulate. | 2985 // after all by folding them into the following HSimulate. |
| 2984 // This must happen after inferring representations. | 2986 // This must happen after inferring representations. |
| 2985 Run<HMergeRemovableSimulatesPhase>(); | 2987 Run<HMergeRemovableSimulatesPhase>(); |
| (...skipping 380 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3366 CHECK_ALIVE(VisitForValue(stmt->tag())); | 3368 CHECK_ALIVE(VisitForValue(stmt->tag())); |
| 3367 Add<HSimulate>(stmt->EntryId()); | 3369 Add<HSimulate>(stmt->EntryId()); |
| 3368 HValue* tag_value = Pop(); | 3370 HValue* tag_value = Pop(); |
| 3369 HBasicBlock* first_test_block = current_block(); | 3371 HBasicBlock* first_test_block = current_block(); |
| 3370 | 3372 |
| 3371 HUnaryControlInstruction* string_check = NULL; | 3373 HUnaryControlInstruction* string_check = NULL; |
| 3372 HBasicBlock* not_string_block = NULL; | 3374 HBasicBlock* not_string_block = NULL; |
| 3373 | 3375 |
| 3374 // Test switch's tag value if all clauses are string literals | 3376 // Test switch's tag value if all clauses are string literals |
| 3375 if (stmt->switch_type() == SwitchStatement::STRING_SWITCH) { | 3377 if (stmt->switch_type() == SwitchStatement::STRING_SWITCH) { |
| 3376 string_check = new(zone()) HIsStringAndBranch(tag_value); | |
| 3377 first_test_block = graph()->CreateBasicBlock(); | 3378 first_test_block = graph()->CreateBasicBlock(); |
| 3378 not_string_block = graph()->CreateBasicBlock(); | 3379 not_string_block = graph()->CreateBasicBlock(); |
| 3379 | 3380 string_check = New<HIsStringAndBranch>( |
| 3380 string_check->SetSuccessorAt(0, first_test_block); | 3381 tag_value, first_test_block, not_string_block); |
| 3381 string_check->SetSuccessorAt(1, not_string_block); | |
| 3382 current_block()->Finish(string_check); | 3382 current_block()->Finish(string_check); |
| 3383 | 3383 |
| 3384 set_current_block(first_test_block); | 3384 set_current_block(first_test_block); |
| 3385 } | 3385 } |
| 3386 | 3386 |
| 3387 // 1. Build all the tests, with dangling true branches | 3387 // 1. Build all the tests, with dangling true branches |
| 3388 BailoutId default_id = BailoutId::None(); | 3388 BailoutId default_id = BailoutId::None(); |
| 3389 for (int i = 0; i < clause_count; ++i) { | 3389 for (int i = 0; i < clause_count; ++i) { |
| 3390 CaseClause* clause = clauses->at(i); | 3390 CaseClause* clause = clauses->at(i); |
| 3391 if (clause->is_default()) { | 3391 if (clause->is_default()) { |
| 3392 default_id = clause->EntryId(); | 3392 default_id = clause->EntryId(); |
| 3393 continue; | 3393 continue; |
| 3394 } | 3394 } |
| 3395 | 3395 |
| 3396 // Generate a compare and branch. | 3396 // Generate a compare and branch. |
| 3397 CHECK_ALIVE(VisitForValue(clause->label())); | 3397 CHECK_ALIVE(VisitForValue(clause->label())); |
| 3398 HValue* label_value = Pop(); | 3398 HValue* label_value = Pop(); |
| 3399 | 3399 |
| 3400 HBasicBlock* next_test_block = graph()->CreateBasicBlock(); | 3400 HBasicBlock* next_test_block = graph()->CreateBasicBlock(); |
| 3401 HBasicBlock* body_block = graph()->CreateBasicBlock(); | 3401 HBasicBlock* body_block = graph()->CreateBasicBlock(); |
| 3402 | 3402 |
| 3403 HControlInstruction* compare; | 3403 HControlInstruction* compare; |
| 3404 | 3404 |
| 3405 if (stmt->switch_type() == SwitchStatement::SMI_SWITCH) { | 3405 if (stmt->switch_type() == SwitchStatement::SMI_SWITCH) { |
| 3406 if (!clause->compare_type()->Is(Type::Smi())) { | 3406 if (!clause->compare_type()->Is(Type::Smi())) { |
| 3407 Add<HDeoptimize>("Non-smi switch type", Deoptimizer::SOFT); | 3407 Add<HDeoptimize>("Non-smi switch type", Deoptimizer::SOFT); |
| 3408 } | 3408 } |
| 3409 | 3409 |
| 3410 HCompareNumericAndBranch* compare_ = | 3410 HCompareNumericAndBranch* compare_ = |
| 3411 new(zone()) HCompareNumericAndBranch(tag_value, | 3411 New<HCompareNumericAndBranch>(tag_value, |
| 3412 label_value, | 3412 label_value, |
| 3413 Token::EQ_STRICT); | 3413 Token::EQ_STRICT); |
| 3414 compare_->set_observed_input_representation( | 3414 compare_->set_observed_input_representation( |
| 3415 Representation::Smi(), Representation::Smi()); | 3415 Representation::Smi(), Representation::Smi()); |
| 3416 compare = compare_; | 3416 compare = compare_; |
| 3417 } else { | 3417 } else { |
| 3418 compare = new(zone()) HStringCompareAndBranch(context, tag_value, | 3418 compare = new(zone()) HStringCompareAndBranch(context, tag_value, |
| 3419 label_value, | 3419 label_value, |
| 3420 Token::EQ_STRICT); | 3420 Token::EQ_STRICT); |
| 3421 } | 3421 } |
| 3422 | 3422 |
| 3423 compare->SetSuccessorAt(0, body_block); | 3423 compare->SetSuccessorAt(0, body_block); |
| (...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3687 HForInCacheArray::cast(array)->set_index_cache( | 3687 HForInCacheArray::cast(array)->set_index_cache( |
| 3688 HForInCacheArray::cast(index_cache)); | 3688 HForInCacheArray::cast(index_cache)); |
| 3689 | 3689 |
| 3690 HBasicBlock* loop_entry = osr_->BuildPossibleOsrLoopEntry(stmt); | 3690 HBasicBlock* loop_entry = osr_->BuildPossibleOsrLoopEntry(stmt); |
| 3691 | 3691 |
| 3692 HValue* index = environment()->ExpressionStackAt(0); | 3692 HValue* index = environment()->ExpressionStackAt(0); |
| 3693 HValue* limit = environment()->ExpressionStackAt(1); | 3693 HValue* limit = environment()->ExpressionStackAt(1); |
| 3694 | 3694 |
| 3695 // Check that we still have more keys. | 3695 // Check that we still have more keys. |
| 3696 HCompareNumericAndBranch* compare_index = | 3696 HCompareNumericAndBranch* compare_index = |
| 3697 new(zone()) HCompareNumericAndBranch(index, limit, Token::LT); | 3697 New<HCompareNumericAndBranch>(index, limit, Token::LT); |
| 3698 compare_index->set_observed_input_representation( | 3698 compare_index->set_observed_input_representation( |
| 3699 Representation::Smi(), Representation::Smi()); | 3699 Representation::Smi(), Representation::Smi()); |
| 3700 | 3700 |
| 3701 HBasicBlock* loop_body = graph()->CreateBasicBlock(); | 3701 HBasicBlock* loop_body = graph()->CreateBasicBlock(); |
| 3702 HBasicBlock* loop_successor = graph()->CreateBasicBlock(); | 3702 HBasicBlock* loop_successor = graph()->CreateBasicBlock(); |
| 3703 | 3703 |
| 3704 compare_index->SetSuccessorAt(0, loop_body); | 3704 compare_index->SetSuccessorAt(0, loop_body); |
| 3705 compare_index->SetSuccessorAt(1, loop_successor); | 3705 compare_index->SetSuccessorAt(1, loop_successor); |
| 3706 current_block()->Finish(compare_index); | 3706 current_block()->Finish(compare_index); |
| 3707 | 3707 |
| (...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4057 *accessors = Handle<AccessorPair>::cast(callback); | 4057 *accessors = Handle<AccessorPair>::cast(callback); |
| 4058 *holder = Handle<JSObject>(lookup.holder()); | 4058 *holder = Handle<JSObject>(lookup.holder()); |
| 4059 return true; | 4059 return true; |
| 4060 } | 4060 } |
| 4061 | 4061 |
| 4062 // We haven't found a JavaScript accessor anywhere. | 4062 // We haven't found a JavaScript accessor anywhere. |
| 4063 return false; | 4063 return false; |
| 4064 } | 4064 } |
| 4065 | 4065 |
| 4066 | 4066 |
| 4067 static bool LookupGetter(Handle<Map> map, | |
| 4068 Handle<String> name, | |
| 4069 Handle<JSFunction>* getter, | |
| 4070 Handle<JSObject>* holder) { | |
| 4071 Handle<AccessorPair> accessors; | |
| 4072 if (LookupAccessorPair(map, name, &accessors, holder) && | |
| 4073 accessors->getter()->IsJSFunction()) { | |
| 4074 *getter = Handle<JSFunction>(JSFunction::cast(accessors->getter())); | |
| 4075 return true; | |
| 4076 } | |
| 4077 return false; | |
| 4078 } | |
| 4079 | |
| 4080 | |
| 4081 static bool LookupSetter(Handle<Map> map, | 4067 static bool LookupSetter(Handle<Map> map, |
| 4082 Handle<String> name, | 4068 Handle<String> name, |
| 4083 Handle<JSFunction>* setter, | 4069 Handle<JSFunction>* setter, |
| 4084 Handle<JSObject>* holder) { | 4070 Handle<JSObject>* holder) { |
| 4085 Handle<AccessorPair> accessors; | 4071 Handle<AccessorPair> accessors; |
| 4086 if (LookupAccessorPair(map, name, &accessors, holder) && | 4072 if (LookupAccessorPair(map, name, &accessors, holder) && |
| 4087 accessors->setter()->IsJSFunction()) { | 4073 accessors->setter()->IsJSFunction()) { |
| 4088 *setter = Handle<JSFunction>(JSFunction::cast(accessors->setter())); | 4074 *setter = Handle<JSFunction>(JSFunction::cast(accessors->setter())); |
| 4089 return true; | 4075 return true; |
| 4090 } | 4076 } |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4185 int flags = expr->fast_elements() | 4171 int flags = expr->fast_elements() |
| 4186 ? ObjectLiteral::kFastElements : ObjectLiteral::kNoFlags; | 4172 ? ObjectLiteral::kFastElements : ObjectLiteral::kNoFlags; |
| 4187 flags |= expr->has_function() | 4173 flags |= expr->has_function() |
| 4188 ? ObjectLiteral::kHasFunction : ObjectLiteral::kNoFlags; | 4174 ? ObjectLiteral::kHasFunction : ObjectLiteral::kNoFlags; |
| 4189 | 4175 |
| 4190 Add<HPushArgument>(Add<HConstant>(closure_literals)); | 4176 Add<HPushArgument>(Add<HConstant>(closure_literals)); |
| 4191 Add<HPushArgument>(Add<HConstant>(literal_index)); | 4177 Add<HPushArgument>(Add<HConstant>(literal_index)); |
| 4192 Add<HPushArgument>(Add<HConstant>(constant_properties)); | 4178 Add<HPushArgument>(Add<HConstant>(constant_properties)); |
| 4193 Add<HPushArgument>(Add<HConstant>(flags)); | 4179 Add<HPushArgument>(Add<HConstant>(flags)); |
| 4194 | 4180 |
| 4195 Runtime::FunctionId function_id = | 4181 Runtime::FunctionId function_id = Runtime::kCreateObjectLiteral; |
| 4196 (expr->depth() > 1 || expr->may_store_doubles()) | |
| 4197 ? Runtime::kCreateObjectLiteral : Runtime::kCreateObjectLiteralShallow; | |
| 4198 literal = Add<HCallRuntime>(isolate()->factory()->empty_string(), | 4182 literal = Add<HCallRuntime>(isolate()->factory()->empty_string(), |
| 4199 Runtime::FunctionForId(function_id), | 4183 Runtime::FunctionForId(function_id), |
| 4200 4); | 4184 4); |
| 4201 } | 4185 } |
| 4202 | 4186 |
| 4203 // The object is expected in the bailout environment during computation | 4187 // The object is expected in the bailout environment during computation |
| 4204 // of the property values and is the value of the entire expression. | 4188 // of the property values and is the value of the entire expression. |
| 4205 Push(literal); | 4189 Push(literal); |
| 4206 | 4190 |
| 4207 expr->CalculateEmitStore(zone()); | 4191 expr->CalculateEmitStore(zone()); |
| (...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4538 if (ComputeLoadStoreField(map, name, &lookup, true)) { | 4522 if (ComputeLoadStoreField(map, name, &lookup, true)) { |
| 4539 HCheckMaps* checked_object = AddCheckMap(object, map); | 4523 HCheckMaps* checked_object = AddCheckMap(object, map); |
| 4540 return BuildStoreNamedField(checked_object, name, value, map, &lookup); | 4524 return BuildStoreNamedField(checked_object, name, value, map, &lookup); |
| 4541 } | 4525 } |
| 4542 | 4526 |
| 4543 // No luck, do a generic store. | 4527 // No luck, do a generic store. |
| 4544 return BuildStoreNamedGeneric(object, name, value); | 4528 return BuildStoreNamedGeneric(object, name, value); |
| 4545 } | 4529 } |
| 4546 | 4530 |
| 4547 | 4531 |
| 4548 static bool CanLoadPropertyFromPrototype(Handle<Map> map, | 4532 bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatibleForLoad( |
| 4549 Handle<Name> name, | 4533 PropertyAccessInfo* info) { |
| 4550 LookupResult* lookup) { | 4534 if (!CanInlinePropertyAccess(*map_)) return false; |
| 4551 if (!CanInlinePropertyAccess(*map)) return false; | 4535 |
| 4552 map->LookupDescriptor(NULL, *name, lookup); | 4536 if (!LookupDescriptor()) return false; |
| 4553 if (lookup->IsFound()) return false; | 4537 |
| 4538 if (!lookup_.IsFound()) { |
| 4539 return (!info->lookup_.IsFound() || !info->holder_.is_null()) && |
| 4540 map_->prototype() == info->map_->prototype(); |
| 4541 } |
| 4542 |
| 4543 if (lookup_.IsPropertyCallbacks()) { |
| 4544 return accessor_.is_identical_to(info->accessor_); |
| 4545 } |
| 4546 |
| 4547 if (lookup_.IsConstant()) { |
| 4548 return constant_.is_identical_to(info->constant_); |
| 4549 } |
| 4550 |
| 4551 ASSERT(lookup_.IsField()); |
| 4552 if (!info->lookup_.IsField()) return false; |
| 4553 |
| 4554 Representation r = access_.representation(); |
| 4555 if (!info->access_.representation().IsCompatibleForLoad(r)) return false; |
| 4556 if (info->access_.offset() != access_.offset()) return false; |
| 4557 if (info->access_.IsInobject() != access_.IsInobject()) return false; |
| 4558 info->GeneralizeRepresentation(r); |
| 4554 return true; | 4559 return true; |
| 4555 } | 4560 } |
| 4556 | 4561 |
| 4557 | 4562 |
| 4558 HInstruction* HOptimizedGraphBuilder::TryLoadPolymorphicAsMonomorphic( | 4563 bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupDescriptor() { |
| 4559 HValue* object, | 4564 map_->LookupDescriptor(NULL, *name_, &lookup_); |
| 4560 SmallMapList* types, | 4565 return LoadResult(map_); |
| 4561 Handle<String> name) { | |
| 4562 // Use monomorphic load if property lookup results in the same field index | |
| 4563 // for all maps. Requires special map check on the set of all handled maps. | |
| 4564 if (types->length() > kMaxLoadPolymorphism) return NULL; | |
| 4565 | |
| 4566 LookupResult lookup(isolate()); | |
| 4567 int count; | |
| 4568 HObjectAccess access = HObjectAccess::ForMap(); // initial value unused. | |
| 4569 for (count = 0; count < types->length(); ++count) { | |
| 4570 Handle<Map> map = types->at(count); | |
| 4571 if (!ComputeLoadStoreField(map, name, &lookup, false)) break; | |
| 4572 | |
| 4573 HObjectAccess new_access = HObjectAccess::ForField(map, &lookup, name); | |
| 4574 | |
| 4575 if (count == 0) { | |
| 4576 // First time through the loop; set access and representation. | |
| 4577 access = new_access; | |
| 4578 } else if (!access.representation().IsCompatibleForLoad( | |
| 4579 new_access.representation())) { | |
| 4580 // Representations did not match. | |
| 4581 break; | |
| 4582 } else if (access.offset() != new_access.offset()) { | |
| 4583 // Offsets did not match. | |
| 4584 break; | |
| 4585 } else if (access.IsInobject() != new_access.IsInobject()) { | |
| 4586 // In-objectness did not match. | |
| 4587 break; | |
| 4588 } | |
| 4589 access = access.WithRepresentation( | |
| 4590 access.representation().generalize(new_access.representation())); | |
| 4591 } | |
| 4592 | |
| 4593 if (count == types->length()) { | |
| 4594 // Everything matched; can use monomorphic load. | |
| 4595 BuildCheckHeapObject(object); | |
| 4596 HCheckMaps* checked_object = Add<HCheckMaps>(object, types); | |
| 4597 return BuildLoadNamedField(checked_object, access); | |
| 4598 } | |
| 4599 | |
| 4600 if (count != 0) return NULL; | |
| 4601 | |
| 4602 // Second chance: the property is on the prototype and all maps have the | |
| 4603 // same prototype. | |
| 4604 Handle<Map> map(types->at(0)); | |
| 4605 if (!CanLoadPropertyFromPrototype(map, name, &lookup)) return NULL; | |
| 4606 | |
| 4607 Handle<Object> prototype(map->prototype(), isolate()); | |
| 4608 for (count = 1; count < types->length(); ++count) { | |
| 4609 Handle<Map> test_map(types->at(count)); | |
| 4610 if (!CanLoadPropertyFromPrototype(test_map, name, &lookup)) return NULL; | |
| 4611 if (test_map->prototype() != *prototype) return NULL; | |
| 4612 } | |
| 4613 | |
| 4614 LookupInPrototypes(map, name, &lookup); | |
| 4615 if (!lookup.IsField()) return NULL; | |
| 4616 | |
| 4617 BuildCheckHeapObject(object); | |
| 4618 Add<HCheckMaps>(object, types); | |
| 4619 | |
| 4620 Handle<JSObject> holder(lookup.holder()); | |
| 4621 Handle<Map> holder_map(holder->map()); | |
| 4622 HValue* checked_holder = BuildCheckPrototypeMaps( | |
| 4623 Handle<JSObject>::cast(prototype), holder); | |
| 4624 return BuildLoadNamedField(checked_holder, | |
| 4625 HObjectAccess::ForField(holder_map, &lookup, name)); | |
| 4626 } | 4566 } |
| 4627 | 4567 |
| 4628 | 4568 |
| 4629 // Returns true if an instance of this map can never find a property with this | 4569 bool HOptimizedGraphBuilder::PropertyAccessInfo::LoadResult(Handle<Map> map) { |
| 4630 // name in its prototype chain. This means all prototypes up to the top are | 4570 if (lookup_.IsField()) { |
| 4631 // fast and don't have the name in them. It would be good if we could optimize | 4571 access_ = HObjectAccess::ForField(map, &lookup_, name_); |
| 4632 // polymorphic loads where the property is sometimes found in the prototype | 4572 } else if (lookup_.IsPropertyCallbacks()) { |
| 4633 // chain. | 4573 Handle<Object> callback(lookup_.GetValueFromMap(*map), isolate()); |
| 4634 static bool PrototypeChainCanNeverResolve( | 4574 if (!callback->IsAccessorPair()) return false; |
| 4635 Handle<Map> map, Handle<String> name) { | 4575 Object* getter = Handle<AccessorPair>::cast(callback)->getter(); |
| 4636 Isolate* isolate = map->GetIsolate(); | 4576 if (!getter->IsJSFunction()) return false; |
| 4637 Object* current = map->prototype(); | 4577 accessor_ = handle(JSFunction::cast(getter)); |
| 4638 while (current != isolate->heap()->null_value()) { | 4578 } else if (lookup_.IsConstant()) { |
| 4639 if (current->IsJSGlobalProxy() || | 4579 constant_ = handle(lookup_.GetConstantFromMap(*map), isolate()); |
| 4640 current->IsGlobalObject() || | 4580 } |
| 4641 !current->IsJSObject() || | 4581 |
| 4642 !CanInlinePropertyAccess(JSObject::cast(current)->map()) || | 4582 return true; |
| 4643 JSObject::cast(current)->IsAccessCheckNeeded()) { | 4583 } |
| 4584 |
| 4585 |
| 4586 bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() { |
| 4587 Handle<Map> map = map_; |
| 4588 while (map->prototype()->IsJSObject()) { |
| 4589 holder_ = handle(JSObject::cast(map->prototype())); |
| 4590 map = Handle<Map>(holder_->map()); |
| 4591 if (!CanInlinePropertyAccess(*map)) { |
| 4592 lookup_.NotFound(); |
| 4644 return false; | 4593 return false; |
| 4645 } | 4594 } |
| 4595 map->LookupDescriptor(*holder_, *name_, &lookup_); |
| 4596 if (lookup_.IsFound()) return LoadResult(map); |
| 4597 } |
| 4598 lookup_.NotFound(); |
| 4599 return true; |
| 4600 } |
| 4646 | 4601 |
| 4647 LookupResult lookup(isolate); | 4602 |
| 4648 Map* map = JSObject::cast(current)->map(); | 4603 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadMonomorphic() { |
| 4649 map->LookupDescriptor(NULL, *name, &lookup); | 4604 if (!CanInlinePropertyAccess(*map_)) return IsStringLength(); |
| 4650 if (lookup.IsFound()) return false; | 4605 if (IsArrayLength()) return true; |
| 4651 if (!lookup.IsCacheable()) return false; | 4606 if (!LookupDescriptor()) return false; |
| 4652 current = JSObject::cast(current)->GetPrototype(); | 4607 if (lookup_.IsFound()) return true; |
| 4608 return LookupInPrototypes(); |
| 4609 } |
| 4610 |
| 4611 |
| 4612 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadAsMonomorphic( |
| 4613 SmallMapList* types) { |
| 4614 ASSERT(map_.is_identical_to(types->first())); |
| 4615 if (!CanLoadMonomorphic()) return false; |
| 4616 if (types->length() > kMaxLoadPolymorphism) return false; |
| 4617 |
| 4618 if (IsStringLength()) { |
| 4619 for (int i = 1; i < types->length(); ++i) { |
| 4620 if (types->at(i)->instance_type() >= FIRST_NONSTRING_TYPE) return false; |
| 4621 } |
| 4622 return true; |
| 4653 } | 4623 } |
| 4624 |
| 4625 if (IsArrayLength()) { |
| 4626 bool is_fast = IsFastElementsKind(map_->elements_kind()); |
| 4627 for (int i = 1; i < types->length(); ++i) { |
| 4628 Handle<Map> test_map = types->at(i); |
| 4629 if (test_map->instance_type() != JS_ARRAY_TYPE) return false; |
| 4630 if (IsFastElementsKind(test_map->elements_kind()) != is_fast) { |
| 4631 return false; |
| 4632 } |
| 4633 } |
| 4634 return true; |
| 4635 } |
| 4636 |
| 4637 if (IsTypedArrayLength()) { |
| 4638 for (int i = 1; i < types->length(); ++i) { |
| 4639 if (types->at(i)->instance_type() != JS_TYPED_ARRAY_TYPE) return false; |
| 4640 } |
| 4641 return true; |
| 4642 } |
| 4643 |
| 4644 for (int i = 1; i < types->length(); ++i) { |
| 4645 PropertyAccessInfo test_info(isolate(), types->at(i), name_); |
| 4646 if (!test_info.IsCompatibleForLoad(this)) return false; |
| 4647 } |
| 4648 |
| 4654 return true; | 4649 return true; |
| 4655 } | 4650 } |
| 4656 | 4651 |
| 4657 | 4652 |
| 4653 HInstruction* HOptimizedGraphBuilder::BuildLoadMonomorphic( |
| 4654 PropertyAccessInfo* info, |
| 4655 HValue* object, |
| 4656 HInstruction* checked_object, |
| 4657 BailoutId ast_id, |
| 4658 BailoutId return_id, |
| 4659 bool can_inline_accessor) { |
| 4660 if (info->IsStringLength()) { |
| 4661 return New<HLoadNamedField>( |
| 4662 checked_object, HObjectAccess::ForStringLength()); |
| 4663 } |
| 4664 |
| 4665 if (info->IsArrayLength()) { |
| 4666 return New<HLoadNamedField>( |
| 4667 checked_object, HObjectAccess::ForArrayLength( |
| 4668 info->map()->elements_kind())); |
| 4669 } |
| 4670 |
| 4671 if (info->IsTypedArrayLength()) { |
| 4672 return New<HLoadNamedField>( |
| 4673 checked_object, HObjectAccess::ForTypedArrayLength()); |
| 4674 } |
| 4675 |
| 4676 HValue* checked_holder = checked_object; |
| 4677 if (info->has_holder()) { |
| 4678 Handle<JSObject> prototype(JSObject::cast(info->map()->prototype())); |
| 4679 checked_holder = BuildCheckPrototypeMaps(prototype, info->holder()); |
| 4680 } |
| 4681 |
| 4682 if (!info->lookup()->IsFound()) return graph()->GetConstantUndefined(); |
| 4683 |
| 4684 if (info->lookup()->IsField()) { |
| 4685 return BuildLoadNamedField(checked_holder, info->access()); |
| 4686 } |
| 4687 |
| 4688 if (info->lookup()->IsPropertyCallbacks()) { |
| 4689 Push(checked_object); |
| 4690 if (FLAG_inline_accessors && |
| 4691 can_inline_accessor && |
| 4692 TryInlineGetter(info->accessor(), ast_id, return_id)) { |
| 4693 return NULL; |
| 4694 } |
| 4695 Add<HPushArgument>(Pop()); |
| 4696 return new(zone()) HCallConstantFunction(info->accessor(), 1); |
| 4697 } |
| 4698 |
| 4699 ASSERT(info->lookup()->IsConstant()); |
| 4700 return New<HConstant>(info->constant()); |
| 4701 } |
| 4702 |
| 4703 |
| 4658 void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField( | 4704 void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField( |
| 4659 int position, | 4705 int position, |
| 4660 BailoutId ast_id, | 4706 BailoutId ast_id, |
| 4707 BailoutId return_id, |
| 4661 HValue* object, | 4708 HValue* object, |
| 4662 SmallMapList* types, | 4709 SmallMapList* types, |
| 4663 Handle<String> name) { | 4710 Handle<String> name) { |
| 4664 HInstruction* instr = TryLoadPolymorphicAsMonomorphic(object, types, name); | |
| 4665 if (instr != NULL) { | |
| 4666 instr->set_position(position); | |
| 4667 return ast_context()->ReturnInstruction(instr, ast_id); | |
| 4668 } | |
| 4669 | |
| 4670 // Something did not match; must use a polymorphic load. | 4711 // Something did not match; must use a polymorphic load. |
| 4671 int count = 0; | 4712 int count = 0; |
| 4672 HBasicBlock* join = NULL; | 4713 HBasicBlock* join = NULL; |
| 4673 for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) { | 4714 for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) { |
| 4674 Handle<Map> map = types->at(i); | 4715 PropertyAccessInfo info(isolate(), types->at(i), name); |
| 4675 LookupResult lookup(isolate()); | 4716 if (info.CanLoadMonomorphic()) { |
| 4676 if (ComputeLoadStoreField(map, name, &lookup, false) || | |
| 4677 (lookup.IsCacheable() && | |
| 4678 CanInlinePropertyAccess(*map) && | |
| 4679 (lookup.IsConstant() || | |
| 4680 (!lookup.IsFound() && | |
| 4681 PrototypeChainCanNeverResolve(map, name))))) { | |
| 4682 if (count == 0) { | 4717 if (count == 0) { |
| 4683 BuildCheckHeapObject(object); | 4718 BuildCheckHeapObject(object); |
| 4684 join = graph()->CreateBasicBlock(); | 4719 join = graph()->CreateBasicBlock(); |
| 4685 } | 4720 } |
| 4686 ++count; | 4721 ++count; |
| 4687 HBasicBlock* if_true = graph()->CreateBasicBlock(); | 4722 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
| 4688 HBasicBlock* if_false = graph()->CreateBasicBlock(); | 4723 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
| 4689 HCompareMap* compare = | 4724 HCompareMap* compare = New<HCompareMap>( |
| 4690 new(zone()) HCompareMap(object, map, if_true, if_false); | 4725 object, info.map(), if_true, if_false); |
| 4691 current_block()->Finish(compare); | 4726 current_block()->Finish(compare); |
| 4692 | 4727 |
| 4693 set_current_block(if_true); | 4728 set_current_block(if_true); |
| 4694 | 4729 |
| 4695 // TODO(verwaest): Merge logic with BuildLoadNamedMonomorphic. | 4730 HInstruction* load = BuildLoadMonomorphic( |
| 4696 if (lookup.IsField()) { | 4731 &info, object, compare, ast_id, return_id, FLAG_polymorphic_inlining); |
| 4697 HObjectAccess access = HObjectAccess::ForField(map, &lookup, name); | 4732 if (load == NULL) { |
| 4698 HLoadNamedField* load = BuildLoadNamedField(compare, access); | 4733 if (HasStackOverflow()) return; |
| 4699 load->set_position(position); | 4734 } else { |
| 4700 AddInstruction(load); | 4735 if (!load->IsLinked()) { |
| 4736 load->set_position(position); |
| 4737 AddInstruction(load); |
| 4738 } |
| 4701 if (!ast_context()->IsEffect()) Push(load); | 4739 if (!ast_context()->IsEffect()) Push(load); |
| 4702 } else if (lookup.IsConstant()) { | |
| 4703 Handle<Object> constant(lookup.GetConstantFromMap(*map), isolate()); | |
| 4704 HConstant* hconstant = Add<HConstant>(constant); | |
| 4705 if (!ast_context()->IsEffect()) Push(hconstant); | |
| 4706 } else { | |
| 4707 ASSERT(!lookup.IsFound()); | |
| 4708 if (map->prototype()->IsJSObject()) { | |
| 4709 Handle<JSObject> prototype(JSObject::cast(map->prototype())); | |
| 4710 Handle<JSObject> holder = prototype; | |
| 4711 while (holder->map()->prototype()->IsJSObject()) { | |
| 4712 holder = handle(JSObject::cast(holder->map()->prototype())); | |
| 4713 } | |
| 4714 BuildCheckPrototypeMaps(prototype, holder); | |
| 4715 } | |
| 4716 if (!ast_context()->IsEffect()) Push(graph()->GetConstantUndefined()); | |
| 4717 } | 4740 } |
| 4718 | 4741 |
| 4719 current_block()->Goto(join); | 4742 if (current_block() != NULL) current_block()->Goto(join); |
| 4720 set_current_block(if_false); | 4743 set_current_block(if_false); |
| 4721 } | 4744 } |
| 4722 } | 4745 } |
| 4723 | 4746 |
| 4724 // Finish up. Unconditionally deoptimize if we've handled all the maps we | 4747 // Finish up. Unconditionally deoptimize if we've handled all the maps we |
| 4725 // know about and do not want to handle ones we've never seen. Otherwise | 4748 // know about and do not want to handle ones we've never seen. Otherwise |
| 4726 // use a generic IC. | 4749 // use a generic IC. |
| 4727 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { | 4750 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { |
| 4751 // Because the deopt may be the only path in the polymorphic load, make sure |
| 4752 // that the environment stack matches the depth on deopt that it otherwise |
| 4753 // would have had after a successful load. |
| 4754 if (!ast_context()->IsEffect()) Push(graph()->GetConstant0()); |
| 4728 FinishExitWithHardDeoptimization("Unknown map in polymorphic load", join); | 4755 FinishExitWithHardDeoptimization("Unknown map in polymorphic load", join); |
| 4729 } else { | 4756 } else { |
| 4730 HValue* context = environment()->context(); | 4757 HValue* context = environment()->context(); |
| 4731 HInstruction* load = new(zone()) HLoadNamedGeneric(context, object, name); | 4758 HInstruction* load = new(zone()) HLoadNamedGeneric(context, object, name); |
| 4732 load->set_position(position); | 4759 load->set_position(position); |
| 4733 AddInstruction(load); | 4760 AddInstruction(load); |
| 4734 if (!ast_context()->IsEffect()) Push(load); | 4761 if (!ast_context()->IsEffect()) Push(load); |
| 4735 | 4762 |
| 4736 if (join != NULL) { | 4763 if (join != NULL) { |
| 4737 current_block()->Goto(join); | 4764 current_block()->Goto(join); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 4753 int position, | 4780 int position, |
| 4754 BailoutId assignment_id, | 4781 BailoutId assignment_id, |
| 4755 HValue* object, | 4782 HValue* object, |
| 4756 HValue* value, | 4783 HValue* value, |
| 4757 SmallMapList* types, | 4784 SmallMapList* types, |
| 4758 Handle<String> name) { | 4785 Handle<String> name) { |
| 4759 // Use monomorphic store if property lookup results in the same field index | 4786 // Use monomorphic store if property lookup results in the same field index |
| 4760 // for all maps. Requires special map check on the set of all handled maps. | 4787 // for all maps. Requires special map check on the set of all handled maps. |
| 4761 if (types->length() > kMaxStorePolymorphism) return false; | 4788 if (types->length() > kMaxStorePolymorphism) return false; |
| 4762 | 4789 |
| 4763 // TODO(verwaest): Merge the checking logic with the code in | |
| 4764 // TryLoadPolymorphicAsMonomorphic. | |
| 4765 LookupResult lookup(isolate()); | 4790 LookupResult lookup(isolate()); |
| 4766 int count; | 4791 int count; |
| 4767 Representation representation = Representation::None(); | 4792 Representation representation = Representation::None(); |
| 4768 HObjectAccess access = HObjectAccess::ForMap(); // initial value unused. | 4793 HObjectAccess access = HObjectAccess::ForMap(); // initial value unused. |
| 4769 for (count = 0; count < types->length(); ++count) { | 4794 for (count = 0; count < types->length(); ++count) { |
| 4770 Handle<Map> map = types->at(count); | 4795 Handle<Map> map = types->at(count); |
| 4771 // Pass false to ignore transitions. | 4796 // Pass false to ignore transitions. |
| 4772 if (!ComputeLoadStoreField(map, name, &lookup, false)) break; | 4797 if (!ComputeLoadStoreField(map, name, &lookup, false)) break; |
| 4773 ASSERT(!map->is_observed()); | 4798 ASSERT(!map->is_observed()); |
| 4774 | 4799 |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4832 Handle<Map> map = types->at(i); | 4857 Handle<Map> map = types->at(i); |
| 4833 LookupResult lookup(isolate()); | 4858 LookupResult lookup(isolate()); |
| 4834 if (ComputeLoadStoreField(map, name, &lookup, true)) { | 4859 if (ComputeLoadStoreField(map, name, &lookup, true)) { |
| 4835 if (count == 0) { | 4860 if (count == 0) { |
| 4836 BuildCheckHeapObject(object); | 4861 BuildCheckHeapObject(object); |
| 4837 join = graph()->CreateBasicBlock(); | 4862 join = graph()->CreateBasicBlock(); |
| 4838 } | 4863 } |
| 4839 ++count; | 4864 ++count; |
| 4840 HBasicBlock* if_true = graph()->CreateBasicBlock(); | 4865 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
| 4841 HBasicBlock* if_false = graph()->CreateBasicBlock(); | 4866 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
| 4842 HCompareMap* compare = | 4867 HCompareMap* compare = New<HCompareMap>(object, map, if_true, if_false); |
| 4843 new(zone()) HCompareMap(object, map, if_true, if_false); | |
| 4844 current_block()->Finish(compare); | 4868 current_block()->Finish(compare); |
| 4845 | 4869 |
| 4846 set_current_block(if_true); | 4870 set_current_block(if_true); |
| 4847 HInstruction* instr; | 4871 HInstruction* instr; |
| 4848 CHECK_ALIVE(instr = BuildStoreNamedField( | 4872 CHECK_ALIVE(instr = BuildStoreNamedField( |
| 4849 compare, name, value, map, &lookup)); | 4873 compare, name, value, map, &lookup)); |
| 4850 instr->set_position(position); | 4874 instr->set_position(position); |
| 4851 // Goto will add the HSimulate for the store. | 4875 // Goto will add the HSimulate for the store. |
| 4852 AddInstruction(instr); | 4876 AddInstruction(instr); |
| 4853 if (!ast_context()->IsEffect()) Push(value); | 4877 if (!ast_context()->IsEffect()) Push(value); |
| (...skipping 499 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5353 HValue* object, | 5377 HValue* object, |
| 5354 Handle<Map> map, | 5378 Handle<Map> map, |
| 5355 Handle<JSFunction> getter, | 5379 Handle<JSFunction> getter, |
| 5356 Handle<JSObject> holder) { | 5380 Handle<JSObject> holder) { |
| 5357 AddCheckConstantFunction(holder, object, map); | 5381 AddCheckConstantFunction(holder, object, map); |
| 5358 Add<HPushArgument>(object); | 5382 Add<HPushArgument>(object); |
| 5359 return new(zone()) HCallConstantFunction(getter, 1); | 5383 return new(zone()) HCallConstantFunction(getter, 1); |
| 5360 } | 5384 } |
| 5361 | 5385 |
| 5362 | 5386 |
| 5363 HInstruction* HOptimizedGraphBuilder::BuildLoadNamedMonomorphic( | |
| 5364 HValue* object, | |
| 5365 Handle<String> name, | |
| 5366 Handle<Map> map) { | |
| 5367 // Handle a load from a known field. | |
| 5368 ASSERT(!map->is_dictionary_map()); | |
| 5369 | |
| 5370 // Handle access to various length properties | |
| 5371 if (name->Equals(isolate()->heap()->length_string())) { | |
| 5372 if (map->instance_type() == JS_ARRAY_TYPE) { | |
| 5373 HCheckMaps* checked_object = AddCheckMap(object, map); | |
| 5374 return New<HLoadNamedField>( | |
| 5375 checked_object, HObjectAccess::ForArrayLength(map->elements_kind())); | |
| 5376 } | |
| 5377 } | |
| 5378 | |
| 5379 LookupResult lookup(isolate()); | |
| 5380 map->LookupDescriptor(NULL, *name, &lookup); | |
| 5381 if (lookup.IsField()) { | |
| 5382 HCheckMaps* checked_object = AddCheckMap(object, map); | |
| 5383 ASSERT(map->IsJSObjectMap()); | |
| 5384 return BuildLoadNamedField( | |
| 5385 checked_object, HObjectAccess::ForField(map, &lookup, name)); | |
| 5386 } | |
| 5387 | |
| 5388 // Handle a load of a constant known function. | |
| 5389 if (lookup.IsConstant()) { | |
| 5390 AddCheckMap(object, map); | |
| 5391 Handle<Object> constant(lookup.GetConstantFromMap(*map), isolate()); | |
| 5392 return New<HConstant>(constant); | |
| 5393 } | |
| 5394 | |
| 5395 if (lookup.IsFound()) { | |
| 5396 // Cannot handle the property, do a generic load instead. | |
| 5397 HValue* context = environment()->context(); | |
| 5398 return new(zone()) HLoadNamedGeneric(context, object, name); | |
| 5399 } | |
| 5400 | |
| 5401 // Handle a load from a known field somewhere in the prototype chain. | |
| 5402 LookupInPrototypes(map, name, &lookup); | |
| 5403 if (lookup.IsField()) { | |
| 5404 Handle<JSObject> prototype(JSObject::cast(map->prototype())); | |
| 5405 Handle<JSObject> holder(lookup.holder()); | |
| 5406 Handle<Map> holder_map(holder->map()); | |
| 5407 AddCheckMap(object, map); | |
| 5408 HValue* checked_holder = BuildCheckPrototypeMaps(prototype, holder); | |
| 5409 return BuildLoadNamedField( | |
| 5410 checked_holder, HObjectAccess::ForField(holder_map, &lookup, name)); | |
| 5411 } | |
| 5412 | |
| 5413 // Handle a load of a constant function somewhere in the prototype chain. | |
| 5414 if (lookup.IsConstant()) { | |
| 5415 Handle<JSObject> prototype(JSObject::cast(map->prototype())); | |
| 5416 Handle<JSObject> holder(lookup.holder()); | |
| 5417 Handle<Map> holder_map(holder->map()); | |
| 5418 AddCheckMap(object, map); | |
| 5419 BuildCheckPrototypeMaps(prototype, holder); | |
| 5420 Handle<Object> constant(lookup.GetConstantFromMap(*holder_map), isolate()); | |
| 5421 return New<HConstant>(constant); | |
| 5422 } | |
| 5423 | |
| 5424 // No luck, do a generic load. | |
| 5425 HValue* context = environment()->context(); | |
| 5426 return new(zone()) HLoadNamedGeneric(context, object, name); | |
| 5427 } | |
| 5428 | |
| 5429 | |
| 5430 HInstruction* HOptimizedGraphBuilder::BuildLoadKeyedGeneric(HValue* object, | 5387 HInstruction* HOptimizedGraphBuilder::BuildLoadKeyedGeneric(HValue* object, |
| 5431 HValue* key) { | 5388 HValue* key) { |
| 5432 HValue* context = environment()->context(); | 5389 HValue* context = environment()->context(); |
| 5433 return new(zone()) HLoadKeyedGeneric(context, object, key); | 5390 return new(zone()) HLoadKeyedGeneric(context, object, key); |
| 5434 } | 5391 } |
| 5435 | 5392 |
| 5436 | 5393 |
| 5437 LoadKeyedHoleMode HOptimizedGraphBuilder::BuildKeyedHoleMode(Handle<Map> map) { | 5394 LoadKeyedHoleMode HOptimizedGraphBuilder::BuildKeyedHoleMode(Handle<Map> map) { |
| 5438 // Loads from a "stock" fast holey double arrays can elide the hole check. | 5395 // Loads from a "stock" fast holey double arrays can elide the hole check. |
| 5439 LoadKeyedHoleMode load_mode = NEVER_RETURN_HOLE; | 5396 LoadKeyedHoleMode load_mode = NEVER_RETURN_HOLE; |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5622 | 5579 |
| 5623 HBasicBlock* join = graph()->CreateBasicBlock(); | 5580 HBasicBlock* join = graph()->CreateBasicBlock(); |
| 5624 | 5581 |
| 5625 for (int i = 0; i < untransitionable_maps.length(); ++i) { | 5582 for (int i = 0; i < untransitionable_maps.length(); ++i) { |
| 5626 Handle<Map> map = untransitionable_maps[i]; | 5583 Handle<Map> map = untransitionable_maps[i]; |
| 5627 if (!map->IsJSObjectMap()) continue; | 5584 if (!map->IsJSObjectMap()) continue; |
| 5628 ElementsKind elements_kind = map->elements_kind(); | 5585 ElementsKind elements_kind = map->elements_kind(); |
| 5629 HBasicBlock* this_map = graph()->CreateBasicBlock(); | 5586 HBasicBlock* this_map = graph()->CreateBasicBlock(); |
| 5630 HBasicBlock* other_map = graph()->CreateBasicBlock(); | 5587 HBasicBlock* other_map = graph()->CreateBasicBlock(); |
| 5631 HCompareMap* mapcompare = | 5588 HCompareMap* mapcompare = |
| 5632 new(zone()) HCompareMap(object, map, this_map, other_map); | 5589 New<HCompareMap>(object, map, this_map, other_map); |
| 5633 current_block()->Finish(mapcompare); | 5590 current_block()->Finish(mapcompare); |
| 5634 | 5591 |
| 5635 set_current_block(this_map); | 5592 set_current_block(this_map); |
| 5636 HInstruction* access = NULL; | 5593 HInstruction* access = NULL; |
| 5637 if (IsDictionaryElementsKind(elements_kind)) { | 5594 if (IsDictionaryElementsKind(elements_kind)) { |
| 5638 access = is_store | 5595 access = is_store |
| 5639 ? AddInstruction(BuildStoreKeyedGeneric(object, key, val)) | 5596 ? AddInstruction(BuildStoreKeyedGeneric(object, key, val)) |
| 5640 : AddInstruction(BuildLoadKeyedGeneric(object, key)); | 5597 : AddInstruction(BuildLoadKeyedGeneric(object, key)); |
| 5641 } else { | 5598 } else { |
| 5642 ASSERT(IsFastElementsKind(elements_kind) || | 5599 ASSERT(IsFastElementsKind(elements_kind) || |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5819 HValue* key, | 5776 HValue* key, |
| 5820 int position) { | 5777 int position) { |
| 5821 ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED); | 5778 ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED); |
| 5822 Push(object); | 5779 Push(object); |
| 5823 if (key != NULL) Push(key); | 5780 if (key != NULL) Push(key); |
| 5824 BuildLoad(expr, position, expr->LoadId()); | 5781 BuildLoad(expr, position, expr->LoadId()); |
| 5825 } | 5782 } |
| 5826 | 5783 |
| 5827 | 5784 |
| 5828 static bool AreStringTypes(SmallMapList* types) { | 5785 static bool AreStringTypes(SmallMapList* types) { |
| 5829 if (types == NULL || types->length() == 0) return false; | |
| 5830 for (int i = 0; i < types->length(); i++) { | 5786 for (int i = 0; i < types->length(); i++) { |
| 5831 if (types->at(i)->instance_type() >= FIRST_NONSTRING_TYPE) return false; | 5787 if (types->at(i)->instance_type() >= FIRST_NONSTRING_TYPE) return false; |
| 5832 } | 5788 } |
| 5833 return true; | 5789 return true; |
| 5834 } | 5790 } |
| 5835 | 5791 |
| 5836 | 5792 |
| 5837 void HOptimizedGraphBuilder::BuildLoad(Property* expr, | 5793 void HOptimizedGraphBuilder::BuildLoad(Property* expr, |
| 5838 int position, | 5794 int position, |
| 5839 BailoutId ast_id) { | 5795 BailoutId ast_id) { |
| 5840 HInstruction* instr = NULL; | 5796 HInstruction* instr = NULL; |
| 5841 if (expr->IsStringAccess()) { | 5797 if (expr->IsStringAccess()) { |
| 5842 HValue* index = Pop(); | 5798 HValue* index = Pop(); |
| 5843 HValue* string = Pop(); | 5799 HValue* string = Pop(); |
| 5844 HValue* context = environment()->context(); | 5800 HValue* context = environment()->context(); |
| 5845 HInstruction* char_code = | 5801 HInstruction* char_code = |
| 5846 BuildStringCharCodeAt(string, index); | 5802 BuildStringCharCodeAt(string, index); |
| 5847 AddInstruction(char_code); | 5803 AddInstruction(char_code); |
| 5848 instr = HStringCharFromCode::New(zone(), context, char_code); | 5804 instr = HStringCharFromCode::New(zone(), context, char_code); |
| 5849 | 5805 |
| 5850 } else if (expr->IsFunctionPrototype()) { | 5806 } else if (expr->IsFunctionPrototype()) { |
| 5851 HValue* function = Pop(); | 5807 HValue* function = Pop(); |
| 5852 BuildCheckHeapObject(function); | 5808 BuildCheckHeapObject(function); |
| 5853 instr = new(zone()) HLoadFunctionPrototype(function); | 5809 instr = new(zone()) HLoadFunctionPrototype(function); |
| 5854 | 5810 |
| 5855 } else if (expr->key()->IsPropertyName()) { | 5811 } else if (expr->key()->IsPropertyName()) { |
| 5856 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); | 5812 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); |
| 5857 HValue* object = Top(); | 5813 HValue* object = Pop(); |
| 5858 | 5814 |
| 5859 SmallMapList* types; | 5815 SmallMapList* types; |
| 5860 bool monomorphic = ComputeReceiverTypes(expr, object, &types); | 5816 ComputeReceiverTypes(expr, object, &types); |
| 5817 ASSERT(types != NULL); |
| 5861 | 5818 |
| 5862 if (monomorphic) { | 5819 if (types->length() > 0) { |
| 5863 Handle<Map> map = types->first(); | 5820 PropertyAccessInfo info(isolate(), types->first(), name); |
| 5864 Handle<JSFunction> getter; | 5821 if (!info.CanLoadAsMonomorphic(types)) { |
| 5865 Handle<JSObject> holder; | 5822 return HandlePolymorphicLoadNamedField( |
| 5866 if (LookupGetter(map, name, &getter, &holder)) { | 5823 position, ast_id, expr->LoadId(), object, types, name); |
| 5867 AddCheckConstantFunction(holder, Top(), map); | 5824 } |
| 5868 if (FLAG_inline_accessors && | 5825 |
| 5869 TryInlineGetter(getter, ast_id, expr->LoadId())) { | 5826 BuildCheckHeapObject(object); |
| 5870 return; | 5827 HInstruction* checked_object; |
| 5871 } | 5828 if (AreStringTypes(types)) { |
| 5872 Add<HPushArgument>(Pop()); | 5829 checked_object = |
| 5873 instr = new(zone()) HCallConstantFunction(getter, 1); | 5830 AddInstruction(HCheckInstanceType::NewIsString(object, zone())); |
| 5874 } else { | 5831 } else { |
| 5875 instr = BuildLoadNamedMonomorphic(Pop(), name, map); | 5832 checked_object = Add<HCheckMaps>(object, types); |
| 5876 } | 5833 } |
| 5877 } else if (AreStringTypes(types) && | 5834 instr = BuildLoadMonomorphic( |
| 5878 name->Equals(isolate()->heap()->length_string())) { | 5835 &info, object, checked_object, ast_id, expr->LoadId()); |
| 5879 BuildCheckHeapObject(Pop()); | 5836 if (instr == NULL) return; |
| 5880 HValue* checked_object = | 5837 if (instr->IsLinked()) return ast_context()->ReturnValue(instr); |
| 5881 AddInstruction(HCheckInstanceType::NewIsString(object, zone())); | |
| 5882 instr = BuildLoadStringLength(object, checked_object); | |
| 5883 } else if (types != NULL && types->length() > 1) { | |
| 5884 return HandlePolymorphicLoadNamedField( | |
| 5885 position, ast_id, Pop(), types, name); | |
| 5886 } else { | 5838 } else { |
| 5887 instr = BuildLoadNamedGeneric(Pop(), name, expr); | 5839 instr = BuildLoadNamedGeneric(object, name, expr); |
| 5888 } | 5840 } |
| 5889 | 5841 |
| 5890 } else { | 5842 } else { |
| 5891 HValue* key = Pop(); | 5843 HValue* key = Pop(); |
| 5892 HValue* obj = Pop(); | 5844 HValue* obj = Pop(); |
| 5893 | 5845 |
| 5894 bool has_side_effects = false; | 5846 bool has_side_effects = false; |
| 5895 HValue* load = HandleKeyedElementAccess( | 5847 HValue* load = HandleKeyedElementAccess( |
| 5896 obj, key, NULL, expr, ast_id, position, | 5848 obj, key, NULL, expr, ast_id, position, |
| 5897 false, // is_store | 5849 false, // is_store |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6012 } | 5964 } |
| 6013 | 5965 |
| 6014 | 5966 |
| 6015 bool HOptimizedGraphBuilder::TryCallPolymorphicAsMonomorphic( | 5967 bool HOptimizedGraphBuilder::TryCallPolymorphicAsMonomorphic( |
| 6016 Call* expr, | 5968 Call* expr, |
| 6017 HValue* receiver, | 5969 HValue* receiver, |
| 6018 SmallMapList* types, | 5970 SmallMapList* types, |
| 6019 Handle<String> name) { | 5971 Handle<String> name) { |
| 6020 if (types->length() > kMaxCallPolymorphism) return false; | 5972 if (types->length() > kMaxCallPolymorphism) return false; |
| 6021 | 5973 |
| 6022 Handle<Map> map(types->at(0)); | 5974 PropertyAccessInfo info(isolate(), types->at(0), name); |
| 6023 LookupResult lookup(isolate()); | 5975 if (!info.CanLoadAsMonomorphic(types)) return false; |
| 6024 if (!CanLoadPropertyFromPrototype(map, name, &lookup)) return false; | 5976 if (!expr->ComputeTarget(info.map(), name)) return false; |
| 6025 | |
| 6026 Handle<Object> prototype(map->prototype(), isolate()); | |
| 6027 for (int count = 1; count < types->length(); ++count) { | |
| 6028 Handle<Map> test_map(types->at(count)); | |
| 6029 if (!CanLoadPropertyFromPrototype(test_map, name, &lookup)) return false; | |
| 6030 if (test_map->prototype() != *prototype) return false; | |
| 6031 } | |
| 6032 | |
| 6033 if (!expr->ComputeTarget(map, name)) return false; | |
| 6034 | 5977 |
| 6035 BuildCheckHeapObject(receiver); | 5978 BuildCheckHeapObject(receiver); |
| 6036 Add<HCheckMaps>(receiver, types); | 5979 Add<HCheckMaps>(receiver, types); |
| 6037 AddCheckPrototypeMaps(expr->holder(), map); | 5980 AddCheckPrototypeMaps(expr->holder(), info.map()); |
| 6038 if (FLAG_trace_inlining) { | 5981 if (FLAG_trace_inlining) { |
| 6039 Handle<JSFunction> caller = current_info()->closure(); | 5982 Handle<JSFunction> caller = current_info()->closure(); |
| 6040 SmartArrayPointer<char> caller_name = | 5983 SmartArrayPointer<char> caller_name = |
| 6041 caller->shared()->DebugName()->ToCString(); | 5984 caller->shared()->DebugName()->ToCString(); |
| 6042 PrintF("Trying to inline the polymorphic call to %s from %s\n", | 5985 PrintF("Trying to inline the polymorphic call to %s from %s\n", |
| 6043 *name->ToCString(), *caller_name); | 5986 *name->ToCString(), *caller_name); |
| 6044 } | 5987 } |
| 6045 | 5988 |
| 6046 if (!TryInlineCall(expr)) { | 5989 if (!TryInlineCall(expr)) { |
| 6047 int argument_count = expr->arguments()->length() + 1; // Includes receiver. | 5990 int argument_count = expr->arguments()->length() + 1; // Includes receiver. |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6104 for (int fn = 0; fn < ordered_functions; ++fn) { | 6047 for (int fn = 0; fn < ordered_functions; ++fn) { |
| 6105 int i = order[fn].index(); | 6048 int i = order[fn].index(); |
| 6106 Handle<Map> map = types->at(i); | 6049 Handle<Map> map = types->at(i); |
| 6107 if (fn == 0) { | 6050 if (fn == 0) { |
| 6108 // Only needed once. | 6051 // Only needed once. |
| 6109 join = graph()->CreateBasicBlock(); | 6052 join = graph()->CreateBasicBlock(); |
| 6110 if (handle_smi) { | 6053 if (handle_smi) { |
| 6111 HBasicBlock* empty_smi_block = graph()->CreateBasicBlock(); | 6054 HBasicBlock* empty_smi_block = graph()->CreateBasicBlock(); |
| 6112 HBasicBlock* not_smi_block = graph()->CreateBasicBlock(); | 6055 HBasicBlock* not_smi_block = graph()->CreateBasicBlock(); |
| 6113 number_block = graph()->CreateBasicBlock(); | 6056 number_block = graph()->CreateBasicBlock(); |
| 6114 HIsSmiAndBranch* smicheck = new(zone()) HIsSmiAndBranch(receiver); | 6057 current_block()->Finish(New<HIsSmiAndBranch>( |
| 6115 smicheck->SetSuccessorAt(0, empty_smi_block); | 6058 receiver, empty_smi_block, not_smi_block)); |
| 6116 smicheck->SetSuccessorAt(1, not_smi_block); | |
| 6117 current_block()->Finish(smicheck); | |
| 6118 empty_smi_block->Goto(number_block); | 6059 empty_smi_block->Goto(number_block); |
| 6119 set_current_block(not_smi_block); | 6060 set_current_block(not_smi_block); |
| 6120 } else { | 6061 } else { |
| 6121 BuildCheckHeapObject(receiver); | 6062 BuildCheckHeapObject(receiver); |
| 6122 } | 6063 } |
| 6123 } | 6064 } |
| 6124 HBasicBlock* if_true = graph()->CreateBasicBlock(); | 6065 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
| 6125 HBasicBlock* if_false = graph()->CreateBasicBlock(); | 6066 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
| 6126 HUnaryControlInstruction* compare; | 6067 HUnaryControlInstruction* compare; |
| 6127 | 6068 |
| 6128 if (handle_smi && map.is_identical_to(number_marker_map)) { | 6069 if (handle_smi && map.is_identical_to(number_marker_map)) { |
| 6129 compare = new(zone()) HCompareMap( | 6070 compare = New<HCompareMap>(receiver, heap_number_map, if_true, if_false); |
| 6130 receiver, heap_number_map, if_true, if_false); | |
| 6131 map = initial_number_map; | 6071 map = initial_number_map; |
| 6132 expr->set_number_check( | 6072 expr->set_number_check( |
| 6133 Handle<JSObject>(JSObject::cast(map->prototype()))); | 6073 Handle<JSObject>(JSObject::cast(map->prototype()))); |
| 6134 } else if (map.is_identical_to(string_marker_map)) { | 6074 } else if (map.is_identical_to(string_marker_map)) { |
| 6135 compare = new(zone()) HIsStringAndBranch(receiver); | 6075 compare = New<HIsStringAndBranch>(receiver, if_true, if_false); |
| 6136 compare->SetSuccessorAt(0, if_true); | |
| 6137 compare->SetSuccessorAt(1, if_false); | |
| 6138 map = initial_string_map; | 6076 map = initial_string_map; |
| 6139 expr->set_string_check( | 6077 expr->set_string_check( |
| 6140 Handle<JSObject>(JSObject::cast(map->prototype()))); | 6078 Handle<JSObject>(JSObject::cast(map->prototype()))); |
| 6141 } else { | 6079 } else { |
| 6142 compare = new(zone()) HCompareMap(receiver, map, if_true, if_false); | 6080 compare = New<HCompareMap>(receiver, map, if_true, if_false); |
| 6143 expr->set_map_check(); | 6081 expr->set_map_check(); |
| 6144 } | 6082 } |
| 6145 | 6083 |
| 6146 current_block()->Finish(compare); | 6084 current_block()->Finish(compare); |
| 6147 | 6085 |
| 6148 if (expr->check_type() == NUMBER_CHECK) { | 6086 if (expr->check_type() == NUMBER_CHECK) { |
| 6149 if_true->Goto(number_block); | 6087 if_true->Goto(number_block); |
| 6150 if_true = number_block; | 6088 if_true = number_block; |
| 6151 number_block->SetJoinId(expr->id()); | 6089 number_block->SetJoinId(expr->id()); |
| 6152 } | 6090 } |
| (...skipping 1487 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7640 return false; | 7578 return false; |
| 7641 } | 7579 } |
| 7642 return (sub->right() == sa); | 7580 return (sub->right() == sa); |
| 7643 } | 7581 } |
| 7644 | 7582 |
| 7645 | 7583 |
| 7646 // Checks if the left and the right are shift instructions with the oposite | 7584 // Checks if the left and the right are shift instructions with the oposite |
| 7647 // directions that can be replaced by one rotate right instruction or not. | 7585 // directions that can be replaced by one rotate right instruction or not. |
| 7648 // Returns the operand and the shift amount for the rotate instruction in the | 7586 // Returns the operand and the shift amount for the rotate instruction in the |
| 7649 // former case. | 7587 // former case. |
| 7650 bool HOptimizedGraphBuilder::MatchRotateRight(HValue* left, | 7588 bool HGraphBuilder::MatchRotateRight(HValue* left, |
| 7651 HValue* right, | 7589 HValue* right, |
| 7652 HValue** operand, | 7590 HValue** operand, |
| 7653 HValue** shift_amount) { | 7591 HValue** shift_amount) { |
| 7654 HShl* shl; | 7592 HShl* shl; |
| 7655 HShr* shr; | 7593 HShr* shr; |
| 7656 if (left->IsShl() && right->IsShr()) { | 7594 if (left->IsShl() && right->IsShr()) { |
| 7657 shl = HShl::cast(left); | 7595 shl = HShl::cast(left); |
| 7658 shr = HShr::cast(right); | 7596 shr = HShr::cast(right); |
| 7659 } else if (left->IsShr() && right->IsShl()) { | 7597 } else if (left->IsShr() && right->IsShl()) { |
| 7660 shl = HShl::cast(right); | 7598 shl = HShl::cast(right); |
| 7661 shr = HShr::cast(left); | 7599 shr = HShr::cast(left); |
| 7662 } else { | 7600 } else { |
| 7663 return false; | 7601 return false; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 7679 HConstant* right_const = HConstant::cast(right); | 7617 HConstant* right_const = HConstant::cast(right); |
| 7680 if (right_const->HasInteger32Value() && | 7618 if (right_const->HasInteger32Value() && |
| 7681 (right_const->Integer32Value() & 0x1f) != 0) { | 7619 (right_const->Integer32Value() & 0x1f) != 0) { |
| 7682 return false; | 7620 return false; |
| 7683 } | 7621 } |
| 7684 } | 7622 } |
| 7685 return true; | 7623 return true; |
| 7686 } | 7624 } |
| 7687 | 7625 |
| 7688 | 7626 |
| 7627 HValue* HGraphBuilder::EnforceNumberType(HValue* number, |
| 7628 Handle<Type> expected) { |
| 7629 if (expected->Is(Type::Smi())) { |
| 7630 return Add<HForceRepresentation>(number, Representation::Smi()); |
| 7631 } |
| 7632 if (expected->Is(Type::Signed32())) { |
| 7633 return Add<HForceRepresentation>(number, Representation::Integer32()); |
| 7634 } |
| 7635 return number; |
| 7636 } |
| 7637 |
| 7638 |
| 7689 HValue* HGraphBuilder::TruncateToNumber(HValue* value, Handle<Type>* expected) { | 7639 HValue* HGraphBuilder::TruncateToNumber(HValue* value, Handle<Type>* expected) { |
| 7690 if (value->IsConstant()) { | 7640 if (value->IsConstant()) { |
| 7691 HConstant* constant = HConstant::cast(value); | 7641 HConstant* constant = HConstant::cast(value); |
| 7692 Maybe<HConstant*> number = constant->CopyToTruncatedNumber(zone()); | 7642 Maybe<HConstant*> number = constant->CopyToTruncatedNumber(zone()); |
| 7693 if (number.has_value) { | 7643 if (number.has_value) { |
| 7694 *expected = handle(Type::Number(), isolate()); | 7644 *expected = handle(Type::Number(), isolate()); |
| 7695 return AddInstruction(number.value); | 7645 return AddInstruction(number.value); |
| 7696 } | 7646 } |
| 7697 } | 7647 } |
| 7698 | 7648 |
| 7649 Handle<Type> expected_type = *expected; |
| 7650 |
| 7651 // Separate the number type from the rest. |
| 7652 Handle<Type> expected_obj = handle(Type::Intersect( |
| 7653 expected_type, handle(Type::NonNumber(), isolate())), isolate()); |
| 7654 Handle<Type> expected_number = handle(Type::Intersect( |
| 7655 expected_type, handle(Type::Number(), isolate())), isolate()); |
| 7656 |
| 7657 // We expect to get a number. |
| 7658 // (We need to check first, since Type::None->Is(Type::Any()) == true. |
| 7659 if (expected_obj->Is(Type::None())) { |
| 7660 ASSERT(!expected_number->Is(Type::None())); |
| 7661 return value; |
| 7662 } |
| 7663 |
| 7664 if (expected_obj->Is(Type::Undefined())) { |
| 7665 // This is already done by HChange. |
| 7666 *expected = handle(Type::Union( |
| 7667 expected_number, handle(Type::Double(), isolate())), isolate()); |
| 7668 return value; |
| 7669 } |
| 7670 |
| 7671 if (expected_obj->Is(Type::Null())) { |
| 7672 *expected = handle(Type::Union( |
| 7673 expected_number, handle(Type::Smi(), isolate())), isolate()); |
| 7674 IfBuilder if_null(this); |
| 7675 if_null.If<HCompareObjectEqAndBranch>(value, |
| 7676 graph()->GetConstantNull()); |
| 7677 if_null.Then(); |
| 7678 Push(graph()->GetConstant0()); |
| 7679 if_null.Else(); |
| 7680 Push(value); |
| 7681 if_null.End(); |
| 7682 return Pop(); |
| 7683 } |
| 7684 |
| 7685 if (expected_obj->Is(Type::Boolean())) { |
| 7686 *expected = handle(Type::Union( |
| 7687 expected_number, handle(Type::Smi(), isolate())), isolate()); |
| 7688 IfBuilder if_true(this); |
| 7689 if_true.If<HCompareObjectEqAndBranch>(value, |
| 7690 graph()->GetConstantTrue()); |
| 7691 if_true.Then(); |
| 7692 Push(graph()->GetConstant1()); |
| 7693 if_true.Else(); |
| 7694 IfBuilder if_false(this); |
| 7695 if_false.If<HCompareObjectEqAndBranch>(value, |
| 7696 graph()->GetConstantFalse()); |
| 7697 if_false.Then(); |
| 7698 Push(graph()->GetConstant0()); |
| 7699 if_false.Else(); |
| 7700 Push(value); |
| 7701 if_false.End(); |
| 7702 if_true.End(); |
| 7703 return Pop(); |
| 7704 } |
| 7705 |
| 7699 return value; | 7706 return value; |
| 7700 } | 7707 } |
| 7701 | 7708 |
| 7702 | 7709 |
| 7703 HInstruction* HOptimizedGraphBuilder::BuildBinaryOperation( | 7710 HInstruction* HOptimizedGraphBuilder::BuildBinaryOperation( |
| 7704 BinaryOperation* expr, | 7711 BinaryOperation* expr, |
| 7705 HValue* left, | 7712 HValue* left, |
| 7706 HValue* right) { | 7713 HValue* right) { |
| 7707 HValue* context = environment()->context(); | 7714 HValue* context = environment()->context(); |
| 7708 Handle<Type> left_type = expr->left()->bounds().lower; | 7715 Handle<Type> left_type = expr->left()->bounds().lower; |
| 7709 Handle<Type> right_type = expr->right()->bounds().lower; | 7716 Handle<Type> right_type = expr->right()->bounds().lower; |
| 7710 Handle<Type> result_type = expr->bounds().lower; | 7717 Handle<Type> result_type = expr->bounds().lower; |
| 7711 Maybe<int> fixed_right_arg = expr->fixed_right_arg(); | 7718 Maybe<int> fixed_right_arg = expr->fixed_right_arg(); |
| 7719 |
| 7720 return HGraphBuilder::BuildBinaryOperation(expr->op(), left, right, |
| 7721 left_type, right_type, result_type, fixed_right_arg, context); |
| 7722 } |
| 7723 |
| 7724 |
| 7725 HInstruction* HGraphBuilder::BuildBinaryOperation( |
| 7726 Token::Value op, |
| 7727 HValue* left, |
| 7728 HValue* right, |
| 7729 Handle<Type> left_type, |
| 7730 Handle<Type> right_type, |
| 7731 Handle<Type> result_type, |
| 7732 Maybe<int> fixed_right_arg, |
| 7733 HValue* context) { |
| 7734 |
| 7712 Representation left_rep = Representation::FromType(left_type); | 7735 Representation left_rep = Representation::FromType(left_type); |
| 7713 Representation right_rep = Representation::FromType(right_type); | 7736 Representation right_rep = Representation::FromType(right_type); |
| 7714 Representation result_rep = Representation::FromType(result_type); | |
| 7715 | 7737 |
| 7716 if (expr->op() != Token::ADD || | 7738 bool maybe_string_add = op == Token::ADD && |
| 7717 (left->type().IsNonString() && right->type().IsNonString())) { | 7739 (left_type->Maybe(Type::String()) || |
| 7718 // For addition we can only truncate the arguments to number if we can | 7740 right_type->Maybe(Type::String())); |
| 7719 // prove that we will not end up in string concatenation mode. | |
| 7720 left = TruncateToNumber(left, &left_type); | |
| 7721 right = TruncateToNumber(right, &right_type); | |
| 7722 } | |
| 7723 | 7741 |
| 7724 if (left_type->Is(Type::None())) { | 7742 if (left_type->Is(Type::None())) { |
| 7725 Add<HDeoptimize>("Insufficient type feedback for LHS of binary operation", | 7743 Add<HDeoptimize>("Insufficient type feedback for LHS of binary operation", |
| 7726 Deoptimizer::SOFT); | 7744 Deoptimizer::SOFT); |
| 7727 // TODO(rossberg): we should be able to get rid of non-continuous defaults. | 7745 // TODO(rossberg): we should be able to get rid of non-continuous |
| 7746 // defaults. |
| 7728 left_type = handle(Type::Any(), isolate()); | 7747 left_type = handle(Type::Any(), isolate()); |
| 7748 } else { |
| 7749 if (!maybe_string_add) left = TruncateToNumber(left, &left_type); |
| 7750 left_rep = Representation::FromType(left_type); |
| 7729 } | 7751 } |
| 7752 |
| 7730 if (right_type->Is(Type::None())) { | 7753 if (right_type->Is(Type::None())) { |
| 7731 Add<HDeoptimize>("Insufficient type feedback for RHS of binary operation", | 7754 Add<HDeoptimize>("Insufficient type feedback for RHS of binary operation", |
| 7732 Deoptimizer::SOFT); | 7755 Deoptimizer::SOFT); |
| 7733 right_type = handle(Type::Any(), isolate()); | 7756 right_type = handle(Type::Any(), isolate()); |
| 7757 } else { |
| 7758 if (!maybe_string_add) right = TruncateToNumber(right, &right_type); |
| 7759 right_rep = Representation::FromType(right_type); |
| 7734 } | 7760 } |
| 7761 |
| 7762 Representation result_rep = Representation::FromType(result_type); |
| 7763 |
| 7764 bool is_string_add = op == Token::ADD && |
| 7765 (left_type->Is(Type::String()) || |
| 7766 right_type->Is(Type::String())); |
| 7767 |
| 7735 HInstruction* instr = NULL; | 7768 HInstruction* instr = NULL; |
| 7736 switch (expr->op()) { | 7769 switch (op) { |
| 7737 case Token::ADD: | 7770 case Token::ADD: |
| 7738 if (left_type->Is(Type::String()) && right_type->Is(Type::String())) { | 7771 if (is_string_add) { |
| 7739 BuildCheckHeapObject(left); | 7772 StringAddFlags flags = STRING_ADD_CHECK_BOTH; |
| 7740 AddInstruction(HCheckInstanceType::NewIsString(left, zone())); | 7773 if (left_type->Is(Type::String())) { |
| 7741 BuildCheckHeapObject(right); | 7774 BuildCheckHeapObject(left); |
| 7742 AddInstruction(HCheckInstanceType::NewIsString(right, zone())); | 7775 AddInstruction(HCheckInstanceType::NewIsString(left, zone())); |
| 7743 instr = HStringAdd::New(zone(), context, left, right); | 7776 flags = STRING_ADD_CHECK_RIGHT; |
| 7777 } |
| 7778 if (right_type->Is(Type::String())) { |
| 7779 BuildCheckHeapObject(right); |
| 7780 AddInstruction(HCheckInstanceType::NewIsString(right, zone())); |
| 7781 flags = (flags == STRING_ADD_CHECK_BOTH) |
| 7782 ? STRING_ADD_CHECK_LEFT : STRING_ADD_CHECK_NONE; |
| 7783 } |
| 7784 instr = HStringAdd::New(zone(), context, left, right, flags); |
| 7744 } else { | 7785 } else { |
| 7745 instr = HAdd::New(zone(), context, left, right); | 7786 instr = HAdd::New(zone(), context, left, right); |
| 7746 } | 7787 } |
| 7747 break; | 7788 break; |
| 7748 case Token::SUB: | 7789 case Token::SUB: |
| 7749 instr = HSub::New(zone(), context, left, right); | 7790 instr = HSub::New(zone(), context, left, right); |
| 7750 break; | 7791 break; |
| 7751 case Token::MUL: | 7792 case Token::MUL: |
| 7752 instr = HMul::New(zone(), context, left, right); | 7793 instr = HMul::New(zone(), context, left, right); |
| 7753 break; | 7794 break; |
| 7754 case Token::MOD: | 7795 case Token::MOD: |
| 7755 instr = HMod::New(zone(), context, left, right, fixed_right_arg); | 7796 instr = HMod::New(zone(), context, left, right, fixed_right_arg); |
| 7756 break; | 7797 break; |
| 7757 case Token::DIV: | 7798 case Token::DIV: |
| 7758 instr = HDiv::New(zone(), context, left, right); | 7799 instr = HDiv::New(zone(), context, left, right); |
| 7759 break; | 7800 break; |
| 7760 case Token::BIT_XOR: | 7801 case Token::BIT_XOR: |
| 7761 case Token::BIT_AND: | 7802 case Token::BIT_AND: |
| 7762 instr = NewUncasted<HBitwise>(expr->op(), left, right); | 7803 instr = NewUncasted<HBitwise>(op, left, right); |
| 7763 break; | 7804 break; |
| 7764 case Token::BIT_OR: { | 7805 case Token::BIT_OR: { |
| 7765 HValue* operand, *shift_amount; | 7806 HValue* operand, *shift_amount; |
| 7766 if (left_type->Is(Type::Signed32()) && | 7807 if (left_type->Is(Type::Signed32()) && |
| 7767 right_type->Is(Type::Signed32()) && | 7808 right_type->Is(Type::Signed32()) && |
| 7768 MatchRotateRight(left, right, &operand, &shift_amount)) { | 7809 MatchRotateRight(left, right, &operand, &shift_amount)) { |
| 7769 instr = new(zone()) HRor(context, operand, shift_amount); | 7810 instr = new(zone()) HRor(context, operand, shift_amount); |
| 7770 } else { | 7811 } else { |
| 7771 instr = NewUncasted<HBitwise>(expr->op(), left, right); | 7812 instr = NewUncasted<HBitwise>(op, left, right); |
| 7772 } | 7813 } |
| 7773 break; | 7814 break; |
| 7774 } | 7815 } |
| 7775 case Token::SAR: | 7816 case Token::SAR: |
| 7776 instr = HSar::New(zone(), context, left, right); | 7817 instr = HSar::New(zone(), context, left, right); |
| 7777 break; | 7818 break; |
| 7778 case Token::SHR: | 7819 case Token::SHR: |
| 7779 instr = HShr::New(zone(), context, left, right); | 7820 instr = HShr::New(zone(), context, left, right); |
| 7780 if (FLAG_opt_safe_uint32_operations && instr->IsShr() && | 7821 if (FLAG_opt_safe_uint32_operations && instr->IsShr() && |
| 7781 CanBeZero(right)) { | 7822 CanBeZero(right)) { |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7876 CHECK_ALIVE(VisitForValue(expr->right())); | 7917 CHECK_ALIVE(VisitForValue(expr->right())); |
| 7877 } | 7918 } |
| 7878 return ast_context()->ReturnValue(Pop()); | 7919 return ast_context()->ReturnValue(Pop()); |
| 7879 } | 7920 } |
| 7880 | 7921 |
| 7881 // We need an extra block to maintain edge-split form. | 7922 // We need an extra block to maintain edge-split form. |
| 7882 HBasicBlock* empty_block = graph()->CreateBasicBlock(); | 7923 HBasicBlock* empty_block = graph()->CreateBasicBlock(); |
| 7883 HBasicBlock* eval_right = graph()->CreateBasicBlock(); | 7924 HBasicBlock* eval_right = graph()->CreateBasicBlock(); |
| 7884 ToBooleanStub::Types expected(expr->left()->to_boolean_types()); | 7925 ToBooleanStub::Types expected(expr->left()->to_boolean_types()); |
| 7885 HBranch* test = is_logical_and | 7926 HBranch* test = is_logical_and |
| 7886 ? new(zone()) HBranch(left_value, expected, eval_right, empty_block) | 7927 ? New<HBranch>(left_value, expected, eval_right, empty_block) |
| 7887 : new(zone()) HBranch(left_value, expected, empty_block, eval_right); | 7928 : New<HBranch>(left_value, expected, empty_block, eval_right); |
| 7888 current_block()->Finish(test); | 7929 current_block()->Finish(test); |
| 7889 | 7930 |
| 7890 set_current_block(eval_right); | 7931 set_current_block(eval_right); |
| 7891 Drop(1); // Value of the left subexpression. | 7932 Drop(1); // Value of the left subexpression. |
| 7892 CHECK_BAILOUT(VisitForValue(expr->right())); | 7933 CHECK_BAILOUT(VisitForValue(expr->right())); |
| 7893 | 7934 |
| 7894 HBasicBlock* join_block = | 7935 HBasicBlock* join_block = |
| 7895 CreateJoin(empty_block, current_block(), expr->id()); | 7936 CreateJoin(empty_block, current_block(), expr->id()); |
| 7896 set_current_block(join_block); | 7937 set_current_block(join_block); |
| 7897 return ast_context()->ReturnValue(Pop()); | 7938 return ast_context()->ReturnValue(Pop()); |
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8100 HCompareObjectEqAndBranch* result = | 8141 HCompareObjectEqAndBranch* result = |
| 8101 New<HCompareObjectEqAndBranch>(left, right); | 8142 New<HCompareObjectEqAndBranch>(left, right); |
| 8102 result->set_position(expr->position()); | 8143 result->set_position(expr->position()); |
| 8103 return ast_context()->ReturnControl(result, expr->id()); | 8144 return ast_context()->ReturnControl(result, expr->id()); |
| 8104 } else { | 8145 } else { |
| 8105 BuildCheckHeapObject(left); | 8146 BuildCheckHeapObject(left); |
| 8106 AddInstruction(HCheckInstanceType::NewIsSpecObject(left, zone())); | 8147 AddInstruction(HCheckInstanceType::NewIsSpecObject(left, zone())); |
| 8107 BuildCheckHeapObject(right); | 8148 BuildCheckHeapObject(right); |
| 8108 AddInstruction(HCheckInstanceType::NewIsSpecObject(right, zone())); | 8149 AddInstruction(HCheckInstanceType::NewIsSpecObject(right, zone())); |
| 8109 HCompareObjectEqAndBranch* result = | 8150 HCompareObjectEqAndBranch* result = |
| 8110 new(zone()) HCompareObjectEqAndBranch(left, right); | 8151 New<HCompareObjectEqAndBranch>(left, right); |
| 8111 result->set_position(expr->position()); | 8152 result->set_position(expr->position()); |
| 8112 return ast_context()->ReturnControl(result, expr->id()); | 8153 return ast_context()->ReturnControl(result, expr->id()); |
| 8113 } | 8154 } |
| 8114 } | 8155 } |
| 8115 default: | 8156 default: |
| 8116 return Bailout(kUnsupportedNonPrimitiveCompare); | 8157 return Bailout(kUnsupportedNonPrimitiveCompare); |
| 8117 } | 8158 } |
| 8118 } else if (combined_type->Is(Type::InternalizedString()) && | 8159 } else if (combined_type->Is(Type::InternalizedString()) && |
| 8119 Token::IsEqualityOp(op)) { | 8160 Token::IsEqualityOp(op)) { |
| 8120 BuildCheckHeapObject(left); | 8161 BuildCheckHeapObject(left); |
| 8121 AddInstruction(HCheckInstanceType::NewIsInternalizedString(left, zone())); | 8162 AddInstruction(HCheckInstanceType::NewIsInternalizedString(left, zone())); |
| 8122 BuildCheckHeapObject(right); | 8163 BuildCheckHeapObject(right); |
| 8123 AddInstruction(HCheckInstanceType::NewIsInternalizedString(right, zone())); | 8164 AddInstruction(HCheckInstanceType::NewIsInternalizedString(right, zone())); |
| 8124 HCompareObjectEqAndBranch* result = | 8165 HCompareObjectEqAndBranch* result = |
| 8125 new(zone()) HCompareObjectEqAndBranch(left, right); | 8166 New<HCompareObjectEqAndBranch>(left, right); |
| 8126 result->set_position(expr->position()); | 8167 result->set_position(expr->position()); |
| 8127 return ast_context()->ReturnControl(result, expr->id()); | 8168 return ast_context()->ReturnControl(result, expr->id()); |
| 8128 } else { | 8169 } else { |
| 8129 if (combined_rep.IsTagged() || combined_rep.IsNone()) { | 8170 if (combined_rep.IsTagged() || combined_rep.IsNone()) { |
| 8130 HCompareGeneric* result = | 8171 HCompareGeneric* result = |
| 8131 new(zone()) HCompareGeneric(context, left, right, op); | 8172 new(zone()) HCompareGeneric(context, left, right, op); |
| 8132 result->set_observed_input_representation(1, left_rep); | 8173 result->set_observed_input_representation(1, left_rep); |
| 8133 result->set_observed_input_representation(2, right_rep); | 8174 result->set_observed_input_representation(2, right_rep); |
| 8134 result->set_position(expr->position()); | 8175 result->set_position(expr->position()); |
| 8135 return ast_context()->ReturnInstruction(result, expr->id()); | 8176 return ast_context()->ReturnInstruction(result, expr->id()); |
| 8136 } else { | 8177 } else { |
| 8137 HCompareNumericAndBranch* result = | 8178 HCompareNumericAndBranch* result = |
| 8138 new(zone()) HCompareNumericAndBranch(left, right, op); | 8179 New<HCompareNumericAndBranch>(left, right, op); |
| 8139 result->set_observed_input_representation(left_rep, right_rep); | 8180 result->set_observed_input_representation(left_rep, right_rep); |
| 8140 result->set_position(expr->position()); | 8181 result->set_position(expr->position()); |
| 8141 return ast_context()->ReturnControl(result, expr->id()); | 8182 return ast_context()->ReturnControl(result, expr->id()); |
| 8142 } | 8183 } |
| 8143 } | 8184 } |
| 8144 } | 8185 } |
| 8145 | 8186 |
| 8146 | 8187 |
| 8147 void HOptimizedGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr, | 8188 void HOptimizedGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr, |
| 8148 Expression* sub_expr, | 8189 Expression* sub_expr, |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8188 HInstruction* HOptimizedGraphBuilder::BuildFastLiteral( | 8229 HInstruction* HOptimizedGraphBuilder::BuildFastLiteral( |
| 8189 Handle<JSObject> boilerplate_object, | 8230 Handle<JSObject> boilerplate_object, |
| 8190 Handle<Object> allocation_site_object, | 8231 Handle<Object> allocation_site_object, |
| 8191 AllocationSiteMode mode) { | 8232 AllocationSiteMode mode) { |
| 8192 NoObservableSideEffectsScope no_effects(this); | 8233 NoObservableSideEffectsScope no_effects(this); |
| 8193 | 8234 |
| 8194 Handle<FixedArrayBase> elements(boilerplate_object->elements()); | 8235 Handle<FixedArrayBase> elements(boilerplate_object->elements()); |
| 8195 int object_size = boilerplate_object->map()->instance_size(); | 8236 int object_size = boilerplate_object->map()->instance_size(); |
| 8196 int object_offset = object_size; | 8237 int object_offset = object_size; |
| 8197 | 8238 |
| 8239 InstanceType instance_type = boilerplate_object->map()->instance_type(); |
| 8198 bool create_allocation_site_info = mode == TRACK_ALLOCATION_SITE && | 8240 bool create_allocation_site_info = mode == TRACK_ALLOCATION_SITE && |
| 8199 AllocationSite::CanTrack(boilerplate_object->map()->instance_type()); | 8241 AllocationSite::CanTrack(instance_type); |
| 8200 | 8242 |
| 8201 // If using allocation sites, then the payload on the site should already | 8243 // If using allocation sites, then the payload on the site should already |
| 8202 // be filled in as a valid (boilerplate) array. | 8244 // be filled in as a valid (boilerplate) array. |
| 8203 ASSERT(!create_allocation_site_info || | 8245 ASSERT(!create_allocation_site_info || |
| 8204 AllocationSite::cast(*allocation_site_object)->IsLiteralSite()); | 8246 AllocationSite::cast(*allocation_site_object)->IsLiteralSite()); |
| 8205 | 8247 |
| 8206 if (create_allocation_site_info) { | 8248 if (create_allocation_site_info) { |
| 8207 object_size += AllocationMemento::kSize; | 8249 object_size += AllocationMemento::kSize; |
| 8208 } | 8250 } |
| 8209 | 8251 |
| 8252 ASSERT(instance_type == JS_ARRAY_TYPE || instance_type == JS_OBJECT_TYPE); |
| 8253 HType type = instance_type == JS_ARRAY_TYPE |
| 8254 ? HType::JSArray() : HType::JSObject(); |
| 8210 HValue* object_size_constant = Add<HConstant>(object_size); | 8255 HValue* object_size_constant = Add<HConstant>(object_size); |
| 8211 HInstruction* object = Add<HAllocate>(object_size_constant, HType::JSObject(), | 8256 HInstruction* object = Add<HAllocate>(object_size_constant, type, |
| 8212 isolate()->heap()->GetPretenureMode(), JS_OBJECT_TYPE); | 8257 isolate()->heap()->GetPretenureMode(), instance_type); |
| 8213 | 8258 |
| 8214 | 8259 |
| 8215 BuildEmitObjectHeader(boilerplate_object, object); | 8260 BuildEmitObjectHeader(boilerplate_object, object); |
| 8216 | 8261 |
| 8217 if (create_allocation_site_info) { | 8262 if (create_allocation_site_info) { |
| 8218 HInstruction* allocation_site = Add<HConstant>(allocation_site_object); | 8263 HInstruction* allocation_site = Add<HConstant>(allocation_site_object); |
| 8219 BuildCreateAllocationMemento(object, object_offset, allocation_site); | 8264 BuildCreateAllocationMemento(object, object_offset, allocation_site); |
| 8220 } | 8265 } |
| 8221 | 8266 |
| 8222 int elements_size = (elements->length() > 0 && | 8267 int elements_size = (elements->length() > 0 && |
| (...skipping 343 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8566 UNREACHABLE(); | 8611 UNREACHABLE(); |
| 8567 } | 8612 } |
| 8568 | 8613 |
| 8569 | 8614 |
| 8570 // Generators for inline runtime functions. | 8615 // Generators for inline runtime functions. |
| 8571 // Support for types. | 8616 // Support for types. |
| 8572 void HOptimizedGraphBuilder::GenerateIsSmi(CallRuntime* call) { | 8617 void HOptimizedGraphBuilder::GenerateIsSmi(CallRuntime* call) { |
| 8573 ASSERT(call->arguments()->length() == 1); | 8618 ASSERT(call->arguments()->length() == 1); |
| 8574 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 8619 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 8575 HValue* value = Pop(); | 8620 HValue* value = Pop(); |
| 8576 HIsSmiAndBranch* result = new(zone()) HIsSmiAndBranch(value); | 8621 HIsSmiAndBranch* result = New<HIsSmiAndBranch>(value); |
| 8577 return ast_context()->ReturnControl(result, call->id()); | 8622 return ast_context()->ReturnControl(result, call->id()); |
| 8578 } | 8623 } |
| 8579 | 8624 |
| 8580 | 8625 |
| 8581 void HOptimizedGraphBuilder::GenerateIsSpecObject(CallRuntime* call) { | 8626 void HOptimizedGraphBuilder::GenerateIsSpecObject(CallRuntime* call) { |
| 8582 ASSERT(call->arguments()->length() == 1); | 8627 ASSERT(call->arguments()->length() == 1); |
| 8583 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 8628 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 8584 HValue* value = Pop(); | 8629 HValue* value = Pop(); |
| 8585 HHasInstanceTypeAndBranch* result = | 8630 HHasInstanceTypeAndBranch* result = |
| 8586 new(zone()) HHasInstanceTypeAndBranch(value, | 8631 new(zone()) HHasInstanceTypeAndBranch(value, |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8627 HHasInstanceTypeAndBranch* result = | 8672 HHasInstanceTypeAndBranch* result = |
| 8628 new(zone()) HHasInstanceTypeAndBranch(value, JS_REGEXP_TYPE); | 8673 new(zone()) HHasInstanceTypeAndBranch(value, JS_REGEXP_TYPE); |
| 8629 return ast_context()->ReturnControl(result, call->id()); | 8674 return ast_context()->ReturnControl(result, call->id()); |
| 8630 } | 8675 } |
| 8631 | 8676 |
| 8632 | 8677 |
| 8633 void HOptimizedGraphBuilder::GenerateIsObject(CallRuntime* call) { | 8678 void HOptimizedGraphBuilder::GenerateIsObject(CallRuntime* call) { |
| 8634 ASSERT(call->arguments()->length() == 1); | 8679 ASSERT(call->arguments()->length() == 1); |
| 8635 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 8680 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 8636 HValue* value = Pop(); | 8681 HValue* value = Pop(); |
| 8637 HIsObjectAndBranch* result = new(zone()) HIsObjectAndBranch(value); | 8682 HIsObjectAndBranch* result = New<HIsObjectAndBranch>(value); |
| 8638 return ast_context()->ReturnControl(result, call->id()); | 8683 return ast_context()->ReturnControl(result, call->id()); |
| 8639 } | 8684 } |
| 8640 | 8685 |
| 8641 | 8686 |
| 8642 void HOptimizedGraphBuilder::GenerateIsNonNegativeSmi(CallRuntime* call) { | 8687 void HOptimizedGraphBuilder::GenerateIsNonNegativeSmi(CallRuntime* call) { |
| 8643 return Bailout(kInlinedRuntimeFunctionIsNonNegativeSmi); | 8688 return Bailout(kInlinedRuntimeFunctionIsNonNegativeSmi); |
| 8644 } | 8689 } |
| 8645 | 8690 |
| 8646 | 8691 |
| 8647 void HOptimizedGraphBuilder::GenerateIsUndetectableObject(CallRuntime* call) { | 8692 void HOptimizedGraphBuilder::GenerateIsUndetectableObject(CallRuntime* call) { |
| 8648 ASSERT(call->arguments()->length() == 1); | 8693 ASSERT(call->arguments()->length() == 1); |
| 8649 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 8694 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 8650 HValue* value = Pop(); | 8695 HValue* value = Pop(); |
| 8651 HIsUndetectableAndBranch* result = | 8696 HIsUndetectableAndBranch* result = New<HIsUndetectableAndBranch>(value); |
| 8652 new(zone()) HIsUndetectableAndBranch(value); | |
| 8653 return ast_context()->ReturnControl(result, call->id()); | 8697 return ast_context()->ReturnControl(result, call->id()); |
| 8654 } | 8698 } |
| 8655 | 8699 |
| 8656 | 8700 |
| 8657 void HOptimizedGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf( | 8701 void HOptimizedGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf( |
| 8658 CallRuntime* call) { | 8702 CallRuntime* call) { |
| 8659 return Bailout(kInlinedRuntimeFunctionIsStringWrapperSafeForDefaultValueOf); | 8703 return Bailout(kInlinedRuntimeFunctionIsStringWrapperSafeForDefaultValueOf); |
| 8660 } | 8704 } |
| 8661 | 8705 |
| 8662 | 8706 |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8764 } | 8808 } |
| 8765 | 8809 |
| 8766 | 8810 |
| 8767 void HOptimizedGraphBuilder::GenerateSetValueOf(CallRuntime* call) { | 8811 void HOptimizedGraphBuilder::GenerateSetValueOf(CallRuntime* call) { |
| 8768 ASSERT(call->arguments()->length() == 2); | 8812 ASSERT(call->arguments()->length() == 2); |
| 8769 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 8813 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 8770 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); | 8814 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); |
| 8771 HValue* value = Pop(); | 8815 HValue* value = Pop(); |
| 8772 HValue* object = Pop(); | 8816 HValue* object = Pop(); |
| 8773 // Check if object is a not a smi. | 8817 // Check if object is a not a smi. |
| 8774 HIsSmiAndBranch* smicheck = new(zone()) HIsSmiAndBranch(object); | |
| 8775 HBasicBlock* if_smi = graph()->CreateBasicBlock(); | 8818 HBasicBlock* if_smi = graph()->CreateBasicBlock(); |
| 8776 HBasicBlock* if_heap_object = graph()->CreateBasicBlock(); | 8819 HBasicBlock* if_heap_object = graph()->CreateBasicBlock(); |
| 8777 HBasicBlock* join = graph()->CreateBasicBlock(); | 8820 HBasicBlock* join = graph()->CreateBasicBlock(); |
| 8778 smicheck->SetSuccessorAt(0, if_smi); | 8821 current_block()->Finish(New<HIsSmiAndBranch>(object, if_smi, if_heap_object)); |
| 8779 smicheck->SetSuccessorAt(1, if_heap_object); | |
| 8780 current_block()->Finish(smicheck); | |
| 8781 if_smi->Goto(join); | 8822 if_smi->Goto(join); |
| 8782 | 8823 |
| 8783 // Check if object is a JSValue. | 8824 // Check if object is a JSValue. |
| 8784 set_current_block(if_heap_object); | 8825 set_current_block(if_heap_object); |
| 8785 HHasInstanceTypeAndBranch* typecheck = | 8826 HHasInstanceTypeAndBranch* typecheck = |
| 8786 new(zone()) HHasInstanceTypeAndBranch(object, JS_VALUE_TYPE); | 8827 new(zone()) HHasInstanceTypeAndBranch(object, JS_VALUE_TYPE); |
| 8787 HBasicBlock* if_js_value = graph()->CreateBasicBlock(); | 8828 HBasicBlock* if_js_value = graph()->CreateBasicBlock(); |
| 8788 HBasicBlock* not_js_value = graph()->CreateBasicBlock(); | 8829 HBasicBlock* not_js_value = graph()->CreateBasicBlock(); |
| 8789 typecheck->SetSuccessorAt(0, if_js_value); | 8830 typecheck->SetSuccessorAt(0, if_js_value); |
| 8790 typecheck->SetSuccessorAt(1, not_js_value); | 8831 typecheck->SetSuccessorAt(1, not_js_value); |
| (...skipping 908 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9699 if (ShouldProduceTraceOutput()) { | 9740 if (ShouldProduceTraceOutput()) { |
| 9700 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 9741 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
| 9701 } | 9742 } |
| 9702 | 9743 |
| 9703 #ifdef DEBUG | 9744 #ifdef DEBUG |
| 9704 graph_->Verify(false); // No full verify. | 9745 graph_->Verify(false); // No full verify. |
| 9705 #endif | 9746 #endif |
| 9706 } | 9747 } |
| 9707 | 9748 |
| 9708 } } // namespace v8::internal | 9749 } } // namespace v8::internal |
| OLD | NEW |