OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
181 | 181 |
182 // Deferred code is the last part of the instruction sequence. Mark | 182 // Deferred code is the last part of the instruction sequence. Mark |
183 // the generated code as done unless we bailed out. | 183 // the generated code as done unless we bailed out. |
184 if (!is_aborted()) status_ = DONE; | 184 if (!is_aborted()) status_ = DONE; |
185 return !is_aborted(); | 185 return !is_aborted(); |
186 } | 186 } |
187 | 187 |
188 | 188 |
189 bool LCodeGen::GenerateSafepointTable() { | 189 bool LCodeGen::GenerateSafepointTable() { |
190 ASSERT(is_done()); | 190 ASSERT(is_done()); |
191 // Ensure that patching a deoptimization point won't overwrite the table. | 191 // Ensure that there is space at the end of the code to write a number |
192 for (int i = 0; i < Assembler::kCallInstructionLength; i++) { | 192 // of jump instructions, as well as to afford writing a call near the end |
193 masm()->int3(); | 193 // of the code. |
| 194 // The jumps are used when there isn't room in the code stream to write |
| 195 // a long call instruction. Instead it writes a shorter call to a |
| 196 // jump instruction in the same code object. |
| 197 // The calls are used when lazy deoptimizing a function and calls to a |
| 198 // deoptimization function. |
| 199 int short_deopts = safepoints_.CountShortDeoptimizationIntervals( |
| 200 static_cast<unsigned>(MacroAssembler::kJumpInstructionLength)); |
| 201 int byte_count = (short_deopts) * MacroAssembler::kJumpInstructionLength; |
| 202 while (byte_count-- > 0) { |
| 203 __ int3(); |
194 } | 204 } |
195 safepoints_.Emit(masm(), StackSlotCount()); | 205 safepoints_.Emit(masm(), StackSlotCount()); |
196 return !is_aborted(); | 206 return !is_aborted(); |
197 } | 207 } |
198 | 208 |
199 | 209 |
200 Register LCodeGen::ToRegister(int index) const { | 210 Register LCodeGen::ToRegister(int index) const { |
201 return Register::FromAllocationIndex(index); | 211 return Register::FromAllocationIndex(index); |
202 } | 212 } |
203 | 213 |
(...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
492 inlined_function_count_ = deoptimization_literals_.length(); | 502 inlined_function_count_ = deoptimization_literals_.length(); |
493 } | 503 } |
494 | 504 |
495 | 505 |
496 void LCodeGen::RecordSafepoint( | 506 void LCodeGen::RecordSafepoint( |
497 LPointerMap* pointers, | 507 LPointerMap* pointers, |
498 Safepoint::Kind kind, | 508 Safepoint::Kind kind, |
499 int arguments, | 509 int arguments, |
500 int deoptimization_index) { | 510 int deoptimization_index) { |
501 const ZoneList<LOperand*>* operands = pointers->operands(); | 511 const ZoneList<LOperand*>* operands = pointers->operands(); |
| 512 |
502 Safepoint safepoint = safepoints_.DefineSafepoint(masm(), | 513 Safepoint safepoint = safepoints_.DefineSafepoint(masm(), |
503 kind, arguments, deoptimization_index); | 514 kind, arguments, deoptimization_index); |
504 for (int i = 0; i < operands->length(); i++) { | 515 for (int i = 0; i < operands->length(); i++) { |
505 LOperand* pointer = operands->at(i); | 516 LOperand* pointer = operands->at(i); |
506 if (pointer->IsStackSlot()) { | 517 if (pointer->IsStackSlot()) { |
507 safepoint.DefinePointerSlot(pointer->index()); | 518 safepoint.DefinePointerSlot(pointer->index()); |
508 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) { | 519 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) { |
509 safepoint.DefinePointerRegister(ToRegister(pointer)); | 520 safepoint.DefinePointerRegister(ToRegister(pointer)); |
510 } | 521 } |
511 } | 522 } |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
656 } | 667 } |
657 | 668 |
658 | 669 |
659 void LCodeGen::DoConstantT(LConstantT* instr) { | 670 void LCodeGen::DoConstantT(LConstantT* instr) { |
660 ASSERT(instr->result()->IsRegister()); | 671 ASSERT(instr->result()->IsRegister()); |
661 __ Move(ToRegister(instr->result()), instr->value()); | 672 __ Move(ToRegister(instr->result()), instr->value()); |
662 } | 673 } |
663 | 674 |
664 | 675 |
665 void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) { | 676 void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) { |
666 Abort("Unimplemented: %s", "DoJSArrayLength"); | 677 Register result = ToRegister(instr->result()); |
| 678 Register array = ToRegister(instr->InputAt(0)); |
| 679 __ movq(result, FieldOperand(array, JSArray::kLengthOffset)); |
667 } | 680 } |
668 | 681 |
669 | 682 |
670 void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) { | 683 void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) { |
671 Abort("Unimplemented: %s", "DoFixedArrayLength"); | 684 Abort("Unimplemented: %s", "DoFixedArrayLength"); |
672 } | 685 } |
673 | 686 |
674 | 687 |
675 void LCodeGen::DoValueOf(LValueOf* instr) { | 688 void LCodeGen::DoValueOf(LValueOf* instr) { |
676 Abort("Unimplemented: %s", "DoValueOf"); | 689 Abort("Unimplemented: %s", "DoValueOf"); |
(...skipping 705 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1382 __ push(rax); | 1395 __ push(rax); |
1383 __ CallRuntime(Runtime::kTraceExit, 1); | 1396 __ CallRuntime(Runtime::kTraceExit, 1); |
1384 } | 1397 } |
1385 __ movq(rsp, rbp); | 1398 __ movq(rsp, rbp); |
1386 __ pop(rbp); | 1399 __ pop(rbp); |
1387 __ ret((ParameterCount() + 1) * kPointerSize); | 1400 __ ret((ParameterCount() + 1) * kPointerSize); |
1388 } | 1401 } |
1389 | 1402 |
1390 | 1403 |
1391 void LCodeGen::DoLoadGlobal(LLoadGlobal* instr) { | 1404 void LCodeGen::DoLoadGlobal(LLoadGlobal* instr) { |
1392 Register result = ToRegister(instr->result()); | 1405 Abort("Unimplemented: %s", "DoLoadGlobal"); |
1393 if (result.is(rax)) { | |
1394 __ load_rax(instr->hydrogen()->cell().location(), | |
1395 RelocInfo::GLOBAL_PROPERTY_CELL); | |
1396 } else { | |
1397 __ movq(result, instr->hydrogen()->cell(), RelocInfo::GLOBAL_PROPERTY_CELL); | |
1398 __ movq(result, Operand(result, 0)); | |
1399 } | |
1400 if (instr->hydrogen()->check_hole_value()) { | |
1401 __ CompareRoot(result, Heap::kTheHoleValueRootIndex); | |
1402 DeoptimizeIf(equal, instr->environment()); | |
1403 } | |
1404 } | 1406 } |
1405 | 1407 |
1406 | 1408 |
1407 void LCodeGen::DoStoreGlobal(LStoreGlobal* instr) { | 1409 void LCodeGen::DoStoreGlobal(LStoreGlobal* instr) { |
1408 Register value = ToRegister(instr->InputAt(0)); | 1410 Register value = ToRegister(instr->InputAt(0)); |
1409 if (value.is(rax)) { | 1411 Register temp = ToRegister(instr->TempAt(0)); |
| 1412 ASSERT(!value.is(temp)); |
| 1413 bool check_hole = instr->hydrogen()->check_hole_value(); |
| 1414 if (!check_hole && value.is(rax)) { |
1410 __ store_rax(instr->hydrogen()->cell().location(), | 1415 __ store_rax(instr->hydrogen()->cell().location(), |
1411 RelocInfo::GLOBAL_PROPERTY_CELL); | 1416 RelocInfo::GLOBAL_PROPERTY_CELL); |
1412 } else { | 1417 return; |
1413 __ movq(kScratchRegister, | |
1414 Handle<Object>::cast(instr->hydrogen()->cell()), | |
1415 RelocInfo::GLOBAL_PROPERTY_CELL); | |
1416 __ movq(Operand(kScratchRegister, 0), value); | |
1417 } | 1418 } |
| 1419 // If the cell we are storing to contains the hole it could have |
| 1420 // been deleted from the property dictionary. In that case, we need |
| 1421 // to update the property details in the property dictionary to mark |
| 1422 // it as no longer deleted. We deoptimize in that case. |
| 1423 __ movq(temp, |
| 1424 Handle<Object>::cast(instr->hydrogen()->cell()), |
| 1425 RelocInfo::GLOBAL_PROPERTY_CELL); |
| 1426 if (check_hole) { |
| 1427 __ CompareRoot(Operand(temp, 0), Heap::kTheHoleValueRootIndex); |
| 1428 DeoptimizeIf(equal, instr->environment()); |
| 1429 } |
| 1430 __ movq(Operand(temp, 0), value); |
1418 } | 1431 } |
1419 | 1432 |
1420 | 1433 |
1421 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) { | 1434 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) { |
1422 Abort("Unimplemented: %s", "DoLoadContextSlot"); | 1435 Abort("Unimplemented: %s", "DoLoadContextSlot"); |
1423 } | 1436 } |
1424 | 1437 |
1425 | 1438 |
1426 void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { | 1439 void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { |
1427 Register object = ToRegister(instr->InputAt(0)); | 1440 Register object = ToRegister(instr->InputAt(0)); |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1513 void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) { | 1526 void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) { |
1514 Register result = ToRegister(instr->result()); | 1527 Register result = ToRegister(instr->result()); |
1515 __ movq(result, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX))); | 1528 __ movq(result, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX))); |
1516 __ movq(result, FieldOperand(result, GlobalObject::kGlobalReceiverOffset)); | 1529 __ movq(result, FieldOperand(result, GlobalObject::kGlobalReceiverOffset)); |
1517 } | 1530 } |
1518 | 1531 |
1519 | 1532 |
1520 void LCodeGen::CallKnownFunction(Handle<JSFunction> function, | 1533 void LCodeGen::CallKnownFunction(Handle<JSFunction> function, |
1521 int arity, | 1534 int arity, |
1522 LInstruction* instr) { | 1535 LInstruction* instr) { |
1523 Abort("Unimplemented: %s", "CallKnownFunction"); | 1536 // Change context if needed. |
| 1537 bool change_context = |
| 1538 (graph()->info()->closure()->context() != function->context()) || |
| 1539 scope()->contains_with() || |
| 1540 (scope()->num_heap_slots() > 0); |
| 1541 if (change_context) { |
| 1542 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); |
| 1543 } |
| 1544 |
| 1545 // Set rax to arguments count if adaption is not needed. Assumes that rax |
| 1546 // is available to write to at this point. |
| 1547 if (!function->NeedsArgumentsAdaption()) { |
| 1548 __ Set(rax, arity); |
| 1549 } |
| 1550 |
| 1551 LPointerMap* pointers = instr->pointer_map(); |
| 1552 RecordPosition(pointers->position()); |
| 1553 |
| 1554 // Invoke function. |
| 1555 if (*function == *graph()->info()->closure()) { |
| 1556 __ CallSelf(); |
| 1557 } else { |
| 1558 __ call(FieldOperand(rdi, JSFunction::kCodeEntryOffset)); |
| 1559 } |
| 1560 |
| 1561 // Setup deoptimization. |
| 1562 RegisterLazyDeoptimization(instr); |
| 1563 |
| 1564 // Restore context. |
| 1565 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
1524 } | 1566 } |
1525 | 1567 |
1526 | 1568 |
1527 void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) { | 1569 void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) { |
1528 Abort("Unimplemented: %s", "DoCallConstantFunction"); | 1570 Abort("Unimplemented: %s", "DoCallConstantFunction"); |
1529 } | 1571 } |
1530 | 1572 |
1531 | 1573 |
1532 void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) { | 1574 void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) { |
1533 Abort("Unimplemented: %s", "DoDeferredMathAbsTaggedHeapNumber"); | 1575 Abort("Unimplemented: %s", "DoDeferredMathAbsTaggedHeapNumber"); |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1598 Abort("Unimplemented: %s", "DoCallFunction"); | 1640 Abort("Unimplemented: %s", "DoCallFunction"); |
1599 } | 1641 } |
1600 | 1642 |
1601 | 1643 |
1602 void LCodeGen::DoCallGlobal(LCallGlobal* instr) { | 1644 void LCodeGen::DoCallGlobal(LCallGlobal* instr) { |
1603 Abort("Unimplemented: %s", "DoCallGlobal"); | 1645 Abort("Unimplemented: %s", "DoCallGlobal"); |
1604 } | 1646 } |
1605 | 1647 |
1606 | 1648 |
1607 void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) { | 1649 void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) { |
1608 Abort("Unimplemented: %s", "DoCallKnownGlobal"); | 1650 ASSERT(ToRegister(instr->result()).is(rax)); |
| 1651 __ Move(rdi, instr->target()); |
| 1652 CallKnownFunction(instr->target(), instr->arity(), instr); |
1609 } | 1653 } |
1610 | 1654 |
1611 | 1655 |
1612 void LCodeGen::DoCallNew(LCallNew* instr) { | 1656 void LCodeGen::DoCallNew(LCallNew* instr) { |
1613 ASSERT(ToRegister(instr->InputAt(0)).is(rdi)); | 1657 ASSERT(ToRegister(instr->InputAt(0)).is(rdi)); |
1614 ASSERT(ToRegister(instr->result()).is(rax)); | 1658 ASSERT(ToRegister(instr->result()).is(rax)); |
1615 | 1659 |
1616 Handle<Code> builtin(Builtins::builtin(Builtins::JSConstructCall)); | 1660 Handle<Code> builtin(Builtins::builtin(Builtins::JSConstructCall)); |
1617 __ Set(rax, instr->arity()); | 1661 __ Set(rax, instr->arity()); |
1618 CallCode(builtin, RelocInfo::CONSTRUCT_CALL, instr); | 1662 CallCode(builtin, RelocInfo::CONSTRUCT_CALL, instr); |
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1804 ASSERT(input->IsRegister()); | 1848 ASSERT(input->IsRegister()); |
1805 Condition cc = masm()->CheckSmi(ToRegister(input)); | 1849 Condition cc = masm()->CheckSmi(ToRegister(input)); |
1806 if (instr->condition() != equal) { | 1850 if (instr->condition() != equal) { |
1807 cc = NegateCondition(cc); | 1851 cc = NegateCondition(cc); |
1808 } | 1852 } |
1809 DeoptimizeIf(cc, instr->environment()); | 1853 DeoptimizeIf(cc, instr->environment()); |
1810 } | 1854 } |
1811 | 1855 |
1812 | 1856 |
1813 void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { | 1857 void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { |
1814 Abort("Unimplemented: %s", "DoCheckInstanceType"); | 1858 Register input = ToRegister(instr->InputAt(0)); |
| 1859 InstanceType first = instr->hydrogen()->first(); |
| 1860 InstanceType last = instr->hydrogen()->last(); |
| 1861 |
| 1862 __ movq(kScratchRegister, FieldOperand(input, HeapObject::kMapOffset)); |
| 1863 |
| 1864 // If there is only one type in the interval check for equality. |
| 1865 if (first == last) { |
| 1866 __ cmpb(FieldOperand(kScratchRegister, Map::kInstanceTypeOffset), |
| 1867 Immediate(static_cast<int8_t>(first))); |
| 1868 DeoptimizeIf(not_equal, instr->environment()); |
| 1869 } else if (first == FIRST_STRING_TYPE && last == LAST_STRING_TYPE) { |
| 1870 // String has a dedicated bit in instance type. |
| 1871 __ testb(FieldOperand(kScratchRegister, Map::kInstanceTypeOffset), |
| 1872 Immediate(kIsNotStringMask)); |
| 1873 DeoptimizeIf(not_zero, instr->environment()); |
| 1874 } else { |
| 1875 __ cmpb(FieldOperand(kScratchRegister, Map::kInstanceTypeOffset), |
| 1876 Immediate(static_cast<int8_t>(first))); |
| 1877 DeoptimizeIf(below, instr->environment()); |
| 1878 // Omit check for the last type. |
| 1879 if (last != LAST_TYPE) { |
| 1880 __ cmpb(FieldOperand(kScratchRegister, Map::kInstanceTypeOffset), |
| 1881 Immediate(static_cast<int8_t>(last))); |
| 1882 DeoptimizeIf(above, instr->environment()); |
| 1883 } |
| 1884 } |
1815 } | 1885 } |
1816 | 1886 |
1817 | 1887 |
1818 void LCodeGen::DoCheckFunction(LCheckFunction* instr) { | 1888 void LCodeGen::DoCheckFunction(LCheckFunction* instr) { |
1819 ASSERT(instr->InputAt(0)->IsRegister()); | 1889 ASSERT(instr->InputAt(0)->IsRegister()); |
1820 Register reg = ToRegister(instr->InputAt(0)); | 1890 Register reg = ToRegister(instr->InputAt(0)); |
1821 __ Cmp(reg, instr->hydrogen()->target()); | 1891 __ Cmp(reg, instr->hydrogen()->target()); |
1822 DeoptimizeIf(not_equal, instr->environment()); | 1892 DeoptimizeIf(not_equal, instr->environment()); |
1823 } | 1893 } |
1824 | 1894 |
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2006 | 2076 |
2007 void LCodeGen::DoOsrEntry(LOsrEntry* instr) { | 2077 void LCodeGen::DoOsrEntry(LOsrEntry* instr) { |
2008 Abort("Unimplemented: %s", "DoOsrEntry"); | 2078 Abort("Unimplemented: %s", "DoOsrEntry"); |
2009 } | 2079 } |
2010 | 2080 |
2011 #undef __ | 2081 #undef __ |
2012 | 2082 |
2013 } } // namespace v8::internal | 2083 } } // namespace v8::internal |
2014 | 2084 |
2015 #endif // V8_TARGET_ARCH_X64 | 2085 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |