| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 47 codegen_->RecordSafepoint(pointers_, deoptimization_index_); | 47 codegen_->RecordSafepoint(pointers_, deoptimization_index_); |
| 48 } | 48 } |
| 49 | 49 |
| 50 private: | 50 private: |
| 51 LCodeGen* codegen_; | 51 LCodeGen* codegen_; |
| 52 LPointerMap* pointers_; | 52 LPointerMap* pointers_; |
| 53 int deoptimization_index_; | 53 int deoptimization_index_; |
| 54 }; | 54 }; |
| 55 | 55 |
| 56 | 56 |
| 57 class LGapNode: public ZoneObject { |
| 58 public: |
| 59 explicit LGapNode(LOperand* operand) |
| 60 : operand_(operand), resolved_(false), visited_id_(-1) { } |
| 61 |
| 62 LOperand* operand() const { return operand_; } |
| 63 bool IsResolved() const { return !IsAssigned() || resolved_; } |
| 64 void MarkResolved() { |
| 65 ASSERT(!IsResolved()); |
| 66 resolved_ = true; |
| 67 } |
| 68 int visited_id() const { return visited_id_; } |
| 69 void set_visited_id(int id) { |
| 70 ASSERT(id > visited_id_); |
| 71 visited_id_ = id; |
| 72 } |
| 73 |
| 74 bool IsAssigned() const { return assigned_from_.is_set(); } |
| 75 LGapNode* assigned_from() const { return assigned_from_.get(); } |
| 76 void set_assigned_from(LGapNode* n) { assigned_from_.set(n); } |
| 77 |
| 78 private: |
| 79 LOperand* operand_; |
| 80 SetOncePointer<LGapNode> assigned_from_; |
| 81 bool resolved_; |
| 82 int visited_id_; |
| 83 }; |
| 84 |
| 85 |
| 86 LGapResolver::LGapResolver() |
| 87 : nodes_(32), |
| 88 identified_cycles_(4), |
| 89 result_(16), |
| 90 next_visited_id_(0) { |
| 91 } |
| 92 |
| 93 |
| 94 const ZoneList<LMoveOperands>* LGapResolver::Resolve( |
| 95 const ZoneList<LMoveOperands>* moves, |
| 96 LOperand* marker_operand) { |
| 97 nodes_.Rewind(0); |
| 98 identified_cycles_.Rewind(0); |
| 99 result_.Rewind(0); |
| 100 next_visited_id_ = 0; |
| 101 |
| 102 for (int i = 0; i < moves->length(); ++i) { |
| 103 LMoveOperands move = moves->at(i); |
| 104 if (!move.IsRedundant()) RegisterMove(move); |
| 105 } |
| 106 |
| 107 for (int i = 0; i < identified_cycles_.length(); ++i) { |
| 108 ResolveCycle(identified_cycles_[i], marker_operand); |
| 109 } |
| 110 |
| 111 int unresolved_nodes; |
| 112 do { |
| 113 unresolved_nodes = 0; |
| 114 for (int j = 0; j < nodes_.length(); j++) { |
| 115 LGapNode* node = nodes_[j]; |
| 116 if (!node->IsResolved() && node->assigned_from()->IsResolved()) { |
| 117 AddResultMove(node->assigned_from(), node); |
| 118 node->MarkResolved(); |
| 119 } |
| 120 if (!node->IsResolved()) ++unresolved_nodes; |
| 121 } |
| 122 } while (unresolved_nodes > 0); |
| 123 return &result_; |
| 124 } |
| 125 |
| 126 |
| 127 void LGapResolver::AddResultMove(LGapNode* from, LGapNode* to) { |
| 128 AddResultMove(from->operand(), to->operand()); |
| 129 } |
| 130 |
| 131 |
| 132 void LGapResolver::AddResultMove(LOperand* from, LOperand* to) { |
| 133 result_.Add(LMoveOperands(from, to)); |
| 134 } |
| 135 |
| 136 |
| 137 void LGapResolver::ResolveCycle(LGapNode* start, LOperand* marker_operand) { |
| 138 ZoneList<LOperand*> cycle_operands(8); |
| 139 cycle_operands.Add(marker_operand); |
| 140 LGapNode* cur = start; |
| 141 do { |
| 142 cur->MarkResolved(); |
| 143 cycle_operands.Add(cur->operand()); |
| 144 cur = cur->assigned_from(); |
| 145 } while (cur != start); |
| 146 cycle_operands.Add(marker_operand); |
| 147 |
| 148 for (int i = cycle_operands.length() - 1; i > 0; --i) { |
| 149 LOperand* from = cycle_operands[i]; |
| 150 LOperand* to = cycle_operands[i - 1]; |
| 151 AddResultMove(from, to); |
| 152 } |
| 153 } |
| 154 |
| 155 |
| 156 bool LGapResolver::CanReach(LGapNode* a, LGapNode* b, int visited_id) { |
| 157 ASSERT(a != b); |
| 158 LGapNode* cur = a; |
| 159 while (cur != b && cur->visited_id() != visited_id && cur->IsAssigned()) { |
| 160 cur->set_visited_id(visited_id); |
| 161 cur = cur->assigned_from(); |
| 162 } |
| 163 |
| 164 return cur == b; |
| 165 } |
| 166 |
| 167 |
| 168 bool LGapResolver::CanReach(LGapNode* a, LGapNode* b) { |
| 169 ASSERT(a != b); |
| 170 return CanReach(a, b, next_visited_id_++); |
| 171 } |
| 172 |
| 173 |
| 174 void LGapResolver::RegisterMove(LMoveOperands move) { |
| 175 if (move.source()->IsConstantOperand()) { |
| 176 // Constant moves should be last in the machine code. Therefore add them |
| 177 // first to the result set. |
| 178 AddResultMove(move.source(), move.destination()); |
| 179 } else { |
| 180 LGapNode* from = LookupNode(move.source()); |
| 181 LGapNode* to = LookupNode(move.destination()); |
| 182 if (to->IsAssigned() && to->assigned_from() == from) { |
| 183 move.Eliminate(); |
| 184 return; |
| 185 } |
| 186 ASSERT(!to->IsAssigned()); |
| 187 if (CanReach(from, to)) { |
| 188 // This introduces a cycle. Save. |
| 189 identified_cycles_.Add(from); |
| 190 } |
| 191 to->set_assigned_from(from); |
| 192 } |
| 193 } |
| 194 |
| 195 |
| 196 LGapNode* LGapResolver::LookupNode(LOperand* operand) { |
| 197 for (int i = 0; i < nodes_.length(); ++i) { |
| 198 if (nodes_[i]->operand()->Equals(operand)) return nodes_[i]; |
| 199 } |
| 200 |
| 201 // No node found => create a new one. |
| 202 LGapNode* result = new LGapNode(operand); |
| 203 nodes_.Add(result); |
| 204 return result; |
| 205 } |
| 206 |
| 207 |
| 57 #define __ masm()-> | 208 #define __ masm()-> |
| 58 | 209 |
| 59 bool LCodeGen::GenerateCode() { | 210 bool LCodeGen::GenerateCode() { |
| 60 HPhase phase("Code generation", chunk()); | 211 HPhase phase("Code generation", chunk()); |
| 61 ASSERT(is_unused()); | 212 ASSERT(is_unused()); |
| 62 status_ = GENERATING; | 213 status_ = GENERATING; |
| 63 CpuFeatures::Scope scope1(VFP3); | 214 CpuFeatures::Scope scope1(VFP3); |
| 64 CpuFeatures::Scope scope2(ARMv7); | 215 CpuFeatures::Scope scope2(ARMv7); |
| 65 return GeneratePrologue() && | 216 return GeneratePrologue() && |
| 66 GenerateBody() && | 217 GenerateBody() && |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 183 | 334 |
| 184 bool LCodeGen::GenerateDeferredCode() { | 335 bool LCodeGen::GenerateDeferredCode() { |
| 185 ASSERT(is_generating()); | 336 ASSERT(is_generating()); |
| 186 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) { | 337 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) { |
| 187 LDeferredCode* code = deferred_[i]; | 338 LDeferredCode* code = deferred_[i]; |
| 188 __ bind(code->entry()); | 339 __ bind(code->entry()); |
| 189 code->Generate(); | 340 code->Generate(); |
| 190 __ jmp(code->exit()); | 341 __ jmp(code->exit()); |
| 191 } | 342 } |
| 192 | 343 |
| 344 // Force constant pool emission at the end of deferred code to make |
| 345 // sure that no constant pools are emitted after the official end of |
| 346 // the instruction sequence. |
| 347 masm()->CheckConstPool(true, false); |
| 348 |
| 193 // Deferred code is the last part of the instruction sequence. Mark | 349 // Deferred code is the last part of the instruction sequence. Mark |
| 194 // the generated code as done unless we bailed out. | 350 // the generated code as done unless we bailed out. |
| 195 if (!is_aborted()) status_ = DONE; | 351 if (!is_aborted()) status_ = DONE; |
| 196 return !is_aborted(); | 352 return !is_aborted(); |
| 197 } | 353 } |
| 198 | 354 |
| 199 | 355 |
| 200 bool LCodeGen::GenerateSafepointTable() { | 356 bool LCodeGen::GenerateSafepointTable() { |
| 201 ASSERT(is_done()); | 357 ASSERT(is_done()); |
| 202 safepoints_.Emit(masm(), StackSlotCount()); | 358 safepoints_.Emit(masm(), StackSlotCount()); |
| (...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 498 } | 654 } |
| 499 | 655 |
| 500 ASSERT(FLAG_deopt_every_n_times < 2); // Other values not supported on ARM. | 656 ASSERT(FLAG_deopt_every_n_times < 2); // Other values not supported on ARM. |
| 501 | 657 |
| 502 if (FLAG_deopt_every_n_times == 1 && | 658 if (FLAG_deopt_every_n_times == 1 && |
| 503 info_->shared_info()->opt_count() == id) { | 659 info_->shared_info()->opt_count() == id) { |
| 504 __ Jump(entry, RelocInfo::RUNTIME_ENTRY); | 660 __ Jump(entry, RelocInfo::RUNTIME_ENTRY); |
| 505 return; | 661 return; |
| 506 } | 662 } |
| 507 | 663 |
| 508 if (cc == no_condition) { | 664 if (cc == kNoCondition) { |
| 509 if (FLAG_trap_on_deopt) __ stop("trap_on_deopt"); | 665 if (FLAG_trap_on_deopt) __ stop("trap_on_deopt"); |
| 510 __ Jump(entry, RelocInfo::RUNTIME_ENTRY); | 666 __ Jump(entry, RelocInfo::RUNTIME_ENTRY); |
| 511 } else { | 667 } else { |
| 512 if (FLAG_trap_on_deopt) { | 668 if (FLAG_trap_on_deopt) { |
| 513 Label done; | 669 Label done; |
| 514 __ b(&done, NegateCondition(cc)); | 670 __ b(&done, NegateCondition(cc)); |
| 515 __ stop("trap_on_deopt"); | 671 __ stop("trap_on_deopt"); |
| 516 __ Jump(entry, RelocInfo::RUNTIME_ENTRY); | 672 __ Jump(entry, RelocInfo::RUNTIME_ENTRY); |
| 517 __ bind(&done); | 673 __ bind(&done); |
| 518 } else { | 674 } else { |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 607 safepoint.DefinePointerSlot(pointer->index()); | 763 safepoint.DefinePointerSlot(pointer->index()); |
| 608 } else if (pointer->IsRegister()) { | 764 } else if (pointer->IsRegister()) { |
| 609 safepoint.DefinePointerRegister(ToRegister(pointer)); | 765 safepoint.DefinePointerRegister(ToRegister(pointer)); |
| 610 } | 766 } |
| 611 } | 767 } |
| 612 // Register cp always contains a pointer to the context. | 768 // Register cp always contains a pointer to the context. |
| 613 safepoint.DefinePointerRegister(cp); | 769 safepoint.DefinePointerRegister(cp); |
| 614 } | 770 } |
| 615 | 771 |
| 616 | 772 |
| 773 void LCodeGen::RecordSafepointWithRegistersAndDoubles( |
| 774 LPointerMap* pointers, |
| 775 int arguments, |
| 776 int deoptimization_index) { |
| 777 const ZoneList<LOperand*>* operands = pointers->operands(); |
| 778 Safepoint safepoint = |
| 779 safepoints_.DefineSafepointWithRegistersAndDoubles( |
| 780 masm(), arguments, deoptimization_index); |
| 781 for (int i = 0; i < operands->length(); i++) { |
| 782 LOperand* pointer = operands->at(i); |
| 783 if (pointer->IsStackSlot()) { |
| 784 safepoint.DefinePointerSlot(pointer->index()); |
| 785 } else if (pointer->IsRegister()) { |
| 786 safepoint.DefinePointerRegister(ToRegister(pointer)); |
| 787 } |
| 788 } |
| 789 // Register cp always contains a pointer to the context. |
| 790 safepoint.DefinePointerRegister(cp); |
| 791 } |
| 792 |
| 793 |
| 617 void LCodeGen::RecordPosition(int position) { | 794 void LCodeGen::RecordPosition(int position) { |
| 618 if (!FLAG_debug_info || position == RelocInfo::kNoPosition) return; | 795 if (!FLAG_debug_info || position == RelocInfo::kNoPosition) return; |
| 619 masm()->positions_recorder()->RecordPosition(position); | 796 masm()->positions_recorder()->RecordPosition(position); |
| 620 } | 797 } |
| 621 | 798 |
| 622 | 799 |
| 623 void LCodeGen::DoLabel(LLabel* label) { | 800 void LCodeGen::DoLabel(LLabel* label) { |
| 624 if (label->is_loop_header()) { | 801 if (label->is_loop_header()) { |
| 625 Comment(";;; B%d - LOOP entry", label->block_id()); | 802 Comment(";;; B%d - LOOP entry", label->block_id()); |
| 626 } else { | 803 } else { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 637 DoubleRegister dbl_scratch = d0; | 814 DoubleRegister dbl_scratch = d0; |
| 638 LUnallocated marker_operand(LUnallocated::NONE); | 815 LUnallocated marker_operand(LUnallocated::NONE); |
| 639 | 816 |
| 640 Register core_scratch = scratch0(); | 817 Register core_scratch = scratch0(); |
| 641 bool destroys_core_scratch = false; | 818 bool destroys_core_scratch = false; |
| 642 | 819 |
| 643 const ZoneList<LMoveOperands>* moves = | 820 const ZoneList<LMoveOperands>* moves = |
| 644 resolver_.Resolve(move->move_operands(), &marker_operand); | 821 resolver_.Resolve(move->move_operands(), &marker_operand); |
| 645 for (int i = moves->length() - 1; i >= 0; --i) { | 822 for (int i = moves->length() - 1; i >= 0; --i) { |
| 646 LMoveOperands move = moves->at(i); | 823 LMoveOperands move = moves->at(i); |
| 647 LOperand* from = move.from(); | 824 LOperand* from = move.source(); |
| 648 LOperand* to = move.to(); | 825 LOperand* to = move.destination(); |
| 649 ASSERT(!from->IsDoubleRegister() || | 826 ASSERT(!from->IsDoubleRegister() || |
| 650 !ToDoubleRegister(from).is(dbl_scratch)); | 827 !ToDoubleRegister(from).is(dbl_scratch)); |
| 651 ASSERT(!to->IsDoubleRegister() || !ToDoubleRegister(to).is(dbl_scratch)); | 828 ASSERT(!to->IsDoubleRegister() || !ToDoubleRegister(to).is(dbl_scratch)); |
| 652 ASSERT(!from->IsRegister() || !ToRegister(from).is(core_scratch)); | 829 ASSERT(!from->IsRegister() || !ToRegister(from).is(core_scratch)); |
| 653 ASSERT(!to->IsRegister() || !ToRegister(to).is(core_scratch)); | 830 ASSERT(!to->IsRegister() || !ToRegister(to).is(core_scratch)); |
| 654 if (from == &marker_operand) { | 831 if (from == &marker_operand) { |
| 655 if (to->IsRegister()) { | 832 if (to->IsRegister()) { |
| 656 __ mov(ToRegister(to), core_scratch); | 833 __ mov(ToRegister(to), core_scratch); |
| 657 ASSERT(destroys_core_scratch); | 834 ASSERT(destroys_core_scratch); |
| 658 } else if (to->IsStackSlot()) { | 835 } else if (to->IsStackSlot()) { |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 780 RegExpExecStub stub; | 957 RegExpExecStub stub; |
| 781 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | 958 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 782 break; | 959 break; |
| 783 } | 960 } |
| 784 case CodeStub::SubString: { | 961 case CodeStub::SubString: { |
| 785 SubStringStub stub; | 962 SubStringStub stub; |
| 786 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | 963 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 787 break; | 964 break; |
| 788 } | 965 } |
| 789 case CodeStub::StringCharAt: { | 966 case CodeStub::StringCharAt: { |
| 790 Abort("StringCharAtStub unimplemented."); | 967 StringCharAtStub stub; |
| 968 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 791 break; | 969 break; |
| 792 } | 970 } |
| 793 case CodeStub::MathPow: { | 971 case CodeStub::MathPow: { |
| 794 Abort("MathPowStub unimplemented."); | 972 Abort("MathPowStub unimplemented."); |
| 795 break; | 973 break; |
| 796 } | 974 } |
| 797 case CodeStub::NumberToString: { | 975 case CodeStub::NumberToString: { |
| 798 NumberToStringStub stub; | 976 NumberToStringStub stub; |
| 799 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | 977 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 800 break; | 978 break; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 820 } | 998 } |
| 821 } | 999 } |
| 822 | 1000 |
| 823 | 1001 |
| 824 void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) { | 1002 void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) { |
| 825 // Nothing to do. | 1003 // Nothing to do. |
| 826 } | 1004 } |
| 827 | 1005 |
| 828 | 1006 |
| 829 void LCodeGen::DoModI(LModI* instr) { | 1007 void LCodeGen::DoModI(LModI* instr) { |
| 830 Abort("DoModI unimplemented."); | 1008 class DeferredModI: public LDeferredCode { |
| 1009 public: |
| 1010 DeferredModI(LCodeGen* codegen, LModI* instr) |
| 1011 : LDeferredCode(codegen), instr_(instr) { } |
| 1012 virtual void Generate() { |
| 1013 codegen()->DoDeferredGenericBinaryStub(instr_, Token::MOD); |
| 1014 } |
| 1015 private: |
| 1016 LModI* instr_; |
| 1017 }; |
| 1018 // These registers hold untagged 32 bit values. |
| 1019 Register left = ToRegister(instr->InputAt(0)); |
| 1020 Register right = ToRegister(instr->InputAt(1)); |
| 1021 Register result = ToRegister(instr->result()); |
| 1022 Register scratch = scratch0(); |
| 1023 |
| 1024 Label deoptimize, done; |
| 1025 // Check for x % 0. |
| 1026 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) { |
| 1027 __ tst(right, Operand(right)); |
| 1028 __ b(eq, &deoptimize); |
| 1029 } |
| 1030 |
| 1031 // Check for (0 % -x) that will produce negative zero. |
| 1032 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 1033 Label ok; |
| 1034 __ tst(left, Operand(left)); |
| 1035 __ b(ne, &ok); |
| 1036 __ tst(right, Operand(right)); |
| 1037 __ b(pl, &ok); |
| 1038 __ b(al, &deoptimize); |
| 1039 __ bind(&ok); |
| 1040 } |
| 1041 |
| 1042 // Try a few common cases before using the generic stub. |
| 1043 Label call_stub; |
| 1044 const int kUnfolds = 3; |
| 1045 // Skip if either side is negative. |
| 1046 __ cmp(left, Operand(0)); |
| 1047 __ cmp(right, Operand(0), NegateCondition(mi)); |
| 1048 __ b(mi, &call_stub); |
| 1049 // If the right hand side is smaller than the (nonnegative) |
| 1050 // left hand side, it is the result. Else try a few subtractions |
| 1051 // of the left hand side. |
| 1052 __ mov(scratch, left); |
| 1053 for (int i = 0; i < kUnfolds; i++) { |
| 1054 // Check if the left hand side is less or equal than the |
| 1055 // the right hand side. |
| 1056 __ cmp(scratch, right); |
| 1057 __ mov(result, scratch, LeaveCC, lt); |
| 1058 __ b(lt, &done); |
| 1059 // If not, reduce the left hand side by the right hand |
| 1060 // side and check again. |
| 1061 if (i < kUnfolds - 1) __ sub(scratch, scratch, right); |
| 1062 } |
| 1063 |
| 1064 // Check for power of two on the right hand side. |
| 1065 __ sub(scratch, right, Operand(1), SetCC); |
| 1066 __ b(mi, &call_stub); |
| 1067 __ tst(scratch, right); |
| 1068 __ b(ne, &call_stub); |
| 1069 // Perform modulo operation. |
| 1070 __ and_(result, scratch, Operand(left)); |
| 1071 |
| 1072 __ bind(&call_stub); |
| 1073 // Call the generic stub. The numbers in r0 and r1 have |
| 1074 // to be tagged to Smis. If that is not possible, deoptimize. |
| 1075 DeferredModI* deferred = new DeferredModI(this, instr); |
| 1076 __ TrySmiTag(left, &deoptimize, scratch); |
| 1077 __ TrySmiTag(right, &deoptimize, scratch); |
| 1078 |
| 1079 __ b(al, deferred->entry()); |
| 1080 __ bind(deferred->exit()); |
| 1081 |
| 1082 // If the result in r0 is a Smi, untag it, else deoptimize. |
| 1083 __ JumpIfNotSmi(result, &deoptimize); |
| 1084 __ SmiUntag(result); |
| 1085 |
| 1086 __ b(al, &done); |
| 1087 __ bind(&deoptimize); |
| 1088 DeoptimizeIf(al, instr->environment()); |
| 1089 __ bind(&done); |
| 831 } | 1090 } |
| 832 | 1091 |
| 833 | 1092 |
| 834 void LCodeGen::DoDivI(LDivI* instr) { | 1093 void LCodeGen::DoDivI(LDivI* instr) { |
| 835 Abort("DoDivI unimplemented."); | 1094 class DeferredDivI: public LDeferredCode { |
| 1095 public: |
| 1096 DeferredDivI(LCodeGen* codegen, LDivI* instr) |
| 1097 : LDeferredCode(codegen), instr_(instr) { } |
| 1098 virtual void Generate() { |
| 1099 codegen()->DoDeferredGenericBinaryStub(instr_, Token::DIV); |
| 1100 } |
| 1101 private: |
| 1102 LDivI* instr_; |
| 1103 }; |
| 1104 |
| 1105 const Register left = ToRegister(instr->InputAt(0)); |
| 1106 const Register right = ToRegister(instr->InputAt(1)); |
| 1107 const Register scratch = scratch0(); |
| 1108 const Register result = ToRegister(instr->result()); |
| 1109 |
| 1110 // Check for x / 0. |
| 1111 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) { |
| 1112 __ tst(right, right); |
| 1113 DeoptimizeIf(eq, instr->environment()); |
| 1114 } |
| 1115 |
| 1116 // Check for (0 / -x) that will produce negative zero. |
| 1117 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 1118 Label left_not_zero; |
| 1119 __ tst(left, Operand(left)); |
| 1120 __ b(ne, &left_not_zero); |
| 1121 __ tst(right, Operand(right)); |
| 1122 DeoptimizeIf(mi, instr->environment()); |
| 1123 __ bind(&left_not_zero); |
| 1124 } |
| 1125 |
| 1126 // Check for (-kMinInt / -1). |
| 1127 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { |
| 1128 Label left_not_min_int; |
| 1129 __ cmp(left, Operand(kMinInt)); |
| 1130 __ b(ne, &left_not_min_int); |
| 1131 __ cmp(right, Operand(-1)); |
| 1132 DeoptimizeIf(eq, instr->environment()); |
| 1133 __ bind(&left_not_min_int); |
| 1134 } |
| 1135 |
| 1136 Label done, deoptimize; |
| 1137 // Test for a few common cases first. |
| 1138 __ cmp(right, Operand(1)); |
| 1139 __ mov(result, left, LeaveCC, eq); |
| 1140 __ b(eq, &done); |
| 1141 |
| 1142 __ cmp(right, Operand(2)); |
| 1143 __ tst(left, Operand(1), eq); |
| 1144 __ mov(result, Operand(left, ASR, 1), LeaveCC, eq); |
| 1145 __ b(eq, &done); |
| 1146 |
| 1147 __ cmp(right, Operand(4)); |
| 1148 __ tst(left, Operand(3), eq); |
| 1149 __ mov(result, Operand(left, ASR, 2), LeaveCC, eq); |
| 1150 __ b(eq, &done); |
| 1151 |
| 1152 // Call the generic stub. The numbers in r0 and r1 have |
| 1153 // to be tagged to Smis. If that is not possible, deoptimize. |
| 1154 DeferredDivI* deferred = new DeferredDivI(this, instr); |
| 1155 |
| 1156 __ TrySmiTag(left, &deoptimize, scratch); |
| 1157 __ TrySmiTag(right, &deoptimize, scratch); |
| 1158 |
| 1159 __ b(al, deferred->entry()); |
| 1160 __ bind(deferred->exit()); |
| 1161 |
| 1162 // If the result in r0 is a Smi, untag it, else deoptimize. |
| 1163 __ JumpIfNotSmi(result, &deoptimize); |
| 1164 __ SmiUntag(result); |
| 1165 __ b(&done); |
| 1166 |
| 1167 __ bind(&deoptimize); |
| 1168 DeoptimizeIf(al, instr->environment()); |
| 1169 __ bind(&done); |
| 1170 } |
| 1171 |
| 1172 |
| 1173 template<int T> |
| 1174 void LCodeGen::DoDeferredGenericBinaryStub(LTemplateInstruction<1, 2, T>* instr, |
| 1175 Token::Value op) { |
| 1176 Register left = ToRegister(instr->InputAt(0)); |
| 1177 Register right = ToRegister(instr->InputAt(1)); |
| 1178 |
| 1179 __ PushSafepointRegistersAndDoubles(); |
| 1180 GenericBinaryOpStub stub(op, OVERWRITE_LEFT, left, right); |
| 1181 __ CallStub(&stub); |
| 1182 RecordSafepointWithRegistersAndDoubles(instr->pointer_map(), |
| 1183 0, |
| 1184 Safepoint::kNoDeoptimizationIndex); |
| 1185 // Overwrite the stored value of r0 with the result of the stub. |
| 1186 __ str(r0, MemOperand(sp, DwVfpRegister::kNumAllocatableRegisters * |
| 1187 kDoubleSize)); |
| 1188 __ PopSafepointRegistersAndDoubles(); |
| 836 } | 1189 } |
| 837 | 1190 |
| 838 | 1191 |
| 839 void LCodeGen::DoMulI(LMulI* instr) { | 1192 void LCodeGen::DoMulI(LMulI* instr) { |
| 840 Register scratch = scratch0(); | 1193 Register scratch = scratch0(); |
| 841 Register left = ToRegister(instr->left()); | 1194 Register left = ToRegister(instr->InputAt(0)); |
| 842 Register right = EmitLoadRegister(instr->right(), scratch); | 1195 Register right = EmitLoadRegister(instr->InputAt(1), scratch); |
| 843 | 1196 |
| 844 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero) && | 1197 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero) && |
| 845 !instr->right()->IsConstantOperand()) { | 1198 !instr->InputAt(1)->IsConstantOperand()) { |
| 846 __ orr(ToRegister(instr->temp()), left, right); | 1199 __ orr(ToRegister(instr->TempAt(0)), left, right); |
| 847 } | 1200 } |
| 848 | 1201 |
| 849 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { | 1202 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { |
| 850 // scratch:left = left * right. | 1203 // scratch:left = left * right. |
| 851 __ smull(scratch, left, left, right); | 1204 __ smull(scratch, left, left, right); |
| 852 __ mov(ip, Operand(left, ASR, 31)); | 1205 __ mov(ip, Operand(left, ASR, 31)); |
| 853 __ cmp(ip, Operand(scratch)); | 1206 __ cmp(ip, Operand(scratch)); |
| 854 DeoptimizeIf(ne, instr->environment()); | 1207 DeoptimizeIf(ne, instr->environment()); |
| 855 } else { | 1208 } else { |
| 856 __ mul(left, left, right); | 1209 __ mul(left, left, right); |
| 857 } | 1210 } |
| 858 | 1211 |
| 859 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { | 1212 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 860 // Bail out if the result is supposed to be negative zero. | 1213 // Bail out if the result is supposed to be negative zero. |
| 861 Label done; | 1214 Label done; |
| 862 __ tst(left, Operand(left)); | 1215 __ tst(left, Operand(left)); |
| 863 __ b(ne, &done); | 1216 __ b(ne, &done); |
| 864 if (instr->right()->IsConstantOperand()) { | 1217 if (instr->InputAt(1)->IsConstantOperand()) { |
| 865 if (ToInteger32(LConstantOperand::cast(instr->right())) < 0) { | 1218 if (ToInteger32(LConstantOperand::cast(instr->InputAt(1))) < 0) { |
| 866 DeoptimizeIf(no_condition, instr->environment()); | 1219 DeoptimizeIf(kNoCondition, instr->environment()); |
| 867 } | 1220 } |
| 868 } else { | 1221 } else { |
| 869 // Test the non-zero operand for negative sign. | 1222 // Test the non-zero operand for negative sign. |
| 870 __ cmp(ToRegister(instr->temp()), Operand(0)); | 1223 __ cmp(ToRegister(instr->TempAt(0)), Operand(0)); |
| 871 DeoptimizeIf(mi, instr->environment()); | 1224 DeoptimizeIf(mi, instr->environment()); |
| 872 } | 1225 } |
| 873 __ bind(&done); | 1226 __ bind(&done); |
| 874 } | 1227 } |
| 875 } | 1228 } |
| 876 | 1229 |
| 877 | 1230 |
| 878 void LCodeGen::DoBitI(LBitI* instr) { | 1231 void LCodeGen::DoBitI(LBitI* instr) { |
| 879 LOperand* left = instr->left(); | 1232 LOperand* left = instr->InputAt(0); |
| 880 LOperand* right = instr->right(); | 1233 LOperand* right = instr->InputAt(1); |
| 881 ASSERT(left->Equals(instr->result())); | 1234 ASSERT(left->Equals(instr->result())); |
| 882 ASSERT(left->IsRegister()); | 1235 ASSERT(left->IsRegister()); |
| 883 Register result = ToRegister(left); | 1236 Register result = ToRegister(left); |
| 884 Register right_reg = EmitLoadRegister(right, ip); | 1237 Register right_reg = EmitLoadRegister(right, ip); |
| 885 switch (instr->op()) { | 1238 switch (instr->op()) { |
| 886 case Token::BIT_AND: | 1239 case Token::BIT_AND: |
| 887 __ and_(result, ToRegister(left), Operand(right_reg)); | 1240 __ and_(result, ToRegister(left), Operand(right_reg)); |
| 888 break; | 1241 break; |
| 889 case Token::BIT_OR: | 1242 case Token::BIT_OR: |
| 890 __ orr(result, ToRegister(left), Operand(right_reg)); | 1243 __ orr(result, ToRegister(left), Operand(right_reg)); |
| 891 break; | 1244 break; |
| 892 case Token::BIT_XOR: | 1245 case Token::BIT_XOR: |
| 893 __ eor(result, ToRegister(left), Operand(right_reg)); | 1246 __ eor(result, ToRegister(left), Operand(right_reg)); |
| 894 break; | 1247 break; |
| 895 default: | 1248 default: |
| 896 UNREACHABLE(); | 1249 UNREACHABLE(); |
| 897 break; | 1250 break; |
| 898 } | 1251 } |
| 899 } | 1252 } |
| 900 | 1253 |
| 901 | 1254 |
| 902 void LCodeGen::DoShiftI(LShiftI* instr) { | 1255 void LCodeGen::DoShiftI(LShiftI* instr) { |
| 903 Register scratch = scratch0(); | 1256 Register scratch = scratch0(); |
| 904 LOperand* left = instr->left(); | 1257 LOperand* left = instr->InputAt(0); |
| 905 LOperand* right = instr->right(); | 1258 LOperand* right = instr->InputAt(1); |
| 906 ASSERT(left->Equals(instr->result())); | 1259 ASSERT(left->Equals(instr->result())); |
| 907 ASSERT(left->IsRegister()); | 1260 ASSERT(left->IsRegister()); |
| 908 Register result = ToRegister(left); | 1261 Register result = ToRegister(left); |
| 909 if (right->IsRegister()) { | 1262 if (right->IsRegister()) { |
| 910 // Mask the right operand. | 1263 // Mask the right operand. |
| 911 __ and_(scratch, ToRegister(right), Operand(0x1F)); | 1264 __ and_(scratch, ToRegister(right), Operand(0x1F)); |
| 912 switch (instr->op()) { | 1265 switch (instr->op()) { |
| 913 case Token::SAR: | 1266 case Token::SAR: |
| 914 __ mov(result, Operand(result, ASR, scratch)); | 1267 __ mov(result, Operand(result, ASR, scratch)); |
| 915 break; | 1268 break; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 952 break; | 1305 break; |
| 953 default: | 1306 default: |
| 954 UNREACHABLE(); | 1307 UNREACHABLE(); |
| 955 break; | 1308 break; |
| 956 } | 1309 } |
| 957 } | 1310 } |
| 958 } | 1311 } |
| 959 | 1312 |
| 960 | 1313 |
| 961 void LCodeGen::DoSubI(LSubI* instr) { | 1314 void LCodeGen::DoSubI(LSubI* instr) { |
| 962 Register left = ToRegister(instr->left()); | 1315 Register left = ToRegister(instr->InputAt(0)); |
| 963 Register right = EmitLoadRegister(instr->right(), ip); | 1316 Register right = EmitLoadRegister(instr->InputAt(1), ip); |
| 964 ASSERT(instr->left()->Equals(instr->result())); | 1317 ASSERT(instr->InputAt(0)->Equals(instr->result())); |
| 965 __ sub(left, left, right, SetCC); | 1318 __ sub(left, left, right, SetCC); |
| 966 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { | 1319 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { |
| 967 DeoptimizeIf(vs, instr->environment()); | 1320 DeoptimizeIf(vs, instr->environment()); |
| 968 } | 1321 } |
| 969 } | 1322 } |
| 970 | 1323 |
| 971 | 1324 |
| 972 void LCodeGen::DoConstantI(LConstantI* instr) { | 1325 void LCodeGen::DoConstantI(LConstantI* instr) { |
| 973 ASSERT(instr->result()->IsRegister()); | 1326 ASSERT(instr->result()->IsRegister()); |
| 974 __ mov(ToRegister(instr->result()), Operand(instr->value())); | 1327 __ mov(ToRegister(instr->result()), Operand(instr->value())); |
| 975 } | 1328 } |
| 976 | 1329 |
| 977 | 1330 |
| 978 void LCodeGen::DoConstantD(LConstantD* instr) { | 1331 void LCodeGen::DoConstantD(LConstantD* instr) { |
| 979 Abort("DoConstantD unimplemented."); | 1332 ASSERT(instr->result()->IsDoubleRegister()); |
| 1333 DwVfpRegister result = ToDoubleRegister(instr->result()); |
| 1334 double v = instr->value(); |
| 1335 __ vmov(result, v); |
| 980 } | 1336 } |
| 981 | 1337 |
| 982 | 1338 |
| 983 void LCodeGen::DoConstantT(LConstantT* instr) { | 1339 void LCodeGen::DoConstantT(LConstantT* instr) { |
| 984 ASSERT(instr->result()->IsRegister()); | 1340 ASSERT(instr->result()->IsRegister()); |
| 985 __ mov(ToRegister(instr->result()), Operand(instr->value())); | 1341 __ mov(ToRegister(instr->result()), Operand(instr->value())); |
| 986 } | 1342 } |
| 987 | 1343 |
| 988 | 1344 |
| 989 void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) { | 1345 void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) { |
| 990 Register result = ToRegister(instr->result()); | 1346 Register result = ToRegister(instr->result()); |
| 991 Register array = ToRegister(instr->input()); | 1347 Register array = ToRegister(instr->InputAt(0)); |
| 992 __ ldr(result, FieldMemOperand(array, JSArray::kLengthOffset)); | 1348 __ ldr(result, FieldMemOperand(array, JSArray::kLengthOffset)); |
| 993 } | 1349 } |
| 994 | 1350 |
| 995 | 1351 |
| 996 void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) { | 1352 void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) { |
| 997 Register result = ToRegister(instr->result()); | 1353 Register result = ToRegister(instr->result()); |
| 998 Register array = ToRegister(instr->input()); | 1354 Register array = ToRegister(instr->InputAt(0)); |
| 999 __ ldr(result, FieldMemOperand(array, FixedArray::kLengthOffset)); | 1355 __ ldr(result, FieldMemOperand(array, FixedArray::kLengthOffset)); |
| 1000 } | 1356 } |
| 1001 | 1357 |
| 1002 | 1358 |
| 1003 void LCodeGen::DoValueOf(LValueOf* instr) { | 1359 void LCodeGen::DoValueOf(LValueOf* instr) { |
| 1004 Register input = ToRegister(instr->input()); | 1360 Register input = ToRegister(instr->InputAt(0)); |
| 1005 Register result = ToRegister(instr->result()); | 1361 Register result = ToRegister(instr->result()); |
| 1006 Register map = ToRegister(instr->temporary()); | 1362 Register map = ToRegister(instr->TempAt(0)); |
| 1007 ASSERT(input.is(result)); | 1363 ASSERT(input.is(result)); |
| 1008 Label done; | 1364 Label done; |
| 1009 | 1365 |
| 1010 // If the object is a smi return the object. | 1366 // If the object is a smi return the object. |
| 1011 __ tst(input, Operand(kSmiTagMask)); | 1367 __ tst(input, Operand(kSmiTagMask)); |
| 1012 __ b(eq, &done); | 1368 __ b(eq, &done); |
| 1013 | 1369 |
| 1014 // If the object is not a value type, return the object. | 1370 // If the object is not a value type, return the object. |
| 1015 __ CompareObjectType(input, map, map, JS_VALUE_TYPE); | 1371 __ CompareObjectType(input, map, map, JS_VALUE_TYPE); |
| 1016 __ b(ne, &done); | 1372 __ b(ne, &done); |
| 1017 __ ldr(result, FieldMemOperand(input, JSValue::kValueOffset)); | 1373 __ ldr(result, FieldMemOperand(input, JSValue::kValueOffset)); |
| 1018 | 1374 |
| 1019 __ bind(&done); | 1375 __ bind(&done); |
| 1020 } | 1376 } |
| 1021 | 1377 |
| 1022 | 1378 |
| 1023 void LCodeGen::DoBitNotI(LBitNotI* instr) { | 1379 void LCodeGen::DoBitNotI(LBitNotI* instr) { |
| 1024 LOperand* input = instr->input(); | 1380 LOperand* input = instr->InputAt(0); |
| 1025 ASSERT(input->Equals(instr->result())); | 1381 ASSERT(input->Equals(instr->result())); |
| 1026 __ mvn(ToRegister(input), Operand(ToRegister(input))); | 1382 __ mvn(ToRegister(input), Operand(ToRegister(input))); |
| 1027 } | 1383 } |
| 1028 | 1384 |
| 1029 | 1385 |
| 1030 void LCodeGen::DoThrow(LThrow* instr) { | 1386 void LCodeGen::DoThrow(LThrow* instr) { |
| 1031 Register input_reg = EmitLoadRegister(instr->input(), ip); | 1387 Register input_reg = EmitLoadRegister(instr->InputAt(0), ip); |
| 1032 __ push(input_reg); | 1388 __ push(input_reg); |
| 1033 CallRuntime(Runtime::kThrow, 1, instr); | 1389 CallRuntime(Runtime::kThrow, 1, instr); |
| 1034 | 1390 |
| 1035 if (FLAG_debug_code) { | 1391 if (FLAG_debug_code) { |
| 1036 __ stop("Unreachable code."); | 1392 __ stop("Unreachable code."); |
| 1037 } | 1393 } |
| 1038 } | 1394 } |
| 1039 | 1395 |
| 1040 | 1396 |
| 1041 void LCodeGen::DoAddI(LAddI* instr) { | 1397 void LCodeGen::DoAddI(LAddI* instr) { |
| 1042 LOperand* left = instr->left(); | 1398 LOperand* left = instr->InputAt(0); |
| 1043 LOperand* right = instr->right(); | 1399 LOperand* right = instr->InputAt(1); |
| 1044 ASSERT(left->Equals(instr->result())); | 1400 ASSERT(left->Equals(instr->result())); |
| 1045 | 1401 |
| 1046 Register right_reg = EmitLoadRegister(right, ip); | 1402 Register right_reg = EmitLoadRegister(right, ip); |
| 1047 __ add(ToRegister(left), ToRegister(left), Operand(right_reg), SetCC); | 1403 __ add(ToRegister(left), ToRegister(left), Operand(right_reg), SetCC); |
| 1048 | 1404 |
| 1049 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { | 1405 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { |
| 1050 DeoptimizeIf(vs, instr->environment()); | 1406 DeoptimizeIf(vs, instr->environment()); |
| 1051 } | 1407 } |
| 1052 } | 1408 } |
| 1053 | 1409 |
| 1054 | 1410 |
| 1055 void LCodeGen::DoArithmeticD(LArithmeticD* instr) { | 1411 void LCodeGen::DoArithmeticD(LArithmeticD* instr) { |
| 1056 DoubleRegister left = ToDoubleRegister(instr->left()); | 1412 DoubleRegister left = ToDoubleRegister(instr->InputAt(0)); |
| 1057 DoubleRegister right = ToDoubleRegister(instr->right()); | 1413 DoubleRegister right = ToDoubleRegister(instr->InputAt(1)); |
| 1058 switch (instr->op()) { | 1414 switch (instr->op()) { |
| 1059 case Token::ADD: | 1415 case Token::ADD: |
| 1060 __ vadd(left, left, right); | 1416 __ vadd(left, left, right); |
| 1061 break; | 1417 break; |
| 1062 case Token::SUB: | 1418 case Token::SUB: |
| 1063 __ vsub(left, left, right); | 1419 __ vsub(left, left, right); |
| 1064 break; | 1420 break; |
| 1065 case Token::MUL: | 1421 case Token::MUL: |
| 1066 __ vmul(left, left, right); | 1422 __ vmul(left, left, right); |
| 1067 break; | 1423 break; |
| 1068 case Token::DIV: | 1424 case Token::DIV: |
| 1069 __ vdiv(left, left, right); | 1425 __ vdiv(left, left, right); |
| 1070 break; | 1426 break; |
| 1071 case Token::MOD: { | 1427 case Token::MOD: { |
| 1072 Abort("DoArithmeticD unimplemented for MOD."); | 1428 Abort("DoArithmeticD unimplemented for MOD."); |
| 1073 break; | 1429 break; |
| 1074 } | 1430 } |
| 1075 default: | 1431 default: |
| 1076 UNREACHABLE(); | 1432 UNREACHABLE(); |
| 1077 break; | 1433 break; |
| 1078 } | 1434 } |
| 1079 } | 1435 } |
| 1080 | 1436 |
| 1081 | 1437 |
| 1082 void LCodeGen::DoArithmeticT(LArithmeticT* instr) { | 1438 void LCodeGen::DoArithmeticT(LArithmeticT* instr) { |
| 1083 ASSERT(ToRegister(instr->left()).is(r1)); | 1439 ASSERT(ToRegister(instr->InputAt(0)).is(r1)); |
| 1084 ASSERT(ToRegister(instr->right()).is(r0)); | 1440 ASSERT(ToRegister(instr->InputAt(1)).is(r0)); |
| 1085 ASSERT(ToRegister(instr->result()).is(r0)); | 1441 ASSERT(ToRegister(instr->result()).is(r0)); |
| 1086 | 1442 |
| 1087 // TODO(regis): Implement TypeRecordingBinaryOpStub and replace current | 1443 // TODO(regis): Implement TypeRecordingBinaryOpStub and replace current |
| 1088 // GenericBinaryOpStub: | 1444 // GenericBinaryOpStub: |
| 1089 // TypeRecordingBinaryOpStub stub(instr->op(), NO_OVERWRITE); | 1445 // TypeRecordingBinaryOpStub stub(instr->op(), NO_OVERWRITE); |
| 1090 GenericBinaryOpStub stub(instr->op(), NO_OVERWRITE, r1, r0); | 1446 GenericBinaryOpStub stub(instr->op(), NO_OVERWRITE, r1, r0); |
| 1091 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | 1447 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 1092 } | 1448 } |
| 1093 | 1449 |
| 1094 | 1450 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1118 } | 1474 } |
| 1119 } | 1475 } |
| 1120 | 1476 |
| 1121 | 1477 |
| 1122 void LCodeGen::DoBranch(LBranch* instr) { | 1478 void LCodeGen::DoBranch(LBranch* instr) { |
| 1123 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1479 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1124 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1480 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1125 | 1481 |
| 1126 Representation r = instr->hydrogen()->representation(); | 1482 Representation r = instr->hydrogen()->representation(); |
| 1127 if (r.IsInteger32()) { | 1483 if (r.IsInteger32()) { |
| 1128 Register reg = ToRegister(instr->input()); | 1484 Register reg = ToRegister(instr->InputAt(0)); |
| 1129 __ cmp(reg, Operand(0)); | 1485 __ cmp(reg, Operand(0)); |
| 1130 EmitBranch(true_block, false_block, nz); | 1486 EmitBranch(true_block, false_block, ne); |
| 1131 } else if (r.IsDouble()) { | 1487 } else if (r.IsDouble()) { |
| 1132 DoubleRegister reg = ToDoubleRegister(instr->input()); | 1488 DoubleRegister reg = ToDoubleRegister(instr->InputAt(0)); |
| 1133 Register scratch = scratch0(); | 1489 Register scratch = scratch0(); |
| 1134 | 1490 |
| 1135 // Test the double value. Zero and NaN are false. | 1491 // Test the double value. Zero and NaN are false. |
| 1136 __ VFPCompareAndLoadFlags(reg, 0.0, scratch); | 1492 __ VFPCompareAndLoadFlags(reg, 0.0, scratch); |
| 1137 __ tst(scratch, Operand(kVFPZConditionFlagBit | kVFPVConditionFlagBit)); | 1493 __ tst(scratch, Operand(kVFPZConditionFlagBit | kVFPVConditionFlagBit)); |
| 1138 EmitBranch(true_block, false_block, ne); | 1494 EmitBranch(true_block, false_block, ne); |
| 1139 } else { | 1495 } else { |
| 1140 ASSERT(r.IsTagged()); | 1496 ASSERT(r.IsTagged()); |
| 1141 Register reg = ToRegister(instr->input()); | 1497 Register reg = ToRegister(instr->InputAt(0)); |
| 1142 if (instr->hydrogen()->type().IsBoolean()) { | 1498 if (instr->hydrogen()->type().IsBoolean()) { |
| 1143 __ LoadRoot(ip, Heap::kTrueValueRootIndex); | 1499 __ LoadRoot(ip, Heap::kTrueValueRootIndex); |
| 1144 __ cmp(reg, ip); | 1500 __ cmp(reg, ip); |
| 1145 EmitBranch(true_block, false_block, eq); | 1501 EmitBranch(true_block, false_block, eq); |
| 1146 } else { | 1502 } else { |
| 1147 Label* true_label = chunk_->GetAssemblyLabel(true_block); | 1503 Label* true_label = chunk_->GetAssemblyLabel(true_block); |
| 1148 Label* false_label = chunk_->GetAssemblyLabel(false_block); | 1504 Label* false_label = chunk_->GetAssemblyLabel(false_block); |
| 1149 | 1505 |
| 1150 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); | 1506 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); |
| 1151 __ cmp(reg, ip); | 1507 __ cmp(reg, ip); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1178 | 1534 |
| 1179 // The conversion stub doesn't cause garbage collections so it's | 1535 // The conversion stub doesn't cause garbage collections so it's |
| 1180 // safe to not record a safepoint after the call. | 1536 // safe to not record a safepoint after the call. |
| 1181 __ bind(&call_stub); | 1537 __ bind(&call_stub); |
| 1182 ToBooleanStub stub(reg); | 1538 ToBooleanStub stub(reg); |
| 1183 RegList saved_regs = kJSCallerSaved | kCalleeSaved; | 1539 RegList saved_regs = kJSCallerSaved | kCalleeSaved; |
| 1184 __ stm(db_w, sp, saved_regs); | 1540 __ stm(db_w, sp, saved_regs); |
| 1185 __ CallStub(&stub); | 1541 __ CallStub(&stub); |
| 1186 __ cmp(reg, Operand(0)); | 1542 __ cmp(reg, Operand(0)); |
| 1187 __ ldm(ia_w, sp, saved_regs); | 1543 __ ldm(ia_w, sp, saved_regs); |
| 1188 EmitBranch(true_block, false_block, nz); | 1544 EmitBranch(true_block, false_block, ne); |
| 1189 } | 1545 } |
| 1190 } | 1546 } |
| 1191 } | 1547 } |
| 1192 | 1548 |
| 1193 | 1549 |
| 1194 void LCodeGen::EmitGoto(int block, LDeferredCode* deferred_stack_check) { | 1550 void LCodeGen::EmitGoto(int block, LDeferredCode* deferred_stack_check) { |
| 1195 block = chunk_->LookupDestination(block); | 1551 block = chunk_->LookupDestination(block); |
| 1196 int next_block = GetNextEmittedBlock(current_block_); | 1552 int next_block = GetNextEmittedBlock(current_block_); |
| 1197 if (block != next_block) { | 1553 if (block != next_block) { |
| 1198 // Perform stack overflow check if this goto needs it before jumping. | 1554 // Perform stack overflow check if this goto needs it before jumping. |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1230 | 1586 |
| 1231 DeferredStackCheck* deferred = NULL; | 1587 DeferredStackCheck* deferred = NULL; |
| 1232 if (instr->include_stack_check()) { | 1588 if (instr->include_stack_check()) { |
| 1233 deferred = new DeferredStackCheck(this, instr); | 1589 deferred = new DeferredStackCheck(this, instr); |
| 1234 } | 1590 } |
| 1235 EmitGoto(instr->block_id(), deferred); | 1591 EmitGoto(instr->block_id(), deferred); |
| 1236 } | 1592 } |
| 1237 | 1593 |
| 1238 | 1594 |
| 1239 Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) { | 1595 Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) { |
| 1240 Condition cond = no_condition; | 1596 Condition cond = kNoCondition; |
| 1241 switch (op) { | 1597 switch (op) { |
| 1242 case Token::EQ: | 1598 case Token::EQ: |
| 1243 case Token::EQ_STRICT: | 1599 case Token::EQ_STRICT: |
| 1244 cond = eq; | 1600 cond = eq; |
| 1245 break; | 1601 break; |
| 1246 case Token::LT: | 1602 case Token::LT: |
| 1247 cond = is_unsigned ? lo : lt; | 1603 cond = is_unsigned ? lo : lt; |
| 1248 break; | 1604 break; |
| 1249 case Token::GT: | 1605 case Token::GT: |
| 1250 cond = is_unsigned ? hi : gt; | 1606 cond = is_unsigned ? hi : gt; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1274 Abort("DoCmpID unimplemented."); | 1630 Abort("DoCmpID unimplemented."); |
| 1275 } | 1631 } |
| 1276 | 1632 |
| 1277 | 1633 |
| 1278 void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { | 1634 void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { |
| 1279 Abort("DoCmpIDAndBranch unimplemented."); | 1635 Abort("DoCmpIDAndBranch unimplemented."); |
| 1280 } | 1636 } |
| 1281 | 1637 |
| 1282 | 1638 |
| 1283 void LCodeGen::DoCmpJSObjectEq(LCmpJSObjectEq* instr) { | 1639 void LCodeGen::DoCmpJSObjectEq(LCmpJSObjectEq* instr) { |
| 1284 Register left = ToRegister(instr->left()); | 1640 Register left = ToRegister(instr->InputAt(0)); |
| 1285 Register right = ToRegister(instr->right()); | 1641 Register right = ToRegister(instr->InputAt(1)); |
| 1286 Register result = ToRegister(instr->result()); | 1642 Register result = ToRegister(instr->result()); |
| 1287 | 1643 |
| 1288 __ cmp(left, Operand(right)); | 1644 __ cmp(left, Operand(right)); |
| 1289 __ LoadRoot(result, Heap::kTrueValueRootIndex, eq); | 1645 __ LoadRoot(result, Heap::kTrueValueRootIndex, eq); |
| 1290 __ LoadRoot(result, Heap::kFalseValueRootIndex, ne); | 1646 __ LoadRoot(result, Heap::kFalseValueRootIndex, ne); |
| 1291 Abort("DoCmpJSObjectEq untested."); | |
| 1292 } | 1647 } |
| 1293 | 1648 |
| 1294 | 1649 |
| 1295 void LCodeGen::DoCmpJSObjectEqAndBranch(LCmpJSObjectEqAndBranch* instr) { | 1650 void LCodeGen::DoCmpJSObjectEqAndBranch(LCmpJSObjectEqAndBranch* instr) { |
| 1296 Abort("DoCmpJSObjectEqAndBranch unimplemented."); | 1651 Register left = ToRegister(instr->InputAt(0)); |
| 1652 Register right = ToRegister(instr->InputAt(1)); |
| 1653 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1654 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1655 |
| 1656 __ cmp(left, Operand(right)); |
| 1657 EmitBranch(true_block, false_block, eq); |
| 1297 } | 1658 } |
| 1298 | 1659 |
| 1299 | 1660 |
| 1300 void LCodeGen::DoIsNull(LIsNull* instr) { | 1661 void LCodeGen::DoIsNull(LIsNull* instr) { |
| 1301 Register reg = ToRegister(instr->input()); | 1662 Register reg = ToRegister(instr->InputAt(0)); |
| 1302 Register result = ToRegister(instr->result()); | 1663 Register result = ToRegister(instr->result()); |
| 1303 | 1664 |
| 1304 __ LoadRoot(ip, Heap::kNullValueRootIndex); | 1665 __ LoadRoot(ip, Heap::kNullValueRootIndex); |
| 1305 __ cmp(reg, ip); | 1666 __ cmp(reg, ip); |
| 1306 if (instr->is_strict()) { | 1667 if (instr->is_strict()) { |
| 1307 __ LoadRoot(result, Heap::kTrueValueRootIndex, eq); | 1668 __ LoadRoot(result, Heap::kTrueValueRootIndex, eq); |
| 1308 __ LoadRoot(result, Heap::kFalseValueRootIndex, ne); | 1669 __ LoadRoot(result, Heap::kFalseValueRootIndex, ne); |
| 1309 } else { | 1670 } else { |
| 1310 Label true_value, false_value, done; | 1671 Label true_value, false_value, done; |
| 1311 __ b(eq, &true_value); | 1672 __ b(eq, &true_value); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1326 __ jmp(&done); | 1687 __ jmp(&done); |
| 1327 __ bind(&true_value); | 1688 __ bind(&true_value); |
| 1328 __ LoadRoot(result, Heap::kTrueValueRootIndex); | 1689 __ LoadRoot(result, Heap::kTrueValueRootIndex); |
| 1329 __ bind(&done); | 1690 __ bind(&done); |
| 1330 } | 1691 } |
| 1331 } | 1692 } |
| 1332 | 1693 |
| 1333 | 1694 |
| 1334 void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) { | 1695 void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) { |
| 1335 Register scratch = scratch0(); | 1696 Register scratch = scratch0(); |
| 1336 Register reg = ToRegister(instr->input()); | 1697 Register reg = ToRegister(instr->InputAt(0)); |
| 1337 | 1698 |
| 1338 // TODO(fsc): If the expression is known to be a smi, then it's | 1699 // TODO(fsc): If the expression is known to be a smi, then it's |
| 1339 // definitely not null. Jump to the false block. | 1700 // definitely not null. Jump to the false block. |
| 1340 | 1701 |
| 1341 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1702 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1342 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1703 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1343 | 1704 |
| 1344 __ LoadRoot(ip, Heap::kNullValueRootIndex); | 1705 __ LoadRoot(ip, Heap::kNullValueRootIndex); |
| 1345 __ cmp(reg, ip); | 1706 __ cmp(reg, ip); |
| 1346 if (instr->is_strict()) { | 1707 if (instr->is_strict()) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1362 EmitBranch(true_block, false_block, ne); | 1723 EmitBranch(true_block, false_block, ne); |
| 1363 } | 1724 } |
| 1364 } | 1725 } |
| 1365 | 1726 |
| 1366 | 1727 |
| 1367 Condition LCodeGen::EmitIsObject(Register input, | 1728 Condition LCodeGen::EmitIsObject(Register input, |
| 1368 Register temp1, | 1729 Register temp1, |
| 1369 Register temp2, | 1730 Register temp2, |
| 1370 Label* is_not_object, | 1731 Label* is_not_object, |
| 1371 Label* is_object) { | 1732 Label* is_object) { |
| 1372 Abort("EmitIsObject unimplemented."); | 1733 __ JumpIfSmi(input, is_not_object); |
| 1373 return ne; | 1734 |
| 1735 __ LoadRoot(temp1, Heap::kNullValueRootIndex); |
| 1736 __ cmp(input, temp1); |
| 1737 __ b(eq, is_object); |
| 1738 |
| 1739 // Load map. |
| 1740 __ ldr(temp1, FieldMemOperand(input, HeapObject::kMapOffset)); |
| 1741 // Undetectable objects behave like undefined. |
| 1742 __ ldrb(temp2, FieldMemOperand(temp1, Map::kBitFieldOffset)); |
| 1743 __ tst(temp2, Operand(1 << Map::kIsUndetectable)); |
| 1744 __ b(ne, is_not_object); |
| 1745 |
| 1746 // Load instance type and check that it is in object type range. |
| 1747 __ ldrb(temp2, FieldMemOperand(temp1, Map::kInstanceTypeOffset)); |
| 1748 __ cmp(temp2, Operand(FIRST_JS_OBJECT_TYPE)); |
| 1749 __ b(lt, is_not_object); |
| 1750 __ cmp(temp2, Operand(LAST_JS_OBJECT_TYPE)); |
| 1751 return le; |
| 1374 } | 1752 } |
| 1375 | 1753 |
| 1376 | 1754 |
| 1377 void LCodeGen::DoIsObject(LIsObject* instr) { | 1755 void LCodeGen::DoIsObject(LIsObject* instr) { |
| 1378 Abort("DoIsObject unimplemented."); | 1756 Register reg = ToRegister(instr->InputAt(0)); |
| 1757 Register result = ToRegister(instr->result()); |
| 1758 Register temp = scratch0(); |
| 1759 Label is_false, is_true, done; |
| 1760 |
| 1761 Condition true_cond = EmitIsObject(reg, result, temp, &is_false, &is_true); |
| 1762 __ b(true_cond, &is_true); |
| 1763 |
| 1764 __ bind(&is_false); |
| 1765 __ LoadRoot(result, Heap::kFalseValueRootIndex); |
| 1766 __ b(&done); |
| 1767 |
| 1768 __ bind(&is_true); |
| 1769 __ LoadRoot(result, Heap::kTrueValueRootIndex); |
| 1770 |
| 1771 __ bind(&done); |
| 1379 } | 1772 } |
| 1380 | 1773 |
| 1381 | 1774 |
| 1382 void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) { | 1775 void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) { |
| 1383 Abort("DoIsObjectAndBranch unimplemented."); | 1776 Register reg = ToRegister(instr->InputAt(0)); |
| 1777 Register temp1 = ToRegister(instr->TempAt(0)); |
| 1778 Register temp2 = scratch0(); |
| 1779 |
| 1780 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1781 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1782 Label* true_label = chunk_->GetAssemblyLabel(true_block); |
| 1783 Label* false_label = chunk_->GetAssemblyLabel(false_block); |
| 1784 |
| 1785 Condition true_cond = |
| 1786 EmitIsObject(reg, temp1, temp2, false_label, true_label); |
| 1787 |
| 1788 EmitBranch(true_block, false_block, true_cond); |
| 1384 } | 1789 } |
| 1385 | 1790 |
| 1386 | 1791 |
| 1387 void LCodeGen::DoIsSmi(LIsSmi* instr) { | 1792 void LCodeGen::DoIsSmi(LIsSmi* instr) { |
| 1388 ASSERT(instr->hydrogen()->value()->representation().IsTagged()); | 1793 ASSERT(instr->hydrogen()->value()->representation().IsTagged()); |
| 1389 Register result = ToRegister(instr->result()); | 1794 Register result = ToRegister(instr->result()); |
| 1390 Register input_reg = EmitLoadRegister(instr->input(), ip); | 1795 Register input_reg = EmitLoadRegister(instr->InputAt(0), ip); |
| 1391 __ tst(input_reg, Operand(kSmiTagMask)); | 1796 __ tst(input_reg, Operand(kSmiTagMask)); |
| 1392 __ LoadRoot(result, Heap::kTrueValueRootIndex); | 1797 __ LoadRoot(result, Heap::kTrueValueRootIndex); |
| 1393 Label done; | 1798 Label done; |
| 1394 __ b(eq, &done); | 1799 __ b(eq, &done); |
| 1395 __ LoadRoot(result, Heap::kFalseValueRootIndex); | 1800 __ LoadRoot(result, Heap::kFalseValueRootIndex); |
| 1396 __ bind(&done); | 1801 __ bind(&done); |
| 1397 } | 1802 } |
| 1398 | 1803 |
| 1399 | 1804 |
| 1400 void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) { | 1805 void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) { |
| 1401 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1806 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1402 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1807 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1403 | 1808 |
| 1404 Register input_reg = EmitLoadRegister(instr->input(), ip); | 1809 Register input_reg = EmitLoadRegister(instr->InputAt(0), ip); |
| 1405 __ tst(input_reg, Operand(kSmiTagMask)); | 1810 __ tst(input_reg, Operand(kSmiTagMask)); |
| 1406 EmitBranch(true_block, false_block, eq); | 1811 EmitBranch(true_block, false_block, eq); |
| 1407 } | 1812 } |
| 1408 | 1813 |
| 1409 | 1814 |
| 1410 InstanceType LHasInstanceType::TestType() { | 1815 static InstanceType TestType(HHasInstanceType* instr) { |
| 1411 InstanceType from = hydrogen()->from(); | 1816 InstanceType from = instr->from(); |
| 1412 InstanceType to = hydrogen()->to(); | 1817 InstanceType to = instr->to(); |
| 1413 if (from == FIRST_TYPE) return to; | 1818 if (from == FIRST_TYPE) return to; |
| 1414 ASSERT(from == to || to == LAST_TYPE); | 1819 ASSERT(from == to || to == LAST_TYPE); |
| 1415 return from; | 1820 return from; |
| 1416 } | 1821 } |
| 1417 | 1822 |
| 1418 | 1823 |
| 1419 Condition LHasInstanceType::BranchCondition() { | 1824 static Condition BranchCondition(HHasInstanceType* instr) { |
| 1420 InstanceType from = hydrogen()->from(); | 1825 InstanceType from = instr->from(); |
| 1421 InstanceType to = hydrogen()->to(); | 1826 InstanceType to = instr->to(); |
| 1422 if (from == to) return eq; | 1827 if (from == to) return eq; |
| 1423 if (to == LAST_TYPE) return hs; | 1828 if (to == LAST_TYPE) return hs; |
| 1424 if (from == FIRST_TYPE) return ls; | 1829 if (from == FIRST_TYPE) return ls; |
| 1425 UNREACHABLE(); | 1830 UNREACHABLE(); |
| 1426 return eq; | 1831 return eq; |
| 1427 } | 1832 } |
| 1428 | 1833 |
| 1429 | 1834 |
| 1430 void LCodeGen::DoHasInstanceType(LHasInstanceType* instr) { | 1835 void LCodeGen::DoHasInstanceType(LHasInstanceType* instr) { |
| 1431 Abort("DoHasInstanceType unimplemented."); | 1836 Register input = ToRegister(instr->InputAt(0)); |
| 1837 Register result = ToRegister(instr->result()); |
| 1838 |
| 1839 ASSERT(instr->hydrogen()->value()->representation().IsTagged()); |
| 1840 Label done; |
| 1841 __ tst(input, Operand(kSmiTagMask)); |
| 1842 __ LoadRoot(result, Heap::kFalseValueRootIndex, eq); |
| 1843 __ b(eq, &done); |
| 1844 __ CompareObjectType(input, result, result, TestType(instr->hydrogen())); |
| 1845 Condition cond = BranchCondition(instr->hydrogen()); |
| 1846 __ LoadRoot(result, Heap::kTrueValueRootIndex, cond); |
| 1847 __ LoadRoot(result, Heap::kFalseValueRootIndex, NegateCondition(cond)); |
| 1848 __ bind(&done); |
| 1432 } | 1849 } |
| 1433 | 1850 |
| 1434 | 1851 |
| 1435 void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { | 1852 void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { |
| 1436 Register scratch = scratch0(); | 1853 Register scratch = scratch0(); |
| 1437 Register input = ToRegister(instr->input()); | 1854 Register input = ToRegister(instr->InputAt(0)); |
| 1438 | 1855 |
| 1439 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1856 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1440 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1857 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1441 | 1858 |
| 1442 Label* false_label = chunk_->GetAssemblyLabel(false_block); | 1859 Label* false_label = chunk_->GetAssemblyLabel(false_block); |
| 1443 | 1860 |
| 1444 __ tst(input, Operand(kSmiTagMask)); | 1861 __ tst(input, Operand(kSmiTagMask)); |
| 1445 __ b(eq, false_label); | 1862 __ b(eq, false_label); |
| 1446 | 1863 |
| 1447 __ CompareObjectType(input, scratch, scratch, instr->TestType()); | 1864 __ CompareObjectType(input, scratch, scratch, TestType(instr->hydrogen())); |
| 1448 EmitBranch(true_block, false_block, instr->BranchCondition()); | 1865 EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen())); |
| 1449 } | 1866 } |
| 1450 | 1867 |
| 1451 | 1868 |
| 1452 void LCodeGen::DoHasCachedArrayIndex(LHasCachedArrayIndex* instr) { | 1869 void LCodeGen::DoHasCachedArrayIndex(LHasCachedArrayIndex* instr) { |
| 1453 Abort("DoHasCachedArrayIndex unimplemented."); | 1870 Abort("DoHasCachedArrayIndex unimplemented."); |
| 1454 } | 1871 } |
| 1455 | 1872 |
| 1456 | 1873 |
| 1457 void LCodeGen::DoHasCachedArrayIndexAndBranch( | 1874 void LCodeGen::DoHasCachedArrayIndexAndBranch( |
| 1458 LHasCachedArrayIndexAndBranch* instr) { | 1875 LHasCachedArrayIndexAndBranch* instr) { |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1511 // booted. This routine isn't expected to work for random API-created | 1928 // booted. This routine isn't expected to work for random API-created |
| 1512 // classes and it doesn't have to because you can't access it with natives | 1929 // classes and it doesn't have to because you can't access it with natives |
| 1513 // syntax. Since both sides are symbols it is sufficient to use an identity | 1930 // syntax. Since both sides are symbols it is sufficient to use an identity |
| 1514 // comparison. | 1931 // comparison. |
| 1515 __ cmp(temp, Operand(class_name)); | 1932 __ cmp(temp, Operand(class_name)); |
| 1516 // End with the answer in flags. | 1933 // End with the answer in flags. |
| 1517 } | 1934 } |
| 1518 | 1935 |
| 1519 | 1936 |
| 1520 void LCodeGen::DoClassOfTest(LClassOfTest* instr) { | 1937 void LCodeGen::DoClassOfTest(LClassOfTest* instr) { |
| 1521 Register input = ToRegister(instr->input()); | 1938 Register input = ToRegister(instr->InputAt(0)); |
| 1522 Register result = ToRegister(instr->result()); | 1939 Register result = ToRegister(instr->result()); |
| 1523 ASSERT(input.is(result)); | 1940 ASSERT(input.is(result)); |
| 1524 Handle<String> class_name = instr->hydrogen()->class_name(); | 1941 Handle<String> class_name = instr->hydrogen()->class_name(); |
| 1525 | 1942 |
| 1526 Label done, is_true, is_false; | 1943 Label done, is_true, is_false; |
| 1527 | 1944 |
| 1528 EmitClassOfTest(&is_true, &is_false, class_name, input, scratch0(), input); | 1945 EmitClassOfTest(&is_true, &is_false, class_name, input, scratch0(), input); |
| 1529 __ b(ne, &is_false); | 1946 __ b(ne, &is_false); |
| 1530 | 1947 |
| 1531 __ bind(&is_true); | 1948 __ bind(&is_true); |
| 1532 __ LoadRoot(result, Heap::kTrueValueRootIndex); | 1949 __ LoadRoot(result, Heap::kTrueValueRootIndex); |
| 1533 __ jmp(&done); | 1950 __ jmp(&done); |
| 1534 | 1951 |
| 1535 __ bind(&is_false); | 1952 __ bind(&is_false); |
| 1536 __ LoadRoot(result, Heap::kFalseValueRootIndex); | 1953 __ LoadRoot(result, Heap::kFalseValueRootIndex); |
| 1537 __ bind(&done); | 1954 __ bind(&done); |
| 1538 } | 1955 } |
| 1539 | 1956 |
| 1540 | 1957 |
| 1541 void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { | 1958 void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { |
| 1542 Register input = ToRegister(instr->input()); | 1959 Register input = ToRegister(instr->InputAt(0)); |
| 1543 Register temp = scratch0(); | 1960 Register temp = scratch0(); |
| 1544 Register temp2 = ToRegister(instr->temporary()); | 1961 Register temp2 = ToRegister(instr->TempAt(0)); |
| 1545 Handle<String> class_name = instr->hydrogen()->class_name(); | 1962 Handle<String> class_name = instr->hydrogen()->class_name(); |
| 1546 | 1963 |
| 1547 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1964 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1548 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1965 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1549 | 1966 |
| 1550 Label* true_label = chunk_->GetAssemblyLabel(true_block); | 1967 Label* true_label = chunk_->GetAssemblyLabel(true_block); |
| 1551 Label* false_label = chunk_->GetAssemblyLabel(false_block); | 1968 Label* false_label = chunk_->GetAssemblyLabel(false_block); |
| 1552 | 1969 |
| 1553 EmitClassOfTest(true_label, false_label, class_name, input, temp, temp2); | 1970 EmitClassOfTest(true_label, false_label, class_name, input, temp, temp2); |
| 1554 | 1971 |
| 1555 EmitBranch(true_block, false_block, eq); | 1972 EmitBranch(true_block, false_block, eq); |
| 1556 } | 1973 } |
| 1557 | 1974 |
| 1558 | 1975 |
| 1559 void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) { | 1976 void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) { |
| 1560 Register reg = ToRegister(instr->input()); | 1977 Register reg = ToRegister(instr->InputAt(0)); |
| 1561 Register temp = ToRegister(instr->temp()); | 1978 Register temp = ToRegister(instr->TempAt(0)); |
| 1562 int true_block = instr->true_block_id(); | 1979 int true_block = instr->true_block_id(); |
| 1563 int false_block = instr->false_block_id(); | 1980 int false_block = instr->false_block_id(); |
| 1564 | 1981 |
| 1565 __ ldr(temp, FieldMemOperand(reg, HeapObject::kMapOffset)); | 1982 __ ldr(temp, FieldMemOperand(reg, HeapObject::kMapOffset)); |
| 1566 __ cmp(temp, Operand(instr->map())); | 1983 __ cmp(temp, Operand(instr->map())); |
| 1567 EmitBranch(true_block, false_block, eq); | 1984 EmitBranch(true_block, false_block, eq); |
| 1568 } | 1985 } |
| 1569 | 1986 |
| 1570 | 1987 |
| 1571 void LCodeGen::DoInstanceOf(LInstanceOf* instr) { | 1988 void LCodeGen::DoInstanceOf(LInstanceOf* instr) { |
| 1572 ASSERT(ToRegister(instr->left()).is(r0)); // Object is in r0. | 1989 ASSERT(ToRegister(instr->InputAt(0)).is(r0)); // Object is in r0. |
| 1573 ASSERT(ToRegister(instr->right()).is(r1)); // Function is in r1. | 1990 ASSERT(ToRegister(instr->InputAt(1)).is(r1)); // Function is in r1. |
| 1574 | 1991 |
| 1575 InstanceofStub stub(InstanceofStub::kArgsInRegisters); | 1992 InstanceofStub stub(InstanceofStub::kArgsInRegisters); |
| 1576 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | 1993 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 1577 | 1994 |
| 1578 Label true_value, done; | 1995 Label true_value, done; |
| 1579 __ tst(r0, r0); | 1996 __ tst(r0, r0); |
| 1580 __ mov(r0, Operand(FACTORY->false_value()), LeaveCC, ne); | 1997 __ mov(r0, Operand(FACTORY->false_value()), LeaveCC, ne); |
| 1581 __ mov(r0, Operand(FACTORY->true_value()), LeaveCC, eq); | 1998 __ mov(r0, Operand(FACTORY->true_value()), LeaveCC, eq); |
| 1582 } | 1999 } |
| 1583 | 2000 |
| 1584 | 2001 |
| 1585 void LCodeGen::DoInstanceOfAndBranch(LInstanceOfAndBranch* instr) { | 2002 void LCodeGen::DoInstanceOfAndBranch(LInstanceOfAndBranch* instr) { |
| 1586 Abort("DoInstanceOfAndBranch unimplemented."); | 2003 Abort("DoInstanceOfAndBranch unimplemented."); |
| 1587 } | 2004 } |
| 1588 | 2005 |
| 1589 | 2006 |
| 1590 void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { | 2007 void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { |
| 1591 Abort("DoInstanceOfKnownGlobal unimplemented."); | 2008 class DeferredInstanceOfKnownGlobal: public LDeferredCode { |
| 2009 public: |
| 2010 DeferredInstanceOfKnownGlobal(LCodeGen* codegen, |
| 2011 LInstanceOfKnownGlobal* instr) |
| 2012 : LDeferredCode(codegen), instr_(instr) { } |
| 2013 virtual void Generate() { |
| 2014 codegen()->DoDeferredLInstanceOfKnownGlobal(instr_, &map_check_); |
| 2015 } |
| 2016 |
| 2017 Label* map_check() { return &map_check_; } |
| 2018 |
| 2019 private: |
| 2020 LInstanceOfKnownGlobal* instr_; |
| 2021 Label map_check_; |
| 2022 }; |
| 2023 |
| 2024 DeferredInstanceOfKnownGlobal* deferred; |
| 2025 deferred = new DeferredInstanceOfKnownGlobal(this, instr); |
| 2026 |
| 2027 Label done, false_result; |
| 2028 Register object = ToRegister(instr->InputAt(0)); |
| 2029 Register temp = ToRegister(instr->TempAt(0)); |
| 2030 Register result = ToRegister(instr->result()); |
| 2031 |
| 2032 ASSERT(object.is(r0)); |
| 2033 ASSERT(result.is(r0)); |
| 2034 |
| 2035 // A Smi is not instance of anything. |
| 2036 __ JumpIfSmi(object, &false_result); |
| 2037 |
| 2038 // This is the inlined call site instanceof cache. The two occurences of the |
| 2039 // hole value will be patched to the last map/result pair generated by the |
| 2040 // instanceof stub. |
| 2041 Label cache_miss; |
| 2042 Register map = temp; |
| 2043 __ ldr(map, FieldMemOperand(object, HeapObject::kMapOffset)); |
| 2044 __ bind(deferred->map_check()); // Label for calculating code patching. |
| 2045 // We use Factory::the_hole_value() on purpose instead of loading from the |
| 2046 // root array to force relocation to be able to later patch with |
| 2047 // the cached map. |
| 2048 __ mov(ip, Operand(FACTORY->the_hole_value())); |
| 2049 __ cmp(map, Operand(ip)); |
| 2050 __ b(ne, &cache_miss); |
| 2051 // We use Factory::the_hole_value() on purpose instead of loading from the |
| 2052 // root array to force relocation to be able to later patch |
| 2053 // with true or false. |
| 2054 __ mov(result, Operand(FACTORY->the_hole_value())); |
| 2055 __ b(&done); |
| 2056 |
| 2057 // The inlined call site cache did not match. Check null and string before |
| 2058 // calling the deferred code. |
| 2059 __ bind(&cache_miss); |
| 2060 // Null is not instance of anything. |
| 2061 __ LoadRoot(ip, Heap::kNullValueRootIndex); |
| 2062 __ cmp(object, Operand(ip)); |
| 2063 __ b(eq, &false_result); |
| 2064 |
| 2065 // String values is not instance of anything. |
| 2066 Condition is_string = masm_->IsObjectStringType(object, temp); |
| 2067 __ b(is_string, &false_result); |
| 2068 |
| 2069 // Go to the deferred code. |
| 2070 __ b(deferred->entry()); |
| 2071 |
| 2072 __ bind(&false_result); |
| 2073 __ LoadRoot(result, Heap::kFalseValueRootIndex); |
| 2074 |
| 2075 // Here result has either true or false. Deferred code also produces true or |
| 2076 // false object. |
| 2077 __ bind(deferred->exit()); |
| 2078 __ bind(&done); |
| 2079 } |
| 2080 |
| 2081 |
| 2082 void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, |
| 2083 Label* map_check) { |
| 2084 Register result = ToRegister(instr->result()); |
| 2085 ASSERT(result.is(r0)); |
| 2086 |
| 2087 InstanceofStub::Flags flags = InstanceofStub::kNoFlags; |
| 2088 flags = static_cast<InstanceofStub::Flags>( |
| 2089 flags | InstanceofStub::kArgsInRegisters); |
| 2090 flags = static_cast<InstanceofStub::Flags>( |
| 2091 flags | InstanceofStub::kCallSiteInlineCheck); |
| 2092 flags = static_cast<InstanceofStub::Flags>( |
| 2093 flags | InstanceofStub::kReturnTrueFalseObject); |
| 2094 InstanceofStub stub(flags); |
| 2095 |
| 2096 __ PushSafepointRegisters(); |
| 2097 |
| 2098 // Get the temp register reserved by the instruction. This needs to be r4 as |
| 2099 // its slot of the pushing of safepoint registers is used to communicate the |
| 2100 // offset to the location of the map check. |
| 2101 Register temp = ToRegister(instr->TempAt(0)); |
| 2102 ASSERT(temp.is(r4)); |
| 2103 __ mov(InstanceofStub::right(), Operand(instr->function())); |
| 2104 static const int kAdditionalDelta = 4; |
| 2105 int delta = masm_->InstructionsGeneratedSince(map_check) + kAdditionalDelta; |
| 2106 Label before_push_delta; |
| 2107 __ bind(&before_push_delta); |
| 2108 __ BlockConstPoolFor(kAdditionalDelta); |
| 2109 __ mov(temp, Operand(delta * kPointerSize)); |
| 2110 __ StoreToSafepointRegisterSlot(temp); |
| 2111 __ Call(stub.GetCode(), RelocInfo::CODE_TARGET); |
| 2112 ASSERT_EQ(kAdditionalDelta, |
| 2113 masm_->InstructionsGeneratedSince(&before_push_delta)); |
| 2114 RecordSafepointWithRegisters( |
| 2115 instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex); |
| 2116 // Put the result value into the result register slot and |
| 2117 // restore all registers. |
| 2118 __ StoreToSafepointRegisterSlot(result); |
| 2119 |
| 2120 __ PopSafepointRegisters(); |
| 1592 } | 2121 } |
| 1593 | 2122 |
| 1594 | 2123 |
| 1595 static Condition ComputeCompareCondition(Token::Value op) { | 2124 static Condition ComputeCompareCondition(Token::Value op) { |
| 1596 switch (op) { | 2125 switch (op) { |
| 1597 case Token::EQ_STRICT: | 2126 case Token::EQ_STRICT: |
| 1598 case Token::EQ: | 2127 case Token::EQ: |
| 1599 return eq; | 2128 return eq; |
| 1600 case Token::LT: | 2129 case Token::LT: |
| 1601 return lt; | 2130 return lt; |
| 1602 case Token::GT: | 2131 case Token::GT: |
| 1603 return gt; | 2132 return gt; |
| 1604 case Token::LTE: | 2133 case Token::LTE: |
| 1605 return le; | 2134 return le; |
| 1606 case Token::GTE: | 2135 case Token::GTE: |
| 1607 return ge; | 2136 return ge; |
| 1608 default: | 2137 default: |
| 1609 UNREACHABLE(); | 2138 UNREACHABLE(); |
| 1610 return no_condition; | 2139 return kNoCondition; |
| 1611 } | 2140 } |
| 1612 } | 2141 } |
| 1613 | 2142 |
| 1614 | 2143 |
| 1615 void LCodeGen::DoCmpT(LCmpT* instr) { | 2144 void LCodeGen::DoCmpT(LCmpT* instr) { |
| 1616 Token::Value op = instr->op(); | 2145 Token::Value op = instr->op(); |
| 1617 | 2146 |
| 1618 Handle<Code> ic = CompareIC::GetUninitialized(op); | 2147 Handle<Code> ic = CompareIC::GetUninitialized(op); |
| 1619 CallCode(ic, RelocInfo::CODE_TARGET, instr); | 2148 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
| 1620 | 2149 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1658 __ ldr(result, FieldMemOperand(ip, JSGlobalPropertyCell::kValueOffset)); | 2187 __ ldr(result, FieldMemOperand(ip, JSGlobalPropertyCell::kValueOffset)); |
| 1659 if (instr->hydrogen()->check_hole_value()) { | 2188 if (instr->hydrogen()->check_hole_value()) { |
| 1660 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 2189 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
| 1661 __ cmp(result, ip); | 2190 __ cmp(result, ip); |
| 1662 DeoptimizeIf(eq, instr->environment()); | 2191 DeoptimizeIf(eq, instr->environment()); |
| 1663 } | 2192 } |
| 1664 } | 2193 } |
| 1665 | 2194 |
| 1666 | 2195 |
| 1667 void LCodeGen::DoStoreGlobal(LStoreGlobal* instr) { | 2196 void LCodeGen::DoStoreGlobal(LStoreGlobal* instr) { |
| 1668 Register value = ToRegister(instr->input()); | 2197 Register value = ToRegister(instr->InputAt(0)); |
| 1669 __ mov(ip, Operand(Handle<Object>(instr->hydrogen()->cell()))); | 2198 __ mov(ip, Operand(Handle<Object>(instr->hydrogen()->cell()))); |
| 1670 __ str(value, FieldMemOperand(ip, JSGlobalPropertyCell::kValueOffset)); | 2199 __ str(value, FieldMemOperand(ip, JSGlobalPropertyCell::kValueOffset)); |
| 1671 } | 2200 } |
| 1672 | 2201 |
| 1673 | 2202 |
| 2203 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) { |
| 2204 // TODO(antonm): load a context with a separate instruction. |
| 2205 Register result = ToRegister(instr->result()); |
| 2206 __ LoadContext(result, instr->context_chain_length()); |
| 2207 __ ldr(result, ContextOperand(result, instr->slot_index())); |
| 2208 } |
| 2209 |
| 2210 |
| 1674 void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { | 2211 void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { |
| 1675 Register object = ToRegister(instr->input()); | 2212 Register object = ToRegister(instr->InputAt(0)); |
| 1676 Register result = ToRegister(instr->result()); | 2213 Register result = ToRegister(instr->result()); |
| 1677 if (instr->hydrogen()->is_in_object()) { | 2214 if (instr->hydrogen()->is_in_object()) { |
| 1678 __ ldr(result, FieldMemOperand(object, instr->hydrogen()->offset())); | 2215 __ ldr(result, FieldMemOperand(object, instr->hydrogen()->offset())); |
| 1679 } else { | 2216 } else { |
| 1680 __ ldr(result, FieldMemOperand(object, JSObject::kPropertiesOffset)); | 2217 __ ldr(result, FieldMemOperand(object, JSObject::kPropertiesOffset)); |
| 1681 __ ldr(result, FieldMemOperand(result, instr->hydrogen()->offset())); | 2218 __ ldr(result, FieldMemOperand(result, instr->hydrogen()->offset())); |
| 1682 } | 2219 } |
| 1683 } | 2220 } |
| 1684 | 2221 |
| 1685 | 2222 |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1733 // in initial map. | 2270 // in initial map. |
| 1734 __ bind(&non_instance); | 2271 __ bind(&non_instance); |
| 1735 __ ldr(result, FieldMemOperand(result, Map::kConstructorOffset)); | 2272 __ ldr(result, FieldMemOperand(result, Map::kConstructorOffset)); |
| 1736 | 2273 |
| 1737 // All done. | 2274 // All done. |
| 1738 __ bind(&done); | 2275 __ bind(&done); |
| 1739 } | 2276 } |
| 1740 | 2277 |
| 1741 | 2278 |
| 1742 void LCodeGen::DoLoadElements(LLoadElements* instr) { | 2279 void LCodeGen::DoLoadElements(LLoadElements* instr) { |
| 1743 ASSERT(instr->result()->Equals(instr->input())); | 2280 ASSERT(instr->result()->Equals(instr->InputAt(0))); |
| 1744 Register reg = ToRegister(instr->input()); | 2281 Register reg = ToRegister(instr->InputAt(0)); |
| 1745 Register scratch = scratch0(); | 2282 Register scratch = scratch0(); |
| 1746 | 2283 |
| 1747 __ ldr(reg, FieldMemOperand(reg, JSObject::kElementsOffset)); | 2284 __ ldr(reg, FieldMemOperand(reg, JSObject::kElementsOffset)); |
| 1748 if (FLAG_debug_code) { | 2285 if (FLAG_debug_code) { |
| 1749 Label done; | 2286 Label done; |
| 1750 __ ldr(scratch, FieldMemOperand(reg, HeapObject::kMapOffset)); | 2287 __ ldr(scratch, FieldMemOperand(reg, HeapObject::kMapOffset)); |
| 1751 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex); | 2288 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex); |
| 1752 __ cmp(scratch, ip); | 2289 __ cmp(scratch, ip); |
| 1753 __ b(eq, &done); | 2290 __ b(eq, &done); |
| 1754 __ LoadRoot(ip, Heap::kFixedCOWArrayMapRootIndex); | 2291 __ LoadRoot(ip, Heap::kFixedCOWArrayMapRootIndex); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1816 __ cmp(result, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); | 2353 __ cmp(result, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); |
| 1817 | 2354 |
| 1818 // Result is the frame pointer for the frame if not adapted and for the real | 2355 // Result is the frame pointer for the frame if not adapted and for the real |
| 1819 // frame below the adaptor frame if adapted. | 2356 // frame below the adaptor frame if adapted. |
| 1820 __ mov(result, fp, LeaveCC, ne); | 2357 __ mov(result, fp, LeaveCC, ne); |
| 1821 __ mov(result, scratch, LeaveCC, eq); | 2358 __ mov(result, scratch, LeaveCC, eq); |
| 1822 } | 2359 } |
| 1823 | 2360 |
| 1824 | 2361 |
| 1825 void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) { | 2362 void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) { |
| 1826 Register elem = ToRegister(instr->input()); | 2363 Register elem = ToRegister(instr->InputAt(0)); |
| 1827 Register result = ToRegister(instr->result()); | 2364 Register result = ToRegister(instr->result()); |
| 1828 | 2365 |
| 1829 Label done; | 2366 Label done; |
| 1830 | 2367 |
| 1831 // If no arguments adaptor frame the number of arguments is fixed. | 2368 // If no arguments adaptor frame the number of arguments is fixed. |
| 1832 __ cmp(fp, elem); | 2369 __ cmp(fp, elem); |
| 1833 __ mov(result, Operand(scope()->num_parameters())); | 2370 __ mov(result, Operand(scope()->num_parameters())); |
| 1834 __ b(eq, &done); | 2371 __ b(eq, &done); |
| 1835 | 2372 |
| 1836 // Arguments adaptor frame present. Get argument length from there. | 2373 // Arguments adaptor frame present. Get argument length from there. |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1901 // which is r0, as expected by InvokeFunction. | 2438 // which is r0, as expected by InvokeFunction. |
| 1902 v8::internal::ParameterCount actual(receiver); | 2439 v8::internal::ParameterCount actual(receiver); |
| 1903 SafepointGenerator safepoint_generator(this, | 2440 SafepointGenerator safepoint_generator(this, |
| 1904 instr->pointer_map(), | 2441 instr->pointer_map(), |
| 1905 Safepoint::kNoDeoptimizationIndex); | 2442 Safepoint::kNoDeoptimizationIndex); |
| 1906 __ InvokeFunction(function, actual, CALL_FUNCTION, &safepoint_generator); | 2443 __ InvokeFunction(function, actual, CALL_FUNCTION, &safepoint_generator); |
| 1907 } | 2444 } |
| 1908 | 2445 |
| 1909 | 2446 |
| 1910 void LCodeGen::DoPushArgument(LPushArgument* instr) { | 2447 void LCodeGen::DoPushArgument(LPushArgument* instr) { |
| 1911 LOperand* argument = instr->input(); | 2448 LOperand* argument = instr->InputAt(0); |
| 1912 if (argument->IsDoubleRegister() || argument->IsDoubleStackSlot()) { | 2449 if (argument->IsDoubleRegister() || argument->IsDoubleStackSlot()) { |
| 1913 Abort("DoPushArgument not implemented for double type."); | 2450 Abort("DoPushArgument not implemented for double type."); |
| 1914 } else { | 2451 } else { |
| 1915 Register argument_reg = EmitLoadRegister(argument, ip); | 2452 Register argument_reg = EmitLoadRegister(argument, ip); |
| 1916 __ push(argument_reg); | 2453 __ push(argument_reg); |
| 1917 } | 2454 } |
| 1918 } | 2455 } |
| 1919 | 2456 |
| 1920 | 2457 |
| 1921 void LCodeGen::DoGlobalObject(LGlobalObject* instr) { | 2458 void LCodeGen::DoGlobalObject(LGlobalObject* instr) { |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1965 | 2502 |
| 1966 | 2503 |
| 1967 void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) { | 2504 void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) { |
| 1968 ASSERT(ToRegister(instr->result()).is(r0)); | 2505 ASSERT(ToRegister(instr->result()).is(r0)); |
| 1969 __ mov(r1, Operand(instr->function())); | 2506 __ mov(r1, Operand(instr->function())); |
| 1970 CallKnownFunction(instr->function(), instr->arity(), instr); | 2507 CallKnownFunction(instr->function(), instr->arity(), instr); |
| 1971 } | 2508 } |
| 1972 | 2509 |
| 1973 | 2510 |
| 1974 void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) { | 2511 void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) { |
| 1975 Abort("DoDeferredMathAbsTaggedHeapNumber unimplemented."); | 2512 Register input = ToRegister(instr->InputAt(0)); |
| 2513 Register scratch = scratch0(); |
| 2514 |
| 2515 // Deoptimize if not a heap number. |
| 2516 __ ldr(scratch, FieldMemOperand(input, HeapObject::kMapOffset)); |
| 2517 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex); |
| 2518 __ cmp(scratch, Operand(ip)); |
| 2519 DeoptimizeIf(ne, instr->environment()); |
| 2520 |
| 2521 Label done; |
| 2522 |
| 2523 Label negative; |
| 2524 __ ldr(scratch, FieldMemOperand(input, HeapNumber::kExponentOffset)); |
| 2525 // Check the sign of the argument. If the argument is positive, just |
| 2526 // return it. We do not need to patch the stack since |input| and |
| 2527 // |result| are the same register and |input| will be restored |
| 2528 // unchanged by popping safepoint registers. |
| 2529 __ tst(scratch, Operand(HeapNumber::kSignMask)); |
| 2530 __ b(ne, &negative); |
| 2531 __ jmp(&done); |
| 2532 |
| 2533 __ bind(&negative); |
| 2534 // Preserve the value of all registers. |
| 2535 __ PushSafepointRegisters(); |
| 2536 |
| 2537 Register tmp = input.is(r0) ? r1 : r0; |
| 2538 Register tmp2 = input.is(r2) ? r3 : r2; |
| 2539 Register tmp3 = input.is(r4) ? r5 : r4; |
| 2540 |
| 2541 Label allocated, slow; |
| 2542 __ LoadRoot(scratch, Heap::kHeapNumberMapRootIndex); |
| 2543 __ AllocateHeapNumber(tmp, tmp2, tmp3, scratch, &slow); |
| 2544 __ b(&allocated); |
| 2545 |
| 2546 // Slow case: Call the runtime system to do the number allocation. |
| 2547 __ bind(&slow); |
| 2548 |
| 2549 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); |
| 2550 RecordSafepointWithRegisters( |
| 2551 instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex); |
| 2552 // Set the pointer to the new heap number in tmp. |
| 2553 if (!tmp.is(r0)) __ mov(tmp, Operand(r0)); |
| 2554 |
| 2555 // Restore input_reg after call to runtime. |
| 2556 MemOperand input_register_slot = masm()->SafepointRegisterSlot(input); |
| 2557 __ ldr(input, input_register_slot); |
| 2558 |
| 2559 __ bind(&allocated); |
| 2560 __ ldr(tmp2, FieldMemOperand(input, HeapNumber::kExponentOffset)); |
| 2561 __ bic(tmp2, tmp2, Operand(HeapNumber::kSignMask)); |
| 2562 __ str(tmp2, FieldMemOperand(tmp, HeapNumber::kExponentOffset)); |
| 2563 __ ldr(tmp2, FieldMemOperand(input, HeapNumber::kMantissaOffset)); |
| 2564 __ str(tmp2, FieldMemOperand(tmp, HeapNumber::kMantissaOffset)); |
| 2565 |
| 2566 __ str(tmp, input_register_slot); |
| 2567 __ PopSafepointRegisters(); |
| 2568 |
| 2569 __ bind(&done); |
| 2570 } |
| 2571 |
| 2572 |
| 2573 void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) { |
| 2574 Label is_positive; |
| 2575 uint32_t kSignMask = 0x80000000u; |
| 2576 Register input = ToRegister(instr->InputAt(0)); |
| 2577 __ tst(input, Operand(kSignMask)); |
| 2578 __ b(eq, &is_positive); |
| 2579 __ rsb(input, input, Operand(0), SetCC); |
| 2580 // Deoptimize on overflow. |
| 2581 DeoptimizeIf(vs, instr->environment()); |
| 2582 __ bind(&is_positive); |
| 1976 } | 2583 } |
| 1977 | 2584 |
| 1978 | 2585 |
| 1979 void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) { | 2586 void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) { |
| 1980 Abort("DoMathAbs unimplemented."); | 2587 // Class for deferred case. |
| 2588 class DeferredMathAbsTaggedHeapNumber: public LDeferredCode { |
| 2589 public: |
| 2590 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen, |
| 2591 LUnaryMathOperation* instr) |
| 2592 : LDeferredCode(codegen), instr_(instr) { } |
| 2593 virtual void Generate() { |
| 2594 codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_); |
| 2595 } |
| 2596 private: |
| 2597 LUnaryMathOperation* instr_; |
| 2598 }; |
| 2599 |
| 2600 ASSERT(instr->InputAt(0)->Equals(instr->result())); |
| 2601 Representation r = instr->hydrogen()->value()->representation(); |
| 2602 if (r.IsDouble()) { |
| 2603 DwVfpRegister input = ToDoubleRegister(instr->InputAt(0)); |
| 2604 // __ vabs(input, input); |
| 2605 Abort("Double DoMathAbs unimplemented"); |
| 2606 } else if (r.IsInteger32()) { |
| 2607 EmitIntegerMathAbs(instr); |
| 2608 } else { |
| 2609 // Representation is tagged. |
| 2610 DeferredMathAbsTaggedHeapNumber* deferred = |
| 2611 new DeferredMathAbsTaggedHeapNumber(this, instr); |
| 2612 Register input = ToRegister(instr->InputAt(0)); |
| 2613 // Smi check. |
| 2614 __ JumpIfNotSmi(input, deferred->entry()); |
| 2615 // If smi, handle it directly. |
| 2616 EmitIntegerMathAbs(instr); |
| 2617 __ bind(deferred->exit()); |
| 2618 } |
| 1981 } | 2619 } |
| 1982 | 2620 |
| 1983 | 2621 |
| 1984 void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) { | 2622 void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) { |
| 1985 DoubleRegister input = ToDoubleRegister(instr->input()); | 2623 DoubleRegister input = ToDoubleRegister(instr->InputAt(0)); |
| 1986 Register result = ToRegister(instr->result()); | 2624 Register result = ToRegister(instr->result()); |
| 1987 Register prev_fpscr = ToRegister(instr->temp()); | 2625 Register prev_fpscr = ToRegister(instr->TempAt(0)); |
| 1988 SwVfpRegister single_scratch = single_scratch0(); | 2626 SwVfpRegister single_scratch = double_scratch0().low(); |
| 1989 Register scratch = scratch0(); | 2627 Register scratch = scratch0(); |
| 1990 | 2628 |
| 1991 // Set custom FPCSR: | 2629 // Set custom FPCSR: |
| 1992 // - Set rounding mode to "Round towards Minus Infinity". | 2630 // - Set rounding mode to "Round towards Minus Infinity". |
| 1993 // - Clear vfp cumulative exception flags. | 2631 // - Clear vfp cumulative exception flags. |
| 1994 // - Make sure Flush-to-zero mode control bit is unset. | 2632 // - Make sure Flush-to-zero mode control bit is unset. |
| 1995 __ vmrs(prev_fpscr); | 2633 __ vmrs(prev_fpscr); |
| 1996 __ bic(scratch, prev_fpscr, | 2634 __ bic(scratch, prev_fpscr, |
| 1997 Operand(kVFPExceptionMask | kVFPRoundingModeMask | kVFPFlushToZeroMask)); | 2635 Operand(kVFPExceptionMask | kVFPRoundingModeMask | kVFPFlushToZeroMask)); |
| 1998 __ orr(scratch, scratch, Operand(kVFPRoundToMinusInfinityBits)); | 2636 __ orr(scratch, scratch, Operand(kVFPRoundToMinusInfinityBits)); |
| 1999 __ vmsr(scratch); | 2637 __ vmsr(scratch); |
| 2000 | 2638 |
| 2001 // Convert the argument to an integer. | 2639 // Convert the argument to an integer. |
| 2002 __ vcvt_s32_f64(single_scratch, | 2640 __ vcvt_s32_f64(single_scratch, |
| 2003 input, | 2641 input, |
| 2004 Assembler::FPSCRRounding, | 2642 Assembler::FPSCRRounding, |
| 2005 al); | 2643 al); |
| 2006 | 2644 |
| 2007 // Retrieve FPSCR and check for vfp exceptions. | 2645 // Retrieve FPSCR and check for vfp exceptions. |
| 2008 __ vmrs(scratch); | 2646 __ vmrs(scratch); |
| 2009 // Restore FPSCR | 2647 // Restore FPSCR |
| 2010 __ vmsr(prev_fpscr); | 2648 __ vmsr(prev_fpscr); |
| 2011 __ tst(scratch, Operand(kVFPExceptionMask)); | 2649 __ tst(scratch, Operand(kVFPExceptionMask)); |
| 2012 DeoptimizeIf(ne, instr->environment()); | 2650 DeoptimizeIf(ne, instr->environment()); |
| 2013 | 2651 |
| 2014 // Move the result back to general purpose register r0. | 2652 // Move the result back to general purpose register r0. |
| 2015 __ vmov(result, single_scratch); | 2653 __ vmov(result, single_scratch); |
| 2654 |
| 2655 // Test for -0. |
| 2656 Label done; |
| 2657 __ cmp(result, Operand(0)); |
| 2658 __ b(ne, &done); |
| 2659 __ vmov(scratch, input.high()); |
| 2660 __ tst(scratch, Operand(HeapNumber::kSignMask)); |
| 2661 DeoptimizeIf(ne, instr->environment()); |
| 2662 __ bind(&done); |
| 2016 } | 2663 } |
| 2017 | 2664 |
| 2018 | 2665 |
| 2019 void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) { | 2666 void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) { |
| 2020 DoubleRegister input = ToDoubleRegister(instr->input()); | 2667 DoubleRegister input = ToDoubleRegister(instr->InputAt(0)); |
| 2021 ASSERT(ToDoubleRegister(instr->result()).is(input)); | 2668 ASSERT(ToDoubleRegister(instr->result()).is(input)); |
| 2022 __ vsqrt(input, input); | 2669 __ vsqrt(input, input); |
| 2023 } | 2670 } |
| 2024 | 2671 |
| 2025 | 2672 |
| 2026 void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) { | 2673 void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) { |
| 2027 switch (instr->op()) { | 2674 switch (instr->op()) { |
| 2028 case kMathAbs: | 2675 case kMathAbs: |
| 2029 DoMathAbs(instr); | 2676 DoMathAbs(instr); |
| 2030 break; | 2677 break; |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2091 | 2738 |
| 2092 | 2739 |
| 2093 void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) { | 2740 void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) { |
| 2094 ASSERT(ToRegister(instr->result()).is(r0)); | 2741 ASSERT(ToRegister(instr->result()).is(r0)); |
| 2095 __ mov(r1, Operand(instr->target())); | 2742 __ mov(r1, Operand(instr->target())); |
| 2096 CallKnownFunction(instr->target(), instr->arity(), instr); | 2743 CallKnownFunction(instr->target(), instr->arity(), instr); |
| 2097 } | 2744 } |
| 2098 | 2745 |
| 2099 | 2746 |
| 2100 void LCodeGen::DoCallNew(LCallNew* instr) { | 2747 void LCodeGen::DoCallNew(LCallNew* instr) { |
| 2101 ASSERT(ToRegister(instr->input()).is(r1)); | 2748 ASSERT(ToRegister(instr->InputAt(0)).is(r1)); |
| 2102 ASSERT(ToRegister(instr->result()).is(r0)); | 2749 ASSERT(ToRegister(instr->result()).is(r0)); |
| 2103 | 2750 |
| 2104 Handle<Code> builtin(Isolate::Current()->builtins()-> | 2751 Handle<Code> builtin(Isolate::Current()->builtins()-> |
| 2105 builtin(Builtins::JSConstructCall)); | 2752 builtin(Builtins::JSConstructCall)); |
| 2106 __ mov(r0, Operand(instr->arity())); | 2753 __ mov(r0, Operand(instr->arity())); |
| 2107 CallCode(builtin, RelocInfo::CONSTRUCT_CALL, instr); | 2754 CallCode(builtin, RelocInfo::CONSTRUCT_CALL, instr); |
| 2108 } | 2755 } |
| 2109 | 2756 |
| 2110 | 2757 |
| 2111 void LCodeGen::DoCallRuntime(LCallRuntime* instr) { | 2758 void LCodeGen::DoCallRuntime(LCallRuntime* instr) { |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2193 ASSERT(ToRegister(instr->object()).is(r2)); | 2840 ASSERT(ToRegister(instr->object()).is(r2)); |
| 2194 ASSERT(ToRegister(instr->key()).is(r1)); | 2841 ASSERT(ToRegister(instr->key()).is(r1)); |
| 2195 ASSERT(ToRegister(instr->value()).is(r0)); | 2842 ASSERT(ToRegister(instr->value()).is(r0)); |
| 2196 | 2843 |
| 2197 Handle<Code> ic(Isolate::Current()->builtins()-> | 2844 Handle<Code> ic(Isolate::Current()->builtins()-> |
| 2198 builtin(Builtins::KeyedStoreIC_Initialize)); | 2845 builtin(Builtins::KeyedStoreIC_Initialize)); |
| 2199 CallCode(ic, RelocInfo::CODE_TARGET, instr); | 2846 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
| 2200 } | 2847 } |
| 2201 | 2848 |
| 2202 | 2849 |
| 2850 void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { |
| 2851 class DeferredStringCharCodeAt: public LDeferredCode { |
| 2852 public: |
| 2853 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr) |
| 2854 : LDeferredCode(codegen), instr_(instr) { } |
| 2855 virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); } |
| 2856 private: |
| 2857 LStringCharCodeAt* instr_; |
| 2858 }; |
| 2859 |
| 2860 Register scratch = scratch0(); |
| 2861 Register string = ToRegister(instr->string()); |
| 2862 Register index = no_reg; |
| 2863 int const_index = -1; |
| 2864 if (instr->index()->IsConstantOperand()) { |
| 2865 const_index = ToInteger32(LConstantOperand::cast(instr->index())); |
| 2866 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue); |
| 2867 if (!Smi::IsValid(const_index)) { |
| 2868 // Guaranteed to be out of bounds because of the assert above. |
| 2869 // So the bounds check that must dominate this instruction must |
| 2870 // have deoptimized already. |
| 2871 if (FLAG_debug_code) { |
| 2872 __ Abort("StringCharCodeAt: out of bounds index."); |
| 2873 } |
| 2874 // No code needs to be generated. |
| 2875 return; |
| 2876 } |
| 2877 } else { |
| 2878 index = ToRegister(instr->index()); |
| 2879 } |
| 2880 Register result = ToRegister(instr->result()); |
| 2881 |
| 2882 DeferredStringCharCodeAt* deferred = |
| 2883 new DeferredStringCharCodeAt(this, instr); |
| 2884 |
| 2885 Label flat_string, ascii_string, done; |
| 2886 |
| 2887 // Fetch the instance type of the receiver into result register. |
| 2888 __ ldr(result, FieldMemOperand(string, HeapObject::kMapOffset)); |
| 2889 __ ldrb(result, FieldMemOperand(result, Map::kInstanceTypeOffset)); |
| 2890 |
| 2891 // We need special handling for non-flat strings. |
| 2892 STATIC_ASSERT(kSeqStringTag == 0); |
| 2893 __ tst(result, Operand(kStringRepresentationMask)); |
| 2894 __ b(eq, &flat_string); |
| 2895 |
| 2896 // Handle non-flat strings. |
| 2897 __ tst(result, Operand(kIsConsStringMask)); |
| 2898 __ b(eq, deferred->entry()); |
| 2899 |
| 2900 // ConsString. |
| 2901 // Check whether the right hand side is the empty string (i.e. if |
| 2902 // this is really a flat string in a cons string). If that is not |
| 2903 // the case we would rather go to the runtime system now to flatten |
| 2904 // the string. |
| 2905 __ ldr(scratch, FieldMemOperand(string, ConsString::kSecondOffset)); |
| 2906 __ LoadRoot(ip, Heap::kEmptyStringRootIndex); |
| 2907 __ cmp(scratch, ip); |
| 2908 __ b(ne, deferred->entry()); |
| 2909 // Get the first of the two strings and load its instance type. |
| 2910 __ ldr(string, FieldMemOperand(string, ConsString::kFirstOffset)); |
| 2911 __ ldr(result, FieldMemOperand(string, HeapObject::kMapOffset)); |
| 2912 __ ldrb(result, FieldMemOperand(result, Map::kInstanceTypeOffset)); |
| 2913 // If the first cons component is also non-flat, then go to runtime. |
| 2914 STATIC_ASSERT(kSeqStringTag == 0); |
| 2915 __ tst(result, Operand(kStringRepresentationMask)); |
| 2916 __ b(ne, deferred->entry()); |
| 2917 |
| 2918 // Check for 1-byte or 2-byte string. |
| 2919 __ bind(&flat_string); |
| 2920 STATIC_ASSERT(kAsciiStringTag != 0); |
| 2921 __ tst(result, Operand(kStringEncodingMask)); |
| 2922 __ b(ne, &ascii_string); |
| 2923 |
| 2924 // 2-byte string. |
| 2925 // Load the 2-byte character code into the result register. |
| 2926 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); |
| 2927 if (instr->index()->IsConstantOperand()) { |
| 2928 __ ldrh(result, |
| 2929 FieldMemOperand(string, |
| 2930 SeqTwoByteString::kHeaderSize + 2 * const_index)); |
| 2931 } else { |
| 2932 __ add(scratch, |
| 2933 string, |
| 2934 Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
| 2935 __ ldrh(result, MemOperand(scratch, index, LSL, 1)); |
| 2936 } |
| 2937 __ jmp(&done); |
| 2938 |
| 2939 // ASCII string. |
| 2940 // Load the byte into the result register. |
| 2941 __ bind(&ascii_string); |
| 2942 if (instr->index()->IsConstantOperand()) { |
| 2943 __ ldrb(result, FieldMemOperand(string, |
| 2944 SeqAsciiString::kHeaderSize + const_index)); |
| 2945 } else { |
| 2946 __ add(scratch, |
| 2947 string, |
| 2948 Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| 2949 __ ldrb(result, MemOperand(scratch, index)); |
| 2950 } |
| 2951 __ bind(&done); |
| 2952 __ bind(deferred->exit()); |
| 2953 } |
| 2954 |
| 2955 |
| 2956 void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) { |
| 2957 Register string = ToRegister(instr->string()); |
| 2958 Register result = ToRegister(instr->result()); |
| 2959 Register scratch = scratch0(); |
| 2960 |
| 2961 // TODO(3095996): Get rid of this. For now, we need to make the |
| 2962 // result register contain a valid pointer because it is already |
| 2963 // contained in the register pointer map. |
| 2964 __ mov(result, Operand(0)); |
| 2965 |
| 2966 __ PushSafepointRegisters(); |
| 2967 __ push(string); |
| 2968 // Push the index as a smi. This is safe because of the checks in |
| 2969 // DoStringCharCodeAt above. |
| 2970 if (instr->index()->IsConstantOperand()) { |
| 2971 int const_index = ToInteger32(LConstantOperand::cast(instr->index())); |
| 2972 __ mov(scratch, Operand(Smi::FromInt(const_index))); |
| 2973 __ push(scratch); |
| 2974 } else { |
| 2975 Register index = ToRegister(instr->index()); |
| 2976 __ SmiTag(index); |
| 2977 __ push(index); |
| 2978 } |
| 2979 __ CallRuntimeSaveDoubles(Runtime::kStringCharCodeAt); |
| 2980 RecordSafepointWithRegisters( |
| 2981 instr->pointer_map(), 2, Safepoint::kNoDeoptimizationIndex); |
| 2982 if (FLAG_debug_code) { |
| 2983 __ AbortIfNotSmi(r0); |
| 2984 } |
| 2985 __ SmiUntag(r0); |
| 2986 MemOperand result_stack_slot = masm()->SafepointRegisterSlot(result); |
| 2987 __ str(r0, result_stack_slot); |
| 2988 __ PopSafepointRegisters(); |
| 2989 } |
| 2990 |
| 2991 |
| 2992 void LCodeGen::DoStringLength(LStringLength* instr) { |
| 2993 Register string = ToRegister(instr->InputAt(0)); |
| 2994 Register result = ToRegister(instr->result()); |
| 2995 __ ldr(result, FieldMemOperand(string, String::kLengthOffset)); |
| 2996 } |
| 2997 |
| 2998 |
| 2203 void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) { | 2999 void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) { |
| 2204 Abort("DoInteger32ToDouble unimplemented."); | 3000 LOperand* input = instr->InputAt(0); |
| 3001 ASSERT(input->IsRegister() || input->IsStackSlot()); |
| 3002 LOperand* output = instr->result(); |
| 3003 ASSERT(output->IsDoubleRegister()); |
| 3004 SwVfpRegister single_scratch = double_scratch0().low(); |
| 3005 if (input->IsStackSlot()) { |
| 3006 Register scratch = scratch0(); |
| 3007 __ ldr(scratch, ToMemOperand(input)); |
| 3008 __ vmov(single_scratch, scratch); |
| 3009 } else { |
| 3010 __ vmov(single_scratch, ToRegister(input)); |
| 3011 } |
| 3012 __ vcvt_f64_s32(ToDoubleRegister(output), single_scratch); |
| 2205 } | 3013 } |
| 2206 | 3014 |
| 2207 | 3015 |
| 2208 void LCodeGen::DoNumberTagI(LNumberTagI* instr) { | 3016 void LCodeGen::DoNumberTagI(LNumberTagI* instr) { |
| 2209 class DeferredNumberTagI: public LDeferredCode { | 3017 class DeferredNumberTagI: public LDeferredCode { |
| 2210 public: | 3018 public: |
| 2211 DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr) | 3019 DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr) |
| 2212 : LDeferredCode(codegen), instr_(instr) { } | 3020 : LDeferredCode(codegen), instr_(instr) { } |
| 2213 virtual void Generate() { codegen()->DoDeferredNumberTagI(instr_); } | 3021 virtual void Generate() { codegen()->DoDeferredNumberTagI(instr_); } |
| 2214 private: | 3022 private: |
| 2215 LNumberTagI* instr_; | 3023 LNumberTagI* instr_; |
| 2216 }; | 3024 }; |
| 2217 | 3025 |
| 2218 LOperand* input = instr->input(); | 3026 LOperand* input = instr->InputAt(0); |
| 2219 ASSERT(input->IsRegister() && input->Equals(instr->result())); | 3027 ASSERT(input->IsRegister() && input->Equals(instr->result())); |
| 2220 Register reg = ToRegister(input); | 3028 Register reg = ToRegister(input); |
| 2221 | 3029 |
| 2222 DeferredNumberTagI* deferred = new DeferredNumberTagI(this, instr); | 3030 DeferredNumberTagI* deferred = new DeferredNumberTagI(this, instr); |
| 2223 __ SmiTag(reg, SetCC); | 3031 __ SmiTag(reg, SetCC); |
| 2224 __ b(vs, deferred->entry()); | 3032 __ b(vs, deferred->entry()); |
| 2225 __ bind(deferred->exit()); | 3033 __ bind(deferred->exit()); |
| 2226 } | 3034 } |
| 2227 | 3035 |
| 2228 | 3036 |
| 2229 void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) { | 3037 void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) { |
| 2230 Label slow; | 3038 Label slow; |
| 2231 Register reg = ToRegister(instr->input()); | 3039 Register reg = ToRegister(instr->InputAt(0)); |
| 2232 DoubleRegister dbl_scratch = d0; | 3040 DoubleRegister dbl_scratch = d0; |
| 2233 SwVfpRegister flt_scratch = s0; | 3041 SwVfpRegister flt_scratch = s0; |
| 2234 | 3042 |
| 2235 // Preserve the value of all registers. | 3043 // Preserve the value of all registers. |
| 2236 __ PushSafepointRegisters(); | 3044 __ PushSafepointRegisters(); |
| 2237 | 3045 |
| 2238 // There was overflow, so bits 30 and 31 of the original integer | 3046 // There was overflow, so bits 30 and 31 of the original integer |
| 2239 // disagree. Try to allocate a heap number in new space and store | 3047 // disagree. Try to allocate a heap number in new space and store |
| 2240 // the value in there. If that fails, call the runtime system. | 3048 // the value in there. If that fails, call the runtime system. |
| 2241 Label done; | 3049 Label done; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2278 void LCodeGen::DoNumberTagD(LNumberTagD* instr) { | 3086 void LCodeGen::DoNumberTagD(LNumberTagD* instr) { |
| 2279 class DeferredNumberTagD: public LDeferredCode { | 3087 class DeferredNumberTagD: public LDeferredCode { |
| 2280 public: | 3088 public: |
| 2281 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr) | 3089 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr) |
| 2282 : LDeferredCode(codegen), instr_(instr) { } | 3090 : LDeferredCode(codegen), instr_(instr) { } |
| 2283 virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); } | 3091 virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); } |
| 2284 private: | 3092 private: |
| 2285 LNumberTagD* instr_; | 3093 LNumberTagD* instr_; |
| 2286 }; | 3094 }; |
| 2287 | 3095 |
| 2288 DoubleRegister input_reg = ToDoubleRegister(instr->input()); | 3096 DoubleRegister input_reg = ToDoubleRegister(instr->InputAt(0)); |
| 2289 Register scratch = scratch0(); | 3097 Register scratch = scratch0(); |
| 2290 Register reg = ToRegister(instr->result()); | 3098 Register reg = ToRegister(instr->result()); |
| 2291 Register temp1 = ToRegister(instr->temp1()); | 3099 Register temp1 = ToRegister(instr->TempAt(0)); |
| 2292 Register temp2 = ToRegister(instr->temp2()); | 3100 Register temp2 = ToRegister(instr->TempAt(1)); |
| 2293 | 3101 |
| 2294 DeferredNumberTagD* deferred = new DeferredNumberTagD(this, instr); | 3102 DeferredNumberTagD* deferred = new DeferredNumberTagD(this, instr); |
| 2295 if (FLAG_inline_new) { | 3103 if (FLAG_inline_new) { |
| 2296 __ LoadRoot(scratch, Heap::kHeapNumberMapRootIndex); | 3104 __ LoadRoot(scratch, Heap::kHeapNumberMapRootIndex); |
| 2297 __ AllocateHeapNumber(reg, temp1, temp2, scratch, deferred->entry()); | 3105 __ AllocateHeapNumber(reg, temp1, temp2, scratch, deferred->entry()); |
| 2298 } else { | 3106 } else { |
| 2299 __ jmp(deferred->entry()); | 3107 __ jmp(deferred->entry()); |
| 2300 } | 3108 } |
| 2301 __ bind(deferred->exit()); | 3109 __ bind(deferred->exit()); |
| 2302 __ sub(ip, reg, Operand(kHeapObjectTag)); | 3110 __ sub(ip, reg, Operand(kHeapObjectTag)); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 2315 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); | 3123 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); |
| 2316 RecordSafepointWithRegisters( | 3124 RecordSafepointWithRegisters( |
| 2317 instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex); | 3125 instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex); |
| 2318 int reg_stack_index = __ SafepointRegisterStackIndex(reg.code()); | 3126 int reg_stack_index = __ SafepointRegisterStackIndex(reg.code()); |
| 2319 __ str(r0, MemOperand(sp, reg_stack_index * kPointerSize)); | 3127 __ str(r0, MemOperand(sp, reg_stack_index * kPointerSize)); |
| 2320 __ PopSafepointRegisters(); | 3128 __ PopSafepointRegisters(); |
| 2321 } | 3129 } |
| 2322 | 3130 |
| 2323 | 3131 |
| 2324 void LCodeGen::DoSmiTag(LSmiTag* instr) { | 3132 void LCodeGen::DoSmiTag(LSmiTag* instr) { |
| 2325 LOperand* input = instr->input(); | 3133 LOperand* input = instr->InputAt(0); |
| 2326 ASSERT(input->IsRegister() && input->Equals(instr->result())); | 3134 ASSERT(input->IsRegister() && input->Equals(instr->result())); |
| 2327 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow)); | 3135 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow)); |
| 2328 __ SmiTag(ToRegister(input)); | 3136 __ SmiTag(ToRegister(input)); |
| 2329 } | 3137 } |
| 2330 | 3138 |
| 2331 | 3139 |
| 2332 void LCodeGen::DoSmiUntag(LSmiUntag* instr) { | 3140 void LCodeGen::DoSmiUntag(LSmiUntag* instr) { |
| 2333 LOperand* input = instr->input(); | 3141 LOperand* input = instr->InputAt(0); |
| 2334 ASSERT(input->IsRegister() && input->Equals(instr->result())); | 3142 ASSERT(input->IsRegister() && input->Equals(instr->result())); |
| 2335 if (instr->needs_check()) { | 3143 if (instr->needs_check()) { |
| 2336 __ tst(ToRegister(input), Operand(kSmiTagMask)); | 3144 __ tst(ToRegister(input), Operand(kSmiTagMask)); |
| 2337 DeoptimizeIf(ne, instr->environment()); | 3145 DeoptimizeIf(ne, instr->environment()); |
| 2338 } | 3146 } |
| 2339 __ SmiUntag(ToRegister(input)); | 3147 __ SmiUntag(ToRegister(input)); |
| 2340 } | 3148 } |
| 2341 | 3149 |
| 2342 | 3150 |
| 2343 void LCodeGen::EmitNumberUntagD(Register input_reg, | 3151 void LCodeGen::EmitNumberUntagD(Register input_reg, |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2390 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr) | 3198 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr) |
| 2391 : LDeferredCode(codegen), instr_(instr) { } | 3199 : LDeferredCode(codegen), instr_(instr) { } |
| 2392 virtual void Generate() { codegen()->DoDeferredTaggedToI(instr_); } | 3200 virtual void Generate() { codegen()->DoDeferredTaggedToI(instr_); } |
| 2393 private: | 3201 private: |
| 2394 LTaggedToI* instr_; | 3202 LTaggedToI* instr_; |
| 2395 }; | 3203 }; |
| 2396 | 3204 |
| 2397 | 3205 |
| 2398 void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { | 3206 void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { |
| 2399 Label done; | 3207 Label done; |
| 2400 Register input_reg = ToRegister(instr->input()); | 3208 Register input_reg = ToRegister(instr->InputAt(0)); |
| 2401 Register scratch = scratch0(); | 3209 Register scratch = scratch0(); |
| 2402 DoubleRegister dbl_scratch = d0; | 3210 DoubleRegister dbl_scratch = d0; |
| 2403 SwVfpRegister flt_scratch = s0; | 3211 SwVfpRegister flt_scratch = s0; |
| 2404 DoubleRegister dbl_tmp = ToDoubleRegister(instr->temp()); | 3212 DoubleRegister dbl_tmp = ToDoubleRegister(instr->TempAt(0)); |
| 2405 | 3213 |
| 2406 // Heap number map check. | 3214 // Heap number map check. |
| 2407 __ ldr(scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset)); | 3215 __ ldr(scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset)); |
| 2408 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex); | 3216 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex); |
| 2409 __ cmp(scratch, Operand(ip)); | 3217 __ cmp(scratch, Operand(ip)); |
| 2410 | 3218 |
| 2411 if (instr->truncating()) { | 3219 if (instr->truncating()) { |
| 2412 Label heap_number; | 3220 Label heap_number; |
| 2413 __ b(eq, &heap_number); | 3221 __ b(eq, &heap_number); |
| 2414 // Check for undefined. Undefined is converted to zero for truncating | 3222 // Check for undefined. Undefined is converted to zero for truncating |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2451 __ vmov(lr, ip, dbl_tmp); | 3259 __ vmov(lr, ip, dbl_tmp); |
| 2452 __ tst(ip, Operand(1 << 31)); // Test sign bit. | 3260 __ tst(ip, Operand(1 << 31)); // Test sign bit. |
| 2453 DeoptimizeIf(ne, instr->environment()); | 3261 DeoptimizeIf(ne, instr->environment()); |
| 2454 } | 3262 } |
| 2455 } | 3263 } |
| 2456 __ bind(&done); | 3264 __ bind(&done); |
| 2457 } | 3265 } |
| 2458 | 3266 |
| 2459 | 3267 |
| 2460 void LCodeGen::DoTaggedToI(LTaggedToI* instr) { | 3268 void LCodeGen::DoTaggedToI(LTaggedToI* instr) { |
| 2461 LOperand* input = instr->input(); | 3269 LOperand* input = instr->InputAt(0); |
| 2462 ASSERT(input->IsRegister()); | 3270 ASSERT(input->IsRegister()); |
| 2463 ASSERT(input->Equals(instr->result())); | 3271 ASSERT(input->Equals(instr->result())); |
| 2464 | 3272 |
| 2465 Register input_reg = ToRegister(input); | 3273 Register input_reg = ToRegister(input); |
| 2466 | 3274 |
| 2467 DeferredTaggedToI* deferred = new DeferredTaggedToI(this, instr); | 3275 DeferredTaggedToI* deferred = new DeferredTaggedToI(this, instr); |
| 2468 | 3276 |
| 2469 // Smi check. | 3277 // Smi check. |
| 2470 __ tst(input_reg, Operand(kSmiTagMask)); | 3278 __ tst(input_reg, Operand(kSmiTagMask)); |
| 2471 __ b(ne, deferred->entry()); | 3279 __ b(ne, deferred->entry()); |
| 2472 | 3280 |
| 2473 // Smi to int32 conversion | 3281 // Smi to int32 conversion |
| 2474 __ SmiUntag(input_reg); // Untag smi. | 3282 __ SmiUntag(input_reg); // Untag smi. |
| 2475 | 3283 |
| 2476 __ bind(deferred->exit()); | 3284 __ bind(deferred->exit()); |
| 2477 } | 3285 } |
| 2478 | 3286 |
| 2479 | 3287 |
| 2480 void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { | 3288 void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { |
| 2481 LOperand* input = instr->input(); | 3289 LOperand* input = instr->InputAt(0); |
| 2482 ASSERT(input->IsRegister()); | 3290 ASSERT(input->IsRegister()); |
| 2483 LOperand* result = instr->result(); | 3291 LOperand* result = instr->result(); |
| 2484 ASSERT(result->IsDoubleRegister()); | 3292 ASSERT(result->IsDoubleRegister()); |
| 2485 | 3293 |
| 2486 Register input_reg = ToRegister(input); | 3294 Register input_reg = ToRegister(input); |
| 2487 DoubleRegister result_reg = ToDoubleRegister(result); | 3295 DoubleRegister result_reg = ToDoubleRegister(result); |
| 2488 | 3296 |
| 2489 EmitNumberUntagD(input_reg, result_reg, instr->environment()); | 3297 EmitNumberUntagD(input_reg, result_reg, instr->environment()); |
| 2490 } | 3298 } |
| 2491 | 3299 |
| 2492 | 3300 |
| 2493 void LCodeGen::DoDoubleToI(LDoubleToI* instr) { | 3301 void LCodeGen::DoDoubleToI(LDoubleToI* instr) { |
| 2494 Abort("DoDoubleToI unimplemented."); | 3302 Abort("DoDoubleToI unimplemented."); |
| 2495 } | 3303 } |
| 2496 | 3304 |
| 2497 | 3305 |
| 2498 void LCodeGen::DoCheckSmi(LCheckSmi* instr) { | 3306 void LCodeGen::DoCheckSmi(LCheckSmi* instr) { |
| 2499 LOperand* input = instr->input(); | 3307 LOperand* input = instr->InputAt(0); |
| 2500 ASSERT(input->IsRegister()); | 3308 ASSERT(input->IsRegister()); |
| 2501 __ tst(ToRegister(input), Operand(kSmiTagMask)); | 3309 __ tst(ToRegister(input), Operand(kSmiTagMask)); |
| 2502 DeoptimizeIf(instr->condition(), instr->environment()); | 3310 DeoptimizeIf(instr->condition(), instr->environment()); |
| 2503 } | 3311 } |
| 2504 | 3312 |
| 2505 | 3313 |
| 2506 void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { | 3314 void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { |
| 2507 Register input = ToRegister(instr->input()); | 3315 Register input = ToRegister(instr->InputAt(0)); |
| 2508 Register scratch = scratch0(); | 3316 Register scratch = scratch0(); |
| 2509 InstanceType first = instr->hydrogen()->first(); | 3317 InstanceType first = instr->hydrogen()->first(); |
| 2510 InstanceType last = instr->hydrogen()->last(); | 3318 InstanceType last = instr->hydrogen()->last(); |
| 2511 | 3319 |
| 2512 __ ldr(scratch, FieldMemOperand(input, HeapObject::kMapOffset)); | 3320 __ ldr(scratch, FieldMemOperand(input, HeapObject::kMapOffset)); |
| 2513 __ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset)); | 3321 __ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset)); |
| 2514 __ cmp(scratch, Operand(first)); | 3322 __ cmp(scratch, Operand(first)); |
| 2515 | 3323 |
| 2516 // If there is only one type in the interval check for equality. | 3324 // If there is only one type in the interval check for equality. |
| 2517 if (first == last) { | 3325 if (first == last) { |
| 2518 DeoptimizeIf(ne, instr->environment()); | 3326 DeoptimizeIf(ne, instr->environment()); |
| 2519 } else { | 3327 } else { |
| 2520 DeoptimizeIf(lo, instr->environment()); | 3328 DeoptimizeIf(lo, instr->environment()); |
| 2521 // Omit check for the last type. | 3329 // Omit check for the last type. |
| 2522 if (last != LAST_TYPE) { | 3330 if (last != LAST_TYPE) { |
| 2523 __ cmp(scratch, Operand(last)); | 3331 __ cmp(scratch, Operand(last)); |
| 2524 DeoptimizeIf(hi, instr->environment()); | 3332 DeoptimizeIf(hi, instr->environment()); |
| 2525 } | 3333 } |
| 2526 } | 3334 } |
| 2527 } | 3335 } |
| 2528 | 3336 |
| 2529 | 3337 |
| 2530 void LCodeGen::DoCheckFunction(LCheckFunction* instr) { | 3338 void LCodeGen::DoCheckFunction(LCheckFunction* instr) { |
| 2531 ASSERT(instr->input()->IsRegister()); | 3339 ASSERT(instr->InputAt(0)->IsRegister()); |
| 2532 Register reg = ToRegister(instr->input()); | 3340 Register reg = ToRegister(instr->InputAt(0)); |
| 2533 __ cmp(reg, Operand(instr->hydrogen()->target())); | 3341 __ cmp(reg, Operand(instr->hydrogen()->target())); |
| 2534 DeoptimizeIf(ne, instr->environment()); | 3342 DeoptimizeIf(ne, instr->environment()); |
| 2535 } | 3343 } |
| 2536 | 3344 |
| 2537 | 3345 |
| 2538 void LCodeGen::DoCheckMap(LCheckMap* instr) { | 3346 void LCodeGen::DoCheckMap(LCheckMap* instr) { |
| 2539 Register scratch = scratch0(); | 3347 Register scratch = scratch0(); |
| 2540 LOperand* input = instr->input(); | 3348 LOperand* input = instr->InputAt(0); |
| 2541 ASSERT(input->IsRegister()); | 3349 ASSERT(input->IsRegister()); |
| 2542 Register reg = ToRegister(input); | 3350 Register reg = ToRegister(input); |
| 2543 __ ldr(scratch, FieldMemOperand(reg, HeapObject::kMapOffset)); | 3351 __ ldr(scratch, FieldMemOperand(reg, HeapObject::kMapOffset)); |
| 2544 __ cmp(scratch, Operand(instr->hydrogen()->map())); | 3352 __ cmp(scratch, Operand(instr->hydrogen()->map())); |
| 2545 DeoptimizeIf(ne, instr->environment()); | 3353 DeoptimizeIf(ne, instr->environment()); |
| 2546 } | 3354 } |
| 2547 | 3355 |
| 2548 | 3356 |
| 2549 void LCodeGen::LoadPrototype(Register result, | 3357 void LCodeGen::LoadHeapObject(Register result, |
| 2550 Handle<JSObject> prototype) { | 3358 Handle<HeapObject> object) { |
| 2551 if (HEAP->InNewSpace(*prototype)) { | 3359 if (HEAP->InNewSpace(*object)) { |
| 2552 Handle<JSGlobalPropertyCell> cell = | 3360 Handle<JSGlobalPropertyCell> cell = |
| 2553 FACTORY->NewJSGlobalPropertyCell(prototype); | 3361 FACTORY->NewJSGlobalPropertyCell(object); |
| 2554 __ mov(result, Operand(cell)); | 3362 __ mov(result, Operand(cell)); |
| 2555 __ ldr(result, FieldMemOperand(result, JSGlobalPropertyCell::kValueOffset)); | 3363 __ ldr(result, FieldMemOperand(result, JSGlobalPropertyCell::kValueOffset)); |
| 2556 } else { | 3364 } else { |
| 2557 __ mov(result, Operand(prototype)); | 3365 __ mov(result, Operand(object)); |
| 2558 } | 3366 } |
| 2559 } | 3367 } |
| 2560 | 3368 |
| 2561 | 3369 |
| 2562 void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) { | 3370 void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) { |
| 2563 Register temp1 = ToRegister(instr->temp1()); | 3371 Register temp1 = ToRegister(instr->TempAt(0)); |
| 2564 Register temp2 = ToRegister(instr->temp2()); | 3372 Register temp2 = ToRegister(instr->TempAt(1)); |
| 2565 | 3373 |
| 2566 Handle<JSObject> holder = instr->holder(); | 3374 Handle<JSObject> holder = instr->holder(); |
| 2567 Handle<JSObject> current_prototype = instr->prototype(); | 3375 Handle<JSObject> current_prototype = instr->prototype(); |
| 2568 | 3376 |
| 2569 // Load prototype object. | 3377 // Load prototype object. |
| 2570 LoadPrototype(temp1, current_prototype); | 3378 LoadHeapObject(temp1, current_prototype); |
| 2571 | 3379 |
| 2572 // Check prototype maps up to the holder. | 3380 // Check prototype maps up to the holder. |
| 2573 while (!current_prototype.is_identical_to(holder)) { | 3381 while (!current_prototype.is_identical_to(holder)) { |
| 2574 __ ldr(temp2, FieldMemOperand(temp1, HeapObject::kMapOffset)); | 3382 __ ldr(temp2, FieldMemOperand(temp1, HeapObject::kMapOffset)); |
| 2575 __ cmp(temp2, Operand(Handle<Map>(current_prototype->map()))); | 3383 __ cmp(temp2, Operand(Handle<Map>(current_prototype->map()))); |
| 2576 DeoptimizeIf(ne, instr->environment()); | 3384 DeoptimizeIf(ne, instr->environment()); |
| 2577 current_prototype = | 3385 current_prototype = |
| 2578 Handle<JSObject>(JSObject::cast(current_prototype->GetPrototype())); | 3386 Handle<JSObject>(JSObject::cast(current_prototype->GetPrototype())); |
| 2579 // Load next prototype object. | 3387 // Load next prototype object. |
| 2580 LoadPrototype(temp1, current_prototype); | 3388 LoadHeapObject(temp1, current_prototype); |
| 2581 } | 3389 } |
| 2582 | 3390 |
| 2583 // Check the holder map. | 3391 // Check the holder map. |
| 2584 __ ldr(temp2, FieldMemOperand(temp1, HeapObject::kMapOffset)); | 3392 __ ldr(temp2, FieldMemOperand(temp1, HeapObject::kMapOffset)); |
| 2585 __ cmp(temp2, Operand(Handle<Map>(current_prototype->map()))); | 3393 __ cmp(temp2, Operand(Handle<Map>(current_prototype->map()))); |
| 2586 DeoptimizeIf(ne, instr->environment()); | 3394 DeoptimizeIf(ne, instr->environment()); |
| 2587 } | 3395 } |
| 2588 | 3396 |
| 2589 | 3397 |
| 2590 void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) { | 3398 void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) { |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2702 __ mov(r1, Operand(pretenure | 3510 __ mov(r1, Operand(pretenure |
| 2703 ? FACTORY->true_value() | 3511 ? FACTORY->true_value() |
| 2704 : FACTORY->false_value())); | 3512 : FACTORY->false_value())); |
| 2705 __ Push(cp, r2, r1); | 3513 __ Push(cp, r2, r1); |
| 2706 CallRuntime(Runtime::kNewClosure, 3, instr); | 3514 CallRuntime(Runtime::kNewClosure, 3, instr); |
| 2707 } | 3515 } |
| 2708 } | 3516 } |
| 2709 | 3517 |
| 2710 | 3518 |
| 2711 void LCodeGen::DoTypeof(LTypeof* instr) { | 3519 void LCodeGen::DoTypeof(LTypeof* instr) { |
| 2712 Register input = ToRegister(instr->input()); | 3520 Register input = ToRegister(instr->InputAt(0)); |
| 2713 __ push(input); | 3521 __ push(input); |
| 2714 CallRuntime(Runtime::kTypeof, 1, instr); | 3522 CallRuntime(Runtime::kTypeof, 1, instr); |
| 2715 } | 3523 } |
| 2716 | 3524 |
| 2717 | 3525 |
| 2718 void LCodeGen::DoTypeofIs(LTypeofIs* instr) { | 3526 void LCodeGen::DoTypeofIs(LTypeofIs* instr) { |
| 2719 Register input = ToRegister(instr->input()); | 3527 Register input = ToRegister(instr->InputAt(0)); |
| 2720 Register result = ToRegister(instr->result()); | 3528 Register result = ToRegister(instr->result()); |
| 2721 Label true_label; | 3529 Label true_label; |
| 2722 Label false_label; | 3530 Label false_label; |
| 2723 Label done; | 3531 Label done; |
| 2724 | 3532 |
| 2725 Condition final_branch_condition = EmitTypeofIs(&true_label, | 3533 Condition final_branch_condition = EmitTypeofIs(&true_label, |
| 2726 &false_label, | 3534 &false_label, |
| 2727 input, | 3535 input, |
| 2728 instr->type_literal()); | 3536 instr->type_literal()); |
| 2729 __ b(final_branch_condition, &true_label); | 3537 __ b(final_branch_condition, &true_label); |
| 2730 __ bind(&false_label); | 3538 __ bind(&false_label); |
| 2731 __ LoadRoot(result, Heap::kFalseValueRootIndex); | 3539 __ LoadRoot(result, Heap::kFalseValueRootIndex); |
| 2732 __ b(&done); | 3540 __ b(&done); |
| 2733 | 3541 |
| 2734 __ bind(&true_label); | 3542 __ bind(&true_label); |
| 2735 __ LoadRoot(result, Heap::kTrueValueRootIndex); | 3543 __ LoadRoot(result, Heap::kTrueValueRootIndex); |
| 2736 | 3544 |
| 2737 __ bind(&done); | 3545 __ bind(&done); |
| 2738 } | 3546 } |
| 2739 | 3547 |
| 2740 | 3548 |
| 2741 void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { | 3549 void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { |
| 2742 Register input = ToRegister(instr->input()); | 3550 Register input = ToRegister(instr->InputAt(0)); |
| 2743 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 3551 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 2744 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 3552 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 2745 Label* true_label = chunk_->GetAssemblyLabel(true_block); | 3553 Label* true_label = chunk_->GetAssemblyLabel(true_block); |
| 2746 Label* false_label = chunk_->GetAssemblyLabel(false_block); | 3554 Label* false_label = chunk_->GetAssemblyLabel(false_block); |
| 2747 | 3555 |
| 2748 Condition final_branch_condition = EmitTypeofIs(true_label, | 3556 Condition final_branch_condition = EmitTypeofIs(true_label, |
| 2749 false_label, | 3557 false_label, |
| 2750 input, | 3558 input, |
| 2751 instr->type_literal()); | 3559 instr->type_literal()); |
| 2752 | 3560 |
| 2753 EmitBranch(true_block, false_block, final_branch_condition); | 3561 EmitBranch(true_block, false_block, final_branch_condition); |
| 2754 } | 3562 } |
| 2755 | 3563 |
| 2756 | 3564 |
| 2757 Condition LCodeGen::EmitTypeofIs(Label* true_label, | 3565 Condition LCodeGen::EmitTypeofIs(Label* true_label, |
| 2758 Label* false_label, | 3566 Label* false_label, |
| 2759 Register input, | 3567 Register input, |
| 2760 Handle<String> type_name) { | 3568 Handle<String> type_name) { |
| 2761 Condition final_branch_condition = no_condition; | 3569 Condition final_branch_condition = kNoCondition; |
| 2762 Register scratch = scratch0(); | 3570 Register scratch = scratch0(); |
| 2763 if (type_name->Equals(HEAP->number_symbol())) { | 3571 if (type_name->Equals(HEAP->number_symbol())) { |
| 2764 __ tst(input, Operand(kSmiTagMask)); | 3572 __ tst(input, Operand(kSmiTagMask)); |
| 2765 __ b(eq, true_label); | 3573 __ b(eq, true_label); |
| 2766 __ ldr(input, FieldMemOperand(input, HeapObject::kMapOffset)); | 3574 __ ldr(input, FieldMemOperand(input, HeapObject::kMapOffset)); |
| 2767 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex); | 3575 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex); |
| 2768 __ cmp(input, Operand(ip)); | 3576 __ cmp(input, Operand(ip)); |
| 2769 final_branch_condition = eq; | 3577 final_branch_condition = eq; |
| 2770 | 3578 |
| 2771 } else if (type_name->Equals(HEAP->string_symbol())) { | 3579 } else if (type_name->Equals(HEAP->string_symbol())) { |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2836 } | 3644 } |
| 2837 | 3645 |
| 2838 | 3646 |
| 2839 void LCodeGen::DoLazyBailout(LLazyBailout* instr) { | 3647 void LCodeGen::DoLazyBailout(LLazyBailout* instr) { |
| 2840 // No code for lazy bailout instruction. Used to capture environment after a | 3648 // No code for lazy bailout instruction. Used to capture environment after a |
| 2841 // call for populating the safepoint data with deoptimization data. | 3649 // call for populating the safepoint data with deoptimization data. |
| 2842 } | 3650 } |
| 2843 | 3651 |
| 2844 | 3652 |
| 2845 void LCodeGen::DoDeoptimize(LDeoptimize* instr) { | 3653 void LCodeGen::DoDeoptimize(LDeoptimize* instr) { |
| 2846 DeoptimizeIf(no_condition, instr->environment()); | 3654 DeoptimizeIf(kNoCondition, instr->environment()); |
| 2847 } | 3655 } |
| 2848 | 3656 |
| 2849 | 3657 |
| 2850 void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) { | 3658 void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) { |
| 2851 Register object = ToRegister(instr->object()); | 3659 Register object = ToRegister(instr->object()); |
| 2852 Register key = ToRegister(instr->key()); | 3660 Register key = ToRegister(instr->key()); |
| 2853 __ Push(object, key); | 3661 __ Push(object, key); |
| 2854 RecordPosition(instr->pointer_map()->position()); | 3662 RecordPosition(instr->pointer_map()->position()); |
| 2855 SafepointGenerator safepoint_generator(this, | 3663 SafepointGenerator safepoint_generator(this, |
| 2856 instr->pointer_map(), | 3664 instr->pointer_map(), |
| (...skipping 15 matching lines...) Expand all Loading... |
| 2872 | 3680 |
| 2873 | 3681 |
| 2874 void LCodeGen::DoOsrEntry(LOsrEntry* instr) { | 3682 void LCodeGen::DoOsrEntry(LOsrEntry* instr) { |
| 2875 Abort("DoOsrEntry unimplemented."); | 3683 Abort("DoOsrEntry unimplemented."); |
| 2876 } | 3684 } |
| 2877 | 3685 |
| 2878 | 3686 |
| 2879 #undef __ | 3687 #undef __ |
| 2880 | 3688 |
| 2881 } } // namespace v8::internal | 3689 } } // namespace v8::internal |
| OLD | NEW |