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 24 matching lines...) Expand all Loading... |
35 #include "codegen.h" | 35 #include "codegen.h" |
36 #include "debug.h" | 36 #include "debug.h" |
37 #include "runtime.h" | 37 #include "runtime.h" |
38 | 38 |
39 namespace v8 { | 39 namespace v8 { |
40 namespace internal { | 40 namespace internal { |
41 | 41 |
42 MacroAssembler::MacroAssembler(Isolate* arg_isolate, void* buffer, int size) | 42 MacroAssembler::MacroAssembler(Isolate* arg_isolate, void* buffer, int size) |
43 : Assembler(arg_isolate, buffer, size), | 43 : Assembler(arg_isolate, buffer, size), |
44 generating_stub_(false), | 44 generating_stub_(false), |
45 allow_stub_calls_(true) { | 45 allow_stub_calls_(true), |
| 46 has_frame_(false) { |
46 if (isolate() != NULL) { | 47 if (isolate() != NULL) { |
47 code_object_ = Handle<Object>(isolate()->heap()->undefined_value(), | 48 code_object_ = Handle<Object>(isolate()->heap()->undefined_value(), |
48 isolate()); | 49 isolate()); |
49 } | 50 } |
50 } | 51 } |
51 | 52 |
52 | 53 |
53 void MacroAssembler::LoadRoot(Register destination, | 54 void MacroAssembler::LoadRoot(Register destination, |
54 Heap::RootListIndex index) { | 55 Heap::RootListIndex index) { |
55 lw(destination, MemOperand(s6, index << kPointerSizeLog2)); | 56 lw(destination, MemOperand(s6, index << kPointerSizeLog2)); |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
112 sw(scratch, MemOperand(object, Page::kDirtyFlagOffset)); | 113 sw(scratch, MemOperand(object, Page::kDirtyFlagOffset)); |
113 } | 114 } |
114 | 115 |
115 | 116 |
116 // Push and pop all registers that can hold pointers. | 117 // Push and pop all registers that can hold pointers. |
117 void MacroAssembler::PushSafepointRegisters() { | 118 void MacroAssembler::PushSafepointRegisters() { |
118 // Safepoints expect a block of kNumSafepointRegisters values on the | 119 // Safepoints expect a block of kNumSafepointRegisters values on the |
119 // stack, so adjust the stack for unsaved registers. | 120 // stack, so adjust the stack for unsaved registers. |
120 const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters; | 121 const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters; |
121 ASSERT(num_unsaved >= 0); | 122 ASSERT(num_unsaved >= 0); |
122 Subu(sp, sp, Operand(num_unsaved * kPointerSize)); | 123 if (num_unsaved > 0) { |
| 124 Subu(sp, sp, Operand(num_unsaved * kPointerSize)); |
| 125 } |
123 MultiPush(kSafepointSavedRegisters); | 126 MultiPush(kSafepointSavedRegisters); |
124 } | 127 } |
125 | 128 |
126 | 129 |
127 void MacroAssembler::PopSafepointRegisters() { | 130 void MacroAssembler::PopSafepointRegisters() { |
128 const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters; | 131 const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters; |
129 MultiPop(kSafepointSavedRegisters); | 132 MultiPop(kSafepointSavedRegisters); |
130 Addu(sp, sp, Operand(num_unsaved * kPointerSize)); | 133 if (num_unsaved > 0) { |
| 134 Addu(sp, sp, Operand(num_unsaved * kPointerSize)); |
| 135 } |
131 } | 136 } |
132 | 137 |
133 | 138 |
134 void MacroAssembler::PushSafepointRegistersAndDoubles() { | 139 void MacroAssembler::PushSafepointRegistersAndDoubles() { |
135 PushSafepointRegisters(); | 140 PushSafepointRegisters(); |
136 Subu(sp, sp, Operand(FPURegister::kNumAllocatableRegisters * kDoubleSize)); | 141 Subu(sp, sp, Operand(FPURegister::kNumAllocatableRegisters * kDoubleSize)); |
137 for (int i = 0; i < FPURegister::kNumAllocatableRegisters; i+=2) { | 142 for (int i = 0; i < FPURegister::kNumAllocatableRegisters; i+=2) { |
138 FPURegister reg = FPURegister::FromAllocationIndex(i); | 143 FPURegister reg = FPURegister::FromAllocationIndex(i); |
139 sdc1(reg, MemOperand(sp, i * kDoubleSize)); | 144 sdc1(reg, MemOperand(sp, i * kDoubleSize)); |
140 } | 145 } |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
173 return kSafepointRegisterStackIndexMap[reg_code]; | 178 return kSafepointRegisterStackIndexMap[reg_code]; |
174 } | 179 } |
175 | 180 |
176 | 181 |
177 MemOperand MacroAssembler::SafepointRegisterSlot(Register reg) { | 182 MemOperand MacroAssembler::SafepointRegisterSlot(Register reg) { |
178 return MemOperand(sp, SafepointRegisterStackIndex(reg.code()) * kPointerSize); | 183 return MemOperand(sp, SafepointRegisterStackIndex(reg.code()) * kPointerSize); |
179 } | 184 } |
180 | 185 |
181 | 186 |
182 MemOperand MacroAssembler::SafepointRegistersAndDoublesSlot(Register reg) { | 187 MemOperand MacroAssembler::SafepointRegistersAndDoublesSlot(Register reg) { |
| 188 UNIMPLEMENTED_MIPS(); |
183 // General purpose registers are pushed last on the stack. | 189 // General purpose registers are pushed last on the stack. |
184 int doubles_size = FPURegister::kNumAllocatableRegisters * kDoubleSize; | 190 int doubles_size = FPURegister::kNumAllocatableRegisters * kDoubleSize; |
185 int register_offset = SafepointRegisterStackIndex(reg.code()) * kPointerSize; | 191 int register_offset = SafepointRegisterStackIndex(reg.code()) * kPointerSize; |
186 return MemOperand(sp, doubles_size + register_offset); | 192 return MemOperand(sp, doubles_size + register_offset); |
187 } | 193 } |
188 | 194 |
189 | 195 |
190 | |
191 | |
192 void MacroAssembler::InNewSpace(Register object, | 196 void MacroAssembler::InNewSpace(Register object, |
193 Register scratch, | 197 Register scratch, |
194 Condition cc, | 198 Condition cc, |
195 Label* branch) { | 199 Label* branch) { |
196 ASSERT(cc == eq || cc == ne); | 200 ASSERT(cc == eq || cc == ne); |
197 And(scratch, object, Operand(ExternalReference::new_space_mask(isolate()))); | 201 And(scratch, object, Operand(ExternalReference::new_space_mask(isolate()))); |
198 Branch(branch, cc, scratch, | 202 Branch(branch, cc, scratch, |
199 Operand(ExternalReference::new_space_start(isolate()))); | 203 Operand(ExternalReference::new_space_start(isolate()))); |
200 } | 204 } |
201 | 205 |
(...skipping 498 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
700 ori(rd, rd, (j.imm32_ & kImm16Mask)); | 704 ori(rd, rd, (j.imm32_ & kImm16Mask)); |
701 } | 705 } |
702 } | 706 } |
703 | 707 |
704 | 708 |
705 void MacroAssembler::MultiPush(RegList regs) { | 709 void MacroAssembler::MultiPush(RegList regs) { |
706 int16_t num_to_push = NumberOfBitsSet(regs); | 710 int16_t num_to_push = NumberOfBitsSet(regs); |
707 int16_t stack_offset = num_to_push * kPointerSize; | 711 int16_t stack_offset = num_to_push * kPointerSize; |
708 | 712 |
709 Subu(sp, sp, Operand(stack_offset)); | 713 Subu(sp, sp, Operand(stack_offset)); |
710 for (int16_t i = kNumRegisters; i > 0; i--) { | 714 for (int16_t i = kNumRegisters - 1; i >= 0; i--) { |
711 if ((regs & (1 << i)) != 0) { | 715 if ((regs & (1 << i)) != 0) { |
712 stack_offset -= kPointerSize; | 716 stack_offset -= kPointerSize; |
713 sw(ToRegister(i), MemOperand(sp, stack_offset)); | 717 sw(ToRegister(i), MemOperand(sp, stack_offset)); |
714 } | 718 } |
715 } | 719 } |
716 } | 720 } |
717 | 721 |
718 | 722 |
719 void MacroAssembler::MultiPushReversed(RegList regs) { | 723 void MacroAssembler::MultiPushReversed(RegList regs) { |
720 int16_t num_to_push = NumberOfBitsSet(regs); | 724 int16_t num_to_push = NumberOfBitsSet(regs); |
(...skipping 18 matching lines...) Expand all Loading... |
739 stack_offset += kPointerSize; | 743 stack_offset += kPointerSize; |
740 } | 744 } |
741 } | 745 } |
742 addiu(sp, sp, stack_offset); | 746 addiu(sp, sp, stack_offset); |
743 } | 747 } |
744 | 748 |
745 | 749 |
746 void MacroAssembler::MultiPopReversed(RegList regs) { | 750 void MacroAssembler::MultiPopReversed(RegList regs) { |
747 int16_t stack_offset = 0; | 751 int16_t stack_offset = 0; |
748 | 752 |
749 for (int16_t i = kNumRegisters; i > 0; i--) { | 753 for (int16_t i = kNumRegisters - 1; i >= 0; i--) { |
750 if ((regs & (1 << i)) != 0) { | 754 if ((regs & (1 << i)) != 0) { |
751 lw(ToRegister(i), MemOperand(sp, stack_offset)); | 755 lw(ToRegister(i), MemOperand(sp, stack_offset)); |
752 stack_offset += kPointerSize; | 756 stack_offset += kPointerSize; |
753 } | 757 } |
754 } | 758 } |
755 addiu(sp, sp, stack_offset); | 759 addiu(sp, sp, stack_offset); |
756 } | 760 } |
757 | 761 |
758 | 762 |
759 void MacroAssembler::MultiPushFPU(RegList regs) { | 763 void MacroAssembler::MultiPushFPU(RegList regs) { |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
807 for (int16_t i = kNumRegisters; i > 0; i--) { | 811 for (int16_t i = kNumRegisters; i > 0; i--) { |
808 if ((regs & (1 << i)) != 0) { | 812 if ((regs & (1 << i)) != 0) { |
809 ldc1(FPURegister::from_code(i), MemOperand(sp, stack_offset)); | 813 ldc1(FPURegister::from_code(i), MemOperand(sp, stack_offset)); |
810 stack_offset += kDoubleSize; | 814 stack_offset += kDoubleSize; |
811 } | 815 } |
812 } | 816 } |
813 addiu(sp, sp, stack_offset); | 817 addiu(sp, sp, stack_offset); |
814 } | 818 } |
815 | 819 |
816 | 820 |
| 821 void MacroAssembler::FlushICache(Register address, unsigned instructions) { |
| 822 RegList saved_regs = kJSCallerSaved | ra.bit(); |
| 823 MultiPush(saved_regs); |
| 824 AllowExternalCallThatCantCauseGC scope(this); |
| 825 |
| 826 // Save to a0 in case address == t0. |
| 827 Move(a0, address); |
| 828 PrepareCallCFunction(2, t0); |
| 829 |
| 830 li(a1, instructions * kInstrSize); |
| 831 CallCFunction(ExternalReference::flush_icache_function(isolate()), 2); |
| 832 MultiPop(saved_regs); |
| 833 } |
| 834 |
| 835 |
817 void MacroAssembler::Ext(Register rt, | 836 void MacroAssembler::Ext(Register rt, |
818 Register rs, | 837 Register rs, |
819 uint16_t pos, | 838 uint16_t pos, |
820 uint16_t size) { | 839 uint16_t size) { |
821 ASSERT(pos < 32); | 840 ASSERT(pos < 32); |
822 ASSERT(pos + size < 33); | 841 ASSERT(pos + size < 33); |
823 | 842 |
824 if (mips32r2) { | 843 if (mips32r2) { |
825 ext_(rt, rs, pos, size); | 844 ext_(rt, rs, pos, size); |
826 } else { | 845 } else { |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
933 Register rs, | 952 Register rs, |
934 FPURegister scratch) { | 953 FPURegister scratch) { |
935 ASSERT(!fd.is(scratch)); | 954 ASSERT(!fd.is(scratch)); |
936 ASSERT(!rs.is(at)); | 955 ASSERT(!rs.is(at)); |
937 | 956 |
938 // Load 2^31 into scratch as its float representation. | 957 // Load 2^31 into scratch as its float representation. |
939 li(at, 0x41E00000); | 958 li(at, 0x41E00000); |
940 mtc1(at, FPURegister::from_code(scratch.code() + 1)); | 959 mtc1(at, FPURegister::from_code(scratch.code() + 1)); |
941 mtc1(zero_reg, scratch); | 960 mtc1(zero_reg, scratch); |
942 // Test if scratch > fd. | 961 // Test if scratch > fd. |
943 c(OLT, D, fd, scratch); | 962 // If fd < 2^31 we can convert it normally. |
944 | |
945 Label simple_convert; | 963 Label simple_convert; |
946 // If fd < 2^31 we can convert it normally. | 964 BranchF(&simple_convert, NULL, lt, fd, scratch); |
947 bc1t(&simple_convert); | |
948 | 965 |
949 // First we subtract 2^31 from fd, then trunc it to rs | 966 // First we subtract 2^31 from fd, then trunc it to rs |
950 // and add 2^31 to rs. | 967 // and add 2^31 to rs. |
951 sub_d(scratch, fd, scratch); | 968 sub_d(scratch, fd, scratch); |
952 trunc_w_d(scratch, scratch); | 969 trunc_w_d(scratch, scratch); |
953 mfc1(rs, scratch); | 970 mfc1(rs, scratch); |
954 Or(rs, rs, 1 << 31); | 971 Or(rs, rs, 1 << 31); |
955 | 972 |
956 Label done; | 973 Label done; |
957 Branch(&done); | 974 Branch(&done); |
958 // Simple conversion. | 975 // Simple conversion. |
959 bind(&simple_convert); | 976 bind(&simple_convert); |
960 trunc_w_d(scratch, fd); | 977 trunc_w_d(scratch, fd); |
961 mfc1(rs, scratch); | 978 mfc1(rs, scratch); |
962 | 979 |
963 bind(&done); | 980 bind(&done); |
964 } | 981 } |
965 | 982 |
966 | 983 |
| 984 void MacroAssembler::BranchF(Label* target, |
| 985 Label* nan, |
| 986 Condition cc, |
| 987 FPURegister cmp1, |
| 988 FPURegister cmp2, |
| 989 BranchDelaySlot bd) { |
| 990 if (cc == al) { |
| 991 Branch(bd, target); |
| 992 return; |
| 993 } |
| 994 |
| 995 ASSERT(nan || target); |
| 996 // Check for unordered (NaN) cases. |
| 997 if (nan) { |
| 998 c(UN, D, cmp1, cmp2); |
| 999 bc1t(nan); |
| 1000 } |
| 1001 |
| 1002 if (target) { |
| 1003 // Here NaN cases were either handled by this function or are assumed to |
| 1004 // have been handled by the caller. |
| 1005 // Unsigned conditions are treated as their signed counterpart. |
| 1006 switch (cc) { |
| 1007 case Uless: |
| 1008 case less: |
| 1009 c(OLT, D, cmp1, cmp2); |
| 1010 bc1t(target); |
| 1011 break; |
| 1012 case Ugreater: |
| 1013 case greater: |
| 1014 c(ULE, D, cmp1, cmp2); |
| 1015 bc1f(target); |
| 1016 break; |
| 1017 case Ugreater_equal: |
| 1018 case greater_equal: |
| 1019 c(ULT, D, cmp1, cmp2); |
| 1020 bc1f(target); |
| 1021 break; |
| 1022 case Uless_equal: |
| 1023 case less_equal: |
| 1024 c(OLE, D, cmp1, cmp2); |
| 1025 bc1t(target); |
| 1026 break; |
| 1027 case eq: |
| 1028 c(EQ, D, cmp1, cmp2); |
| 1029 bc1t(target); |
| 1030 break; |
| 1031 case ne: |
| 1032 c(EQ, D, cmp1, cmp2); |
| 1033 bc1f(target); |
| 1034 break; |
| 1035 default: |
| 1036 CHECK(0); |
| 1037 }; |
| 1038 } |
| 1039 |
| 1040 if (bd == PROTECT) { |
| 1041 nop(); |
| 1042 } |
| 1043 } |
| 1044 |
| 1045 |
| 1046 void MacroAssembler::Move(FPURegister dst, double imm) { |
| 1047 ASSERT(CpuFeatures::IsEnabled(FPU)); |
| 1048 static const DoubleRepresentation minus_zero(-0.0); |
| 1049 static const DoubleRepresentation zero(0.0); |
| 1050 DoubleRepresentation value(imm); |
| 1051 // Handle special values first. |
| 1052 bool force_load = dst.is(kDoubleRegZero); |
| 1053 if (value.bits == zero.bits && !force_load) { |
| 1054 mov_d(dst, kDoubleRegZero); |
| 1055 } else if (value.bits == minus_zero.bits && !force_load) { |
| 1056 neg_d(dst, kDoubleRegZero); |
| 1057 } else { |
| 1058 uint32_t lo, hi; |
| 1059 DoubleAsTwoUInt32(imm, &lo, &hi); |
| 1060 // Move the low part of the double into the lower of the corresponding FPU |
| 1061 // register of FPU register pair. |
| 1062 if (lo != 0) { |
| 1063 li(at, Operand(lo)); |
| 1064 mtc1(at, dst); |
| 1065 } else { |
| 1066 mtc1(zero_reg, dst); |
| 1067 } |
| 1068 // Move the high part of the double into the higher of the corresponding FPU |
| 1069 // register of FPU register pair. |
| 1070 if (hi != 0) { |
| 1071 li(at, Operand(hi)); |
| 1072 mtc1(at, dst.high()); |
| 1073 } else { |
| 1074 mtc1(zero_reg, dst.high()); |
| 1075 } |
| 1076 } |
| 1077 } |
| 1078 |
| 1079 |
967 // Tries to get a signed int32 out of a double precision floating point heap | 1080 // Tries to get a signed int32 out of a double precision floating point heap |
968 // number. Rounds towards 0. Branch to 'not_int32' if the double is out of the | 1081 // number. Rounds towards 0. Branch to 'not_int32' if the double is out of the |
969 // 32bits signed integer range. | 1082 // 32bits signed integer range. |
970 // This method implementation differs from the ARM version for performance | 1083 // This method implementation differs from the ARM version for performance |
971 // reasons. | 1084 // reasons. |
972 void MacroAssembler::ConvertToInt32(Register source, | 1085 void MacroAssembler::ConvertToInt32(Register source, |
973 Register dest, | 1086 Register dest, |
974 Register scratch, | 1087 Register scratch, |
975 Register scratch2, | 1088 Register scratch2, |
976 FPURegister double_scratch, | 1089 FPURegister double_scratch, |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1055 // Trick to check sign bit (msb) held in dest, count leading zero. | 1168 // Trick to check sign bit (msb) held in dest, count leading zero. |
1056 // 0 indicates negative, save negative version with conditional move. | 1169 // 0 indicates negative, save negative version with conditional move. |
1057 clz(dest, dest); | 1170 clz(dest, dest); |
1058 movz(scratch, scratch2, dest); | 1171 movz(scratch, scratch2, dest); |
1059 mov(dest, scratch); | 1172 mov(dest, scratch); |
1060 } | 1173 } |
1061 bind(&done); | 1174 bind(&done); |
1062 } | 1175 } |
1063 | 1176 |
1064 | 1177 |
| 1178 void MacroAssembler::EmitFPUTruncate(FPURoundingMode rounding_mode, |
| 1179 FPURegister result, |
| 1180 DoubleRegister double_input, |
| 1181 Register scratch1, |
| 1182 Register except_flag, |
| 1183 CheckForInexactConversion check_inexact) { |
| 1184 ASSERT(CpuFeatures::IsSupported(FPU)); |
| 1185 CpuFeatures::Scope scope(FPU); |
| 1186 |
| 1187 int32_t except_mask = kFCSRFlagMask; // Assume interested in all exceptions. |
| 1188 |
| 1189 if (check_inexact == kDontCheckForInexactConversion) { |
| 1190 // Ingore inexact exceptions. |
| 1191 except_mask &= ~kFCSRInexactFlagMask; |
| 1192 } |
| 1193 |
| 1194 // Save FCSR. |
| 1195 cfc1(scratch1, FCSR); |
| 1196 // Disable FPU exceptions. |
| 1197 ctc1(zero_reg, FCSR); |
| 1198 |
| 1199 // Do operation based on rounding mode. |
| 1200 switch (rounding_mode) { |
| 1201 case kRoundToNearest: |
| 1202 round_w_d(result, double_input); |
| 1203 break; |
| 1204 case kRoundToZero: |
| 1205 trunc_w_d(result, double_input); |
| 1206 break; |
| 1207 case kRoundToPlusInf: |
| 1208 ceil_w_d(result, double_input); |
| 1209 break; |
| 1210 case kRoundToMinusInf: |
| 1211 floor_w_d(result, double_input); |
| 1212 break; |
| 1213 } // End of switch-statement. |
| 1214 |
| 1215 // Retrieve FCSR. |
| 1216 cfc1(except_flag, FCSR); |
| 1217 // Restore FCSR. |
| 1218 ctc1(scratch1, FCSR); |
| 1219 |
| 1220 // Check for fpu exceptions. |
| 1221 And(except_flag, except_flag, Operand(except_mask)); |
| 1222 } |
| 1223 |
| 1224 |
1065 void MacroAssembler::EmitOutOfInt32RangeTruncate(Register result, | 1225 void MacroAssembler::EmitOutOfInt32RangeTruncate(Register result, |
1066 Register input_high, | 1226 Register input_high, |
1067 Register input_low, | 1227 Register input_low, |
1068 Register scratch) { | 1228 Register scratch) { |
1069 Label done, normal_exponent, restore_sign; | 1229 Label done, normal_exponent, restore_sign; |
1070 // Extract the biased exponent in result. | 1230 // Extract the biased exponent in result. |
1071 Ext(result, | 1231 Ext(result, |
1072 input_high, | 1232 input_high, |
1073 HeapNumber::kExponentShift, | 1233 HeapNumber::kExponentShift, |
1074 HeapNumber::kExponentBits); | 1234 HeapNumber::kExponentBits); |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1141 Subu(result, zero_reg, input_high); | 1301 Subu(result, zero_reg, input_high); |
1142 movz(result, input_high, scratch); | 1302 movz(result, input_high, scratch); |
1143 bind(&done); | 1303 bind(&done); |
1144 } | 1304 } |
1145 | 1305 |
1146 | 1306 |
1147 void MacroAssembler::EmitECMATruncate(Register result, | 1307 void MacroAssembler::EmitECMATruncate(Register result, |
1148 FPURegister double_input, | 1308 FPURegister double_input, |
1149 FPURegister single_scratch, | 1309 FPURegister single_scratch, |
1150 Register scratch, | 1310 Register scratch, |
1151 Register input_high, | 1311 Register scratch2, |
1152 Register input_low) { | 1312 Register scratch3) { |
1153 CpuFeatures::Scope scope(FPU); | 1313 CpuFeatures::Scope scope(FPU); |
1154 ASSERT(!input_high.is(result)); | 1314 ASSERT(!scratch2.is(result)); |
1155 ASSERT(!input_low.is(result)); | 1315 ASSERT(!scratch3.is(result)); |
1156 ASSERT(!input_low.is(input_high)); | 1316 ASSERT(!scratch3.is(scratch2)); |
1157 ASSERT(!scratch.is(result) && | 1317 ASSERT(!scratch.is(result) && |
1158 !scratch.is(input_high) && | 1318 !scratch.is(scratch2) && |
1159 !scratch.is(input_low)); | 1319 !scratch.is(scratch3)); |
1160 ASSERT(!single_scratch.is(double_input)); | 1320 ASSERT(!single_scratch.is(double_input)); |
1161 | 1321 |
1162 Label done; | 1322 Label done; |
1163 Label manual; | 1323 Label manual; |
1164 | 1324 |
1165 // Clear cumulative exception flags and save the FCSR. | 1325 // Clear cumulative exception flags and save the FCSR. |
1166 Register scratch2 = input_high; | |
1167 cfc1(scratch2, FCSR); | 1326 cfc1(scratch2, FCSR); |
1168 ctc1(zero_reg, FCSR); | 1327 ctc1(zero_reg, FCSR); |
1169 // Try a conversion to a signed integer. | 1328 // Try a conversion to a signed integer. |
1170 trunc_w_d(single_scratch, double_input); | 1329 trunc_w_d(single_scratch, double_input); |
1171 mfc1(result, single_scratch); | 1330 mfc1(result, single_scratch); |
1172 // Retrieve and restore the FCSR. | 1331 // Retrieve and restore the FCSR. |
1173 cfc1(scratch, FCSR); | 1332 cfc1(scratch, FCSR); |
1174 ctc1(scratch2, FCSR); | 1333 ctc1(scratch2, FCSR); |
1175 // Check for overflow and NaNs. | 1334 // Check for overflow and NaNs. |
1176 And(scratch, | 1335 And(scratch, |
1177 scratch, | 1336 scratch, |
1178 kFCSROverflowFlagMask | kFCSRUnderflowFlagMask | kFCSRInvalidOpFlagMask); | 1337 kFCSROverflowFlagMask | kFCSRUnderflowFlagMask | kFCSRInvalidOpFlagMask); |
1179 // If we had no exceptions we are done. | 1338 // If we had no exceptions we are done. |
1180 Branch(&done, eq, scratch, Operand(zero_reg)); | 1339 Branch(&done, eq, scratch, Operand(zero_reg)); |
1181 | 1340 |
1182 // Load the double value and perform a manual truncation. | 1341 // Load the double value and perform a manual truncation. |
| 1342 Register input_high = scratch2; |
| 1343 Register input_low = scratch3; |
1183 Move(input_low, input_high, double_input); | 1344 Move(input_low, input_high, double_input); |
1184 EmitOutOfInt32RangeTruncate(result, | 1345 EmitOutOfInt32RangeTruncate(result, |
1185 input_high, | 1346 input_high, |
1186 input_low, | 1347 input_low, |
1187 scratch); | 1348 scratch); |
1188 bind(&done); | 1349 bind(&done); |
1189 } | 1350 } |
1190 | 1351 |
1191 | 1352 |
1192 void MacroAssembler::GetLeastBitsFromSmi(Register dst, | 1353 void MacroAssembler::GetLeastBitsFromSmi(Register dst, |
(...skipping 11 matching lines...) Expand all Loading... |
1204 | 1365 |
1205 | 1366 |
1206 // Emulated condtional branches do not emit a nop in the branch delay slot. | 1367 // Emulated condtional branches do not emit a nop in the branch delay slot. |
1207 // | 1368 // |
1208 // BRANCH_ARGS_CHECK checks that conditional jump arguments are correct. | 1369 // BRANCH_ARGS_CHECK checks that conditional jump arguments are correct. |
1209 #define BRANCH_ARGS_CHECK(cond, rs, rt) ASSERT( \ | 1370 #define BRANCH_ARGS_CHECK(cond, rs, rt) ASSERT( \ |
1210 (cond == cc_always && rs.is(zero_reg) && rt.rm().is(zero_reg)) || \ | 1371 (cond == cc_always && rs.is(zero_reg) && rt.rm().is(zero_reg)) || \ |
1211 (cond != cc_always && (!rs.is(zero_reg) || !rt.rm().is(zero_reg)))) | 1372 (cond != cc_always && (!rs.is(zero_reg) || !rt.rm().is(zero_reg)))) |
1212 | 1373 |
1213 | 1374 |
1214 bool MacroAssembler::UseAbsoluteCodePointers() { | |
1215 if (is_trampoline_emitted()) { | |
1216 return true; | |
1217 } else { | |
1218 return false; | |
1219 } | |
1220 } | |
1221 | |
1222 | |
1223 void MacroAssembler::Branch(int16_t offset, BranchDelaySlot bdslot) { | 1375 void MacroAssembler::Branch(int16_t offset, BranchDelaySlot bdslot) { |
1224 BranchShort(offset, bdslot); | 1376 BranchShort(offset, bdslot); |
1225 } | 1377 } |
1226 | 1378 |
1227 | 1379 |
1228 void MacroAssembler::Branch(int16_t offset, Condition cond, Register rs, | 1380 void MacroAssembler::Branch(int16_t offset, Condition cond, Register rs, |
1229 const Operand& rt, | 1381 const Operand& rt, |
1230 BranchDelaySlot bdslot) { | 1382 BranchDelaySlot bdslot) { |
1231 BranchShort(offset, cond, rs, rt, bdslot); | 1383 BranchShort(offset, cond, rs, rt, bdslot); |
1232 } | 1384 } |
1233 | 1385 |
1234 | 1386 |
1235 void MacroAssembler::Branch(Label* L, BranchDelaySlot bdslot) { | 1387 void MacroAssembler::Branch(Label* L, BranchDelaySlot bdslot) { |
1236 bool is_label_near = is_near(L); | 1388 if (L->is_bound()) { |
1237 if (UseAbsoluteCodePointers() && !is_label_near) { | 1389 if (is_near(L)) { |
1238 Jr(L, bdslot); | 1390 BranchShort(L, bdslot); |
| 1391 } else { |
| 1392 Jr(L, bdslot); |
| 1393 } |
1239 } else { | 1394 } else { |
1240 BranchShort(L, bdslot); | 1395 if (is_trampoline_emitted()) { |
| 1396 Jr(L, bdslot); |
| 1397 } else { |
| 1398 BranchShort(L, bdslot); |
| 1399 } |
1241 } | 1400 } |
1242 } | 1401 } |
1243 | 1402 |
1244 | 1403 |
1245 void MacroAssembler::Branch(Label* L, Condition cond, Register rs, | 1404 void MacroAssembler::Branch(Label* L, Condition cond, Register rs, |
1246 const Operand& rt, | 1405 const Operand& rt, |
1247 BranchDelaySlot bdslot) { | 1406 BranchDelaySlot bdslot) { |
1248 bool is_label_near = is_near(L); | 1407 if (L->is_bound()) { |
1249 if (UseAbsoluteCodePointers() && !is_label_near) { | 1408 if (is_near(L)) { |
1250 Label skip; | 1409 BranchShort(L, cond, rs, rt, bdslot); |
1251 Condition neg_cond = NegateCondition(cond); | 1410 } else { |
1252 BranchShort(&skip, neg_cond, rs, rt); | 1411 Label skip; |
1253 Jr(L, bdslot); | 1412 Condition neg_cond = NegateCondition(cond); |
1254 bind(&skip); | 1413 BranchShort(&skip, neg_cond, rs, rt); |
| 1414 Jr(L, bdslot); |
| 1415 bind(&skip); |
| 1416 } |
1255 } else { | 1417 } else { |
1256 BranchShort(L, cond, rs, rt, bdslot); | 1418 if (is_trampoline_emitted()) { |
| 1419 Label skip; |
| 1420 Condition neg_cond = NegateCondition(cond); |
| 1421 BranchShort(&skip, neg_cond, rs, rt); |
| 1422 Jr(L, bdslot); |
| 1423 bind(&skip); |
| 1424 } else { |
| 1425 BranchShort(L, cond, rs, rt, bdslot); |
| 1426 } |
1257 } | 1427 } |
1258 } | 1428 } |
1259 | 1429 |
1260 | 1430 |
1261 void MacroAssembler::BranchShort(int16_t offset, BranchDelaySlot bdslot) { | 1431 void MacroAssembler::BranchShort(int16_t offset, BranchDelaySlot bdslot) { |
1262 b(offset); | 1432 b(offset); |
1263 | 1433 |
1264 // Emit a nop in the branch delay slot if required. | 1434 // Emit a nop in the branch delay slot if required. |
1265 if (bdslot == PROTECT) | 1435 if (bdslot == PROTECT) |
1266 nop(); | 1436 nop(); |
1267 } | 1437 } |
1268 | 1438 |
1269 | 1439 |
1270 void MacroAssembler::BranchShort(int16_t offset, Condition cond, Register rs, | 1440 void MacroAssembler::BranchShort(int16_t offset, Condition cond, Register rs, |
1271 const Operand& rt, | 1441 const Operand& rt, |
1272 BranchDelaySlot bdslot) { | 1442 BranchDelaySlot bdslot) { |
1273 BRANCH_ARGS_CHECK(cond, rs, rt); | 1443 BRANCH_ARGS_CHECK(cond, rs, rt); |
1274 ASSERT(!rs.is(zero_reg)); | 1444 ASSERT(!rs.is(zero_reg)); |
1275 Register r2 = no_reg; | 1445 Register r2 = no_reg; |
1276 Register scratch = at; | 1446 Register scratch = at; |
1277 | 1447 |
1278 if (rt.is_reg()) { | 1448 if (rt.is_reg()) { |
1279 // We don't want any other register but scratch clobbered. | 1449 // NOTE: 'at' can be clobbered by Branch but it is legal to use it as rs or |
1280 ASSERT(!scratch.is(rs) && !scratch.is(rt.rm_)); | 1450 // rt. |
1281 r2 = rt.rm_; | 1451 r2 = rt.rm_; |
1282 switch (cond) { | 1452 switch (cond) { |
1283 case cc_always: | 1453 case cc_always: |
1284 b(offset); | 1454 b(offset); |
1285 break; | 1455 break; |
1286 case eq: | 1456 case eq: |
1287 beq(rs, r2, offset); | 1457 beq(rs, r2, offset); |
1288 break; | 1458 break; |
1289 case ne: | 1459 case ne: |
1290 bne(rs, r2, offset); | 1460 bne(rs, r2, offset); |
(...skipping 481 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1772 | 1942 |
1773 | 1943 |
1774 void MacroAssembler::BranchAndLink(int16_t offset, Condition cond, Register rs, | 1944 void MacroAssembler::BranchAndLink(int16_t offset, Condition cond, Register rs, |
1775 const Operand& rt, | 1945 const Operand& rt, |
1776 BranchDelaySlot bdslot) { | 1946 BranchDelaySlot bdslot) { |
1777 BranchAndLinkShort(offset, cond, rs, rt, bdslot); | 1947 BranchAndLinkShort(offset, cond, rs, rt, bdslot); |
1778 } | 1948 } |
1779 | 1949 |
1780 | 1950 |
1781 void MacroAssembler::BranchAndLink(Label* L, BranchDelaySlot bdslot) { | 1951 void MacroAssembler::BranchAndLink(Label* L, BranchDelaySlot bdslot) { |
1782 bool is_label_near = is_near(L); | 1952 if (L->is_bound()) { |
1783 if (UseAbsoluteCodePointers() && !is_label_near) { | 1953 if (is_near(L)) { |
1784 Jalr(L, bdslot); | 1954 BranchAndLinkShort(L, bdslot); |
| 1955 } else { |
| 1956 Jalr(L, bdslot); |
| 1957 } |
1785 } else { | 1958 } else { |
1786 BranchAndLinkShort(L, bdslot); | 1959 if (is_trampoline_emitted()) { |
| 1960 Jalr(L, bdslot); |
| 1961 } else { |
| 1962 BranchAndLinkShort(L, bdslot); |
| 1963 } |
1787 } | 1964 } |
1788 } | 1965 } |
1789 | 1966 |
1790 | 1967 |
1791 void MacroAssembler::BranchAndLink(Label* L, Condition cond, Register rs, | 1968 void MacroAssembler::BranchAndLink(Label* L, Condition cond, Register rs, |
1792 const Operand& rt, | 1969 const Operand& rt, |
1793 BranchDelaySlot bdslot) { | 1970 BranchDelaySlot bdslot) { |
1794 bool is_label_near = is_near(L); | 1971 if (L->is_bound()) { |
1795 if (UseAbsoluteCodePointers() && !is_label_near) { | 1972 if (is_near(L)) { |
1796 Label skip; | 1973 BranchAndLinkShort(L, cond, rs, rt, bdslot); |
1797 Condition neg_cond = NegateCondition(cond); | 1974 } else { |
1798 BranchShort(&skip, neg_cond, rs, rt); | 1975 Label skip; |
1799 Jalr(L, bdslot); | 1976 Condition neg_cond = NegateCondition(cond); |
1800 bind(&skip); | 1977 BranchShort(&skip, neg_cond, rs, rt); |
| 1978 Jalr(L, bdslot); |
| 1979 bind(&skip); |
| 1980 } |
1801 } else { | 1981 } else { |
1802 BranchAndLinkShort(L, cond, rs, rt, bdslot); | 1982 if (is_trampoline_emitted()) { |
| 1983 Label skip; |
| 1984 Condition neg_cond = NegateCondition(cond); |
| 1985 BranchShort(&skip, neg_cond, rs, rt); |
| 1986 Jalr(L, bdslot); |
| 1987 bind(&skip); |
| 1988 } else { |
| 1989 BranchAndLinkShort(L, cond, rs, rt, bdslot); |
| 1990 } |
1803 } | 1991 } |
1804 } | 1992 } |
1805 | 1993 |
1806 | 1994 |
1807 // We need to use a bgezal or bltzal, but they can't be used directly with the | 1995 // We need to use a bgezal or bltzal, but they can't be used directly with the |
1808 // slt instructions. We could use sub or add instead but we would miss overflow | 1996 // slt instructions. We could use sub or add instead but we would miss overflow |
1809 // cases, so we keep slt and add an intermediate third instruction. | 1997 // cases, so we keep slt and add an intermediate third instruction. |
1810 void MacroAssembler::BranchAndLinkShort(int16_t offset, | 1998 void MacroAssembler::BranchAndLinkShort(int16_t offset, |
1811 BranchDelaySlot bdslot) { | 1999 BranchDelaySlot bdslot) { |
1812 bal(offset); | 2000 bal(offset); |
(...skipping 486 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2299 | 2487 |
2300 void MacroAssembler::Push(Handle<Object> handle) { | 2488 void MacroAssembler::Push(Handle<Object> handle) { |
2301 li(at, Operand(handle)); | 2489 li(at, Operand(handle)); |
2302 push(at); | 2490 push(at); |
2303 } | 2491 } |
2304 | 2492 |
2305 | 2493 |
2306 #ifdef ENABLE_DEBUGGER_SUPPORT | 2494 #ifdef ENABLE_DEBUGGER_SUPPORT |
2307 | 2495 |
2308 void MacroAssembler::DebugBreak() { | 2496 void MacroAssembler::DebugBreak() { |
2309 ASSERT(allow_stub_calls()); | |
2310 mov(a0, zero_reg); | 2497 mov(a0, zero_reg); |
2311 li(a1, Operand(ExternalReference(Runtime::kDebugBreak, isolate()))); | 2498 li(a1, Operand(ExternalReference(Runtime::kDebugBreak, isolate()))); |
2312 CEntryStub ces(1); | 2499 CEntryStub ces(1); |
| 2500 ASSERT(AllowThisStubCall(&ces)); |
2313 Call(ces.GetCode(), RelocInfo::DEBUG_BREAK); | 2501 Call(ces.GetCode(), RelocInfo::DEBUG_BREAK); |
2314 } | 2502 } |
2315 | 2503 |
2316 #endif // ENABLE_DEBUGGER_SUPPORT | 2504 #endif // ENABLE_DEBUGGER_SUPPORT |
2317 | 2505 |
2318 | 2506 |
2319 // --------------------------------------------------------------------------- | 2507 // --------------------------------------------------------------------------- |
2320 // Exception handling. | 2508 // Exception handling. |
2321 | 2509 |
2322 void MacroAssembler::PushTryHandler(CodeLocation try_location, | 2510 void MacroAssembler::PushTryHandler(CodeLocation try_location, |
(...skipping 645 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2968 Addu(dst, dst, 1); | 3156 Addu(dst, dst, 1); |
2969 Subu(length, length, Operand(1)); | 3157 Subu(length, length, Operand(1)); |
2970 Branch(&byte_loop_1, ne, length, Operand(zero_reg)); | 3158 Branch(&byte_loop_1, ne, length, Operand(zero_reg)); |
2971 bind(&done); | 3159 bind(&done); |
2972 } | 3160 } |
2973 | 3161 |
2974 | 3162 |
2975 void MacroAssembler::CheckFastElements(Register map, | 3163 void MacroAssembler::CheckFastElements(Register map, |
2976 Register scratch, | 3164 Register scratch, |
2977 Label* fail) { | 3165 Label* fail) { |
2978 STATIC_ASSERT(FAST_ELEMENTS == 0); | 3166 STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS == 0); |
| 3167 STATIC_ASSERT(FAST_ELEMENTS == 1); |
2979 lbu(scratch, FieldMemOperand(map, Map::kBitField2Offset)); | 3168 lbu(scratch, FieldMemOperand(map, Map::kBitField2Offset)); |
2980 Branch(fail, hi, scratch, Operand(Map::kMaximumBitField2FastElementValue)); | 3169 Branch(fail, hi, scratch, Operand(Map::kMaximumBitField2FastElementValue)); |
2981 } | 3170 } |
2982 | 3171 |
2983 | 3172 |
2984 void MacroAssembler::CheckMap(Register obj, | 3173 void MacroAssembler::CheckMap(Register obj, |
2985 Register scratch, | 3174 Register scratch, |
2986 Handle<Map> map, | 3175 Handle<Map> map, |
2987 Label* fail, | 3176 Label* fail, |
2988 SmiCheckType smi_check_type) { | 3177 SmiCheckType smi_check_type) { |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3164 } | 3353 } |
3165 } | 3354 } |
3166 | 3355 |
3167 | 3356 |
3168 void MacroAssembler::InvokeCode(Register code, | 3357 void MacroAssembler::InvokeCode(Register code, |
3169 const ParameterCount& expected, | 3358 const ParameterCount& expected, |
3170 const ParameterCount& actual, | 3359 const ParameterCount& actual, |
3171 InvokeFlag flag, | 3360 InvokeFlag flag, |
3172 const CallWrapper& call_wrapper, | 3361 const CallWrapper& call_wrapper, |
3173 CallKind call_kind) { | 3362 CallKind call_kind) { |
| 3363 // You can't call a function without a valid frame. |
| 3364 ASSERT(flag == JUMP_FUNCTION || has_frame()); |
| 3365 |
3174 Label done; | 3366 Label done; |
3175 | 3367 |
3176 InvokePrologue(expected, actual, Handle<Code>::null(), code, &done, flag, | 3368 InvokePrologue(expected, actual, Handle<Code>::null(), code, &done, flag, |
3177 call_wrapper, call_kind); | 3369 call_wrapper, call_kind); |
3178 if (flag == CALL_FUNCTION) { | 3370 if (flag == CALL_FUNCTION) { |
| 3371 call_wrapper.BeforeCall(CallSize(code)); |
3179 SetCallKind(t1, call_kind); | 3372 SetCallKind(t1, call_kind); |
3180 Call(code); | 3373 Call(code); |
| 3374 call_wrapper.AfterCall(); |
3181 } else { | 3375 } else { |
3182 ASSERT(flag == JUMP_FUNCTION); | 3376 ASSERT(flag == JUMP_FUNCTION); |
3183 SetCallKind(t1, call_kind); | 3377 SetCallKind(t1, call_kind); |
3184 Jump(code); | 3378 Jump(code); |
3185 } | 3379 } |
3186 // Continue here if InvokePrologue does handle the invocation due to | 3380 // Continue here if InvokePrologue does handle the invocation due to |
3187 // mismatched parameter counts. | 3381 // mismatched parameter counts. |
3188 bind(&done); | 3382 bind(&done); |
3189 } | 3383 } |
3190 | 3384 |
3191 | 3385 |
3192 void MacroAssembler::InvokeCode(Handle<Code> code, | 3386 void MacroAssembler::InvokeCode(Handle<Code> code, |
3193 const ParameterCount& expected, | 3387 const ParameterCount& expected, |
3194 const ParameterCount& actual, | 3388 const ParameterCount& actual, |
3195 RelocInfo::Mode rmode, | 3389 RelocInfo::Mode rmode, |
3196 InvokeFlag flag, | 3390 InvokeFlag flag, |
3197 CallKind call_kind) { | 3391 CallKind call_kind) { |
| 3392 // You can't call a function without a valid frame. |
| 3393 ASSERT(flag == JUMP_FUNCTION || has_frame()); |
| 3394 |
3198 Label done; | 3395 Label done; |
3199 | 3396 |
3200 InvokePrologue(expected, actual, code, no_reg, &done, flag, | 3397 InvokePrologue(expected, actual, code, no_reg, &done, flag, |
3201 NullCallWrapper(), call_kind); | 3398 NullCallWrapper(), call_kind); |
3202 if (flag == CALL_FUNCTION) { | 3399 if (flag == CALL_FUNCTION) { |
3203 SetCallKind(t1, call_kind); | 3400 SetCallKind(t1, call_kind); |
3204 Call(code, rmode); | 3401 Call(code, rmode); |
3205 } else { | 3402 } else { |
3206 SetCallKind(t1, call_kind); | 3403 SetCallKind(t1, call_kind); |
3207 Jump(code, rmode); | 3404 Jump(code, rmode); |
3208 } | 3405 } |
3209 // Continue here if InvokePrologue does handle the invocation due to | 3406 // Continue here if InvokePrologue does handle the invocation due to |
3210 // mismatched parameter counts. | 3407 // mismatched parameter counts. |
3211 bind(&done); | 3408 bind(&done); |
3212 } | 3409 } |
3213 | 3410 |
3214 | 3411 |
3215 void MacroAssembler::InvokeFunction(Register function, | 3412 void MacroAssembler::InvokeFunction(Register function, |
3216 const ParameterCount& actual, | 3413 const ParameterCount& actual, |
3217 InvokeFlag flag, | 3414 InvokeFlag flag, |
3218 const CallWrapper& call_wrapper, | 3415 const CallWrapper& call_wrapper, |
3219 CallKind call_kind) { | 3416 CallKind call_kind) { |
| 3417 // You can't call a function without a valid frame. |
| 3418 ASSERT(flag == JUMP_FUNCTION || has_frame()); |
| 3419 |
3220 // Contract with called JS functions requires that function is passed in a1. | 3420 // Contract with called JS functions requires that function is passed in a1. |
3221 ASSERT(function.is(a1)); | 3421 ASSERT(function.is(a1)); |
3222 Register expected_reg = a2; | 3422 Register expected_reg = a2; |
3223 Register code_reg = a3; | 3423 Register code_reg = a3; |
3224 | 3424 |
3225 lw(code_reg, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset)); | 3425 lw(code_reg, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset)); |
3226 lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset)); | 3426 lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset)); |
3227 lw(expected_reg, | 3427 lw(expected_reg, |
3228 FieldMemOperand(code_reg, | 3428 FieldMemOperand(code_reg, |
3229 SharedFunctionInfo::kFormalParameterCountOffset)); | 3429 SharedFunctionInfo::kFormalParameterCountOffset)); |
3230 sra(expected_reg, expected_reg, kSmiTagSize); | 3430 sra(expected_reg, expected_reg, kSmiTagSize); |
3231 lw(code_reg, FieldMemOperand(a1, JSFunction::kCodeEntryOffset)); | 3431 lw(code_reg, FieldMemOperand(a1, JSFunction::kCodeEntryOffset)); |
3232 | 3432 |
3233 ParameterCount expected(expected_reg); | 3433 ParameterCount expected(expected_reg); |
3234 InvokeCode(code_reg, expected, actual, flag, call_wrapper, call_kind); | 3434 InvokeCode(code_reg, expected, actual, flag, call_wrapper, call_kind); |
3235 } | 3435 } |
3236 | 3436 |
3237 | 3437 |
3238 void MacroAssembler::InvokeFunction(JSFunction* function, | 3438 void MacroAssembler::InvokeFunction(JSFunction* function, |
3239 const ParameterCount& actual, | 3439 const ParameterCount& actual, |
3240 InvokeFlag flag, | 3440 InvokeFlag flag, |
3241 CallKind call_kind) { | 3441 CallKind call_kind) { |
| 3442 // You can't call a function without a valid frame. |
| 3443 ASSERT(flag == JUMP_FUNCTION || has_frame()); |
| 3444 |
3242 ASSERT(function->is_compiled()); | 3445 ASSERT(function->is_compiled()); |
3243 | 3446 |
3244 // Get the function and setup the context. | 3447 // Get the function and setup the context. |
3245 li(a1, Operand(Handle<JSFunction>(function))); | 3448 li(a1, Operand(Handle<JSFunction>(function))); |
3246 lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset)); | 3449 lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset)); |
3247 | 3450 |
3248 // Invoke the cached code. | 3451 // Invoke the cached code. |
3249 Handle<Code> code(function->code()); | 3452 Handle<Code> code(function->code()); |
3250 ParameterCount expected(function->shared()->formal_parameter_count()); | 3453 ParameterCount expected(function->shared()->formal_parameter_count()); |
3251 if (V8::UseCrankshaft()) { | 3454 if (V8::UseCrankshaft()) { |
3252 UNIMPLEMENTED_MIPS(); | 3455 // TODO(kasperl): For now, we always call indirectly through the |
| 3456 // code field in the function to allow recompilation to take effect |
| 3457 // without changing any of the call sites. |
| 3458 lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset)); |
| 3459 InvokeCode(a3, expected, actual, flag, NullCallWrapper(), call_kind); |
3253 } else { | 3460 } else { |
3254 InvokeCode(code, expected, actual, RelocInfo::CODE_TARGET, flag, call_kind); | 3461 InvokeCode(code, expected, actual, RelocInfo::CODE_TARGET, flag, call_kind); |
3255 } | 3462 } |
3256 } | 3463 } |
3257 | 3464 |
3258 | 3465 |
3259 void MacroAssembler::IsObjectJSObjectType(Register heap_object, | 3466 void MacroAssembler::IsObjectJSObjectType(Register heap_object, |
3260 Register map, | 3467 Register map, |
3261 Register scratch, | 3468 Register scratch, |
3262 Label* fail) { | 3469 Label* fail) { |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3342 lw(map, FieldMemOperand(object, HeapObject::kMapOffset)); | 3549 lw(map, FieldMemOperand(object, HeapObject::kMapOffset)); |
3343 lbu(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset)); | 3550 lbu(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset)); |
3344 } | 3551 } |
3345 | 3552 |
3346 | 3553 |
3347 // ----------------------------------------------------------------------------- | 3554 // ----------------------------------------------------------------------------- |
3348 // Runtime calls. | 3555 // Runtime calls. |
3349 | 3556 |
3350 void MacroAssembler::CallStub(CodeStub* stub, Condition cond, | 3557 void MacroAssembler::CallStub(CodeStub* stub, Condition cond, |
3351 Register r1, const Operand& r2) { | 3558 Register r1, const Operand& r2) { |
3352 ASSERT(allow_stub_calls()); // Stub calls are not allowed in some stubs. | 3559 ASSERT(AllowThisStubCall(stub)); // Stub calls are not allowed in some stubs. |
3353 Call(stub->GetCode(), RelocInfo::CODE_TARGET, kNoASTId, cond, r1, r2); | 3560 Call(stub->GetCode(), RelocInfo::CODE_TARGET, kNoASTId, cond, r1, r2); |
3354 } | 3561 } |
3355 | 3562 |
3356 | 3563 |
3357 MaybeObject* MacroAssembler::TryCallStub(CodeStub* stub, Condition cond, | 3564 MaybeObject* MacroAssembler::TryCallStub(CodeStub* stub, Condition cond, |
3358 Register r1, const Operand& r2) { | 3565 Register r1, const Operand& r2) { |
3359 ASSERT(allow_stub_calls()); // Stub calls are not allowed in some stubs. | 3566 ASSERT(AllowThisStubCall(stub)); // Stub calls are not allowed in some stubs. |
3360 Object* result; | 3567 Object* result; |
3361 { MaybeObject* maybe_result = stub->TryGetCode(); | 3568 { MaybeObject* maybe_result = stub->TryGetCode(); |
3362 if (!maybe_result->ToObject(&result)) return maybe_result; | 3569 if (!maybe_result->ToObject(&result)) return maybe_result; |
3363 } | 3570 } |
3364 Call(Handle<Code>(Code::cast(result)), RelocInfo::CODE_TARGET, | 3571 Call(Handle<Code>(Code::cast(result)), RelocInfo::CODE_TARGET, |
3365 kNoASTId, cond, r1, r2); | 3572 kNoASTId, cond, r1, r2); |
3366 return result; | 3573 return result; |
3367 } | 3574 } |
3368 | 3575 |
3369 | 3576 |
3370 void MacroAssembler::TailCallStub(CodeStub* stub) { | 3577 void MacroAssembler::TailCallStub(CodeStub* stub) { |
3371 ASSERT(allow_stub_calls()); // Stub calls are not allowed in some stubs. | 3578 ASSERT(allow_stub_calls_ || stub->CompilingCallsToThisStubIsGCSafe()); |
3372 Jump(stub->GetCode(), RelocInfo::CODE_TARGET); | 3579 Jump(stub->GetCode(), RelocInfo::CODE_TARGET); |
3373 } | 3580 } |
3374 | 3581 |
3375 | 3582 |
3376 MaybeObject* MacroAssembler::TryTailCallStub(CodeStub* stub, | 3583 MaybeObject* MacroAssembler::TryTailCallStub(CodeStub* stub, |
3377 Condition cond, | 3584 Condition cond, |
3378 Register r1, | 3585 Register r1, |
3379 const Operand& r2) { | 3586 const Operand& r2) { |
3380 ASSERT(allow_stub_calls()); // Stub calls are not allowed in some stubs. | |
3381 Object* result; | 3587 Object* result; |
3382 { MaybeObject* maybe_result = stub->TryGetCode(); | 3588 { MaybeObject* maybe_result = stub->TryGetCode(); |
3383 if (!maybe_result->ToObject(&result)) return maybe_result; | 3589 if (!maybe_result->ToObject(&result)) return maybe_result; |
3384 } | 3590 } |
3385 Jump(Handle<Code>(Code::cast(result)), RelocInfo::CODE_TARGET, cond, r1, r2); | 3591 Jump(Handle<Code>(Code::cast(result)), RelocInfo::CODE_TARGET, cond, r1, r2); |
3386 return result; | 3592 return result; |
3387 } | 3593 } |
3388 | 3594 |
3389 | 3595 |
3390 static int AddressOffset(ExternalReference ref0, ExternalReference ref1) { | 3596 static int AddressOffset(ExternalReference ref0, ExternalReference ref1) { |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3479 li(a0, Operand(ExternalReference::isolate_address())); | 3685 li(a0, Operand(ExternalReference::isolate_address())); |
3480 CallCFunction(ExternalReference::delete_handle_scope_extensions(isolate()), | 3686 CallCFunction(ExternalReference::delete_handle_scope_extensions(isolate()), |
3481 1); | 3687 1); |
3482 mov(v0, s0); | 3688 mov(v0, s0); |
3483 jmp(&leave_exit_frame); | 3689 jmp(&leave_exit_frame); |
3484 | 3690 |
3485 return result; | 3691 return result; |
3486 } | 3692 } |
3487 | 3693 |
3488 | 3694 |
| 3695 bool MacroAssembler::AllowThisStubCall(CodeStub* stub) { |
| 3696 if (!has_frame_ && stub->SometimesSetsUpAFrame()) return false; |
| 3697 return allow_stub_calls_ || stub->CompilingCallsToThisStubIsGCSafe(); |
| 3698 } |
| 3699 |
| 3700 |
3489 void MacroAssembler::IllegalOperation(int num_arguments) { | 3701 void MacroAssembler::IllegalOperation(int num_arguments) { |
3490 if (num_arguments > 0) { | 3702 if (num_arguments > 0) { |
3491 addiu(sp, sp, num_arguments * kPointerSize); | 3703 addiu(sp, sp, num_arguments * kPointerSize); |
3492 } | 3704 } |
3493 LoadRoot(v0, Heap::kUndefinedValueRootIndex); | 3705 LoadRoot(v0, Heap::kUndefinedValueRootIndex); |
3494 } | 3706 } |
3495 | 3707 |
3496 | 3708 |
3497 void MacroAssembler::IndexFromHash(Register hash, | 3709 void MacroAssembler::IndexFromHash(Register hash, |
3498 Register index) { | 3710 Register index) { |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3559 void MacroAssembler::AdduAndCheckForOverflow(Register dst, | 3771 void MacroAssembler::AdduAndCheckForOverflow(Register dst, |
3560 Register left, | 3772 Register left, |
3561 Register right, | 3773 Register right, |
3562 Register overflow_dst, | 3774 Register overflow_dst, |
3563 Register scratch) { | 3775 Register scratch) { |
3564 ASSERT(!dst.is(overflow_dst)); | 3776 ASSERT(!dst.is(overflow_dst)); |
3565 ASSERT(!dst.is(scratch)); | 3777 ASSERT(!dst.is(scratch)); |
3566 ASSERT(!overflow_dst.is(scratch)); | 3778 ASSERT(!overflow_dst.is(scratch)); |
3567 ASSERT(!overflow_dst.is(left)); | 3779 ASSERT(!overflow_dst.is(left)); |
3568 ASSERT(!overflow_dst.is(right)); | 3780 ASSERT(!overflow_dst.is(right)); |
3569 ASSERT(!left.is(right)); | 3781 |
| 3782 if (left.is(right) && dst.is(left)) { |
| 3783 ASSERT(!dst.is(t9)); |
| 3784 ASSERT(!scratch.is(t9)); |
| 3785 ASSERT(!left.is(t9)); |
| 3786 ASSERT(!right.is(t9)); |
| 3787 ASSERT(!overflow_dst.is(t9)); |
| 3788 mov(t9, right); |
| 3789 right = t9; |
| 3790 } |
3570 | 3791 |
3571 if (dst.is(left)) { | 3792 if (dst.is(left)) { |
3572 mov(scratch, left); // Preserve left. | 3793 mov(scratch, left); // Preserve left. |
3573 addu(dst, left, right); // Left is overwritten. | 3794 addu(dst, left, right); // Left is overwritten. |
3574 xor_(scratch, dst, scratch); // Original left. | 3795 xor_(scratch, dst, scratch); // Original left. |
3575 xor_(overflow_dst, dst, right); | 3796 xor_(overflow_dst, dst, right); |
3576 and_(overflow_dst, overflow_dst, scratch); | 3797 and_(overflow_dst, overflow_dst, scratch); |
3577 } else if (dst.is(right)) { | 3798 } else if (dst.is(right)) { |
3578 mov(scratch, right); // Preserve right. | 3799 mov(scratch, right); // Preserve right. |
3579 addu(dst, left, right); // Right is overwritten. | 3800 addu(dst, left, right); // Right is overwritten. |
(...skipping 12 matching lines...) Expand all Loading... |
3592 void MacroAssembler::SubuAndCheckForOverflow(Register dst, | 3813 void MacroAssembler::SubuAndCheckForOverflow(Register dst, |
3593 Register left, | 3814 Register left, |
3594 Register right, | 3815 Register right, |
3595 Register overflow_dst, | 3816 Register overflow_dst, |
3596 Register scratch) { | 3817 Register scratch) { |
3597 ASSERT(!dst.is(overflow_dst)); | 3818 ASSERT(!dst.is(overflow_dst)); |
3598 ASSERT(!dst.is(scratch)); | 3819 ASSERT(!dst.is(scratch)); |
3599 ASSERT(!overflow_dst.is(scratch)); | 3820 ASSERT(!overflow_dst.is(scratch)); |
3600 ASSERT(!overflow_dst.is(left)); | 3821 ASSERT(!overflow_dst.is(left)); |
3601 ASSERT(!overflow_dst.is(right)); | 3822 ASSERT(!overflow_dst.is(right)); |
3602 ASSERT(!left.is(right)); | |
3603 ASSERT(!scratch.is(left)); | 3823 ASSERT(!scratch.is(left)); |
3604 ASSERT(!scratch.is(right)); | 3824 ASSERT(!scratch.is(right)); |
3605 | 3825 |
| 3826 // This happens with some crankshaft code. Since Subu works fine if |
| 3827 // left == right, let's not make that restriction here. |
| 3828 if (left.is(right)) { |
| 3829 mov(dst, zero_reg); |
| 3830 mov(overflow_dst, zero_reg); |
| 3831 return; |
| 3832 } |
| 3833 |
3606 if (dst.is(left)) { | 3834 if (dst.is(left)) { |
3607 mov(scratch, left); // Preserve left. | 3835 mov(scratch, left); // Preserve left. |
3608 subu(dst, left, right); // Left is overwritten. | 3836 subu(dst, left, right); // Left is overwritten. |
3609 xor_(overflow_dst, dst, scratch); // scratch is original left. | 3837 xor_(overflow_dst, dst, scratch); // scratch is original left. |
3610 xor_(scratch, scratch, right); // scratch is original left. | 3838 xor_(scratch, scratch, right); // scratch is original left. |
3611 and_(overflow_dst, scratch, overflow_dst); | 3839 and_(overflow_dst, scratch, overflow_dst); |
3612 } else if (dst.is(right)) { | 3840 } else if (dst.is(right)) { |
3613 mov(scratch, right); // Preserve right. | 3841 mov(scratch, right); // Preserve right. |
3614 subu(dst, left, right); // Right is overwritten. | 3842 subu(dst, left, right); // Right is overwritten. |
3615 xor_(overflow_dst, dst, left); | 3843 xor_(overflow_dst, dst, left); |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3715 const ExternalReference& builtin) { | 3943 const ExternalReference& builtin) { |
3716 li(a1, Operand(builtin)); | 3944 li(a1, Operand(builtin)); |
3717 CEntryStub stub(1); | 3945 CEntryStub stub(1); |
3718 return TryTailCallStub(&stub); | 3946 return TryTailCallStub(&stub); |
3719 } | 3947 } |
3720 | 3948 |
3721 | 3949 |
3722 void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, | 3950 void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, |
3723 InvokeFlag flag, | 3951 InvokeFlag flag, |
3724 const CallWrapper& call_wrapper) { | 3952 const CallWrapper& call_wrapper) { |
| 3953 // You can't call a builtin without a valid frame. |
| 3954 ASSERT(flag == JUMP_FUNCTION || has_frame()); |
| 3955 |
3725 GetBuiltinEntry(t9, id); | 3956 GetBuiltinEntry(t9, id); |
3726 if (flag == CALL_FUNCTION) { | 3957 if (flag == CALL_FUNCTION) { |
3727 call_wrapper.BeforeCall(CallSize(t9)); | 3958 call_wrapper.BeforeCall(CallSize(t9)); |
3728 SetCallKind(t1, CALL_AS_METHOD); | 3959 SetCallKind(t1, CALL_AS_METHOD); |
3729 Call(t9); | 3960 Call(t9); |
3730 call_wrapper.AfterCall(); | 3961 call_wrapper.AfterCall(); |
3731 } else { | 3962 } else { |
3732 ASSERT(flag == JUMP_FUNCTION); | 3963 ASSERT(flag == JUMP_FUNCTION); |
3733 SetCallKind(t1, CALL_AS_METHOD); | 3964 SetCallKind(t1, CALL_AS_METHOD); |
3734 Jump(t9); | 3965 Jump(t9); |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3847 // from the real pointer as a smi. | 4078 // from the real pointer as a smi. |
3848 intptr_t p1 = reinterpret_cast<intptr_t>(msg); | 4079 intptr_t p1 = reinterpret_cast<intptr_t>(msg); |
3849 intptr_t p0 = (p1 & ~kSmiTagMask) + kSmiTag; | 4080 intptr_t p0 = (p1 & ~kSmiTagMask) + kSmiTag; |
3850 ASSERT(reinterpret_cast<Object*>(p0)->IsSmi()); | 4081 ASSERT(reinterpret_cast<Object*>(p0)->IsSmi()); |
3851 #ifdef DEBUG | 4082 #ifdef DEBUG |
3852 if (msg != NULL) { | 4083 if (msg != NULL) { |
3853 RecordComment("Abort message: "); | 4084 RecordComment("Abort message: "); |
3854 RecordComment(msg); | 4085 RecordComment(msg); |
3855 } | 4086 } |
3856 #endif | 4087 #endif |
3857 // Disable stub call restrictions to always allow calls to abort. | |
3858 AllowStubCallsScope allow_scope(this, true); | |
3859 | 4088 |
3860 li(a0, Operand(p0)); | 4089 li(a0, Operand(p0)); |
3861 push(a0); | 4090 push(a0); |
3862 li(a0, Operand(Smi::FromInt(p1 - p0))); | 4091 li(a0, Operand(Smi::FromInt(p1 - p0))); |
3863 push(a0); | 4092 push(a0); |
3864 CallRuntime(Runtime::kAbort, 2); | 4093 // Disable stub call restrictions to always allow calls to abort. |
| 4094 if (!has_frame_) { |
| 4095 // We don't actually want to generate a pile of code for this, so just |
| 4096 // claim there is a stack frame, without generating one. |
| 4097 FrameScope scope(this, StackFrame::NONE); |
| 4098 CallRuntime(Runtime::kAbort, 2); |
| 4099 } else { |
| 4100 CallRuntime(Runtime::kAbort, 2); |
| 4101 } |
3865 // Will not return here. | 4102 // Will not return here. |
3866 if (is_trampoline_pool_blocked()) { | 4103 if (is_trampoline_pool_blocked()) { |
3867 // If the calling code cares about the exact number of | 4104 // If the calling code cares about the exact number of |
3868 // instructions generated, we insert padding here to keep the size | 4105 // instructions generated, we insert padding here to keep the size |
3869 // of the Abort macro constant. | 4106 // of the Abort macro constant. |
3870 // Currently in debug mode with debug_code enabled the number of | 4107 // Currently in debug mode with debug_code enabled the number of |
3871 // generated instructions is 14, so we use this as a maximum value. | 4108 // generated instructions is 14, so we use this as a maximum value. |
3872 static const int kExpectedAbortInstructions = 14; | 4109 static const int kExpectedAbortInstructions = 14; |
3873 int abort_instructions = InstructionsGeneratedSince(&abort_start); | 4110 int abort_instructions = InstructionsGeneratedSince(&abort_start); |
3874 ASSERT(abort_instructions <= kExpectedAbortInstructions); | 4111 ASSERT(abort_instructions <= kExpectedAbortInstructions); |
(...skipping 363 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4238 int kFlatAsciiStringMask = | 4475 int kFlatAsciiStringMask = |
4239 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask; | 4476 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask; |
4240 int kFlatAsciiStringTag = ASCII_STRING_TYPE; | 4477 int kFlatAsciiStringTag = ASCII_STRING_TYPE; |
4241 And(scratch, type, Operand(kFlatAsciiStringMask)); | 4478 And(scratch, type, Operand(kFlatAsciiStringMask)); |
4242 Branch(failure, ne, scratch, Operand(kFlatAsciiStringTag)); | 4479 Branch(failure, ne, scratch, Operand(kFlatAsciiStringTag)); |
4243 } | 4480 } |
4244 | 4481 |
4245 | 4482 |
4246 static const int kRegisterPassedArguments = 4; | 4483 static const int kRegisterPassedArguments = 4; |
4247 | 4484 |
4248 void MacroAssembler::PrepareCallCFunction(int num_arguments, Register scratch) { | 4485 int MacroAssembler::CalculateStackPassedWords(int num_reg_arguments, |
| 4486 int num_double_arguments) { |
| 4487 int stack_passed_words = 0; |
| 4488 num_reg_arguments += 2 * num_double_arguments; |
| 4489 |
| 4490 // Up to four simple arguments are passed in registers a0..a3. |
| 4491 if (num_reg_arguments > kRegisterPassedArguments) { |
| 4492 stack_passed_words += num_reg_arguments - kRegisterPassedArguments; |
| 4493 } |
| 4494 stack_passed_words += kCArgSlotCount; |
| 4495 return stack_passed_words; |
| 4496 } |
| 4497 |
| 4498 |
| 4499 void MacroAssembler::PrepareCallCFunction(int num_reg_arguments, |
| 4500 int num_double_arguments, |
| 4501 Register scratch) { |
4249 int frame_alignment = ActivationFrameAlignment(); | 4502 int frame_alignment = ActivationFrameAlignment(); |
4250 | 4503 |
4251 // Up to four simple arguments are passed in registers a0..a3. | 4504 // Up to four simple arguments are passed in registers a0..a3. |
4252 // Those four arguments must have reserved argument slots on the stack for | 4505 // Those four arguments must have reserved argument slots on the stack for |
4253 // mips, even though those argument slots are not normally used. | 4506 // mips, even though those argument slots are not normally used. |
4254 // Remaining arguments are pushed on the stack, above (higher address than) | 4507 // Remaining arguments are pushed on the stack, above (higher address than) |
4255 // the argument slots. | 4508 // the argument slots. |
4256 int stack_passed_arguments = ((num_arguments <= kRegisterPassedArguments) ? | 4509 int stack_passed_arguments = CalculateStackPassedWords( |
4257 0 : num_arguments - kRegisterPassedArguments) + | 4510 num_reg_arguments, num_double_arguments); |
4258 kCArgSlotCount; | |
4259 if (frame_alignment > kPointerSize) { | 4511 if (frame_alignment > kPointerSize) { |
4260 // Make stack end at alignment and make room for num_arguments - 4 words | 4512 // Make stack end at alignment and make room for num_arguments - 4 words |
4261 // and the original value of sp. | 4513 // and the original value of sp. |
4262 mov(scratch, sp); | 4514 mov(scratch, sp); |
4263 Subu(sp, sp, Operand((stack_passed_arguments + 1) * kPointerSize)); | 4515 Subu(sp, sp, Operand((stack_passed_arguments + 1) * kPointerSize)); |
4264 ASSERT(IsPowerOf2(frame_alignment)); | 4516 ASSERT(IsPowerOf2(frame_alignment)); |
4265 And(sp, sp, Operand(-frame_alignment)); | 4517 And(sp, sp, Operand(-frame_alignment)); |
4266 sw(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize)); | 4518 sw(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize)); |
4267 } else { | 4519 } else { |
4268 Subu(sp, sp, Operand(stack_passed_arguments * kPointerSize)); | 4520 Subu(sp, sp, Operand(stack_passed_arguments * kPointerSize)); |
4269 } | 4521 } |
4270 } | 4522 } |
4271 | 4523 |
4272 | 4524 |
| 4525 void MacroAssembler::PrepareCallCFunction(int num_reg_arguments, |
| 4526 Register scratch) { |
| 4527 PrepareCallCFunction(num_reg_arguments, 0, scratch); |
| 4528 } |
| 4529 |
| 4530 |
| 4531 void MacroAssembler::CallCFunction(ExternalReference function, |
| 4532 int num_reg_arguments, |
| 4533 int num_double_arguments) { |
| 4534 CallCFunctionHelper(no_reg, |
| 4535 function, |
| 4536 t8, |
| 4537 num_reg_arguments, |
| 4538 num_double_arguments); |
| 4539 } |
| 4540 |
| 4541 |
| 4542 void MacroAssembler::CallCFunction(Register function, |
| 4543 Register scratch, |
| 4544 int num_reg_arguments, |
| 4545 int num_double_arguments) { |
| 4546 CallCFunctionHelper(function, |
| 4547 ExternalReference::the_hole_value_location(isolate()), |
| 4548 scratch, |
| 4549 num_reg_arguments, |
| 4550 num_double_arguments); |
| 4551 } |
| 4552 |
| 4553 |
4273 void MacroAssembler::CallCFunction(ExternalReference function, | 4554 void MacroAssembler::CallCFunction(ExternalReference function, |
4274 int num_arguments) { | 4555 int num_arguments) { |
4275 CallCFunctionHelper(no_reg, function, t8, num_arguments); | 4556 CallCFunction(function, num_arguments, 0); |
4276 } | 4557 } |
4277 | 4558 |
4278 | 4559 |
4279 void MacroAssembler::CallCFunction(Register function, | 4560 void MacroAssembler::CallCFunction(Register function, |
4280 Register scratch, | 4561 Register scratch, |
4281 int num_arguments) { | 4562 int num_arguments) { |
4282 CallCFunctionHelper(function, | 4563 CallCFunction(function, scratch, num_arguments, 0); |
4283 ExternalReference::the_hole_value_location(isolate()), | |
4284 scratch, | |
4285 num_arguments); | |
4286 } | 4564 } |
4287 | 4565 |
4288 | 4566 |
4289 void MacroAssembler::CallCFunctionHelper(Register function, | 4567 void MacroAssembler::CallCFunctionHelper(Register function, |
4290 ExternalReference function_reference, | 4568 ExternalReference function_reference, |
4291 Register scratch, | 4569 Register scratch, |
4292 int num_arguments) { | 4570 int num_reg_arguments, |
| 4571 int num_double_arguments) { |
| 4572 ASSERT(has_frame()); |
4293 // Make sure that the stack is aligned before calling a C function unless | 4573 // Make sure that the stack is aligned before calling a C function unless |
4294 // running in the simulator. The simulator has its own alignment check which | 4574 // running in the simulator. The simulator has its own alignment check which |
4295 // provides more information. | 4575 // provides more information. |
4296 // The argument stots are presumed to have been set up by | 4576 // The argument stots are presumed to have been set up by |
4297 // PrepareCallCFunction. The C function must be called via t9, for mips ABI. | 4577 // PrepareCallCFunction. The C function must be called via t9, for mips ABI. |
4298 | 4578 |
4299 #if defined(V8_HOST_ARCH_MIPS) | 4579 #if defined(V8_HOST_ARCH_MIPS) |
4300 if (emit_debug_code()) { | 4580 if (emit_debug_code()) { |
4301 int frame_alignment = OS::ActivationFrameAlignment(); | 4581 int frame_alignment = OS::ActivationFrameAlignment(); |
4302 int frame_alignment_mask = frame_alignment - 1; | 4582 int frame_alignment_mask = frame_alignment - 1; |
(...skipping 17 matching lines...) Expand all Loading... |
4320 if (function.is(no_reg)) { | 4600 if (function.is(no_reg)) { |
4321 function = t9; | 4601 function = t9; |
4322 li(function, Operand(function_reference)); | 4602 li(function, Operand(function_reference)); |
4323 } else if (!function.is(t9)) { | 4603 } else if (!function.is(t9)) { |
4324 mov(t9, function); | 4604 mov(t9, function); |
4325 function = t9; | 4605 function = t9; |
4326 } | 4606 } |
4327 | 4607 |
4328 Call(function); | 4608 Call(function); |
4329 | 4609 |
4330 int stack_passed_arguments = ((num_arguments <= kRegisterPassedArguments) ? | 4610 int stack_passed_arguments = CalculateStackPassedWords( |
4331 0 : num_arguments - kRegisterPassedArguments) + | 4611 num_reg_arguments, num_double_arguments); |
4332 kCArgSlotCount; | |
4333 | 4612 |
4334 if (OS::ActivationFrameAlignment() > kPointerSize) { | 4613 if (OS::ActivationFrameAlignment() > kPointerSize) { |
4335 lw(sp, MemOperand(sp, stack_passed_arguments * kPointerSize)); | 4614 lw(sp, MemOperand(sp, stack_passed_arguments * kPointerSize)); |
4336 } else { | 4615 } else { |
4337 Addu(sp, sp, Operand(stack_passed_arguments * sizeof(kPointerSize))); | 4616 Addu(sp, sp, Operand(stack_passed_arguments * sizeof(kPointerSize))); |
4338 } | 4617 } |
4339 } | 4618 } |
4340 | 4619 |
4341 | 4620 |
4342 #undef BRANCH_ARGS_CHECK | 4621 #undef BRANCH_ARGS_CHECK |
4343 | 4622 |
4344 | 4623 |
| 4624 void MacroAssembler::PatchRelocatedValue(Register li_location, |
| 4625 Register scratch, |
| 4626 Register new_value) { |
| 4627 lw(scratch, MemOperand(li_location)); |
| 4628 // At this point scratch is a lui(at, ...) instruction. |
| 4629 if (emit_debug_code()) { |
| 4630 And(scratch, scratch, kOpcodeMask); |
| 4631 Check(eq, "The instruction to patch should be a lui.", |
| 4632 scratch, Operand(LUI)); |
| 4633 lw(scratch, MemOperand(li_location)); |
| 4634 } |
| 4635 srl(t9, new_value, kImm16Bits); |
| 4636 Ins(scratch, t9, 0, kImm16Bits); |
| 4637 sw(scratch, MemOperand(li_location)); |
| 4638 |
| 4639 lw(scratch, MemOperand(li_location, kInstrSize)); |
| 4640 // scratch is now ori(at, ...). |
| 4641 if (emit_debug_code()) { |
| 4642 And(scratch, scratch, kOpcodeMask); |
| 4643 Check(eq, "The instruction to patch should be an ori.", |
| 4644 scratch, Operand(ORI)); |
| 4645 lw(scratch, MemOperand(li_location, kInstrSize)); |
| 4646 } |
| 4647 Ins(scratch, new_value, 0, kImm16Bits); |
| 4648 sw(scratch, MemOperand(li_location, kInstrSize)); |
| 4649 |
| 4650 // Update the I-cache so the new lui and ori can be executed. |
| 4651 FlushICache(li_location, 2); |
| 4652 } |
| 4653 |
| 4654 |
4345 void MacroAssembler::LoadInstanceDescriptors(Register map, | 4655 void MacroAssembler::LoadInstanceDescriptors(Register map, |
4346 Register descriptors) { | 4656 Register descriptors) { |
4347 lw(descriptors, | 4657 lw(descriptors, |
4348 FieldMemOperand(map, Map::kInstanceDescriptorsOrBitField3Offset)); | 4658 FieldMemOperand(map, Map::kInstanceDescriptorsOrBitField3Offset)); |
4349 Label not_smi; | 4659 Label not_smi; |
4350 JumpIfNotSmi(descriptors, ¬_smi); | 4660 JumpIfNotSmi(descriptors, ¬_smi); |
4351 li(descriptors, Operand(FACTORY->empty_descriptor_array())); | 4661 li(descriptors, Operand(FACTORY->empty_descriptor_array())); |
4352 bind(¬_smi); | 4662 bind(¬_smi); |
4353 } | 4663 } |
4354 | 4664 |
4355 | 4665 |
| 4666 void MacroAssembler::ClampUint8(Register output_reg, Register input_reg) { |
| 4667 ASSERT(!output_reg.is(input_reg)); |
| 4668 Label done; |
| 4669 li(output_reg, Operand(255)); |
| 4670 // Normal branch: nop in delay slot. |
| 4671 Branch(&done, gt, input_reg, Operand(output_reg)); |
| 4672 // Use delay slot in this branch. |
| 4673 Branch(USE_DELAY_SLOT, &done, lt, input_reg, Operand(zero_reg)); |
| 4674 mov(output_reg, zero_reg); // In delay slot. |
| 4675 mov(output_reg, input_reg); // Value is in range 0..255. |
| 4676 bind(&done); |
| 4677 } |
| 4678 |
| 4679 |
| 4680 void MacroAssembler::ClampDoubleToUint8(Register result_reg, |
| 4681 DoubleRegister input_reg, |
| 4682 DoubleRegister temp_double_reg) { |
| 4683 Label above_zero; |
| 4684 Label done; |
| 4685 Label in_bounds; |
| 4686 |
| 4687 Move(temp_double_reg, 0.0); |
| 4688 BranchF(&above_zero, NULL, gt, input_reg, temp_double_reg); |
| 4689 |
| 4690 // Double value is less than zero, NaN or Inf, return 0. |
| 4691 mov(result_reg, zero_reg); |
| 4692 Branch(&done); |
| 4693 |
| 4694 // Double value is >= 255, return 255. |
| 4695 bind(&above_zero); |
| 4696 Move(temp_double_reg, 255.0); |
| 4697 BranchF(&in_bounds, NULL, le, input_reg, temp_double_reg); |
| 4698 li(result_reg, Operand(255)); |
| 4699 Branch(&done); |
| 4700 |
| 4701 // In 0-255 range, round and truncate. |
| 4702 bind(&in_bounds); |
| 4703 round_w_d(temp_double_reg, input_reg); |
| 4704 mfc1(result_reg, temp_double_reg); |
| 4705 bind(&done); |
| 4706 } |
| 4707 |
| 4708 |
4356 CodePatcher::CodePatcher(byte* address, int instructions) | 4709 CodePatcher::CodePatcher(byte* address, int instructions) |
4357 : address_(address), | 4710 : address_(address), |
4358 instructions_(instructions), | 4711 instructions_(instructions), |
4359 size_(instructions * Assembler::kInstrSize), | 4712 size_(instructions * Assembler::kInstrSize), |
4360 masm_(Isolate::Current(), address, size_ + Assembler::kGap) { | 4713 masm_(Isolate::Current(), address, size_ + Assembler::kGap) { |
4361 // Create a new macro assembler pointing to the address of the code to patch. | 4714 // Create a new macro assembler pointing to the address of the code to patch. |
4362 // The size is adjusted with kGap on order for the assembler to generate size | 4715 // The size is adjusted with kGap on order for the assembler to generate size |
4363 // bytes of instructions without failing with buffer size constraints. | 4716 // bytes of instructions without failing with buffer size constraints. |
4364 ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); | 4717 ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); |
4365 } | 4718 } |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4403 opcode == BGTZL); | 4756 opcode == BGTZL); |
4404 opcode = (cond == eq) ? BEQ : BNE; | 4757 opcode = (cond == eq) ? BEQ : BNE; |
4405 instr = (instr & ~kOpcodeMask) | opcode; | 4758 instr = (instr & ~kOpcodeMask) | opcode; |
4406 masm_.emit(instr); | 4759 masm_.emit(instr); |
4407 } | 4760 } |
4408 | 4761 |
4409 | 4762 |
4410 } } // namespace v8::internal | 4763 } } // namespace v8::internal |
4411 | 4764 |
4412 #endif // V8_TARGET_ARCH_MIPS | 4765 #endif // V8_TARGET_ARCH_MIPS |
OLD | NEW |