| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 182 static Register registers[] = { x0 }; | 182 static Register registers[] = { x0 }; |
| 183 descriptor->register_param_count_ = sizeof(registers) / sizeof(registers[0]); | 183 descriptor->register_param_count_ = sizeof(registers) / sizeof(registers[0]); |
| 184 descriptor->register_params_ = registers; | 184 descriptor->register_params_ = registers; |
| 185 descriptor->deoptimization_handler_ = | 185 descriptor->deoptimization_handler_ = |
| 186 FUNCTION_ADDR(CompareNilIC_Miss); | 186 FUNCTION_ADDR(CompareNilIC_Miss); |
| 187 descriptor->SetMissHandler( | 187 descriptor->SetMissHandler( |
| 188 ExternalReference(IC_Utility(IC::kCompareNilIC_Miss), isolate)); | 188 ExternalReference(IC_Utility(IC::kCompareNilIC_Miss), isolate)); |
| 189 } | 189 } |
| 190 | 190 |
| 191 | 191 |
| 192 void BinaryOpStub::InitializeInterfaceDescriptor( |
| 193 Isolate* isolate, |
| 194 CodeStubInterfaceDescriptor* descriptor) { |
| 195 // x1: left operand |
| 196 // x0: right operand |
| 197 static Register registers[] = { x1, x0 }; |
| 198 descriptor->register_param_count_ = sizeof(registers) / sizeof(registers[0]); |
| 199 descriptor->register_params_ = registers; |
| 200 descriptor->deoptimization_handler_ = FUNCTION_ADDR(BinaryOpIC_Miss); |
| 201 descriptor->SetMissHandler( |
| 202 ExternalReference(IC_Utility(IC::kBinaryOpIC_Miss), isolate)); |
| 203 } |
| 204 |
| 205 |
| 192 static void InitializeArrayConstructorDescriptor( | 206 static void InitializeArrayConstructorDescriptor( |
| 193 Isolate* isolate, | 207 Isolate* isolate, |
| 194 CodeStubInterfaceDescriptor* descriptor, | 208 CodeStubInterfaceDescriptor* descriptor, |
| 195 int constant_stack_parameter_count) { | 209 int constant_stack_parameter_count) { |
| 196 // x1: function | 210 // x1: function |
| 197 // x2: type info cell with elements kind | 211 // x2: type info cell with elements kind |
| 198 static Register registers[] = { x1, x2 }; | 212 static Register registers[] = { x1, x2 }; |
| 199 descriptor->register_param_count_ = sizeof(registers) / sizeof(registers[0]); | 213 descriptor->register_param_count_ = sizeof(registers) / sizeof(registers[0]); |
| 200 if (constant_stack_parameter_count != 0) { | 214 if (constant_stack_parameter_count != 0) { |
| 201 // stack param count needs (constructor pointer, and single argument) | 215 // stack param count needs (constructor pointer, and single argument) |
| (...skipping 750 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 952 | 966 |
| 953 void StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime( | 967 void StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime( |
| 954 Isolate* isolate) { | 968 Isolate* isolate) { |
| 955 StoreBufferOverflowStub stub1(kDontSaveFPRegs); | 969 StoreBufferOverflowStub stub1(kDontSaveFPRegs); |
| 956 stub1.GetCode(isolate)->set_is_pregenerated(true); | 970 stub1.GetCode(isolate)->set_is_pregenerated(true); |
| 957 StoreBufferOverflowStub stub2(kSaveFPRegs); | 971 StoreBufferOverflowStub stub2(kSaveFPRegs); |
| 958 stub2.GetCode(isolate)->set_is_pregenerated(true); | 972 stub2.GetCode(isolate)->set_is_pregenerated(true); |
| 959 } | 973 } |
| 960 | 974 |
| 961 | 975 |
| 962 void BinaryOpStub::Initialize() { | |
| 963 // Nothing to do here. | |
| 964 } | |
| 965 | |
| 966 | |
| 967 void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { | |
| 968 ASM_LOCATION("BinaryOpStub::GenerateTypeTransition"); | |
| 969 Label get_result; | |
| 970 | |
| 971 __ Mov(x12, Operand(Smi::FromInt(MinorKey()))); | |
| 972 __ Push(x1, x0, x12); | |
| 973 | |
| 974 __ TailCallExternalReference( | |
| 975 ExternalReference(IC_Utility(IC::kBinaryOp_Patch), masm->isolate()), | |
| 976 3, | |
| 977 1); | |
| 978 } | |
| 979 | |
| 980 | |
| 981 void BinaryOpStub::GenerateTypeTransitionWithSavedArgs( | |
| 982 MacroAssembler* masm) { | |
| 983 UNIMPLEMENTED(); | |
| 984 } | |
| 985 | |
| 986 | |
| 987 void BinaryOpStub_GenerateSmiSmiOperation(MacroAssembler* masm, | |
| 988 Token::Value op) { | |
| 989 ASM_LOCATION("BinaryOpStub_GenerateSmiSmiOperation"); | |
| 990 Register left = x1; | |
| 991 Register right = x0; | |
| 992 Register scratch1 = x10; | |
| 993 Register scratch2 = x11; | |
| 994 // Note that 'result' aliases 'right'. The code below must care not to | |
| 995 // overwrite 'right' before it is certain it won't be needed. | |
| 996 Register result = x0; | |
| 997 | |
| 998 // Adapt the code below if that does not hold. | |
| 999 STATIC_ASSERT(kSmiTag == 0); | |
| 1000 STATIC_ASSERT(kSmiShift == 32); | |
| 1001 | |
| 1002 // TODO(alexandre): The code below mostly uses 64-bits operations, knowing | |
| 1003 // that the input are Smis. | |
| 1004 // Use of 32-bits instructions should be investigated. For example maybe speed | |
| 1005 // or power consumption could be improved. | |
| 1006 | |
| 1007 Label overflow, not_smi_result; | |
| 1008 switch (op) { | |
| 1009 case Token::ADD: | |
| 1010 __ Adds(result, left, right); // Add optimistically. | |
| 1011 __ B(vs, &overflow); | |
| 1012 __ Ret(); | |
| 1013 __ Bind(&overflow); | |
| 1014 // Revert optimistic add. | |
| 1015 __ Sub(right, result, left); | |
| 1016 break; | |
| 1017 | |
| 1018 case Token::SUB: | |
| 1019 // Subtract optimistically. | |
| 1020 __ Subs(result, left, right); | |
| 1021 __ B(vs, &overflow); | |
| 1022 __ Ret(); | |
| 1023 __ Bind(&overflow); | |
| 1024 // Revert optimistic subtract. | |
| 1025 __ Sub(right, left, result); | |
| 1026 break; | |
| 1027 | |
| 1028 case Token::MUL: { | |
| 1029 Label not_minus_zero; | |
| 1030 | |
| 1031 // Use smulh to avoid shifting right the inputs. | |
| 1032 // scratch1 = bits<127:64> of left * right. | |
| 1033 __ Smulh(scratch1, left, right); | |
| 1034 | |
| 1035 // Check if the result is a Smi. | |
| 1036 __ Cbnz(scratch1, ¬_minus_zero); | |
| 1037 | |
| 1038 // Check for minus zero. | |
| 1039 // Exclusive or the arguments and check the sign bit of the result. | |
| 1040 __ Eor(scratch2, left, right); | |
| 1041 __ Tbnz(scratch2, kXSignBit, ¬_smi_result); | |
| 1042 | |
| 1043 // At this point, the result is zero, which needs no smi conversion. | |
| 1044 STATIC_ASSERT(kSmiTag == 0); | |
| 1045 __ Mov(result, scratch1); | |
| 1046 __ Ret(); | |
| 1047 | |
| 1048 __ Bind(¬_minus_zero); | |
| 1049 // Check if the result is a signed 32 bits. | |
| 1050 // It is if bits 63-31 are sign bits. | |
| 1051 __ Cls(scratch2, scratch1); | |
| 1052 __ Cmp(scratch2, kXRegSize - kSmiShift); | |
| 1053 __ B(lt, ¬_smi_result); | |
| 1054 | |
| 1055 // Tag the result. | |
| 1056 __ SmiTag(result, scratch1); | |
| 1057 __ Ret(); | |
| 1058 break; | |
| 1059 } | |
| 1060 | |
| 1061 case Token::DIV: { | |
| 1062 // Check for division by zero. | |
| 1063 __ Cbz(right, ¬_smi_result); | |
| 1064 // Try integer division. | |
| 1065 // If the remainder is not zero jump the result is not a Smi. | |
| 1066 __ Sdiv(scratch1, left, right); | |
| 1067 // scratch2 = quotient * right. | |
| 1068 __ Mul(scratch2, scratch1, right); | |
| 1069 __ Cmp(scratch2, left); | |
| 1070 __ B(ne, ¬_smi_result); | |
| 1071 // Check for -0 (result is zero and right is negative). | |
| 1072 Label not_minus_zero; | |
| 1073 __ Cbnz(scratch1, ¬_minus_zero); | |
| 1074 __ Tbnz(right, kXSignBit, ¬_smi_result); | |
| 1075 __ Bind(¬_minus_zero); | |
| 1076 // Check for minus_int / -1. | |
| 1077 __ Eor(scratch2, scratch1, 1L << 31); | |
| 1078 __ Cbz(scratch2, ¬_smi_result); | |
| 1079 // Tag the result and return. | |
| 1080 __ SmiTag(result, scratch1); | |
| 1081 __ Ret(); | |
| 1082 break; | |
| 1083 } | |
| 1084 | |
| 1085 case Token::MOD: { | |
| 1086 Label not_minus_zero; | |
| 1087 // Check for division by zero. | |
| 1088 __ Cbz(right, ¬_smi_result); | |
| 1089 // Compute: | |
| 1090 // modulo = left - quotient * right | |
| 1091 __ Sdiv(scratch1, left, right); | |
| 1092 __ Msub(scratch1, scratch1, right, left); | |
| 1093 __ Cbnz(scratch1, ¬_minus_zero); | |
| 1094 // Check if the result should be minus zero. | |
| 1095 __ Tbnz(left, kXSignBit, ¬_smi_result); | |
| 1096 __ Bind(¬_minus_zero); | |
| 1097 __ Mov(result, scratch1); | |
| 1098 __ Ret(); | |
| 1099 break; | |
| 1100 } | |
| 1101 | |
| 1102 case Token::BIT_OR: | |
| 1103 __ Orr(result, left, right); | |
| 1104 __ Ret(); | |
| 1105 break; | |
| 1106 | |
| 1107 case Token::BIT_AND: | |
| 1108 __ And(result, left, right); | |
| 1109 __ Ret(); | |
| 1110 break; | |
| 1111 | |
| 1112 case Token::BIT_XOR: | |
| 1113 __ Eor(result, left, right); | |
| 1114 __ Ret(); | |
| 1115 break; | |
| 1116 | |
| 1117 // For shift operations, only the 5 least significant bits of the rhs | |
| 1118 // are used (see ECMA-262 11.7.1 and following). | |
| 1119 // We would like to use the implicit masking operation performed by the | |
| 1120 // shift instructions, but that would require using W registers and thus | |
| 1121 // untagging. | |
| 1122 case Token::SAR: | |
| 1123 __ Ubfx(right, right, kSmiShift, 5); | |
| 1124 __ Asr(result, left, right); | |
| 1125 __ Bic(result, result, kSmiShiftMask); | |
| 1126 __ Ret(); | |
| 1127 break; | |
| 1128 | |
| 1129 case Token::SHR: { | |
| 1130 __ Ubfx(scratch1, right, kSmiShift, 5); | |
| 1131 // SHR must not yield a negative value. This can only happen if left is | |
| 1132 // negative and we shift right by zero. | |
| 1133 Label right_not_zero; | |
| 1134 __ Cbnz(scratch1, &right_not_zero); | |
| 1135 __ Tbnz(left, kXSignBit, ¬_smi_result); | |
| 1136 __ Bind(&right_not_zero); | |
| 1137 __ Lsr(result, left, scratch1); | |
| 1138 __ Bic(result, result, kSmiShiftMask); | |
| 1139 __ Ret(); | |
| 1140 break; | |
| 1141 } | |
| 1142 | |
| 1143 case Token::SHL: | |
| 1144 __ Ubfx(scratch1, right, kSmiShift, 5); | |
| 1145 __ Lsl(result, left, scratch1); | |
| 1146 __ Ret(); | |
| 1147 break; | |
| 1148 | |
| 1149 default: | |
| 1150 UNREACHABLE(); | |
| 1151 } | |
| 1152 | |
| 1153 __ Bind(¬_smi_result); | |
| 1154 } | |
| 1155 | |
| 1156 | |
| 1157 void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm, | |
| 1158 Register result, | |
| 1159 Register heap_number_map, | |
| 1160 Register scratch1, | |
| 1161 Register scratch2, | |
| 1162 Label* gc_required, | |
| 1163 OverwriteMode mode); | |
| 1164 | |
| 1165 | |
| 1166 void BinaryOpStub_GenerateFPOperation(MacroAssembler* masm, | |
| 1167 BinaryOpIC::TypeInfo left_type, | |
| 1168 BinaryOpIC::TypeInfo right_type, | |
| 1169 bool smi_operands, | |
| 1170 Label* not_numbers, | |
| 1171 Label* gc_required, | |
| 1172 Label* miss, | |
| 1173 Token::Value op, | |
| 1174 OverwriteMode mode) { | |
| 1175 ASM_LOCATION("BinaryOpStub_GenerateFPOperation"); | |
| 1176 | |
| 1177 Register result = x0; | |
| 1178 FPRegister result_d = d0; | |
| 1179 Register right = x0; | |
| 1180 Register left = x1; | |
| 1181 Register heap_result = x21; | |
| 1182 | |
| 1183 ASSERT(smi_operands || (not_numbers != NULL)); | |
| 1184 if (smi_operands) { | |
| 1185 __ AssertSmi(left); | |
| 1186 __ AssertSmi(right); | |
| 1187 } | |
| 1188 if (left_type == BinaryOpIC::SMI) { | |
| 1189 __ JumpIfNotSmi(left, miss); | |
| 1190 } | |
| 1191 if (right_type == BinaryOpIC::SMI) { | |
| 1192 __ JumpIfNotSmi(right, miss); | |
| 1193 } | |
| 1194 | |
| 1195 Register heap_number_map = x2; | |
| 1196 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); | |
| 1197 | |
| 1198 switch (op) { | |
| 1199 case Token::ADD: | |
| 1200 case Token::SUB: | |
| 1201 case Token::MUL: | |
| 1202 case Token::DIV: | |
| 1203 case Token::MOD: { | |
| 1204 FPRegister left_d = d0; | |
| 1205 FPRegister right_d = d1; | |
| 1206 Label do_operation; | |
| 1207 | |
| 1208 __ SmiUntagToDouble(left_d, left, kSpeculativeUntag); | |
| 1209 __ SmiUntagToDouble(right_d, right, kSpeculativeUntag); | |
| 1210 | |
| 1211 if (!smi_operands) { | |
| 1212 if (left_type != BinaryOpIC::SMI) { | |
| 1213 Label left_done; | |
| 1214 Label* left_not_heap = | |
| 1215 (left_type == BinaryOpIC::NUMBER) ? miss : not_numbers; | |
| 1216 __ JumpIfSmi(left, &left_done); | |
| 1217 | |
| 1218 // Left not smi: load if heap number. | |
| 1219 __ JumpIfNotHeapNumber(left, left_not_heap, heap_number_map); | |
| 1220 __ Ldr(left_d, FieldMemOperand(left, HeapNumber::kValueOffset)); | |
| 1221 __ Bind(&left_done); | |
| 1222 } | |
| 1223 | |
| 1224 if (right_type != BinaryOpIC::SMI) { | |
| 1225 Label* right_not_heap = | |
| 1226 (right_type == BinaryOpIC::NUMBER) ? miss : not_numbers; | |
| 1227 __ JumpIfSmi(right, &do_operation); | |
| 1228 | |
| 1229 // Right not smi: load if heap number. | |
| 1230 __ JumpIfNotHeapNumber(right, right_not_heap, heap_number_map); | |
| 1231 __ Ldr(right_d, FieldMemOperand(right, HeapNumber::kValueOffset)); | |
| 1232 } | |
| 1233 } | |
| 1234 | |
| 1235 // Left and right are doubles in left_d and right_d. Calculate the result. | |
| 1236 __ Bind(&do_operation); | |
| 1237 | |
| 1238 BinaryOpStub_GenerateHeapResultAllocation( | |
| 1239 masm, heap_result, heap_number_map, x10, x11, gc_required, mode); | |
| 1240 | |
| 1241 switch (op) { | |
| 1242 case Token::ADD: __ Fadd(result_d, left_d, right_d); break; | |
| 1243 case Token::SUB: __ Fsub(result_d, left_d, right_d); break; | |
| 1244 case Token::MUL: __ Fmul(result_d, left_d, right_d); break; | |
| 1245 case Token::DIV: __ Fdiv(result_d, left_d, right_d); break; | |
| 1246 case Token::MOD: { | |
| 1247 Register saved_lr = x20; | |
| 1248 __ Mov(saved_lr, lr); | |
| 1249 AllowExternalCallThatCantCauseGC scope(masm); | |
| 1250 __ CallCFunction( | |
| 1251 ExternalReference::double_fp_operation(op, masm->isolate()), | |
| 1252 0, 2); | |
| 1253 __ Mov(lr, saved_lr); | |
| 1254 break; | |
| 1255 } | |
| 1256 default: UNREACHABLE(); | |
| 1257 } | |
| 1258 | |
| 1259 __ Str(result_d, FieldMemOperand(heap_result, HeapNumber::kValueOffset)); | |
| 1260 __ Mov(result, heap_result); | |
| 1261 __ Ret(); | |
| 1262 break; | |
| 1263 } | |
| 1264 | |
| 1265 case Token::BIT_OR: | |
| 1266 case Token::BIT_XOR: | |
| 1267 case Token::BIT_AND: | |
| 1268 case Token::SAR: | |
| 1269 case Token::SHR: | |
| 1270 case Token::SHL: { | |
| 1271 Label do_operation, result_not_smi; | |
| 1272 | |
| 1273 if (!smi_operands) { | |
| 1274 Label left_is_smi; | |
| 1275 // Convert heap number operands to smis. | |
| 1276 if (left_type != BinaryOpIC::SMI) { | |
| 1277 __ JumpIfSmi(left, &left_is_smi); | |
| 1278 __ JumpIfNotHeapNumber(left, not_numbers, heap_number_map); | |
| 1279 __ HeapNumberECMA262ToInt32(left, left, x10, x11, d0, | |
| 1280 MacroAssembler::SMI); | |
| 1281 } | |
| 1282 __ Bind(&left_is_smi); | |
| 1283 if (right_type != BinaryOpIC::SMI) { | |
| 1284 __ JumpIfSmi(right, &do_operation); | |
| 1285 __ JumpIfNotHeapNumber(right, not_numbers, heap_number_map); | |
| 1286 __ HeapNumberECMA262ToInt32(right, right, x10, x11, d0, | |
| 1287 MacroAssembler::SMI); | |
| 1288 } | |
| 1289 } | |
| 1290 | |
| 1291 // Left and right are smis. Calculate the result. | |
| 1292 __ Bind(&do_operation); | |
| 1293 switch (op) { | |
| 1294 case Token::BIT_OR: __ Orr(result, left, right); break; | |
| 1295 case Token::BIT_XOR: __ Eor(result, left, right); break; | |
| 1296 case Token::BIT_AND: __ And(result, left, right); break; | |
| 1297 | |
| 1298 // For shift operations, only the 5 least significant bits of the rhs | |
| 1299 // are used (see ECMA-262 11.7.1 and following). | |
| 1300 // We would like to use the implicit masking operation performed by the | |
| 1301 // shift instructions, but that would require using W registers and thus | |
| 1302 // untagging. | |
| 1303 case Token::SAR: | |
| 1304 __ Ubfx(right, right, kSmiShift, 5); | |
| 1305 __ Asr(result, left, right); | |
| 1306 // Clear bits shifted right. | |
| 1307 __ Bic(result, result, kSmiShiftMask); | |
| 1308 break; | |
| 1309 case Token::SHL: | |
| 1310 __ Ubfx(right, right, kSmiShift, 5); | |
| 1311 __ Lsl(result, left, right); | |
| 1312 break; | |
| 1313 case Token::SHR: { | |
| 1314 Label ok; | |
| 1315 // SHR must always yield a positive result. | |
| 1316 // This is a problem if right is zero and left is negative. | |
| 1317 __ Ubfx(right, right, kSmiShift, 5); | |
| 1318 __ Cbnz(right, &ok); | |
| 1319 __ Cmp(left, 0); | |
| 1320 __ B(mi, &result_not_smi); | |
| 1321 __ Bind(&ok); | |
| 1322 __ Lsr(result, left, right); | |
| 1323 // Clear bits shifted right. | |
| 1324 __ Bic(result, result, kSmiShiftMask); | |
| 1325 break; | |
| 1326 } | |
| 1327 default: UNREACHABLE(); | |
| 1328 } | |
| 1329 __ Ret(); | |
| 1330 | |
| 1331 __ Bind(&result_not_smi); | |
| 1332 // We know the operation was shift right, the left operand is negative, | |
| 1333 // and the right is zero. The result will be the left operand cast to a | |
| 1334 // positive value, as a heap number. | |
| 1335 __ Ucvtf(result_d, left, kSmiShift); | |
| 1336 if (smi_operands) { | |
| 1337 __ AllocateHeapNumber(heap_result, gc_required, x10, x11, | |
| 1338 heap_number_map); | |
| 1339 } else { | |
| 1340 BinaryOpStub_GenerateHeapResultAllocation(masm, heap_result, | |
| 1341 heap_number_map, x10, x11, | |
| 1342 gc_required, mode); | |
| 1343 } | |
| 1344 | |
| 1345 // Nothing can go wrong now, so move the heap number to the result | |
| 1346 // register. | |
| 1347 __ Mov(result, heap_result); | |
| 1348 | |
| 1349 // Now store the double result into the allocated heap number, and return. | |
| 1350 __ Str(result_d, FieldMemOperand(result, HeapNumber::kValueOffset)); | |
| 1351 __ Ret(); | |
| 1352 break; | |
| 1353 } | |
| 1354 default: | |
| 1355 UNREACHABLE(); | |
| 1356 } | |
| 1357 } | |
| 1358 | |
| 1359 | |
| 1360 // Generate the smi code. If the operation on smis are successful this return is | |
| 1361 // generated. If the result is not a smi and heap number allocation is not | |
| 1362 // requested the code falls through. If number allocation is requested but a | |
| 1363 // heap number cannot be allocated the code jumps to the label gc_required. | |
| 1364 void BinaryOpStub_GenerateSmiCode( | |
| 1365 MacroAssembler* masm, | |
| 1366 Label* use_runtime, | |
| 1367 Label* gc_required, | |
| 1368 Token::Value op, | |
| 1369 BinaryOpStub::SmiCodeGenerateHeapNumberResults allow_heapnumber_results, | |
| 1370 OverwriteMode mode) { | |
| 1371 ASM_LOCATION("BinaryOpStub_GenerateSmiCode"); | |
| 1372 Label not_smis; | |
| 1373 | |
| 1374 Register left = x1; | |
| 1375 Register right = x0; | |
| 1376 | |
| 1377 // Perform combined smi check on both operands. | |
| 1378 __ JumpIfEitherNotSmi(left, right, ¬_smis); | |
| 1379 | |
| 1380 // If the smi-smi operation results in a smi, the result is returned from the | |
| 1381 // code generated for the operation. Otherwise, execution falls through to | |
| 1382 // the following code. | |
| 1383 BinaryOpStub_GenerateSmiSmiOperation(masm, op); | |
| 1384 | |
| 1385 // If heap number results are allowed, generate the result in an allocated | |
| 1386 // heap number. | |
| 1387 if (allow_heapnumber_results == BinaryOpStub::ALLOW_HEAPNUMBER_RESULTS) { | |
| 1388 BinaryOpStub_GenerateFPOperation(masm, BinaryOpIC::UNINITIALIZED, | |
| 1389 BinaryOpIC::UNINITIALIZED, true, | |
| 1390 use_runtime, gc_required, ¬_smis, op, | |
| 1391 mode); | |
| 1392 } | |
| 1393 | |
| 1394 __ Bind(¬_smis); | |
| 1395 } | |
| 1396 | |
| 1397 | |
| 1398 void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { | |
| 1399 ASM_LOCATION("BinaryOpStub::GenerateSmiStub"); | |
| 1400 Label right_arg_changed, call_runtime; | |
| 1401 | |
| 1402 if ((op_ == Token::MOD) && encoded_right_arg_.has_value) { | |
| 1403 // It is guaranteed that the value will fit into a Smi, because if it | |
| 1404 // didn't, we wouldn't be here, see BinaryOp_Patch. | |
| 1405 __ CompareAndBranch(x0, Operand(Smi::FromInt(fixed_right_arg_value())), ne, | |
| 1406 &right_arg_changed); | |
| 1407 } | |
| 1408 | |
| 1409 #ifdef DEBUG | |
| 1410 Register saved_left = x18; | |
| 1411 Register saved_right = x19; | |
| 1412 if (masm->emit_debug_code()) { | |
| 1413 __ Mov(saved_left, x1); | |
| 1414 __ Mov(saved_right, x0); | |
| 1415 } | |
| 1416 #endif | |
| 1417 | |
| 1418 if (result_type_ == BinaryOpIC::UNINITIALIZED || | |
| 1419 result_type_ == BinaryOpIC::SMI) { | |
| 1420 // Only allow smi results. No allocation should take place, so we don't need | |
| 1421 // a label for gc. | |
| 1422 BinaryOpStub_GenerateSmiCode(masm, &call_runtime, NULL, op_, | |
| 1423 NO_HEAPNUMBER_RESULTS, mode_); | |
| 1424 } else { | |
| 1425 // Allow heap number result and don't make a transition if a heap number | |
| 1426 // cannot be allocated. | |
| 1427 BinaryOpStub_GenerateSmiCode(masm, &call_runtime, &call_runtime, op_, | |
| 1428 ALLOW_HEAPNUMBER_RESULTS, mode_); | |
| 1429 } | |
| 1430 | |
| 1431 // Code falls through if the result is not returned as either a smi or heap | |
| 1432 // number. | |
| 1433 __ Bind(&right_arg_changed); | |
| 1434 GenerateTypeTransition(masm); | |
| 1435 | |
| 1436 __ Bind(&call_runtime); | |
| 1437 #ifdef DEBUG | |
| 1438 if (masm->emit_debug_code()) { | |
| 1439 __ Cmp(saved_left, x1); | |
| 1440 __ Assert(eq, kLhsHasBeenClobbered); | |
| 1441 __ Cmp(saved_right, x0); | |
| 1442 __ Assert(eq, kRhsHasBeenClobbered); | |
| 1443 } | |
| 1444 #endif | |
| 1445 { | |
| 1446 FrameScope scope(masm, StackFrame::INTERNAL); | |
| 1447 GenerateRegisterArgsPush(masm); | |
| 1448 GenerateCallRuntime(masm); | |
| 1449 } | |
| 1450 __ Ret(); | |
| 1451 } | |
| 1452 | |
| 1453 | |
| 1454 void BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) { | |
| 1455 ASM_LOCATION("BinaryOpStub::GenerateBothStringStub"); | |
| 1456 ASSERT((left_type_ == BinaryOpIC::STRING) && | |
| 1457 (right_type_ == BinaryOpIC::STRING)); | |
| 1458 ASSERT(op_ == Token::ADD); | |
| 1459 Label call_transition; | |
| 1460 | |
| 1461 // If both arguments are strings, call the string add stub. Otherwise, do a | |
| 1462 // transition. | |
| 1463 | |
| 1464 Register left = x1; | |
| 1465 Register right = x0; | |
| 1466 | |
| 1467 // Test if left operand is a smi or string. | |
| 1468 __ JumpIfSmi(left, &call_transition); | |
| 1469 __ JumpIfObjectType(left, x2, x2, FIRST_NONSTRING_TYPE, &call_transition, ge); | |
| 1470 | |
| 1471 // Test if right operand is a smi or string. | |
| 1472 __ JumpIfSmi(right, &call_transition); | |
| 1473 __ JumpIfObjectType(right, x2, x2, FIRST_NONSTRING_TYPE, &call_transition, | |
| 1474 ge); | |
| 1475 | |
| 1476 StringAddStub string_add_stub( | |
| 1477 static_cast<StringAddFlags>(STRING_ADD_CHECK_NONE | | |
| 1478 STRING_ADD_ERECT_FRAME)); | |
| 1479 GenerateRegisterArgsPush(masm); | |
| 1480 __ TailCallStub(&string_add_stub); | |
| 1481 | |
| 1482 __ Bind(&call_transition); | |
| 1483 GenerateTypeTransition(masm); | |
| 1484 } | |
| 1485 | |
| 1486 | |
| 1487 void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { | |
| 1488 // On a64 the smis are 32 bits, so we should never see the INT32 type. | |
| 1489 UNREACHABLE(); | |
| 1490 } | |
| 1491 | |
| 1492 | |
| 1493 void BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) { | |
| 1494 ASM_LOCATION("BinaryOpStub::GenerateOddballStub"); | |
| 1495 Register right = x0; | |
| 1496 Register left = x1; | |
| 1497 | |
| 1498 if (op_ == Token::ADD) { | |
| 1499 // Handle string addition here, because it is the only operation that does | |
| 1500 // not do a ToNumber conversion on the operands. | |
| 1501 GenerateAddStrings(masm); | |
| 1502 } | |
| 1503 | |
| 1504 // Convert oddball arguments to numbers. | |
| 1505 Label check, done; | |
| 1506 __ JumpIfNotRoot(left, Heap::kUndefinedValueRootIndex, &check); | |
| 1507 if (Token::IsBitOp(op_)) { | |
| 1508 __ Mov(left, 0); | |
| 1509 } else { | |
| 1510 __ LoadRoot(left, Heap::kNanValueRootIndex); | |
| 1511 } | |
| 1512 __ B(&done); | |
| 1513 | |
| 1514 __ Bind(&check); | |
| 1515 __ JumpIfNotRoot(right, Heap::kUndefinedValueRootIndex, &done); | |
| 1516 if (Token::IsBitOp(op_)) { | |
| 1517 __ Mov(right, 0); | |
| 1518 } else { | |
| 1519 __ LoadRoot(right, Heap::kNanValueRootIndex); | |
| 1520 } | |
| 1521 | |
| 1522 __ Bind(&done); | |
| 1523 | |
| 1524 GenerateNumberStub(masm); | |
| 1525 } | |
| 1526 | |
| 1527 | |
| 1528 void BinaryOpStub::GenerateNumberStub(MacroAssembler* masm) { | |
| 1529 ASM_LOCATION("BinaryOpStub::GenerateNumberStub"); | |
| 1530 Label call_runtime, transition; | |
| 1531 | |
| 1532 BinaryOpStub_GenerateFPOperation(masm, left_type_, right_type_, false, | |
| 1533 &transition, &call_runtime, &transition, | |
| 1534 op_, mode_); | |
| 1535 | |
| 1536 __ Bind(&transition); | |
| 1537 GenerateTypeTransition(masm); | |
| 1538 | |
| 1539 __ Bind(&call_runtime); | |
| 1540 { | |
| 1541 FrameScope scope(masm, StackFrame::INTERNAL); | |
| 1542 GenerateRegisterArgsPush(masm); | |
| 1543 GenerateCallRuntime(masm); | |
| 1544 } | |
| 1545 __ Ret(); | |
| 1546 } | |
| 1547 | |
| 1548 | |
| 1549 void BinaryOpStub::GenerateGeneric(MacroAssembler* masm) { | |
| 1550 ASM_LOCATION("BinaryOpStub::GenerateGeneric"); | |
| 1551 Label call_runtime, call_string_add_or_runtime, transition; | |
| 1552 | |
| 1553 BinaryOpStub_GenerateSmiCode(masm, &call_runtime, &call_runtime, op_, | |
| 1554 ALLOW_HEAPNUMBER_RESULTS, mode_); | |
| 1555 | |
| 1556 BinaryOpStub_GenerateFPOperation(masm, left_type_, right_type_, false, | |
| 1557 &call_string_add_or_runtime, &call_runtime, | |
| 1558 &transition, op_, mode_); | |
| 1559 | |
| 1560 __ Bind(&transition); | |
| 1561 GenerateTypeTransition(masm); | |
| 1562 | |
| 1563 __ Bind(&call_string_add_or_runtime); | |
| 1564 if (op_ == Token::ADD) { | |
| 1565 GenerateAddStrings(masm); | |
| 1566 } | |
| 1567 | |
| 1568 __ Bind(&call_runtime); | |
| 1569 { | |
| 1570 FrameScope scope(masm, StackFrame::INTERNAL); | |
| 1571 GenerateRegisterArgsPush(masm); | |
| 1572 GenerateCallRuntime(masm); | |
| 1573 } | |
| 1574 __ Ret(); | |
| 1575 } | |
| 1576 | |
| 1577 | |
| 1578 void BinaryOpStub::GenerateAddStrings(MacroAssembler* masm) { | |
| 1579 ASM_LOCATION("BinaryOpStub::GenerateAddStrings"); | |
| 1580 ASSERT(op_ == Token::ADD); | |
| 1581 Label left_not_string, call_runtime; | |
| 1582 | |
| 1583 Register left = x1; | |
| 1584 Register right = x0; | |
| 1585 | |
| 1586 // Check if left argument is a string. | |
| 1587 __ JumpIfSmi(left, &left_not_string); | |
| 1588 __ JumpIfObjectType(left, x2, x2, FIRST_NONSTRING_TYPE, &left_not_string, ge); | |
| 1589 | |
| 1590 StringAddStub string_add_left_stub( | |
| 1591 static_cast<StringAddFlags>(STRING_ADD_CHECK_RIGHT | | |
| 1592 STRING_ADD_ERECT_FRAME)); | |
| 1593 GenerateRegisterArgsPush(masm); | |
| 1594 __ TailCallStub(&string_add_left_stub); | |
| 1595 | |
| 1596 // Left operand is not a string, test right. | |
| 1597 __ Bind(&left_not_string); | |
| 1598 __ JumpIfSmi(right, &call_runtime); | |
| 1599 __ JumpIfObjectType(right, x2, x2, FIRST_NONSTRING_TYPE, &call_runtime, ge); | |
| 1600 | |
| 1601 StringAddStub string_add_right_stub( | |
| 1602 static_cast<StringAddFlags>(STRING_ADD_CHECK_LEFT | | |
| 1603 STRING_ADD_ERECT_FRAME)); | |
| 1604 GenerateRegisterArgsPush(masm); | |
| 1605 __ TailCallStub(&string_add_right_stub); | |
| 1606 | |
| 1607 // Neither argument is a string. | |
| 1608 __ Bind(&call_runtime); | |
| 1609 } | |
| 1610 | |
| 1611 | |
| 1612 void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm, | |
| 1613 Register result, | |
| 1614 Register heap_number_map, | |
| 1615 Register scratch1, | |
| 1616 Register scratch2, | |
| 1617 Label* gc_required, | |
| 1618 OverwriteMode mode) { | |
| 1619 ASM_LOCATION("BinaryOpStub::GenerateHeapResultAllocation"); | |
| 1620 ASSERT(!AreAliased(result, heap_number_map, scratch1, scratch2)); | |
| 1621 | |
| 1622 if ((mode == OVERWRITE_LEFT) || (mode == OVERWRITE_RIGHT)) { | |
| 1623 Label skip_allocation, allocated; | |
| 1624 Register overwritable_operand = (mode == OVERWRITE_LEFT) ? x1 : x0; | |
| 1625 if (masm->emit_debug_code()) { | |
| 1626 // Check that the overwritable operand is a Smi or a HeapNumber. | |
| 1627 Label ok; | |
| 1628 __ JumpIfSmi(overwritable_operand, &ok); | |
| 1629 __ JumpIfHeapNumber(overwritable_operand, &ok); | |
| 1630 __ Abort(kExpectedSmiOrHeapNumber); | |
| 1631 __ Bind(&ok); | |
| 1632 } | |
| 1633 // If the overwritable operand is already a HeapNumber, we can skip | |
| 1634 // allocation of a heap number. | |
| 1635 __ JumpIfNotSmi(overwritable_operand, &skip_allocation); | |
| 1636 // Allocate a heap number for the result. | |
| 1637 __ AllocateHeapNumber(result, gc_required, scratch1, scratch2, | |
| 1638 heap_number_map); | |
| 1639 __ B(&allocated); | |
| 1640 __ Bind(&skip_allocation); | |
| 1641 // Use object holding the overwritable operand for result. | |
| 1642 __ Mov(result, overwritable_operand); | |
| 1643 __ Bind(&allocated); | |
| 1644 } else { | |
| 1645 ASSERT(mode == NO_OVERWRITE); | |
| 1646 __ AllocateHeapNumber(result, gc_required, scratch1, scratch2, | |
| 1647 heap_number_map); | |
| 1648 } | |
| 1649 } | |
| 1650 | |
| 1651 | |
| 1652 void BinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) { | |
| 1653 __ Push(x1, x0); | |
| 1654 } | |
| 1655 | |
| 1656 | |
| 1657 void TranscendentalCacheStub::Generate(MacroAssembler* masm) { | 976 void TranscendentalCacheStub::Generate(MacroAssembler* masm) { |
| 1658 // Untagged case: | 977 // Untagged case: |
| 1659 // Input: double in d0 | 978 // Input: double in d0 |
| 1660 // Result: double in d0 | 979 // Result: double in d0 |
| 1661 // | 980 // |
| 1662 // Tagged case: | 981 // Tagged case: |
| 1663 // Input: tagged value in jssp[0] | 982 // Input: tagged value in jssp[0] |
| 1664 // Result: tagged value in x0 | 983 // Result: tagged value in x0 |
| 1665 | 984 |
| 1666 const bool tagged = (argument_type_ == TAGGED); | 985 const bool tagged = (argument_type_ == TAGGED); |
| (...skipping 467 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2134 // It is important that the following stubs are generated in this order | 1453 // It is important that the following stubs are generated in this order |
| 2135 // because pregenerated stubs can only call other pregenerated stubs. | 1454 // because pregenerated stubs can only call other pregenerated stubs. |
| 2136 // RecordWriteStub uses StoreBufferOverflowStub, which in turn uses | 1455 // RecordWriteStub uses StoreBufferOverflowStub, which in turn uses |
| 2137 // CEntryStub. | 1456 // CEntryStub. |
| 2138 CEntryStub::GenerateAheadOfTime(isolate); | 1457 CEntryStub::GenerateAheadOfTime(isolate); |
| 2139 StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate); | 1458 StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate); |
| 2140 StubFailureTrampolineStub::GenerateAheadOfTime(isolate); | 1459 StubFailureTrampolineStub::GenerateAheadOfTime(isolate); |
| 2141 RecordWriteStub::GenerateFixedRegStubsAheadOfTime(isolate); | 1460 RecordWriteStub::GenerateFixedRegStubsAheadOfTime(isolate); |
| 2142 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate); | 1461 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate); |
| 2143 CreateAllocationSiteStub::GenerateAheadOfTime(isolate); | 1462 CreateAllocationSiteStub::GenerateAheadOfTime(isolate); |
| 1463 BinaryOpStub::GenerateAheadOfTime(isolate); |
| 2144 } | 1464 } |
| 2145 | 1465 |
| 2146 | 1466 |
| 2147 void CodeStub::GenerateFPStubs(Isolate* isolate) { | 1467 void CodeStub::GenerateFPStubs(Isolate* isolate) { |
| 2148 // Floating-point code doesn't get special handling in A64, so there's | 1468 // Floating-point code doesn't get special handling in A64, so there's |
| 2149 // nothing to do here. | 1469 // nothing to do here. |
| 2150 USE(isolate); | 1470 USE(isolate); |
| 2151 } | 1471 } |
| 2152 | 1472 |
| 2153 | 1473 |
| (...skipping 4695 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6849 __ Bind(&fast_elements_case); | 6169 __ Bind(&fast_elements_case); |
| 6850 GenerateCase(masm, FAST_ELEMENTS); | 6170 GenerateCase(masm, FAST_ELEMENTS); |
| 6851 } | 6171 } |
| 6852 | 6172 |
| 6853 | 6173 |
| 6854 #undef __ | 6174 #undef __ |
| 6855 | 6175 |
| 6856 } } // namespace v8::internal | 6176 } } // namespace v8::internal |
| 6857 | 6177 |
| 6858 #endif // V8_TARGET_ARCH_A64 | 6178 #endif // V8_TARGET_ARCH_A64 |
| OLD | NEW |