OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
161 static Register registers[] = { r0 }; | 161 static Register registers[] = { r0 }; |
162 descriptor->register_param_count_ = 1; | 162 descriptor->register_param_count_ = 1; |
163 descriptor->register_params_ = registers; | 163 descriptor->register_params_ = registers; |
164 descriptor->deoptimization_handler_ = | 164 descriptor->deoptimization_handler_ = |
165 FUNCTION_ADDR(CompareNilIC_Miss); | 165 FUNCTION_ADDR(CompareNilIC_Miss); |
166 descriptor->SetMissHandler( | 166 descriptor->SetMissHandler( |
167 ExternalReference(IC_Utility(IC::kCompareNilIC_Miss), isolate)); | 167 ExternalReference(IC_Utility(IC::kCompareNilIC_Miss), isolate)); |
168 } | 168 } |
169 | 169 |
170 | 170 |
| 171 void BinaryOpStub::InitializeInterfaceDescriptor( |
| 172 Isolate* isolate, |
| 173 CodeStubInterfaceDescriptor* descriptor) { |
| 174 static Register registers[] = { r1, r0 }; |
| 175 descriptor->register_param_count_ = 2; |
| 176 descriptor->register_params_ = registers; |
| 177 descriptor->deoptimization_handler_ = FUNCTION_ADDR(BinaryOpIC_Miss); |
| 178 descriptor->SetMissHandler( |
| 179 ExternalReference(IC_Utility(IC::kBinaryOpIC_Miss), isolate)); |
| 180 } |
| 181 |
| 182 |
171 static void InitializeArrayConstructorDescriptor( | 183 static void InitializeArrayConstructorDescriptor( |
172 Isolate* isolate, | 184 Isolate* isolate, |
173 CodeStubInterfaceDescriptor* descriptor, | 185 CodeStubInterfaceDescriptor* descriptor, |
174 int constant_stack_parameter_count) { | 186 int constant_stack_parameter_count) { |
175 // register state | 187 // register state |
176 // r0 -- number of arguments | 188 // r0 -- number of arguments |
177 // r1 -- function | 189 // r1 -- function |
178 // r2 -- type info cell with elements kind | 190 // r2 -- type info cell with elements kind |
179 static Register registers[] = { r1, r2 }; | 191 static Register registers[] = { r1, r2 }; |
180 descriptor->register_param_count_ = 2; | 192 descriptor->register_param_count_ = 2; |
(...skipping 997 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1178 __ CallCFunction( | 1190 __ CallCFunction( |
1179 ExternalReference::store_buffer_overflow_function(masm->isolate()), | 1191 ExternalReference::store_buffer_overflow_function(masm->isolate()), |
1180 argument_count); | 1192 argument_count); |
1181 if (save_doubles_ == kSaveFPRegs) { | 1193 if (save_doubles_ == kSaveFPRegs) { |
1182 __ RestoreFPRegs(sp, scratch); | 1194 __ RestoreFPRegs(sp, scratch); |
1183 } | 1195 } |
1184 __ ldm(ia_w, sp, kCallerSaved | pc.bit()); // Also pop pc to get Ret(0). | 1196 __ ldm(ia_w, sp, kCallerSaved | pc.bit()); // Also pop pc to get Ret(0). |
1185 } | 1197 } |
1186 | 1198 |
1187 | 1199 |
1188 // Generates code to call a C function to do a double operation. | |
1189 // This code never falls through, but returns with a heap number containing | |
1190 // the result in r0. | |
1191 // Register heapnumber_result must be a heap number in which the | |
1192 // result of the operation will be stored. | |
1193 // Requires the following layout on entry: | |
1194 // d0: Left value. | |
1195 // d1: Right value. | |
1196 // If soft float ABI, use also r0, r1, r2, r3. | |
1197 static void CallCCodeForDoubleOperation(MacroAssembler* masm, | |
1198 Token::Value op, | |
1199 Register heap_number_result, | |
1200 Register scratch) { | |
1201 // Assert that heap_number_result is callee-saved. | |
1202 // We currently always use r5 to pass it. | |
1203 ASSERT(heap_number_result.is(r5)); | |
1204 | |
1205 // Push the current return address before the C call. Return will be | |
1206 // through pop(pc) below. | |
1207 __ push(lr); | |
1208 __ PrepareCallCFunction(0, 2, scratch); | |
1209 if (!masm->use_eabi_hardfloat()) { | |
1210 __ vmov(r0, r1, d0); | |
1211 __ vmov(r2, r3, d1); | |
1212 } | |
1213 { | |
1214 AllowExternalCallThatCantCauseGC scope(masm); | |
1215 __ CallCFunction( | |
1216 ExternalReference::double_fp_operation(op, masm->isolate()), 0, 2); | |
1217 } | |
1218 // Store answer in the overwritable heap number. Double returned in | |
1219 // registers r0 and r1 or in d0. | |
1220 if (masm->use_eabi_hardfloat()) { | |
1221 __ vstr(d0, FieldMemOperand(heap_number_result, HeapNumber::kValueOffset)); | |
1222 } else { | |
1223 __ Strd(r0, r1, | |
1224 FieldMemOperand(heap_number_result, HeapNumber::kValueOffset)); | |
1225 } | |
1226 // Place heap_number_result in r0 and return to the pushed return address. | |
1227 __ mov(r0, Operand(heap_number_result)); | |
1228 __ pop(pc); | |
1229 } | |
1230 | |
1231 | |
1232 void BinaryOpStub::Initialize() { | |
1233 platform_specific_bit_ = true; // VFP2 is a base requirement for V8 | |
1234 } | |
1235 | |
1236 | |
1237 void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { | |
1238 Label get_result; | |
1239 | |
1240 __ Push(r1, r0); | |
1241 | |
1242 __ mov(r2, Operand(Smi::FromInt(MinorKey()))); | |
1243 __ push(r2); | |
1244 | |
1245 __ TailCallExternalReference( | |
1246 ExternalReference(IC_Utility(IC::kBinaryOp_Patch), | |
1247 masm->isolate()), | |
1248 3, | |
1249 1); | |
1250 } | |
1251 | |
1252 | |
1253 void BinaryOpStub::GenerateTypeTransitionWithSavedArgs( | |
1254 MacroAssembler* masm) { | |
1255 UNIMPLEMENTED(); | |
1256 } | |
1257 | |
1258 | |
1259 void BinaryOpStub_GenerateSmiSmiOperation(MacroAssembler* masm, | |
1260 Token::Value op, | |
1261 Register scratch1, | |
1262 Register scratch2) { | |
1263 Register left = r1; | |
1264 Register right = r0; | |
1265 | |
1266 ASSERT(right.is(r0)); | |
1267 ASSERT(!AreAliased(left, right, scratch1, scratch2, ip)); | |
1268 STATIC_ASSERT(kSmiTag == 0); | |
1269 | |
1270 Label not_smi_result; | |
1271 switch (op) { | |
1272 case Token::ADD: | |
1273 __ add(right, left, Operand(right), SetCC); // Add optimistically. | |
1274 __ Ret(vc); | |
1275 __ sub(right, right, Operand(left)); // Revert optimistic add. | |
1276 break; | |
1277 case Token::SUB: | |
1278 __ sub(right, left, Operand(right), SetCC); // Subtract optimistically. | |
1279 __ Ret(vc); | |
1280 __ sub(right, left, Operand(right)); // Revert optimistic subtract. | |
1281 break; | |
1282 case Token::MUL: | |
1283 // Remove tag from one of the operands. This way the multiplication result | |
1284 // will be a smi if it fits the smi range. | |
1285 __ SmiUntag(ip, right); | |
1286 // Do multiplication | |
1287 // scratch1 = lower 32 bits of ip * left. | |
1288 // scratch2 = higher 32 bits of ip * left. | |
1289 __ smull(scratch1, scratch2, left, ip); | |
1290 // Check for overflowing the smi range - no overflow if higher 33 bits of | |
1291 // the result are identical. | |
1292 __ mov(ip, Operand(scratch1, ASR, 31)); | |
1293 __ cmp(ip, Operand(scratch2)); | |
1294 __ b(ne, ¬_smi_result); | |
1295 // Go slow on zero result to handle -0. | |
1296 __ cmp(scratch1, Operand::Zero()); | |
1297 __ mov(right, Operand(scratch1), LeaveCC, ne); | |
1298 __ Ret(ne); | |
1299 // We need -0 if we were multiplying a negative number with 0 to get 0. | |
1300 // We know one of them was zero. | |
1301 __ add(scratch2, right, Operand(left), SetCC); | |
1302 __ mov(right, Operand(Smi::FromInt(0)), LeaveCC, pl); | |
1303 __ Ret(pl); // Return smi 0 if the non-zero one was positive. | |
1304 // We fall through here if we multiplied a negative number with 0, because | |
1305 // that would mean we should produce -0. | |
1306 break; | |
1307 case Token::DIV: { | |
1308 Label div_with_sdiv; | |
1309 | |
1310 // Check for 0 divisor. | |
1311 __ cmp(right, Operand::Zero()); | |
1312 __ b(eq, ¬_smi_result); | |
1313 | |
1314 // Check for power of two on the right hand side. | |
1315 __ sub(scratch1, right, Operand(1)); | |
1316 __ tst(scratch1, right); | |
1317 if (CpuFeatures::IsSupported(SUDIV)) { | |
1318 __ b(ne, &div_with_sdiv); | |
1319 // Check for no remainder. | |
1320 __ tst(left, scratch1); | |
1321 __ b(ne, ¬_smi_result); | |
1322 // Check for positive left hand side. | |
1323 __ cmp(left, Operand::Zero()); | |
1324 __ b(mi, &div_with_sdiv); | |
1325 } else { | |
1326 __ b(ne, ¬_smi_result); | |
1327 // Check for positive and no remainder. | |
1328 __ orr(scratch2, scratch1, Operand(0x80000000u)); | |
1329 __ tst(left, scratch2); | |
1330 __ b(ne, ¬_smi_result); | |
1331 } | |
1332 | |
1333 // Perform division by shifting. | |
1334 __ clz(scratch1, scratch1); | |
1335 __ rsb(scratch1, scratch1, Operand(31)); | |
1336 __ mov(right, Operand(left, LSR, scratch1)); | |
1337 __ Ret(); | |
1338 | |
1339 if (CpuFeatures::IsSupported(SUDIV)) { | |
1340 CpuFeatureScope scope(masm, SUDIV); | |
1341 Label result_not_zero; | |
1342 | |
1343 __ bind(&div_with_sdiv); | |
1344 // Do division. | |
1345 __ sdiv(scratch1, left, right); | |
1346 // Check that the remainder is zero. | |
1347 __ mls(scratch2, scratch1, right, left); | |
1348 __ cmp(scratch2, Operand::Zero()); | |
1349 __ b(ne, ¬_smi_result); | |
1350 // Check for negative zero result. | |
1351 __ cmp(scratch1, Operand::Zero()); | |
1352 __ b(ne, &result_not_zero); | |
1353 __ cmp(right, Operand::Zero()); | |
1354 __ b(lt, ¬_smi_result); | |
1355 __ bind(&result_not_zero); | |
1356 // Check for the corner case of dividing the most negative smi by -1. | |
1357 __ cmp(scratch1, Operand(0x40000000)); | |
1358 __ b(eq, ¬_smi_result); | |
1359 // Tag and return the result. | |
1360 __ SmiTag(right, scratch1); | |
1361 __ Ret(); | |
1362 } | |
1363 break; | |
1364 } | |
1365 case Token::MOD: { | |
1366 Label modulo_with_sdiv; | |
1367 | |
1368 if (CpuFeatures::IsSupported(SUDIV)) { | |
1369 // Check for x % 0. | |
1370 __ cmp(right, Operand::Zero()); | |
1371 __ b(eq, ¬_smi_result); | |
1372 | |
1373 // Check for two positive smis. | |
1374 __ orr(scratch1, left, Operand(right)); | |
1375 __ tst(scratch1, Operand(0x80000000u)); | |
1376 __ b(ne, &modulo_with_sdiv); | |
1377 | |
1378 // Check for power of two on the right hand side. | |
1379 __ sub(scratch1, right, Operand(1)); | |
1380 __ tst(scratch1, right); | |
1381 __ b(ne, &modulo_with_sdiv); | |
1382 } else { | |
1383 // Check for two positive smis. | |
1384 __ orr(scratch1, left, Operand(right)); | |
1385 __ tst(scratch1, Operand(0x80000000u)); | |
1386 __ b(ne, ¬_smi_result); | |
1387 | |
1388 // Check for power of two on the right hand side. | |
1389 __ JumpIfNotPowerOfTwoOrZero(right, scratch1, ¬_smi_result); | |
1390 } | |
1391 | |
1392 // Perform modulus by masking (scratch1 contains right - 1). | |
1393 __ and_(right, left, Operand(scratch1)); | |
1394 __ Ret(); | |
1395 | |
1396 if (CpuFeatures::IsSupported(SUDIV)) { | |
1397 CpuFeatureScope scope(masm, SUDIV); | |
1398 __ bind(&modulo_with_sdiv); | |
1399 __ mov(scratch2, right); | |
1400 // Perform modulus with sdiv and mls. | |
1401 __ sdiv(scratch1, left, right); | |
1402 __ mls(right, scratch1, right, left); | |
1403 // Return if the result is not 0. | |
1404 __ cmp(right, Operand::Zero()); | |
1405 __ Ret(ne); | |
1406 // The result is 0, check for -0 case. | |
1407 __ cmp(left, Operand::Zero()); | |
1408 __ Ret(pl); | |
1409 // This is a -0 case, restore the value of right. | |
1410 __ mov(right, scratch2); | |
1411 // We fall through here to not_smi_result to produce -0. | |
1412 } | |
1413 break; | |
1414 } | |
1415 case Token::BIT_OR: | |
1416 __ orr(right, left, Operand(right)); | |
1417 __ Ret(); | |
1418 break; | |
1419 case Token::BIT_AND: | |
1420 __ and_(right, left, Operand(right)); | |
1421 __ Ret(); | |
1422 break; | |
1423 case Token::BIT_XOR: | |
1424 __ eor(right, left, Operand(right)); | |
1425 __ Ret(); | |
1426 break; | |
1427 case Token::SAR: | |
1428 // Remove tags from right operand. | |
1429 __ GetLeastBitsFromSmi(scratch1, right, 5); | |
1430 __ mov(right, Operand(left, ASR, scratch1)); | |
1431 // Smi tag result. | |
1432 __ bic(right, right, Operand(kSmiTagMask)); | |
1433 __ Ret(); | |
1434 break; | |
1435 case Token::SHR: | |
1436 // Remove tags from operands. We can't do this on a 31 bit number | |
1437 // because then the 0s get shifted into bit 30 instead of bit 31. | |
1438 __ SmiUntag(scratch1, left); | |
1439 __ GetLeastBitsFromSmi(scratch2, right, 5); | |
1440 __ mov(scratch1, Operand(scratch1, LSR, scratch2)); | |
1441 // Unsigned shift is not allowed to produce a negative number, so | |
1442 // check the sign bit and the sign bit after Smi tagging. | |
1443 __ tst(scratch1, Operand(0xc0000000)); | |
1444 __ b(ne, ¬_smi_result); | |
1445 // Smi tag result. | |
1446 __ SmiTag(right, scratch1); | |
1447 __ Ret(); | |
1448 break; | |
1449 case Token::SHL: | |
1450 // Remove tags from operands. | |
1451 __ SmiUntag(scratch1, left); | |
1452 __ GetLeastBitsFromSmi(scratch2, right, 5); | |
1453 __ mov(scratch1, Operand(scratch1, LSL, scratch2)); | |
1454 // Check that the signed result fits in a Smi. | |
1455 __ TrySmiTag(right, scratch1, ¬_smi_result); | |
1456 __ Ret(); | |
1457 break; | |
1458 default: | |
1459 UNREACHABLE(); | |
1460 } | |
1461 __ bind(¬_smi_result); | |
1462 } | |
1463 | |
1464 | |
1465 void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm, | |
1466 Register result, | |
1467 Register heap_number_map, | |
1468 Register scratch1, | |
1469 Register scratch2, | |
1470 Label* gc_required, | |
1471 OverwriteMode mode); | |
1472 | |
1473 | |
1474 void BinaryOpStub_GenerateFPOperation(MacroAssembler* masm, | |
1475 BinaryOpIC::TypeInfo left_type, | |
1476 BinaryOpIC::TypeInfo right_type, | |
1477 bool smi_operands, | |
1478 Label* not_numbers, | |
1479 Label* gc_required, | |
1480 Label* miss, | |
1481 Token::Value op, | |
1482 OverwriteMode mode, | |
1483 Register scratch1, | |
1484 Register scratch2, | |
1485 Register scratch3, | |
1486 Register scratch4) { | |
1487 Register left = r1; | |
1488 Register right = r0; | |
1489 Register result = scratch3; | |
1490 ASSERT(!AreAliased(left, right, scratch1, scratch2, scratch3, scratch4)); | |
1491 | |
1492 ASSERT(smi_operands || (not_numbers != NULL)); | |
1493 if (smi_operands) { | |
1494 __ AssertSmi(left); | |
1495 __ AssertSmi(right); | |
1496 } | |
1497 if (left_type == BinaryOpIC::SMI) { | |
1498 __ JumpIfNotSmi(left, miss); | |
1499 } | |
1500 if (right_type == BinaryOpIC::SMI) { | |
1501 __ JumpIfNotSmi(right, miss); | |
1502 } | |
1503 | |
1504 Register heap_number_map = scratch4; | |
1505 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); | |
1506 | |
1507 switch (op) { | |
1508 case Token::ADD: | |
1509 case Token::SUB: | |
1510 case Token::MUL: | |
1511 case Token::DIV: | |
1512 case Token::MOD: { | |
1513 // Allocate new heap number for result. | |
1514 BinaryOpStub_GenerateHeapResultAllocation( | |
1515 masm, result, heap_number_map, scratch1, scratch2, gc_required, mode); | |
1516 | |
1517 // Load left and right operands into d0 and d1. | |
1518 if (smi_operands) { | |
1519 __ SmiToDouble(d1, right); | |
1520 __ SmiToDouble(d0, left); | |
1521 } else { | |
1522 // Load right operand into d1. | |
1523 if (right_type == BinaryOpIC::INT32) { | |
1524 __ LoadNumberAsInt32Double( | |
1525 right, d1, heap_number_map, scratch1, d8, miss); | |
1526 } else { | |
1527 Label* fail = (right_type == BinaryOpIC::NUMBER) ? miss : not_numbers; | |
1528 __ LoadNumber(right, d1, heap_number_map, scratch1, fail); | |
1529 } | |
1530 // Load left operand into d0. | |
1531 if (left_type == BinaryOpIC::INT32) { | |
1532 __ LoadNumberAsInt32Double( | |
1533 left, d0, heap_number_map, scratch1, d8, miss); | |
1534 } else { | |
1535 Label* fail = (left_type == BinaryOpIC::NUMBER) ? miss : not_numbers; | |
1536 __ LoadNumber( | |
1537 left, d0, heap_number_map, scratch1, fail); | |
1538 } | |
1539 } | |
1540 | |
1541 // Calculate the result. | |
1542 if (op != Token::MOD) { | |
1543 // Using VFP registers: | |
1544 // d0: Left value | |
1545 // d1: Right value | |
1546 switch (op) { | |
1547 case Token::ADD: | |
1548 __ vadd(d5, d0, d1); | |
1549 break; | |
1550 case Token::SUB: | |
1551 __ vsub(d5, d0, d1); | |
1552 break; | |
1553 case Token::MUL: | |
1554 __ vmul(d5, d0, d1); | |
1555 break; | |
1556 case Token::DIV: | |
1557 __ vdiv(d5, d0, d1); | |
1558 break; | |
1559 default: | |
1560 UNREACHABLE(); | |
1561 } | |
1562 | |
1563 __ sub(r0, result, Operand(kHeapObjectTag)); | |
1564 __ vstr(d5, r0, HeapNumber::kValueOffset); | |
1565 __ add(r0, r0, Operand(kHeapObjectTag)); | |
1566 __ Ret(); | |
1567 } else { | |
1568 // Call the C function to handle the double operation. | |
1569 CallCCodeForDoubleOperation(masm, op, result, scratch1); | |
1570 if (FLAG_debug_code) { | |
1571 __ stop("Unreachable code."); | |
1572 } | |
1573 } | |
1574 break; | |
1575 } | |
1576 case Token::BIT_OR: | |
1577 case Token::BIT_XOR: | |
1578 case Token::BIT_AND: | |
1579 case Token::SAR: | |
1580 case Token::SHR: | |
1581 case Token::SHL: { | |
1582 if (smi_operands) { | |
1583 __ SmiUntag(r3, left); | |
1584 __ SmiUntag(r2, right); | |
1585 } else { | |
1586 // Convert operands to 32-bit integers. Right in r2 and left in r3. | |
1587 __ TruncateNumberToI(left, r3, heap_number_map, scratch1, not_numbers); | |
1588 __ TruncateNumberToI(right, r2, heap_number_map, scratch1, not_numbers); | |
1589 } | |
1590 | |
1591 Label result_not_a_smi; | |
1592 switch (op) { | |
1593 case Token::BIT_OR: | |
1594 __ orr(r2, r3, Operand(r2)); | |
1595 break; | |
1596 case Token::BIT_XOR: | |
1597 __ eor(r2, r3, Operand(r2)); | |
1598 break; | |
1599 case Token::BIT_AND: | |
1600 __ and_(r2, r3, Operand(r2)); | |
1601 break; | |
1602 case Token::SAR: | |
1603 // Use only the 5 least significant bits of the shift count. | |
1604 __ GetLeastBitsFromInt32(r2, r2, 5); | |
1605 __ mov(r2, Operand(r3, ASR, r2)); | |
1606 break; | |
1607 case Token::SHR: | |
1608 // Use only the 5 least significant bits of the shift count. | |
1609 __ GetLeastBitsFromInt32(r2, r2, 5); | |
1610 __ mov(r2, Operand(r3, LSR, r2), SetCC); | |
1611 // SHR is special because it is required to produce a positive answer. | |
1612 // The code below for writing into heap numbers isn't capable of | |
1613 // writing the register as an unsigned int so we go to slow case if we | |
1614 // hit this case. | |
1615 __ b(mi, &result_not_a_smi); | |
1616 break; | |
1617 case Token::SHL: | |
1618 // Use only the 5 least significant bits of the shift count. | |
1619 __ GetLeastBitsFromInt32(r2, r2, 5); | |
1620 __ mov(r2, Operand(r3, LSL, r2)); | |
1621 break; | |
1622 default: | |
1623 UNREACHABLE(); | |
1624 } | |
1625 | |
1626 // Check that the *signed* result fits in a smi. | |
1627 __ TrySmiTag(r0, r2, &result_not_a_smi); | |
1628 __ Ret(); | |
1629 | |
1630 // Allocate new heap number for result. | |
1631 __ bind(&result_not_a_smi); | |
1632 if (smi_operands) { | |
1633 __ AllocateHeapNumber( | |
1634 result, scratch1, scratch2, heap_number_map, gc_required); | |
1635 } else { | |
1636 BinaryOpStub_GenerateHeapResultAllocation( | |
1637 masm, result, heap_number_map, scratch1, scratch2, gc_required, | |
1638 mode); | |
1639 } | |
1640 | |
1641 // r2: Answer as signed int32. | |
1642 // result: Heap number to write answer into. | |
1643 | |
1644 // Nothing can go wrong now, so move the heap number to r0, which is the | |
1645 // result. | |
1646 __ mov(r0, Operand(result)); | |
1647 | |
1648 // Convert the int32 in r2 to the heap number in r0. r3 is corrupted. As | |
1649 // mentioned above SHR needs to always produce a positive result. | |
1650 __ vmov(s0, r2); | |
1651 if (op == Token::SHR) { | |
1652 __ vcvt_f64_u32(d0, s0); | |
1653 } else { | |
1654 __ vcvt_f64_s32(d0, s0); | |
1655 } | |
1656 __ sub(r3, r0, Operand(kHeapObjectTag)); | |
1657 __ vstr(d0, r3, HeapNumber::kValueOffset); | |
1658 __ Ret(); | |
1659 break; | |
1660 } | |
1661 default: | |
1662 UNREACHABLE(); | |
1663 } | |
1664 } | |
1665 | |
1666 | |
1667 // Generate the smi code. If the operation on smis are successful this return is | |
1668 // generated. If the result is not a smi and heap number allocation is not | |
1669 // requested the code falls through. If number allocation is requested but a | |
1670 // heap number cannot be allocated the code jumps to the label gc_required. | |
1671 void BinaryOpStub_GenerateSmiCode( | |
1672 MacroAssembler* masm, | |
1673 Label* use_runtime, | |
1674 Label* gc_required, | |
1675 Token::Value op, | |
1676 BinaryOpStub::SmiCodeGenerateHeapNumberResults allow_heapnumber_results, | |
1677 OverwriteMode mode, | |
1678 Register scratch1, | |
1679 Register scratch2, | |
1680 Register scratch3, | |
1681 Register scratch4) { | |
1682 Label not_smis; | |
1683 | |
1684 Register left = r1; | |
1685 Register right = r0; | |
1686 ASSERT(!AreAliased(left, right, scratch1, scratch2, scratch3, scratch4)); | |
1687 | |
1688 // Perform combined smi check on both operands. | |
1689 __ orr(scratch1, left, Operand(right)); | |
1690 __ JumpIfNotSmi(scratch1, ¬_smis); | |
1691 | |
1692 // If the smi-smi operation results in a smi return is generated. | |
1693 BinaryOpStub_GenerateSmiSmiOperation(masm, op, scratch1, scratch2); | |
1694 | |
1695 // If heap number results are possible generate the result in an allocated | |
1696 // heap number. | |
1697 if (allow_heapnumber_results == BinaryOpStub::ALLOW_HEAPNUMBER_RESULTS) { | |
1698 BinaryOpStub_GenerateFPOperation( | |
1699 masm, BinaryOpIC::UNINITIALIZED, BinaryOpIC::UNINITIALIZED, true, | |
1700 use_runtime, gc_required, ¬_smis, op, mode, scratch2, scratch3, | |
1701 scratch1, scratch4); | |
1702 } | |
1703 __ bind(¬_smis); | |
1704 } | |
1705 | |
1706 | |
1707 void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { | |
1708 Label right_arg_changed, call_runtime; | |
1709 | |
1710 if (op_ == Token::MOD && encoded_right_arg_.has_value) { | |
1711 // It is guaranteed that the value will fit into a Smi, because if it | |
1712 // didn't, we wouldn't be here, see BinaryOp_Patch. | |
1713 __ cmp(r0, Operand(Smi::FromInt(fixed_right_arg_value()))); | |
1714 __ b(ne, &right_arg_changed); | |
1715 } | |
1716 | |
1717 if (result_type_ == BinaryOpIC::UNINITIALIZED || | |
1718 result_type_ == BinaryOpIC::SMI) { | |
1719 // Only allow smi results. | |
1720 BinaryOpStub_GenerateSmiCode(masm, &call_runtime, NULL, op_, | |
1721 NO_HEAPNUMBER_RESULTS, mode_, r5, r6, r4, r9); | |
1722 } else { | |
1723 // Allow heap number result and don't make a transition if a heap number | |
1724 // cannot be allocated. | |
1725 BinaryOpStub_GenerateSmiCode(masm, &call_runtime, &call_runtime, op_, | |
1726 ALLOW_HEAPNUMBER_RESULTS, mode_, r5, r6, r4, r9); | |
1727 } | |
1728 | |
1729 // Code falls through if the result is not returned as either a smi or heap | |
1730 // number. | |
1731 __ bind(&right_arg_changed); | |
1732 GenerateTypeTransition(masm); | |
1733 | |
1734 __ bind(&call_runtime); | |
1735 { | |
1736 FrameScope scope(masm, StackFrame::INTERNAL); | |
1737 GenerateRegisterArgsPush(masm); | |
1738 GenerateCallRuntime(masm); | |
1739 } | |
1740 __ Ret(); | |
1741 } | |
1742 | |
1743 | |
1744 void BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) { | |
1745 Label call_runtime; | |
1746 ASSERT(left_type_ == BinaryOpIC::STRING && right_type_ == BinaryOpIC::STRING); | |
1747 ASSERT(op_ == Token::ADD); | |
1748 // If both arguments are strings, call the string add stub. | |
1749 // Otherwise, do a transition. | |
1750 | |
1751 // Registers containing left and right operands respectively. | |
1752 Register left = r1; | |
1753 Register right = r0; | |
1754 | |
1755 // Test if left operand is a string. | |
1756 __ JumpIfSmi(left, &call_runtime); | |
1757 __ CompareObjectType(left, r2, r2, FIRST_NONSTRING_TYPE); | |
1758 __ b(ge, &call_runtime); | |
1759 | |
1760 // Test if right operand is a string. | |
1761 __ JumpIfSmi(right, &call_runtime); | |
1762 __ CompareObjectType(right, r2, r2, FIRST_NONSTRING_TYPE); | |
1763 __ b(ge, &call_runtime); | |
1764 | |
1765 StringAddStub string_add_stub( | |
1766 (StringAddFlags)(STRING_ADD_CHECK_NONE | STRING_ADD_ERECT_FRAME)); | |
1767 GenerateRegisterArgsPush(masm); | |
1768 __ TailCallStub(&string_add_stub); | |
1769 | |
1770 __ bind(&call_runtime); | |
1771 GenerateTypeTransition(masm); | |
1772 } | |
1773 | |
1774 | |
1775 void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { | |
1776 ASSERT(Max(left_type_, right_type_) == BinaryOpIC::INT32); | |
1777 | |
1778 Register left = r1; | |
1779 Register right = r0; | |
1780 Register scratch1 = r4; | |
1781 Register scratch2 = r9; | |
1782 Register scratch3 = r5; | |
1783 LowDwVfpRegister double_scratch = d0; | |
1784 | |
1785 Register heap_number_result = no_reg; | |
1786 Register heap_number_map = r6; | |
1787 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); | |
1788 | |
1789 Label call_runtime; | |
1790 // Labels for type transition, used for wrong input or output types. | |
1791 // Both label are currently actually bound to the same position. We use two | |
1792 // different label to differentiate the cause leading to type transition. | |
1793 Label transition; | |
1794 | |
1795 // Smi-smi fast case. | |
1796 Label skip; | |
1797 __ orr(scratch1, left, right); | |
1798 __ JumpIfNotSmi(scratch1, &skip); | |
1799 BinaryOpStub_GenerateSmiSmiOperation(masm, op_, scratch2, scratch3); | |
1800 // Fall through if the result is not a smi. | |
1801 __ bind(&skip); | |
1802 | |
1803 switch (op_) { | |
1804 case Token::ADD: | |
1805 case Token::SUB: | |
1806 case Token::MUL: | |
1807 case Token::DIV: | |
1808 case Token::MOD: { | |
1809 // It could be that only SMIs have been seen at either the left | |
1810 // or the right operand. For precise type feedback, patch the IC | |
1811 // again if this changes. | |
1812 if (left_type_ == BinaryOpIC::SMI) { | |
1813 __ JumpIfNotSmi(left, &transition); | |
1814 } | |
1815 if (right_type_ == BinaryOpIC::SMI) { | |
1816 __ JumpIfNotSmi(right, &transition); | |
1817 } | |
1818 // Load both operands and check that they are 32-bit integer. | |
1819 // Jump to type transition if they are not. The registers r0 and r1 (right | |
1820 // and left) are preserved for the runtime call. | |
1821 __ LoadNumberAsInt32Double( | |
1822 right, d1, heap_number_map, scratch1, d8, &transition); | |
1823 __ LoadNumberAsInt32Double( | |
1824 left, d0, heap_number_map, scratch1, d8, &transition); | |
1825 | |
1826 if (op_ != Token::MOD) { | |
1827 Label return_heap_number; | |
1828 switch (op_) { | |
1829 case Token::ADD: | |
1830 __ vadd(d5, d0, d1); | |
1831 break; | |
1832 case Token::SUB: | |
1833 __ vsub(d5, d0, d1); | |
1834 break; | |
1835 case Token::MUL: | |
1836 __ vmul(d5, d0, d1); | |
1837 break; | |
1838 case Token::DIV: | |
1839 __ vdiv(d5, d0, d1); | |
1840 break; | |
1841 default: | |
1842 UNREACHABLE(); | |
1843 } | |
1844 | |
1845 if (result_type_ <= BinaryOpIC::INT32) { | |
1846 __ TryDoubleToInt32Exact(scratch1, d5, d8); | |
1847 // If the ne condition is set, result does | |
1848 // not fit in a 32-bit integer. | |
1849 __ b(ne, &transition); | |
1850 // Try to tag the result as a Smi, return heap number on overflow. | |
1851 __ SmiTag(scratch1, SetCC); | |
1852 __ b(vs, &return_heap_number); | |
1853 // Check for minus zero, transition in that case (because we need | |
1854 // to return a heap number). | |
1855 Label not_zero; | |
1856 ASSERT(kSmiTag == 0); | |
1857 __ b(ne, ¬_zero); | |
1858 __ VmovHigh(scratch2, d5); | |
1859 __ tst(scratch2, Operand(HeapNumber::kSignMask)); | |
1860 __ b(ne, &transition); | |
1861 __ bind(¬_zero); | |
1862 __ mov(r0, scratch1); | |
1863 __ Ret(); | |
1864 } | |
1865 | |
1866 __ bind(&return_heap_number); | |
1867 // Return a heap number, or fall through to type transition or runtime | |
1868 // call if we can't. | |
1869 // We are using vfp registers so r5 is available. | |
1870 heap_number_result = r5; | |
1871 BinaryOpStub_GenerateHeapResultAllocation(masm, | |
1872 heap_number_result, | |
1873 heap_number_map, | |
1874 scratch1, | |
1875 scratch2, | |
1876 &call_runtime, | |
1877 mode_); | |
1878 __ sub(r0, heap_number_result, Operand(kHeapObjectTag)); | |
1879 __ vstr(d5, r0, HeapNumber::kValueOffset); | |
1880 __ mov(r0, heap_number_result); | |
1881 __ Ret(); | |
1882 | |
1883 // A DIV operation expecting an integer result falls through | |
1884 // to type transition. | |
1885 | |
1886 } else { | |
1887 if (encoded_right_arg_.has_value) { | |
1888 __ Vmov(d8, fixed_right_arg_value(), scratch1); | |
1889 __ VFPCompareAndSetFlags(d1, d8); | |
1890 __ b(ne, &transition); | |
1891 } | |
1892 | |
1893 // Allocate a heap number to store the result. | |
1894 heap_number_result = r5; | |
1895 BinaryOpStub_GenerateHeapResultAllocation(masm, | |
1896 heap_number_result, | |
1897 heap_number_map, | |
1898 scratch1, | |
1899 scratch2, | |
1900 &call_runtime, | |
1901 mode_); | |
1902 | |
1903 // Call the C function to handle the double operation. | |
1904 CallCCodeForDoubleOperation(masm, op_, heap_number_result, scratch1); | |
1905 if (FLAG_debug_code) { | |
1906 __ stop("Unreachable code."); | |
1907 } | |
1908 | |
1909 __ b(&call_runtime); | |
1910 } | |
1911 | |
1912 break; | |
1913 } | |
1914 | |
1915 case Token::BIT_OR: | |
1916 case Token::BIT_XOR: | |
1917 case Token::BIT_AND: | |
1918 case Token::SAR: | |
1919 case Token::SHR: | |
1920 case Token::SHL: { | |
1921 Label return_heap_number; | |
1922 // Convert operands to 32-bit integers. Right in r2 and left in r3. The | |
1923 // registers r0 and r1 (right and left) are preserved for the runtime | |
1924 // call. | |
1925 __ LoadNumberAsInt32(left, r3, heap_number_map, | |
1926 scratch1, d0, d1, &transition); | |
1927 __ LoadNumberAsInt32(right, r2, heap_number_map, | |
1928 scratch1, d0, d1, &transition); | |
1929 | |
1930 // The ECMA-262 standard specifies that, for shift operations, only the | |
1931 // 5 least significant bits of the shift value should be used. | |
1932 switch (op_) { | |
1933 case Token::BIT_OR: | |
1934 __ orr(r2, r3, Operand(r2)); | |
1935 break; | |
1936 case Token::BIT_XOR: | |
1937 __ eor(r2, r3, Operand(r2)); | |
1938 break; | |
1939 case Token::BIT_AND: | |
1940 __ and_(r2, r3, Operand(r2)); | |
1941 break; | |
1942 case Token::SAR: | |
1943 __ and_(r2, r2, Operand(0x1f)); | |
1944 __ mov(r2, Operand(r3, ASR, r2)); | |
1945 break; | |
1946 case Token::SHR: | |
1947 __ and_(r2, r2, Operand(0x1f)); | |
1948 __ mov(r2, Operand(r3, LSR, r2), SetCC); | |
1949 // SHR is special because it is required to produce a positive answer. | |
1950 // We only get a negative result if the shift value (r2) is 0. | |
1951 // This result cannot be respresented as a signed 32-bit integer, try | |
1952 // to return a heap number if we can. | |
1953 __ b(mi, (result_type_ <= BinaryOpIC::INT32) | |
1954 ? &transition | |
1955 : &return_heap_number); | |
1956 break; | |
1957 case Token::SHL: | |
1958 __ and_(r2, r2, Operand(0x1f)); | |
1959 __ mov(r2, Operand(r3, LSL, r2)); | |
1960 break; | |
1961 default: | |
1962 UNREACHABLE(); | |
1963 } | |
1964 | |
1965 // Check if the result fits in a smi. If not try to return a heap number. | |
1966 // (We know the result is an int32). | |
1967 __ TrySmiTag(r0, r2, &return_heap_number); | |
1968 __ Ret(); | |
1969 | |
1970 __ bind(&return_heap_number); | |
1971 heap_number_result = r5; | |
1972 BinaryOpStub_GenerateHeapResultAllocation(masm, | |
1973 heap_number_result, | |
1974 heap_number_map, | |
1975 scratch1, | |
1976 scratch2, | |
1977 &call_runtime, | |
1978 mode_); | |
1979 | |
1980 if (op_ != Token::SHR) { | |
1981 // Convert the result to a floating point value. | |
1982 __ vmov(double_scratch.low(), r2); | |
1983 __ vcvt_f64_s32(double_scratch, double_scratch.low()); | |
1984 } else { | |
1985 // The result must be interpreted as an unsigned 32-bit integer. | |
1986 __ vmov(double_scratch.low(), r2); | |
1987 __ vcvt_f64_u32(double_scratch, double_scratch.low()); | |
1988 } | |
1989 | |
1990 // Store the result. | |
1991 __ sub(r0, heap_number_result, Operand(kHeapObjectTag)); | |
1992 __ vstr(double_scratch, r0, HeapNumber::kValueOffset); | |
1993 __ mov(r0, heap_number_result); | |
1994 __ Ret(); | |
1995 | |
1996 break; | |
1997 } | |
1998 | |
1999 default: | |
2000 UNREACHABLE(); | |
2001 } | |
2002 | |
2003 // We never expect DIV to yield an integer result, so we always generate | |
2004 // type transition code for DIV operations expecting an integer result: the | |
2005 // code will fall through to this type transition. | |
2006 if (transition.is_linked() || | |
2007 ((op_ == Token::DIV) && (result_type_ <= BinaryOpIC::INT32))) { | |
2008 __ bind(&transition); | |
2009 GenerateTypeTransition(masm); | |
2010 } | |
2011 | |
2012 __ bind(&call_runtime); | |
2013 { | |
2014 FrameScope scope(masm, StackFrame::INTERNAL); | |
2015 GenerateRegisterArgsPush(masm); | |
2016 GenerateCallRuntime(masm); | |
2017 } | |
2018 __ Ret(); | |
2019 } | |
2020 | |
2021 | |
2022 void BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) { | |
2023 Label call_runtime; | |
2024 | |
2025 if (op_ == Token::ADD) { | |
2026 // Handle string addition here, because it is the only operation | |
2027 // that does not do a ToNumber conversion on the operands. | |
2028 GenerateAddStrings(masm); | |
2029 } | |
2030 | |
2031 // Convert oddball arguments to numbers. | |
2032 Label check, done; | |
2033 __ CompareRoot(r1, Heap::kUndefinedValueRootIndex); | |
2034 __ b(ne, &check); | |
2035 if (Token::IsBitOp(op_)) { | |
2036 __ mov(r1, Operand(Smi::FromInt(0))); | |
2037 } else { | |
2038 __ LoadRoot(r1, Heap::kNanValueRootIndex); | |
2039 } | |
2040 __ jmp(&done); | |
2041 __ bind(&check); | |
2042 __ CompareRoot(r0, Heap::kUndefinedValueRootIndex); | |
2043 __ b(ne, &done); | |
2044 if (Token::IsBitOp(op_)) { | |
2045 __ mov(r0, Operand(Smi::FromInt(0))); | |
2046 } else { | |
2047 __ LoadRoot(r0, Heap::kNanValueRootIndex); | |
2048 } | |
2049 __ bind(&done); | |
2050 | |
2051 GenerateNumberStub(masm); | |
2052 } | |
2053 | |
2054 | |
2055 void BinaryOpStub::GenerateNumberStub(MacroAssembler* masm) { | |
2056 Label call_runtime, transition; | |
2057 BinaryOpStub_GenerateFPOperation( | |
2058 masm, left_type_, right_type_, false, | |
2059 &transition, &call_runtime, &transition, op_, mode_, r6, r4, r5, r9); | |
2060 | |
2061 __ bind(&transition); | |
2062 GenerateTypeTransition(masm); | |
2063 | |
2064 __ bind(&call_runtime); | |
2065 { | |
2066 FrameScope scope(masm, StackFrame::INTERNAL); | |
2067 GenerateRegisterArgsPush(masm); | |
2068 GenerateCallRuntime(masm); | |
2069 } | |
2070 __ Ret(); | |
2071 } | |
2072 | |
2073 | |
2074 void BinaryOpStub::GenerateGeneric(MacroAssembler* masm) { | |
2075 Label call_runtime, call_string_add_or_runtime, transition; | |
2076 | |
2077 BinaryOpStub_GenerateSmiCode( | |
2078 masm, &call_runtime, &call_runtime, op_, ALLOW_HEAPNUMBER_RESULTS, mode_, | |
2079 r5, r6, r4, r9); | |
2080 | |
2081 BinaryOpStub_GenerateFPOperation( | |
2082 masm, left_type_, right_type_, false, | |
2083 &call_string_add_or_runtime, &call_runtime, &transition, op_, mode_, r6, | |
2084 r4, r5, r9); | |
2085 | |
2086 __ bind(&transition); | |
2087 GenerateTypeTransition(masm); | |
2088 | |
2089 __ bind(&call_string_add_or_runtime); | |
2090 if (op_ == Token::ADD) { | |
2091 GenerateAddStrings(masm); | |
2092 } | |
2093 | |
2094 __ bind(&call_runtime); | |
2095 { | |
2096 FrameScope scope(masm, StackFrame::INTERNAL); | |
2097 GenerateRegisterArgsPush(masm); | |
2098 GenerateCallRuntime(masm); | |
2099 } | |
2100 __ Ret(); | |
2101 } | |
2102 | |
2103 | |
2104 void BinaryOpStub::GenerateAddStrings(MacroAssembler* masm) { | |
2105 ASSERT(op_ == Token::ADD); | |
2106 Label left_not_string, call_runtime; | |
2107 | |
2108 Register left = r1; | |
2109 Register right = r0; | |
2110 | |
2111 // Check if left argument is a string. | |
2112 __ JumpIfSmi(left, &left_not_string); | |
2113 __ CompareObjectType(left, r2, r2, FIRST_NONSTRING_TYPE); | |
2114 __ b(ge, &left_not_string); | |
2115 | |
2116 StringAddStub string_add_left_stub( | |
2117 (StringAddFlags)(STRING_ADD_CHECK_RIGHT | STRING_ADD_ERECT_FRAME)); | |
2118 GenerateRegisterArgsPush(masm); | |
2119 __ TailCallStub(&string_add_left_stub); | |
2120 | |
2121 // Left operand is not a string, test right. | |
2122 __ bind(&left_not_string); | |
2123 __ JumpIfSmi(right, &call_runtime); | |
2124 __ CompareObjectType(right, r2, r2, FIRST_NONSTRING_TYPE); | |
2125 __ b(ge, &call_runtime); | |
2126 | |
2127 StringAddStub string_add_right_stub( | |
2128 (StringAddFlags)(STRING_ADD_CHECK_LEFT | STRING_ADD_ERECT_FRAME)); | |
2129 GenerateRegisterArgsPush(masm); | |
2130 __ TailCallStub(&string_add_right_stub); | |
2131 | |
2132 // At least one argument is not a string. | |
2133 __ bind(&call_runtime); | |
2134 } | |
2135 | |
2136 | |
2137 void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm, | |
2138 Register result, | |
2139 Register heap_number_map, | |
2140 Register scratch1, | |
2141 Register scratch2, | |
2142 Label* gc_required, | |
2143 OverwriteMode mode) { | |
2144 // Code below will scratch result if allocation fails. To keep both arguments | |
2145 // intact for the runtime call result cannot be one of these. | |
2146 ASSERT(!result.is(r0) && !result.is(r1)); | |
2147 | |
2148 if (mode == OVERWRITE_LEFT || mode == OVERWRITE_RIGHT) { | |
2149 Label skip_allocation, allocated; | |
2150 Register overwritable_operand = mode == OVERWRITE_LEFT ? r1 : r0; | |
2151 // If the overwritable operand is already an object, we skip the | |
2152 // allocation of a heap number. | |
2153 __ JumpIfNotSmi(overwritable_operand, &skip_allocation); | |
2154 // Allocate a heap number for the result. | |
2155 __ AllocateHeapNumber( | |
2156 result, scratch1, scratch2, heap_number_map, gc_required); | |
2157 __ b(&allocated); | |
2158 __ bind(&skip_allocation); | |
2159 // Use object holding the overwritable operand for result. | |
2160 __ mov(result, Operand(overwritable_operand)); | |
2161 __ bind(&allocated); | |
2162 } else { | |
2163 ASSERT(mode == NO_OVERWRITE); | |
2164 __ AllocateHeapNumber( | |
2165 result, scratch1, scratch2, heap_number_map, gc_required); | |
2166 } | |
2167 } | |
2168 | |
2169 | |
2170 void BinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) { | |
2171 __ Push(r1, r0); | |
2172 } | |
2173 | |
2174 | |
2175 void TranscendentalCacheStub::Generate(MacroAssembler* masm) { | 1200 void TranscendentalCacheStub::Generate(MacroAssembler* masm) { |
2176 // Untagged case: double input in d2, double result goes | 1201 // Untagged case: double input in d2, double result goes |
2177 // into d2. | 1202 // into d2. |
2178 // Tagged case: tagged input on top of stack and in r0, | 1203 // Tagged case: tagged input on top of stack and in r0, |
2179 // tagged result (heap number) goes into r0. | 1204 // tagged result (heap number) goes into r0. |
2180 | 1205 |
2181 Label input_not_smi; | 1206 Label input_not_smi; |
2182 Label loaded; | 1207 Label loaded; |
2183 Label calculate; | 1208 Label calculate; |
2184 Label invalid_cache; | 1209 Label invalid_cache; |
(...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2607 | 1632 |
2608 | 1633 |
2609 void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) { | 1634 void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) { |
2610 CEntryStub::GenerateAheadOfTime(isolate); | 1635 CEntryStub::GenerateAheadOfTime(isolate); |
2611 WriteInt32ToHeapNumberStub::GenerateFixedRegStubsAheadOfTime(isolate); | 1636 WriteInt32ToHeapNumberStub::GenerateFixedRegStubsAheadOfTime(isolate); |
2612 StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate); | 1637 StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate); |
2613 StubFailureTrampolineStub::GenerateAheadOfTime(isolate); | 1638 StubFailureTrampolineStub::GenerateAheadOfTime(isolate); |
2614 RecordWriteStub::GenerateFixedRegStubsAheadOfTime(isolate); | 1639 RecordWriteStub::GenerateFixedRegStubsAheadOfTime(isolate); |
2615 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate); | 1640 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate); |
2616 CreateAllocationSiteStub::GenerateAheadOfTime(isolate); | 1641 CreateAllocationSiteStub::GenerateAheadOfTime(isolate); |
| 1642 BinaryOpStub::GenerateAheadOfTime(isolate); |
2617 } | 1643 } |
2618 | 1644 |
2619 | 1645 |
2620 void CodeStub::GenerateFPStubs(Isolate* isolate) { | 1646 void CodeStub::GenerateFPStubs(Isolate* isolate) { |
2621 SaveFPRegsMode mode = kSaveFPRegs; | 1647 SaveFPRegsMode mode = kSaveFPRegs; |
2622 CEntryStub save_doubles(1, mode); | 1648 CEntryStub save_doubles(1, mode); |
2623 StoreBufferOverflowStub stub(mode); | 1649 StoreBufferOverflowStub stub(mode); |
2624 // These stubs might already be in the snapshot, detect that and don't | 1650 // These stubs might already be in the snapshot, detect that and don't |
2625 // regenerate, which would lead to code stub initialization state being messed | 1651 // regenerate, which would lead to code stub initialization state being messed |
2626 // up. | 1652 // up. |
(...skipping 4436 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7063 __ bind(&fast_elements_case); | 6089 __ bind(&fast_elements_case); |
7064 GenerateCase(masm, FAST_ELEMENTS); | 6090 GenerateCase(masm, FAST_ELEMENTS); |
7065 } | 6091 } |
7066 | 6092 |
7067 | 6093 |
7068 #undef __ | 6094 #undef __ |
7069 | 6095 |
7070 } } // namespace v8::internal | 6096 } } // namespace v8::internal |
7071 | 6097 |
7072 #endif // V8_TARGET_ARCH_ARM | 6098 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |