| OLD | NEW |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #if V8_TARGET_ARCH_PPC | 5 #if V8_TARGET_ARCH_PPC |
| 6 | 6 |
| 7 #include "src/base/bits.h" | 7 #include "src/base/bits.h" |
| 8 #include "src/bootstrapper.h" | 8 #include "src/bootstrapper.h" |
| 9 #include "src/code-stubs.h" | 9 #include "src/code-stubs.h" |
| 10 #include "src/codegen.h" | 10 #include "src/codegen.h" |
| (...skipping 1349 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1360 // Restore callee-saved registers. | 1360 // Restore callee-saved registers. |
| 1361 __ MultiPop(kCalleeSaved); | 1361 __ MultiPop(kCalleeSaved); |
| 1362 | 1362 |
| 1363 // Return | 1363 // Return |
| 1364 __ LoadP(r0, MemOperand(sp, kStackFrameLRSlot * kPointerSize)); | 1364 __ LoadP(r0, MemOperand(sp, kStackFrameLRSlot * kPointerSize)); |
| 1365 __ mtlr(r0); | 1365 __ mtlr(r0); |
| 1366 __ blr(); | 1366 __ blr(); |
| 1367 } | 1367 } |
| 1368 | 1368 |
| 1369 | 1369 |
| 1370 // Uses registers r3 to r7. | 1370 void InstanceOfStub::Generate(MacroAssembler* masm) { |
| 1371 // Expected input (depending on whether args are in registers or on the stack): | 1371 Register const object = r4; // Object (lhs). |
| 1372 // * object: r3 or at sp + 1 * kPointerSize. | 1372 Register const function = r3; // Function (rhs). |
| 1373 // * function: r4 or at sp. | 1373 Register const object_map = r5; // Map of {object}. |
| 1374 // | 1374 Register const function_map = r6; // Map of {function}. |
| 1375 // An inlined call site may have been generated before calling this stub. | 1375 Register const function_prototype = r7; // Prototype of {function}. |
| 1376 // In this case the offset to the inline site to patch is passed in r8. | 1376 Register const scratch = r8; |
| 1377 // (See LCodeGen::DoInstanceOfKnownGlobal) | |
| 1378 void InstanceofStub::Generate(MacroAssembler* masm) { | |
| 1379 // Call site inlining and patching implies arguments in registers. | |
| 1380 DCHECK(HasArgsInRegisters() || !HasCallSiteInlineCheck()); | |
| 1381 | 1377 |
| 1382 // Fixed register usage throughout the stub: | 1378 DCHECK(object.is(InstanceOfDescriptor::LeftRegister())); |
| 1383 const Register object = r3; // Object (lhs). | 1379 DCHECK(function.is(InstanceOfDescriptor::RightRegister())); |
| 1384 Register map = r6; // Map of the object. | |
| 1385 const Register function = r4; // Function (rhs). | |
| 1386 const Register prototype = r7; // Prototype of the function. | |
| 1387 // The map_check_delta was stored in r8 | |
| 1388 // The bool_load_delta was stored in r9 | |
| 1389 // (See LCodeGen::DoDeferredLInstanceOfKnownGlobal). | |
| 1390 const Register map_check_delta = r8; | |
| 1391 const Register bool_load_delta = r9; | |
| 1392 const Register inline_site = r10; | |
| 1393 const Register scratch = r5; | |
| 1394 Register scratch3 = no_reg; | |
| 1395 Label slow, loop, is_instance, is_not_instance, not_js_object; | |
| 1396 | 1380 |
| 1397 if (!HasArgsInRegisters()) { | 1381 // Check if {object} is a smi. |
| 1398 __ LoadP(object, MemOperand(sp, 1 * kPointerSize)); | 1382 Label object_is_smi; |
| 1399 __ LoadP(function, MemOperand(sp, 0)); | 1383 __ JumpIfSmi(object, &object_is_smi); |
| 1400 } | |
| 1401 | 1384 |
| 1402 // Check that the left hand is a JS object and load map. | 1385 // Lookup the {function} and the {object} map in the global instanceof cache. |
| 1403 __ JumpIfSmi(object, ¬_js_object); | 1386 // Note: This is safe because we clear the global instanceof cache whenever |
| 1404 __ IsObjectJSObjectType(object, map, scratch, ¬_js_object); | 1387 // we change the prototype of any object. |
| 1388 Label fast_case, slow_case; |
| 1389 __ LoadP(object_map, FieldMemOperand(object, HeapObject::kMapOffset)); |
| 1390 __ CompareRoot(function, Heap::kInstanceofCacheFunctionRootIndex); |
| 1391 __ bne(&fast_case); |
| 1392 __ CompareRoot(object_map, Heap::kInstanceofCacheMapRootIndex); |
| 1393 __ bne(&fast_case); |
| 1394 __ LoadRoot(r3, Heap::kInstanceofCacheAnswerRootIndex); |
| 1395 __ Ret(); |
| 1405 | 1396 |
| 1406 // If there is a call site cache don't look in the global cache, but do the | 1397 // If {object} is a smi we can safely return false if {function} is a JS |
| 1407 // real lookup and update the call site cache. | 1398 // function, otherwise we have to miss to the runtime and throw an exception. |
| 1408 if (!HasCallSiteInlineCheck() && !ReturnTrueFalseObject()) { | 1399 __ bind(&object_is_smi); |
| 1409 Label miss; | 1400 __ JumpIfSmi(function, &slow_case); |
| 1410 __ CompareRoot(function, Heap::kInstanceofCacheFunctionRootIndex); | 1401 __ CompareObjectType(function, function_map, scratch, JS_FUNCTION_TYPE); |
| 1411 __ bne(&miss); | 1402 __ bne(&slow_case); |
| 1412 __ CompareRoot(map, Heap::kInstanceofCacheMapRootIndex); | 1403 __ LoadRoot(r3, Heap::kFalseValueRootIndex); |
| 1413 __ bne(&miss); | 1404 __ Ret(); |
| 1414 __ LoadRoot(r3, Heap::kInstanceofCacheAnswerRootIndex); | |
| 1415 __ Ret(HasArgsInRegisters() ? 0 : 2); | |
| 1416 | 1405 |
| 1417 __ bind(&miss); | 1406 // Fast-case: The {function} must be a valid JSFunction. |
| 1418 } | 1407 __ bind(&fast_case); |
| 1408 __ JumpIfSmi(function, &slow_case); |
| 1409 __ CompareObjectType(function, function_map, scratch, JS_FUNCTION_TYPE); |
| 1410 __ bne(&slow_case); |
| 1419 | 1411 |
| 1420 // Get the prototype of the function. | 1412 // Ensure that {function} has an instance prototype. |
| 1421 __ TryGetFunctionPrototype(function, prototype, scratch, &slow, true); | 1413 __ lbz(scratch, FieldMemOperand(function_map, Map::kBitFieldOffset)); |
| 1414 __ TestBit(scratch, Map::HasNonInstancePrototype, r0); |
| 1415 __ bne(&slow_case, cr0); |
| 1422 | 1416 |
| 1423 // Check that the function prototype is a JS object. | 1417 // Ensure that {function} is not bound. |
| 1424 __ JumpIfSmi(prototype, &slow); | 1418 Register const shared_info = scratch; |
| 1425 __ IsObjectJSObjectType(prototype, scratch, scratch, &slow); | 1419 __ LoadP(shared_info, |
| 1420 FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset)); |
| 1421 __ lwz(scratch, FieldMemOperand(shared_info, |
| 1422 SharedFunctionInfo::kCompilerHintsOffset)); |
| 1423 __ TestBit(scratch, |
| 1424 #if V8_TARGET_ARCH_PPC64 |
| 1425 SharedFunctionInfo::kBoundFunction, |
| 1426 #else |
| 1427 SharedFunctionInfo::kBoundFunction + kSmiTagSize, |
| 1428 #endif |
| 1429 r0); |
| 1430 __ bne(&slow_case, cr0); |
| 1426 | 1431 |
| 1427 // Update the global instanceof or call site inlined cache with the current | 1432 // Get the "prototype" (or initial map) of the {function}. |
| 1428 // map and function. The cached answer will be set when it is known below. | 1433 __ LoadP(function_prototype, |
| 1429 if (!HasCallSiteInlineCheck()) { | 1434 FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); |
| 1430 __ StoreRoot(function, Heap::kInstanceofCacheFunctionRootIndex); | 1435 __ AssertNotSmi(function_prototype); |
| 1431 __ StoreRoot(map, Heap::kInstanceofCacheMapRootIndex); | |
| 1432 } else { | |
| 1433 DCHECK(HasArgsInRegisters()); | |
| 1434 // Patch the (relocated) inlined map check. | |
| 1435 | 1436 |
| 1436 const Register offset = map_check_delta; | 1437 // Resolve the prototype if the {function} has an initial map. Afterwards the |
| 1437 __ mflr(inline_site); | 1438 // {function_prototype} will be either the JSReceiver prototype object or the |
| 1438 __ sub(inline_site, inline_site, offset); | 1439 // hole value, which means that no instances of the {function} were created so |
| 1439 // Get the map location in offset and patch it. | 1440 // far and hence we should return false. |
| 1440 __ GetRelocatedValue(inline_site, offset, scratch); | 1441 Label function_prototype_valid; |
| 1441 __ StoreP(map, FieldMemOperand(offset, Cell::kValueOffset), r0); | 1442 __ CompareObjectType(function_prototype, scratch, scratch, MAP_TYPE); |
| 1443 __ bne(&function_prototype_valid); |
| 1444 __ LoadP(function_prototype, |
| 1445 FieldMemOperand(function_prototype, Map::kPrototypeOffset)); |
| 1446 __ bind(&function_prototype_valid); |
| 1447 __ AssertNotSmi(function_prototype); |
| 1442 | 1448 |
| 1443 __ mr(r11, map); | 1449 // Update the global instanceof cache with the current {object} map and |
| 1444 __ RecordWriteField(offset, Cell::kValueOffset, r11, function, | 1450 // {function}. The cached answer will be set when it is known below. |
| 1445 kLRHasNotBeenSaved, kDontSaveFPRegs, | 1451 __ StoreRoot(function, Heap::kInstanceofCacheFunctionRootIndex); |
| 1446 OMIT_REMEMBERED_SET, OMIT_SMI_CHECK); | 1452 __ StoreRoot(object_map, Heap::kInstanceofCacheMapRootIndex); |
| 1447 } | |
| 1448 | 1453 |
| 1449 // Register mapping: r6 is object map and r7 is function prototype. | 1454 // Loop through the prototype chain looking for the {function} prototype. |
| 1450 // Get prototype of object into r5. | 1455 // Assume true, and change to false if not found. |
| 1451 __ LoadP(scratch, FieldMemOperand(map, Map::kPrototypeOffset)); | 1456 Register const object_prototype = object_map; |
| 1457 Register const null = scratch; |
| 1458 Label done, loop; |
| 1459 __ LoadRoot(r3, Heap::kTrueValueRootIndex); |
| 1460 __ LoadRoot(null, Heap::kNullValueRootIndex); |
| 1461 __ bind(&loop); |
| 1462 __ LoadP(object_prototype, |
| 1463 FieldMemOperand(object_map, Map::kPrototypeOffset)); |
| 1464 __ cmp(object_prototype, function_prototype); |
| 1465 __ beq(&done); |
| 1466 __ cmp(object_prototype, null); |
| 1467 __ LoadP(object_map, |
| 1468 FieldMemOperand(object_prototype, HeapObject::kMapOffset)); |
| 1469 __ bne(&loop); |
| 1470 __ LoadRoot(r3, Heap::kFalseValueRootIndex); |
| 1471 __ bind(&done); |
| 1472 __ StoreRoot(r3, Heap::kInstanceofCacheAnswerRootIndex); |
| 1473 __ Ret(); |
| 1452 | 1474 |
| 1453 // We don't need map any more. Use it as a scratch register. | 1475 // Slow-case: Call the runtime function. |
| 1454 scratch3 = map; | 1476 __ bind(&slow_case); |
| 1455 map = no_reg; | 1477 __ Push(object, function); |
| 1456 | 1478 __ TailCallRuntime(Runtime::kInstanceOf, 2, 1); |
| 1457 // Loop through the prototype chain looking for the function prototype. | |
| 1458 __ LoadRoot(scratch3, Heap::kNullValueRootIndex); | |
| 1459 __ bind(&loop); | |
| 1460 __ cmp(scratch, prototype); | |
| 1461 __ beq(&is_instance); | |
| 1462 __ cmp(scratch, scratch3); | |
| 1463 __ beq(&is_not_instance); | |
| 1464 __ LoadP(scratch, FieldMemOperand(scratch, HeapObject::kMapOffset)); | |
| 1465 __ LoadP(scratch, FieldMemOperand(scratch, Map::kPrototypeOffset)); | |
| 1466 __ b(&loop); | |
| 1467 Factory* factory = isolate()->factory(); | |
| 1468 | |
| 1469 __ bind(&is_instance); | |
| 1470 if (!HasCallSiteInlineCheck()) { | |
| 1471 __ LoadSmiLiteral(r3, Smi::FromInt(0)); | |
| 1472 __ StoreRoot(r3, Heap::kInstanceofCacheAnswerRootIndex); | |
| 1473 if (ReturnTrueFalseObject()) { | |
| 1474 __ Move(r3, factory->true_value()); | |
| 1475 } | |
| 1476 } else { | |
| 1477 // Patch the call site to return true. | |
| 1478 __ LoadRoot(r3, Heap::kTrueValueRootIndex); | |
| 1479 __ add(inline_site, inline_site, bool_load_delta); | |
| 1480 // Get the boolean result location in scratch and patch it. | |
| 1481 __ SetRelocatedValue(inline_site, scratch, r3); | |
| 1482 | |
| 1483 if (!ReturnTrueFalseObject()) { | |
| 1484 __ LoadSmiLiteral(r3, Smi::FromInt(0)); | |
| 1485 } | |
| 1486 } | |
| 1487 __ Ret(HasArgsInRegisters() ? 0 : 2); | |
| 1488 | |
| 1489 __ bind(&is_not_instance); | |
| 1490 if (!HasCallSiteInlineCheck()) { | |
| 1491 __ LoadSmiLiteral(r3, Smi::FromInt(1)); | |
| 1492 __ StoreRoot(r3, Heap::kInstanceofCacheAnswerRootIndex); | |
| 1493 if (ReturnTrueFalseObject()) { | |
| 1494 __ Move(r3, factory->false_value()); | |
| 1495 } | |
| 1496 } else { | |
| 1497 // Patch the call site to return false. | |
| 1498 __ LoadRoot(r3, Heap::kFalseValueRootIndex); | |
| 1499 __ add(inline_site, inline_site, bool_load_delta); | |
| 1500 // Get the boolean result location in scratch and patch it. | |
| 1501 __ SetRelocatedValue(inline_site, scratch, r3); | |
| 1502 | |
| 1503 if (!ReturnTrueFalseObject()) { | |
| 1504 __ LoadSmiLiteral(r3, Smi::FromInt(1)); | |
| 1505 } | |
| 1506 } | |
| 1507 __ Ret(HasArgsInRegisters() ? 0 : 2); | |
| 1508 | |
| 1509 Label object_not_null, object_not_null_or_smi; | |
| 1510 __ bind(¬_js_object); | |
| 1511 // Before null, smi and string value checks, check that the rhs is a function | |
| 1512 // as for a non-function rhs an exception needs to be thrown. | |
| 1513 __ JumpIfSmi(function, &slow); | |
| 1514 __ CompareObjectType(function, scratch3, scratch, JS_FUNCTION_TYPE); | |
| 1515 __ bne(&slow); | |
| 1516 | |
| 1517 // Null is not instance of anything. | |
| 1518 __ Cmpi(object, Operand(isolate()->factory()->null_value()), r0); | |
| 1519 __ bne(&object_not_null); | |
| 1520 if (ReturnTrueFalseObject()) { | |
| 1521 __ Move(r3, factory->false_value()); | |
| 1522 } else { | |
| 1523 __ LoadSmiLiteral(r3, Smi::FromInt(1)); | |
| 1524 } | |
| 1525 __ Ret(HasArgsInRegisters() ? 0 : 2); | |
| 1526 | |
| 1527 __ bind(&object_not_null); | |
| 1528 // Smi values are not instances of anything. | |
| 1529 __ JumpIfNotSmi(object, &object_not_null_or_smi); | |
| 1530 if (ReturnTrueFalseObject()) { | |
| 1531 __ Move(r3, factory->false_value()); | |
| 1532 } else { | |
| 1533 __ LoadSmiLiteral(r3, Smi::FromInt(1)); | |
| 1534 } | |
| 1535 __ Ret(HasArgsInRegisters() ? 0 : 2); | |
| 1536 | |
| 1537 __ bind(&object_not_null_or_smi); | |
| 1538 // String values are not instances of anything. | |
| 1539 __ IsObjectJSStringType(object, scratch, &slow); | |
| 1540 if (ReturnTrueFalseObject()) { | |
| 1541 __ Move(r3, factory->false_value()); | |
| 1542 } else { | |
| 1543 __ LoadSmiLiteral(r3, Smi::FromInt(1)); | |
| 1544 } | |
| 1545 __ Ret(HasArgsInRegisters() ? 0 : 2); | |
| 1546 | |
| 1547 // Slow-case. Tail call builtin. | |
| 1548 __ bind(&slow); | |
| 1549 if (!ReturnTrueFalseObject()) { | |
| 1550 if (HasArgsInRegisters()) { | |
| 1551 __ Push(r3, r4); | |
| 1552 } | |
| 1553 __ InvokeBuiltin(Context::INSTANCE_OF_BUILTIN_INDEX, JUMP_FUNCTION); | |
| 1554 } else { | |
| 1555 { | |
| 1556 FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); | |
| 1557 __ Push(r3, r4); | |
| 1558 __ InvokeBuiltin(Context::INSTANCE_OF_BUILTIN_INDEX, CALL_FUNCTION); | |
| 1559 } | |
| 1560 if (CpuFeatures::IsSupported(ISELECT)) { | |
| 1561 __ cmpi(r3, Operand::Zero()); | |
| 1562 __ LoadRoot(r3, Heap::kTrueValueRootIndex); | |
| 1563 __ LoadRoot(r4, Heap::kFalseValueRootIndex); | |
| 1564 __ isel(eq, r3, r3, r4); | |
| 1565 } else { | |
| 1566 Label true_value, done; | |
| 1567 __ cmpi(r3, Operand::Zero()); | |
| 1568 __ beq(&true_value); | |
| 1569 | |
| 1570 __ LoadRoot(r3, Heap::kFalseValueRootIndex); | |
| 1571 __ b(&done); | |
| 1572 | |
| 1573 __ bind(&true_value); | |
| 1574 __ LoadRoot(r3, Heap::kTrueValueRootIndex); | |
| 1575 | |
| 1576 __ bind(&done); | |
| 1577 } | |
| 1578 __ Ret(HasArgsInRegisters() ? 0 : 2); | |
| 1579 } | |
| 1580 } | 1479 } |
| 1581 | 1480 |
| 1582 | 1481 |
| 1583 void FunctionPrototypeStub::Generate(MacroAssembler* masm) { | 1482 void FunctionPrototypeStub::Generate(MacroAssembler* masm) { |
| 1584 Label miss; | 1483 Label miss; |
| 1585 Register receiver = LoadDescriptor::ReceiverRegister(); | 1484 Register receiver = LoadDescriptor::ReceiverRegister(); |
| 1586 // Ensure that the vector and slot registers won't be clobbered before | 1485 // Ensure that the vector and slot registers won't be clobbered before |
| 1587 // calling the miss handler. | 1486 // calling the miss handler. |
| 1588 DCHECK(!AreAliased(r7, r8, LoadWithVectorDescriptor::VectorRegister(), | 1487 DCHECK(!AreAliased(r7, r8, LoadWithVectorDescriptor::VectorRegister(), |
| 1589 LoadWithVectorDescriptor::SlotRegister())); | 1488 LoadWithVectorDescriptor::SlotRegister())); |
| (...skipping 4238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5828 kStackUnwindSpace, NULL, | 5727 kStackUnwindSpace, NULL, |
| 5829 MemOperand(fp, 6 * kPointerSize), NULL); | 5728 MemOperand(fp, 6 * kPointerSize), NULL); |
| 5830 } | 5729 } |
| 5831 | 5730 |
| 5832 | 5731 |
| 5833 #undef __ | 5732 #undef __ |
| 5834 } // namespace internal | 5733 } // namespace internal |
| 5835 } // namespace v8 | 5734 } // namespace v8 |
| 5836 | 5735 |
| 5837 #endif // V8_TARGET_ARCH_PPC | 5736 #endif // V8_TARGET_ARCH_PPC |
| OLD | NEW |