| 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 | 
|---|