Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: src/mips/code-stubs-mips.cc

Issue 1304633002: Correctify instanceof and make it optimizable. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: REBASE. Add MIPS/MIPS64 ports. Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/interface-descriptors.cc ('k') | src/mips/interface-descriptors-mips.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 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_MIPS 5 #if V8_TARGET_ARCH_MIPS
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 1395 matching lines...) Expand 10 before | Expand all | Expand 10 after
1406 1406
1407 StubRuntimeCallHelper call_helper; 1407 StubRuntimeCallHelper call_helper;
1408 char_at_generator.GenerateSlow(masm, PART_OF_IC_HANDLER, call_helper); 1408 char_at_generator.GenerateSlow(masm, PART_OF_IC_HANDLER, call_helper);
1409 1409
1410 __ bind(&miss); 1410 __ bind(&miss);
1411 PropertyAccessCompiler::TailCallBuiltin( 1411 PropertyAccessCompiler::TailCallBuiltin(
1412 masm, PropertyAccessCompiler::MissBuiltin(Code::KEYED_LOAD_IC)); 1412 masm, PropertyAccessCompiler::MissBuiltin(Code::KEYED_LOAD_IC));
1413 } 1413 }
1414 1414
1415 1415
1416 // Uses registers a0 to t0. 1416 void InstanceOfStub::Generate(MacroAssembler* masm) {
1417 // Expected input (depending on whether args are in registers or on the stack): 1417 Register const object = a1; // Object (lhs).
1418 // * object: a0 or at sp + 1 * kPointerSize. 1418 Register const function = a0; // Function (rhs).
1419 // * function: a1 or at sp. 1419 Register const object_map = a2; // Map of {object}.
1420 // 1420 Register const function_map = a3; // Map of {function}.
1421 // An inlined call site may have been generated before calling this stub. 1421 Register const function_prototype = t0; // Prototype of {function}.
1422 // In this case the offset to the inline site to patch is passed on the stack, 1422 Register const scratch = t1;
1423 // in the safepoint slot for register t0.
1424 void InstanceofStub::Generate(MacroAssembler* masm) {
1425 // Call site inlining and patching implies arguments in registers.
1426 DCHECK(HasArgsInRegisters() || !HasCallSiteInlineCheck());
1427 1423
1428 // Fixed register usage throughout the stub: 1424 DCHECK(object.is(InstanceOfDescriptor::LeftRegister()));
1429 const Register object = a0; // Object (lhs). 1425 DCHECK(function.is(InstanceOfDescriptor::RightRegister()));
1430 Register map = a3; // Map of the object.
1431 const Register function = a1; // Function (rhs).
1432 const Register prototype = t0; // Prototype of the function.
1433 const Register inline_site = t5;
1434 const Register scratch = a2;
1435 1426
1436 const int32_t kDeltaToLoadBoolResult = 5 * kPointerSize; 1427 // Check if {object} is a smi.
1428 Label object_is_smi;
1429 __ JumpIfSmi(object, &object_is_smi);
1437 1430
1438 Label slow, loop, is_instance, is_not_instance, not_js_object; 1431 // Lookup the {function} and the {object} map in the global instanceof cache.
1432 // Note: This is safe because we clear the global instanceof cache whenever
1433 // we change the prototype of any object.
1434 Label fast_case, slow_case;
1435 __ lw(object_map, FieldMemOperand(object, HeapObject::kMapOffset));
1436 __ LoadRoot(at, Heap::kInstanceofCacheFunctionRootIndex);
1437 __ Branch(&fast_case, ne, function, Operand(at));
1438 __ LoadRoot(at, Heap::kInstanceofCacheMapRootIndex);
1439 __ Branch(&fast_case, ne, object_map, Operand(at));
1440 __ Ret(USE_DELAY_SLOT);
1441 __ LoadRoot(v0, Heap::kInstanceofCacheAnswerRootIndex); // In delay slot.
1439 1442
1440 if (!HasArgsInRegisters()) { 1443 // If {object} is a smi we can safely return false if {function} is a JS
1441 __ lw(object, MemOperand(sp, 1 * kPointerSize)); 1444 // function, otherwise we have to miss to the runtime and throw an exception.
1442 __ lw(function, MemOperand(sp, 0)); 1445 __ bind(&object_is_smi);
1443 } 1446 __ JumpIfSmi(function, &slow_case);
1447 __ GetObjectType(function, function_map, scratch);
1448 __ Branch(&slow_case, ne, scratch, Operand(JS_FUNCTION_TYPE));
1449 __ Ret(USE_DELAY_SLOT);
1450 __ LoadRoot(v0, Heap::kFalseValueRootIndex); // In delay slot.
1444 1451
1445 // Check that the left hand is a JS object and load map. 1452 // Fast-case: The {function} must be a valid JSFunction.
1446 __ JumpIfSmi(object, &not_js_object); 1453 __ bind(&fast_case);
1447 __ IsObjectJSObjectType(object, map, scratch, &not_js_object); 1454 __ JumpIfSmi(function, &slow_case);
1455 __ GetObjectType(function, function_map, scratch);
1456 __ Branch(&slow_case, ne, scratch, Operand(JS_FUNCTION_TYPE));
1448 1457
1449 // If there is a call site cache don't look in the global cache, but do the 1458 // Ensure that {function} has an instance prototype.
1450 // real lookup and update the call site cache. 1459 __ lbu(scratch, FieldMemOperand(function_map, Map::kBitFieldOffset));
1451 if (!HasCallSiteInlineCheck() && !ReturnTrueFalseObject()) { 1460 __ And(at, scratch, Operand(1 << Map::kHasNonInstancePrototype));
1452 Label miss; 1461 __ Branch(&slow_case, ne, at, Operand(zero_reg));
1453 __ LoadRoot(at, Heap::kInstanceofCacheFunctionRootIndex);
1454 __ Branch(&miss, ne, function, Operand(at));
1455 __ LoadRoot(at, Heap::kInstanceofCacheMapRootIndex);
1456 __ Branch(&miss, ne, map, Operand(at));
1457 __ LoadRoot(v0, Heap::kInstanceofCacheAnswerRootIndex);
1458 __ DropAndRet(HasArgsInRegisters() ? 0 : 2);
1459 1462
1460 __ bind(&miss); 1463 // Ensure that {function} is not bound.
1461 } 1464 Register const shared_info = scratch;
1465 __ lw(shared_info,
1466 FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
1467 __ lbu(scratch,
1468 FieldMemOperand(shared_info, SharedFunctionInfo::kBoundByteOffset));
1469 __ And(at, scratch, Operand(1 << SharedFunctionInfo::kBoundBitWithinByte));
1470 __ Branch(&slow_case, ne, at, Operand(zero_reg));
1462 1471
1463 // Get the prototype of the function. 1472 // Get the "prototype" (or initial map) of the {function}.
1464 __ TryGetFunctionPrototype(function, prototype, scratch, &slow, true); 1473 __ lw(function_prototype,
1474 FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
1475 __ AssertNotSmi(function_prototype);
1465 1476
1466 // Check that the function prototype is a JS object. 1477 // Resolve the prototype if the {function} has an initial map. Afterwards the
1467 __ JumpIfSmi(prototype, &slow); 1478 // {function_prototype} will be either the JSReceiver prototype object or the
1468 __ IsObjectJSObjectType(prototype, scratch, scratch, &slow); 1479 // hole value, which means that no instances of the {function} were created so
1480 // far and hence we should return false.
1481 Label function_prototype_valid;
1482 __ GetObjectType(function_prototype, scratch, scratch);
1483 __ Branch(&function_prototype_valid, ne, scratch, Operand(MAP_TYPE));
1484 __ lw(function_prototype,
1485 FieldMemOperand(function_prototype, Map::kPrototypeOffset));
1486 __ bind(&function_prototype_valid);
1487 __ AssertNotSmi(function_prototype);
1469 1488
1470 // Update the global instanceof or call site inlined cache with the current 1489 // Update the global instanceof cache with the current {object} map and
1471 // map and function. The cached answer will be set when it is known below. 1490 // {function}. The cached answer will be set when it is known below.
1472 if (!HasCallSiteInlineCheck()) { 1491 __ StoreRoot(function, Heap::kInstanceofCacheFunctionRootIndex);
1473 __ StoreRoot(function, Heap::kInstanceofCacheFunctionRootIndex); 1492 __ StoreRoot(object_map, Heap::kInstanceofCacheMapRootIndex);
1474 __ StoreRoot(map, Heap::kInstanceofCacheMapRootIndex);
1475 } else {
1476 DCHECK(HasArgsInRegisters());
1477 // Patch the (relocated) inlined map check.
1478 1493
1479 // The offset was stored in t0 safepoint slot. 1494 // Loop through the prototype chain looking for the {function} prototype.
1480 // (See LCodeGen::DoDeferredLInstanceOfKnownGlobal). 1495 // Assume true, and change to false if not found.
1481 __ LoadFromSafepointRegisterSlot(scratch, t0); 1496 Register const object_prototype = object_map;
1482 __ Subu(inline_site, ra, scratch); 1497 Register const null = scratch;
1483 // Get the map location in scratch and patch it. 1498 Label done, loop;
1484 __ GetRelocatedValue(inline_site, scratch, v1); // v1 used as scratch. 1499 __ LoadRoot(v0, Heap::kTrueValueRootIndex);
1485 __ sw(map, FieldMemOperand(scratch, Cell::kValueOffset)); 1500 __ LoadRoot(null, Heap::kNullValueRootIndex);
1501 __ bind(&loop);
1502 __ lw(object_prototype, FieldMemOperand(object_map, Map::kPrototypeOffset));
1503 __ Branch(&done, eq, object_prototype, Operand(function_prototype));
1504 __ Branch(USE_DELAY_SLOT, &loop, ne, object_prototype, Operand(null));
1505 __ lw(object_map, FieldMemOperand(object_prototype, HeapObject::kMapOffset));
1506 __ LoadRoot(v0, Heap::kFalseValueRootIndex);
1507 __ bind(&done);
1508 __ Ret(USE_DELAY_SLOT);
1509 __ StoreRoot(v0, Heap::kInstanceofCacheAnswerRootIndex); // In delay slot.
1486 1510
1487 __ mov(t4, map); 1511 // Slow-case: Call the runtime function.
1488 // |scratch| points at the beginning of the cell. Calculate the field 1512 __ bind(&slow_case);
1489 // containing the map. 1513 __ Push(object, function);
1490 __ Addu(function, scratch, Operand(Cell::kValueOffset - 1)); 1514 __ TailCallRuntime(Runtime::kInstanceOf, 2, 1);
1491 __ RecordWriteField(scratch, Cell::kValueOffset, t4, function,
1492 kRAHasNotBeenSaved, kDontSaveFPRegs,
1493 OMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
1494 }
1495
1496 // Register mapping: a3 is object map and t0 is function prototype.
1497 // Get prototype of object into a2.
1498 __ lw(scratch, FieldMemOperand(map, Map::kPrototypeOffset));
1499
1500 // We don't need map any more. Use it as a scratch register.
1501 Register scratch2 = map;
1502 map = no_reg;
1503
1504 // Loop through the prototype chain looking for the function prototype.
1505 __ LoadRoot(scratch2, Heap::kNullValueRootIndex);
1506 __ bind(&loop);
1507 __ Branch(&is_instance, eq, scratch, Operand(prototype));
1508 __ Branch(&is_not_instance, eq, scratch, Operand(scratch2));
1509 __ lw(scratch, FieldMemOperand(scratch, HeapObject::kMapOffset));
1510 __ lw(scratch, FieldMemOperand(scratch, Map::kPrototypeOffset));
1511 __ Branch(&loop);
1512
1513 __ bind(&is_instance);
1514 DCHECK_EQ(static_cast<Smi*>(0), Smi::FromInt(0));
1515 if (!HasCallSiteInlineCheck()) {
1516 __ mov(v0, zero_reg);
1517 __ StoreRoot(v0, Heap::kInstanceofCacheAnswerRootIndex);
1518 if (ReturnTrueFalseObject()) {
1519 __ LoadRoot(v0, Heap::kTrueValueRootIndex);
1520 }
1521 } else {
1522 // Patch the call site to return true.
1523 __ LoadRoot(v0, Heap::kTrueValueRootIndex);
1524 __ Addu(inline_site, inline_site, Operand(kDeltaToLoadBoolResult));
1525 // Get the boolean result location in scratch and patch it.
1526 __ PatchRelocatedValue(inline_site, scratch, v0);
1527
1528 if (!ReturnTrueFalseObject()) {
1529 __ mov(v0, zero_reg);
1530 }
1531 }
1532 __ DropAndRet(HasArgsInRegisters() ? 0 : 2);
1533
1534 __ bind(&is_not_instance);
1535 if (!HasCallSiteInlineCheck()) {
1536 __ li(v0, Operand(Smi::FromInt(1)));
1537 __ StoreRoot(v0, Heap::kInstanceofCacheAnswerRootIndex);
1538 if (ReturnTrueFalseObject()) {
1539 __ LoadRoot(v0, Heap::kFalseValueRootIndex);
1540 }
1541 } else {
1542 // Patch the call site to return false.
1543 __ LoadRoot(v0, Heap::kFalseValueRootIndex);
1544 __ Addu(inline_site, inline_site, Operand(kDeltaToLoadBoolResult));
1545 // Get the boolean result location in scratch and patch it.
1546 __ PatchRelocatedValue(inline_site, scratch, v0);
1547
1548 if (!ReturnTrueFalseObject()) {
1549 __ li(v0, Operand(Smi::FromInt(1)));
1550 }
1551 }
1552
1553 __ DropAndRet(HasArgsInRegisters() ? 0 : 2);
1554
1555 Label object_not_null, object_not_null_or_smi;
1556 __ bind(&not_js_object);
1557 // Before null, smi and string value checks, check that the rhs is a function
1558 // as for a non-function rhs an exception needs to be thrown.
1559 __ JumpIfSmi(function, &slow);
1560 __ GetObjectType(function, scratch2, scratch);
1561 __ Branch(&slow, ne, scratch, Operand(JS_FUNCTION_TYPE));
1562
1563 // Null is not instance of anything.
1564 __ Branch(&object_not_null, ne, object,
1565 Operand(isolate()->factory()->null_value()));
1566 if (ReturnTrueFalseObject()) {
1567 __ LoadRoot(v0, Heap::kFalseValueRootIndex);
1568 } else {
1569 __ li(v0, Operand(Smi::FromInt(1)));
1570 }
1571 __ DropAndRet(HasArgsInRegisters() ? 0 : 2);
1572
1573 __ bind(&object_not_null);
1574 // Smi values are not instances of anything.
1575 __ JumpIfNotSmi(object, &object_not_null_or_smi);
1576 if (ReturnTrueFalseObject()) {
1577 __ LoadRoot(v0, Heap::kFalseValueRootIndex);
1578 } else {
1579 __ li(v0, Operand(Smi::FromInt(1)));
1580 }
1581 __ DropAndRet(HasArgsInRegisters() ? 0 : 2);
1582
1583 __ bind(&object_not_null_or_smi);
1584 // String values are not instances of anything.
1585 __ IsObjectJSStringType(object, scratch, &slow);
1586 if (ReturnTrueFalseObject()) {
1587 __ LoadRoot(v0, Heap::kFalseValueRootIndex);
1588 } else {
1589 __ li(v0, Operand(Smi::FromInt(1)));
1590 }
1591 __ DropAndRet(HasArgsInRegisters() ? 0 : 2);
1592
1593 // Slow-case. Tail call builtin.
1594 __ bind(&slow);
1595 if (!ReturnTrueFalseObject()) {
1596 if (HasArgsInRegisters()) {
1597 __ Push(a0, a1);
1598 }
1599 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
1600 } else {
1601 {
1602 FrameScope scope(masm, StackFrame::INTERNAL);
1603 __ Push(a0, a1);
1604 __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_FUNCTION);
1605 }
1606 __ mov(a0, v0);
1607 __ LoadRoot(v0, Heap::kTrueValueRootIndex);
1608 __ DropAndRet(HasArgsInRegisters() ? 0 : 2, eq, a0, Operand(zero_reg));
1609 __ LoadRoot(v0, Heap::kFalseValueRootIndex);
1610 __ DropAndRet(HasArgsInRegisters() ? 0 : 2);
1611 }
1612 } 1515 }
1613 1516
1614 1517
1615 void FunctionPrototypeStub::Generate(MacroAssembler* masm) { 1518 void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
1616 Label miss; 1519 Label miss;
1617 Register receiver = LoadDescriptor::ReceiverRegister(); 1520 Register receiver = LoadDescriptor::ReceiverRegister();
1618 // Ensure that the vector and slot registers won't be clobbered before 1521 // Ensure that the vector and slot registers won't be clobbered before
1619 // calling the miss handler. 1522 // calling the miss handler.
1620 DCHECK(!AreAliased(t0, t1, LoadWithVectorDescriptor::VectorRegister(), 1523 DCHECK(!AreAliased(t0, t1, LoadWithVectorDescriptor::VectorRegister(),
1621 LoadWithVectorDescriptor::SlotRegister())); 1524 LoadWithVectorDescriptor::SlotRegister()));
(...skipping 4100 matching lines...) Expand 10 before | Expand all | Expand 10 after
5722 MemOperand(fp, 6 * kPointerSize), NULL); 5625 MemOperand(fp, 6 * kPointerSize), NULL);
5723 } 5626 }
5724 5627
5725 5628
5726 #undef __ 5629 #undef __
5727 5630
5728 } // namespace internal 5631 } // namespace internal
5729 } // namespace v8 5632 } // namespace v8
5730 5633
5731 #endif // V8_TARGET_ARCH_MIPS 5634 #endif // V8_TARGET_ARCH_MIPS
OLDNEW
« no previous file with comments | « src/interface-descriptors.cc ('k') | src/mips/interface-descriptors-mips.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698