OLD | NEW |
1 // Copyright (c) 1994-2006 Sun Microsystems Inc. | 1 // Copyright (c) 1994-2006 Sun Microsystems Inc. |
2 // All Rights Reserved. | 2 // All Rights Reserved. |
3 // | 3 // |
4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
5 // modification, are permitted provided that the following conditions | 5 // modification, are permitted provided that the following conditions |
6 // are met: | 6 // are met: |
7 // | 7 // |
8 // - Redistributions of source code must retain the above copyright notice, | 8 // - Redistributions of source code must retain the above copyright notice, |
9 // this list of conditions and the following disclaimer. | 9 // this list of conditions and the following disclaimer. |
10 // | 10 // |
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
210 // We leave space (kMaxBlockTrampolineSectionSize) | 210 // We leave space (kMaxBlockTrampolineSectionSize) |
211 // for BlockTrampolinePoolScope buffer. | 211 // for BlockTrampolinePoolScope buffer. |
212 next_buffer_check_ = | 212 next_buffer_check_ = |
213 FLAG_force_long_branches ? kMaxInt : kMaxCondBranchReach - | 213 FLAG_force_long_branches ? kMaxInt : kMaxCondBranchReach - |
214 kMaxBlockTrampolineSectionSize; | 214 kMaxBlockTrampolineSectionSize; |
215 internal_trampoline_exception_ = false; | 215 internal_trampoline_exception_ = false; |
216 last_bound_pos_ = 0; | 216 last_bound_pos_ = 0; |
217 trampoline_emitted_ = FLAG_force_long_branches; | 217 trampoline_emitted_ = FLAG_force_long_branches; |
218 unbound_labels_count_ = 0; | 218 unbound_labels_count_ = 0; |
219 ClearRecordedAstId(); | 219 ClearRecordedAstId(); |
| 220 relocations_.reserve(128); |
220 } | 221 } |
221 | 222 |
222 | 223 |
223 void Assembler::GetCode(CodeDesc* desc) { | 224 void Assembler::GetCode(CodeDesc* desc) { |
224 reloc_info_writer.Finish(); | 225 EmitRelocations(); |
225 | 226 |
226 // Set up code descriptor. | 227 // Set up code descriptor. |
227 desc->buffer = buffer_; | 228 desc->buffer = buffer_; |
228 desc->buffer_size = buffer_size_; | 229 desc->buffer_size = buffer_size_; |
229 desc->instr_size = pc_offset(); | 230 desc->instr_size = pc_offset(); |
230 desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos(); | 231 desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos(); |
231 desc->origin = this; | 232 desc->origin = this; |
232 } | 233 } |
233 | 234 |
234 | 235 |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
371 // instruction using the label. | 372 // instruction using the label. |
372 | 373 |
373 | 374 |
374 // The link chain is terminated by a negative code position (must be aligned) | 375 // The link chain is terminated by a negative code position (must be aligned) |
375 const int kEndOfChain = -4; | 376 const int kEndOfChain = -4; |
376 | 377 |
377 | 378 |
378 // Dummy opcodes for unbound label mov instructions or jump table entries. | 379 // Dummy opcodes for unbound label mov instructions or jump table entries. |
379 enum { | 380 enum { |
380 kUnboundMovLabelOffsetOpcode = 0 << 26, | 381 kUnboundMovLabelOffsetOpcode = 0 << 26, |
381 kUnboundMovLabelAddrOpcode = 1 << 26, | 382 kUnboundAddLabelOffsetOpcode = 1 << 26, |
382 kUnboundJumpTableEntryOpcode = 2 << 26 | 383 kUnboundMovLabelAddrOpcode = 2 << 26, |
| 384 kUnboundJumpTableEntryOpcode = 3 << 26 |
383 }; | 385 }; |
384 | 386 |
385 | 387 |
386 int Assembler::target_at(int pos) { | 388 int Assembler::target_at(int pos) { |
387 Instr instr = instr_at(pos); | 389 Instr instr = instr_at(pos); |
388 // check which type of branch this is 16 or 26 bit offset | 390 // check which type of branch this is 16 or 26 bit offset |
389 int opcode = instr & kOpcodeMask; | 391 int opcode = instr & kOpcodeMask; |
390 int link; | 392 int link; |
391 switch (opcode) { | 393 switch (opcode) { |
392 case BX: | 394 case BX: |
393 link = SIGN_EXT_IMM26(instr & kImm26Mask); | 395 link = SIGN_EXT_IMM26(instr & kImm26Mask); |
394 link &= ~(kAAMask | kLKMask); // discard AA|LK bits if present | 396 link &= ~(kAAMask | kLKMask); // discard AA|LK bits if present |
395 break; | 397 break; |
396 case BCX: | 398 case BCX: |
397 link = SIGN_EXT_IMM16((instr & kImm16Mask)); | 399 link = SIGN_EXT_IMM16((instr & kImm16Mask)); |
398 link &= ~(kAAMask | kLKMask); // discard AA|LK bits if present | 400 link &= ~(kAAMask | kLKMask); // discard AA|LK bits if present |
399 break; | 401 break; |
400 case kUnboundMovLabelOffsetOpcode: | 402 case kUnboundMovLabelOffsetOpcode: |
| 403 case kUnboundAddLabelOffsetOpcode: |
401 case kUnboundMovLabelAddrOpcode: | 404 case kUnboundMovLabelAddrOpcode: |
402 case kUnboundJumpTableEntryOpcode: | 405 case kUnboundJumpTableEntryOpcode: |
403 link = SIGN_EXT_IMM26(instr & kImm26Mask); | 406 link = SIGN_EXT_IMM26(instr & kImm26Mask); |
404 link <<= 2; | 407 link <<= 2; |
405 break; | 408 break; |
406 default: | 409 default: |
407 DCHECK(false); | 410 DCHECK(false); |
408 return -1; | 411 return -1; |
409 } | 412 } |
410 | 413 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
447 case kUnboundMovLabelOffsetOpcode: { | 450 case kUnboundMovLabelOffsetOpcode: { |
448 // Load the position of the label relative to the generated code object | 451 // Load the position of the label relative to the generated code object |
449 // pointer in a register. | 452 // pointer in a register. |
450 Register dst = Register::from_code(instr_at(pos + kInstrSize)); | 453 Register dst = Register::from_code(instr_at(pos + kInstrSize)); |
451 int32_t offset = target_pos + (Code::kHeaderSize - kHeapObjectTag); | 454 int32_t offset = target_pos + (Code::kHeaderSize - kHeapObjectTag); |
452 CodePatcher patcher(reinterpret_cast<byte*>(buffer_ + pos), 2, | 455 CodePatcher patcher(reinterpret_cast<byte*>(buffer_ + pos), 2, |
453 CodePatcher::DONT_FLUSH); | 456 CodePatcher::DONT_FLUSH); |
454 patcher.masm()->bitwise_mov32(dst, offset); | 457 patcher.masm()->bitwise_mov32(dst, offset); |
455 break; | 458 break; |
456 } | 459 } |
| 460 case kUnboundAddLabelOffsetOpcode: { |
| 461 // dst = base + position + immediate |
| 462 Instr operands = instr_at(pos + kInstrSize); |
| 463 Register dst = Register::from_code((operands >> 21) & 0x1f); |
| 464 Register base = Register::from_code((operands >> 16) & 0x1f); |
| 465 int32_t offset = target_pos + SIGN_EXT_IMM16(operands & kImm16Mask); |
| 466 CodePatcher patcher(reinterpret_cast<byte*>(buffer_ + pos), 2, |
| 467 CodePatcher::DONT_FLUSH); |
| 468 patcher.masm()->bitwise_add32(dst, base, offset); |
| 469 break; |
| 470 } |
457 case kUnboundMovLabelAddrOpcode: { | 471 case kUnboundMovLabelAddrOpcode: { |
458 // Load the address of the label in a register. | 472 // Load the address of the label in a register. |
459 Register dst = Register::from_code(instr_at(pos + kInstrSize)); | 473 Register dst = Register::from_code(instr_at(pos + kInstrSize)); |
460 intptr_t addr = reinterpret_cast<uintptr_t>(buffer_ + target_pos); | |
461 CodePatcher patcher(reinterpret_cast<byte*>(buffer_ + pos), | 474 CodePatcher patcher(reinterpret_cast<byte*>(buffer_ + pos), |
462 kMovInstructions, CodePatcher::DONT_FLUSH); | 475 kMovInstructions, CodePatcher::DONT_FLUSH); |
463 AddBoundInternalReferenceLoad(pos); | 476 // Keep internal references relative until EmitRelocations. |
464 patcher.masm()->bitwise_mov(dst, addr); | 477 patcher.masm()->bitwise_mov(dst, target_pos); |
465 break; | 478 break; |
466 } | 479 } |
467 case kUnboundJumpTableEntryOpcode: { | 480 case kUnboundJumpTableEntryOpcode: { |
468 intptr_t addr = reinterpret_cast<uintptr_t>(buffer_ + target_pos); | |
469 CodePatcher patcher(reinterpret_cast<byte*>(buffer_ + pos), | 481 CodePatcher patcher(reinterpret_cast<byte*>(buffer_ + pos), |
470 kPointerSize / kInstrSize, CodePatcher::DONT_FLUSH); | 482 kPointerSize / kInstrSize, CodePatcher::DONT_FLUSH); |
471 AddBoundInternalReference(pos); | 483 // Keep internal references relative until EmitRelocations. |
472 patcher.masm()->emit_ptr(addr); | 484 patcher.masm()->emit_ptr(target_pos); |
473 break; | 485 break; |
474 } | 486 } |
475 default: | 487 default: |
476 DCHECK(false); | 488 DCHECK(false); |
477 break; | 489 break; |
478 } | 490 } |
479 } | 491 } |
480 | 492 |
481 | 493 |
482 int Assembler::max_reach_from(int pos) { | 494 int Assembler::max_reach_from(int pos) { |
483 Instr instr = instr_at(pos); | 495 Instr instr = instr_at(pos); |
484 int opcode = instr & kOpcodeMask; | 496 int opcode = instr & kOpcodeMask; |
485 | 497 |
486 // check which type of branch this is 16 or 26 bit offset | 498 // check which type of branch this is 16 or 26 bit offset |
487 switch (opcode) { | 499 switch (opcode) { |
488 case BX: | 500 case BX: |
489 return 26; | 501 return 26; |
490 case BCX: | 502 case BCX: |
491 return 16; | 503 return 16; |
492 case kUnboundMovLabelOffsetOpcode: | 504 case kUnboundMovLabelOffsetOpcode: |
| 505 case kUnboundAddLabelOffsetOpcode: |
493 case kUnboundMovLabelAddrOpcode: | 506 case kUnboundMovLabelAddrOpcode: |
494 case kUnboundJumpTableEntryOpcode: | 507 case kUnboundJumpTableEntryOpcode: |
495 return 0; // no limit on reach | 508 return 0; // no limit on reach |
496 } | 509 } |
497 | 510 |
498 DCHECK(false); | 511 DCHECK(false); |
499 return 0; | 512 return 0; |
500 } | 513 } |
501 | 514 |
502 | 515 |
(...skipping 977 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1480 Label instructions; | 1493 Label instructions; |
1481 DCHECK(pc_offset() == 0); | 1494 DCHECK(pc_offset() == 0); |
1482 emit_label_addr(&instructions); | 1495 emit_label_addr(&instructions); |
1483 emit_ptr(0); | 1496 emit_ptr(0); |
1484 emit_ptr(0); | 1497 emit_ptr(0); |
1485 bind(&instructions); | 1498 bind(&instructions); |
1486 #endif | 1499 #endif |
1487 } | 1500 } |
1488 | 1501 |
1489 | 1502 |
1490 void Assembler::RelocateInternalReference(Address pc, intptr_t delta, | |
1491 Address code_start, | |
1492 RelocInfo::Mode rmode, | |
1493 ICacheFlushMode icache_flush_mode) { | |
1494 if (RelocInfo::IsInternalReference(rmode)) { | |
1495 // Jump table entry | |
1496 DCHECK(delta || code_start); | |
1497 uintptr_t* entry = reinterpret_cast<uintptr_t*>(pc); | |
1498 if (delta) { | |
1499 *entry += delta; | |
1500 } else { | |
1501 // remove when serializer properly supports internal references | |
1502 *entry = reinterpret_cast<uintptr_t>(code_start) + 3 * kPointerSize; | |
1503 } | |
1504 } else { | |
1505 // mov sequence | |
1506 DCHECK(delta || code_start); | |
1507 DCHECK(RelocInfo::IsInternalReferenceEncoded(rmode)); | |
1508 ConstantPoolArray* constant_pool = NULL; | |
1509 Address addr; | |
1510 if (delta) { | |
1511 addr = target_address_at(pc, constant_pool) + delta; | |
1512 } else { | |
1513 // remove when serializer properly supports internal references | |
1514 addr = code_start; | |
1515 } | |
1516 set_target_address_at(pc, constant_pool, addr, icache_flush_mode); | |
1517 } | |
1518 } | |
1519 | |
1520 | |
1521 void Assembler::EnsureSpaceFor(int space_needed) { | 1503 void Assembler::EnsureSpaceFor(int space_needed) { |
1522 if (buffer_space() <= (kGap + space_needed)) { | 1504 if (buffer_space() <= (kGap + space_needed)) { |
1523 GrowBuffer(space_needed); | 1505 GrowBuffer(space_needed); |
1524 } | 1506 } |
1525 } | 1507 } |
1526 | 1508 |
1527 | 1509 |
1528 bool Operand::must_output_reloc_info(const Assembler* assembler) const { | 1510 bool Operand::must_output_reloc_info(const Assembler* assembler) const { |
1529 if (rmode_ == RelocInfo::EXTERNAL_REFERENCE) { | 1511 if (rmode_ == RelocInfo::EXTERNAL_REFERENCE) { |
1530 if (assembler != NULL && assembler->predictable_code_size()) return true; | 1512 if (assembler != NULL && assembler->predictable_code_size()) return true; |
1531 return assembler->serializer_enabled(); | 1513 return assembler->serializer_enabled(); |
1532 } else if (RelocInfo::IsNone(rmode_)) { | 1514 } else if (RelocInfo::IsNone(rmode_)) { |
1533 return false; | 1515 return false; |
1534 } | 1516 } |
1535 return true; | 1517 return true; |
1536 } | 1518 } |
1537 | 1519 |
1538 | 1520 |
1539 // Primarily used for loading constants | 1521 // Primarily used for loading constants |
1540 // This should really move to be in macro-assembler as it | 1522 // This should really move to be in macro-assembler as it |
1541 // is really a pseudo instruction | 1523 // is really a pseudo instruction |
1542 // Some usages of this intend for a FIXED_SEQUENCE to be used | 1524 // Some usages of this intend for a FIXED_SEQUENCE to be used |
1543 // Todo - break this dependency so we can optimize mov() in general | 1525 // Todo - break this dependency so we can optimize mov() in general |
1544 // and only use the generic version when we require a fixed sequence | 1526 // and only use the generic version when we require a fixed sequence |
1545 void Assembler::mov(Register dst, const Operand& src) { | 1527 void Assembler::mov(Register dst, const Operand& src) { |
1546 intptr_t value = src.immediate(); | 1528 intptr_t value = src.immediate(); |
| 1529 bool relocatable = src.must_output_reloc_info(this); |
1547 bool canOptimize; | 1530 bool canOptimize; |
1548 RelocInfo rinfo(pc_, src.rmode_, value, NULL); | |
1549 | 1531 |
1550 canOptimize = !(src.must_output_reloc_info(this) || | 1532 canOptimize = |
1551 (is_trampoline_pool_blocked() && !is_int16(value))); | 1533 !(relocatable || (is_trampoline_pool_blocked() && !is_int16(value))); |
1552 | 1534 |
1553 if (canOptimize) { | 1535 if (canOptimize) { |
1554 if (is_int16(value)) { | 1536 if (is_int16(value)) { |
1555 li(dst, Operand(value)); | 1537 li(dst, Operand(value)); |
1556 } else { | 1538 } else { |
1557 uint16_t u16; | 1539 uint16_t u16; |
1558 #if V8_TARGET_ARCH_PPC64 | 1540 #if V8_TARGET_ARCH_PPC64 |
1559 if (is_int32(value)) { | 1541 if (is_int32(value)) { |
1560 #endif | 1542 #endif |
1561 lis(dst, Operand(value >> 16)); | 1543 lis(dst, Operand(value >> 16)); |
(...skipping 17 matching lines...) Expand all Loading... |
1579 #endif | 1561 #endif |
1580 u16 = (value & 0xffff); | 1562 u16 = (value & 0xffff); |
1581 if (u16) { | 1563 if (u16) { |
1582 ori(dst, dst, Operand(u16)); | 1564 ori(dst, dst, Operand(u16)); |
1583 } | 1565 } |
1584 } | 1566 } |
1585 return; | 1567 return; |
1586 } | 1568 } |
1587 | 1569 |
1588 DCHECK(!canOptimize); | 1570 DCHECK(!canOptimize); |
1589 if (src.must_output_reloc_info(this)) { | 1571 if (relocatable) { |
1590 RecordRelocInfo(rinfo); | 1572 RecordRelocInfo(src.rmode_); |
1591 } | 1573 } |
1592 bitwise_mov(dst, value); | 1574 bitwise_mov(dst, value); |
1593 } | 1575 } |
1594 | 1576 |
1595 | 1577 |
1596 void Assembler::bitwise_mov(Register dst, intptr_t value) { | 1578 void Assembler::bitwise_mov(Register dst, intptr_t value) { |
1597 BlockTrampolinePoolScope block_trampoline_pool(this); | 1579 BlockTrampolinePoolScope block_trampoline_pool(this); |
1598 #if V8_TARGET_ARCH_PPC64 | 1580 #if V8_TARGET_ARCH_PPC64 |
1599 int32_t hi_32 = static_cast<int32_t>(value >> 32); | 1581 int32_t hi_32 = static_cast<int32_t>(value >> 32); |
1600 int32_t lo_32 = static_cast<int32_t>(value); | 1582 int32_t lo_32 = static_cast<int32_t>(value); |
(...skipping 17 matching lines...) Expand all Loading... |
1618 | 1600 |
1619 void Assembler::bitwise_mov32(Register dst, int32_t value) { | 1601 void Assembler::bitwise_mov32(Register dst, int32_t value) { |
1620 BlockTrampolinePoolScope block_trampoline_pool(this); | 1602 BlockTrampolinePoolScope block_trampoline_pool(this); |
1621 int hi_word = static_cast<int>(value >> 16); | 1603 int hi_word = static_cast<int>(value >> 16); |
1622 int lo_word = static_cast<int>(value & 0xffff); | 1604 int lo_word = static_cast<int>(value & 0xffff); |
1623 lis(dst, Operand(SIGN_EXT_IMM16(hi_word))); | 1605 lis(dst, Operand(SIGN_EXT_IMM16(hi_word))); |
1624 ori(dst, dst, Operand(lo_word)); | 1606 ori(dst, dst, Operand(lo_word)); |
1625 } | 1607 } |
1626 | 1608 |
1627 | 1609 |
| 1610 void Assembler::bitwise_add32(Register dst, Register src, int32_t value) { |
| 1611 BlockTrampolinePoolScope block_trampoline_pool(this); |
| 1612 if (is_int16(value)) { |
| 1613 addi(dst, src, Operand(value)); |
| 1614 nop(); |
| 1615 } else { |
| 1616 int hi_word = static_cast<int>(value >> 16); |
| 1617 int lo_word = static_cast<int>(value & 0xffff); |
| 1618 if (lo_word & 0x8000) hi_word++; |
| 1619 addis(dst, src, Operand(SIGN_EXT_IMM16(hi_word))); |
| 1620 addic(dst, dst, Operand(SIGN_EXT_IMM16(lo_word))); |
| 1621 } |
| 1622 } |
| 1623 |
| 1624 |
1628 void Assembler::mov_label_offset(Register dst, Label* label) { | 1625 void Assembler::mov_label_offset(Register dst, Label* label) { |
1629 int position = link(label); | 1626 int position = link(label); |
1630 if (label->is_bound()) { | 1627 if (label->is_bound()) { |
1631 // Load the position of the label relative to the generated code object. | 1628 // Load the position of the label relative to the generated code object. |
1632 mov(dst, Operand(position + Code::kHeaderSize - kHeapObjectTag)); | 1629 mov(dst, Operand(position + Code::kHeaderSize - kHeapObjectTag)); |
1633 } else { | 1630 } else { |
1634 // Encode internal reference to unbound label. We use a dummy opcode | 1631 // Encode internal reference to unbound label. We use a dummy opcode |
1635 // such that it won't collide with any opcode that might appear in the | 1632 // such that it won't collide with any opcode that might appear in the |
1636 // label's chain. Encode the destination register in the 2nd instruction. | 1633 // label's chain. Encode the destination register in the 2nd instruction. |
1637 int link = position - pc_offset(); | 1634 int link = position - pc_offset(); |
1638 DCHECK_EQ(0, link & 3); | 1635 DCHECK_EQ(0, link & 3); |
1639 link >>= 2; | 1636 link >>= 2; |
1640 DCHECK(is_int26(link)); | 1637 DCHECK(is_int26(link)); |
1641 | 1638 |
1642 // When the label is bound, these instructions will be patched | 1639 // When the label is bound, these instructions will be patched |
1643 // with a 2 instruction mov sequence that will load the | 1640 // with a 2 instruction mov sequence that will load the |
1644 // destination register with the position of the label from the | 1641 // destination register with the position of the label from the |
1645 // beginning of the code. | 1642 // beginning of the code. |
1646 // | 1643 // |
1647 // target_at extracts the link and target_at_put patches the instructions. | 1644 // target_at extracts the link and target_at_put patches the instructions. |
1648 BlockTrampolinePoolScope block_trampoline_pool(this); | 1645 BlockTrampolinePoolScope block_trampoline_pool(this); |
1649 emit(kUnboundMovLabelOffsetOpcode | (link & kImm26Mask)); | 1646 emit(kUnboundMovLabelOffsetOpcode | (link & kImm26Mask)); |
1650 emit(dst.code()); | 1647 emit(dst.code()); |
1651 } | 1648 } |
1652 } | 1649 } |
1653 | 1650 |
1654 | 1651 |
| 1652 void Assembler::add_label_offset(Register dst, Register base, Label* label, |
| 1653 int delta) { |
| 1654 int position = link(label); |
| 1655 if (label->is_bound()) { |
| 1656 // dst = base + position + delta |
| 1657 position += delta; |
| 1658 bitwise_add32(dst, base, position); |
| 1659 } else { |
| 1660 // Encode internal reference to unbound label. We use a dummy opcode |
| 1661 // such that it won't collide with any opcode that might appear in the |
| 1662 // label's chain. Encode the operands in the 2nd instruction. |
| 1663 int link = position - pc_offset(); |
| 1664 DCHECK_EQ(0, link & 3); |
| 1665 link >>= 2; |
| 1666 DCHECK(is_int26(link)); |
| 1667 DCHECK(is_int16(delta)); |
| 1668 |
| 1669 BlockTrampolinePoolScope block_trampoline_pool(this); |
| 1670 emit(kUnboundAddLabelOffsetOpcode | (link & kImm26Mask)); |
| 1671 emit(dst.code() * B21 | base.code() * B16 | (delta & kImm16Mask)); |
| 1672 } |
| 1673 } |
| 1674 |
| 1675 |
1655 void Assembler::mov_label_addr(Register dst, Label* label) { | 1676 void Assembler::mov_label_addr(Register dst, Label* label) { |
1656 CheckBuffer(); | 1677 CheckBuffer(); |
1657 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED); | 1678 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED); |
1658 int position = link(label); | 1679 int position = link(label); |
1659 if (label->is_bound()) { | 1680 if (label->is_bound()) { |
1660 // CheckBuffer() is called too frequently. This will pre-grow | 1681 // Keep internal references relative until EmitRelocations. |
1661 // the buffer if needed to avoid spliting the relocation and instructions | 1682 bitwise_mov(dst, position); |
1662 EnsureSpaceFor(kMovInstructions * kInstrSize); | |
1663 | |
1664 intptr_t addr = reinterpret_cast<uintptr_t>(buffer_ + position); | |
1665 AddBoundInternalReferenceLoad(pc_offset()); | |
1666 bitwise_mov(dst, addr); | |
1667 } else { | 1683 } else { |
1668 // Encode internal reference to unbound label. We use a dummy opcode | 1684 // Encode internal reference to unbound label. We use a dummy opcode |
1669 // such that it won't collide with any opcode that might appear in the | 1685 // such that it won't collide with any opcode that might appear in the |
1670 // label's chain. Encode the destination register in the 2nd instruction. | 1686 // label's chain. Encode the destination register in the 2nd instruction. |
1671 int link = position - pc_offset(); | 1687 int link = position - pc_offset(); |
1672 DCHECK_EQ(0, link & 3); | 1688 DCHECK_EQ(0, link & 3); |
1673 link >>= 2; | 1689 link >>= 2; |
1674 DCHECK(is_int26(link)); | 1690 DCHECK(is_int26(link)); |
1675 | 1691 |
1676 // When the label is bound, these instructions will be patched | 1692 // When the label is bound, these instructions will be patched |
1677 // with a multi-instruction mov sequence that will load the | 1693 // with a multi-instruction mov sequence that will load the |
1678 // destination register with the address of the label. | 1694 // destination register with the address of the label. |
1679 // | 1695 // |
1680 // target_at extracts the link and target_at_put patches the instructions. | 1696 // target_at extracts the link and target_at_put patches the instructions. |
1681 BlockTrampolinePoolScope block_trampoline_pool(this); | 1697 BlockTrampolinePoolScope block_trampoline_pool(this); |
1682 emit(kUnboundMovLabelAddrOpcode | (link & kImm26Mask)); | 1698 emit(kUnboundMovLabelAddrOpcode | (link & kImm26Mask)); |
1683 emit(dst.code()); | 1699 emit(dst.code()); |
1684 DCHECK(kMovInstructions >= 2); | 1700 DCHECK(kMovInstructions >= 2); |
1685 for (int i = 0; i < kMovInstructions - 2; i++) nop(); | 1701 for (int i = 0; i < kMovInstructions - 2; i++) nop(); |
1686 } | 1702 } |
1687 } | 1703 } |
1688 | 1704 |
1689 | 1705 |
1690 void Assembler::emit_label_addr(Label* label) { | 1706 void Assembler::emit_label_addr(Label* label) { |
1691 CheckBuffer(); | 1707 CheckBuffer(); |
1692 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE); | 1708 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE); |
1693 int position = link(label); | 1709 int position = link(label); |
1694 if (label->is_bound()) { | 1710 if (label->is_bound()) { |
1695 // CheckBuffer() is called too frequently. This will pre-grow | 1711 // Keep internal references relative until EmitRelocations. |
1696 // the buffer if needed to avoid spliting the relocation and entry. | 1712 emit_ptr(position); |
1697 EnsureSpaceFor(kPointerSize); | |
1698 | |
1699 intptr_t addr = reinterpret_cast<uintptr_t>(buffer_ + position); | |
1700 AddBoundInternalReference(pc_offset()); | |
1701 emit_ptr(addr); | |
1702 } else { | 1713 } else { |
1703 // Encode internal reference to unbound label. We use a dummy opcode | 1714 // Encode internal reference to unbound label. We use a dummy opcode |
1704 // such that it won't collide with any opcode that might appear in the | 1715 // such that it won't collide with any opcode that might appear in the |
1705 // label's chain. | 1716 // label's chain. |
1706 int link = position - pc_offset(); | 1717 int link = position - pc_offset(); |
1707 DCHECK_EQ(0, link & 3); | 1718 DCHECK_EQ(0, link & 3); |
1708 link >>= 2; | 1719 link >>= 2; |
1709 DCHECK(is_int26(link)); | 1720 DCHECK(is_int26(link)); |
1710 | 1721 |
1711 // When the label is bound, the instruction(s) will be patched | 1722 // When the label is bound, the instruction(s) will be patched |
(...skipping 499 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2211 desc.reloc_size); | 2222 desc.reloc_size); |
2212 | 2223 |
2213 // Switch buffers. | 2224 // Switch buffers. |
2214 DeleteArray(buffer_); | 2225 DeleteArray(buffer_); |
2215 buffer_ = desc.buffer; | 2226 buffer_ = desc.buffer; |
2216 buffer_size_ = desc.buffer_size; | 2227 buffer_size_ = desc.buffer_size; |
2217 pc_ += pc_delta; | 2228 pc_ += pc_delta; |
2218 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta, | 2229 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta, |
2219 reloc_info_writer.last_pc() + pc_delta); | 2230 reloc_info_writer.last_pc() + pc_delta); |
2220 | 2231 |
2221 // Relocate internal references | 2232 // Nothing else to do here since we keep all internal references and |
2222 for (int pos : internal_reference_positions_) { | 2233 // deferred relocation entries relative to the buffer (until |
2223 RelocateInternalReference(buffer_ + pos, pc_delta, 0, | 2234 // EmitRelocations). |
2224 RelocInfo::INTERNAL_REFERENCE); | |
2225 } | |
2226 for (int pos : internal_reference_load_positions_) { | |
2227 RelocateInternalReference(buffer_ + pos, pc_delta, 0, | |
2228 RelocInfo::INTERNAL_REFERENCE_ENCODED); | |
2229 } | |
2230 } | 2235 } |
2231 | 2236 |
2232 | 2237 |
2233 void Assembler::db(uint8_t data) { | 2238 void Assembler::db(uint8_t data) { |
2234 CheckBuffer(); | 2239 CheckBuffer(); |
2235 *reinterpret_cast<uint8_t*>(pc_) = data; | 2240 *reinterpret_cast<uint8_t*>(pc_) = data; |
2236 pc_ += sizeof(uint8_t); | 2241 pc_ += sizeof(uint8_t); |
2237 } | 2242 } |
2238 | 2243 |
2239 | 2244 |
2240 void Assembler::dd(uint32_t data) { | 2245 void Assembler::dd(uint32_t data) { |
2241 CheckBuffer(); | 2246 CheckBuffer(); |
2242 *reinterpret_cast<uint32_t*>(pc_) = data; | 2247 *reinterpret_cast<uint32_t*>(pc_) = data; |
2243 pc_ += sizeof(uint32_t); | 2248 pc_ += sizeof(uint32_t); |
2244 } | 2249 } |
2245 | 2250 |
2246 | 2251 |
2247 void Assembler::emit_ptr(intptr_t data) { | 2252 void Assembler::emit_ptr(intptr_t data) { |
2248 CheckBuffer(); | 2253 CheckBuffer(); |
2249 *reinterpret_cast<intptr_t*>(pc_) = data; | 2254 *reinterpret_cast<intptr_t*>(pc_) = data; |
2250 pc_ += sizeof(intptr_t); | 2255 pc_ += sizeof(intptr_t); |
2251 } | 2256 } |
2252 | 2257 |
2253 | 2258 |
| 2259 void Assembler::emit_double(double value) { |
| 2260 CheckBuffer(); |
| 2261 *reinterpret_cast<double*>(pc_) = value; |
| 2262 pc_ += sizeof(double); |
| 2263 } |
| 2264 |
| 2265 |
2254 void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) { | 2266 void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) { |
2255 RelocInfo rinfo(pc_, rmode, data, NULL); | 2267 DeferredRelocInfo rinfo(pc_offset(), rmode, data); |
2256 RecordRelocInfo(rinfo); | 2268 RecordRelocInfo(rinfo); |
2257 } | 2269 } |
2258 | 2270 |
2259 | 2271 |
2260 void Assembler::RecordRelocInfo(const RelocInfo& rinfo) { | 2272 void Assembler::RecordRelocInfo(const DeferredRelocInfo& rinfo) { |
2261 if (rinfo.rmode() >= RelocInfo::JS_RETURN && | 2273 if (rinfo.rmode() >= RelocInfo::JS_RETURN && |
2262 rinfo.rmode() <= RelocInfo::DEBUG_BREAK_SLOT) { | 2274 rinfo.rmode() <= RelocInfo::DEBUG_BREAK_SLOT) { |
2263 // Adjust code for new modes. | 2275 // Adjust code for new modes. |
2264 DCHECK(RelocInfo::IsDebugBreakSlot(rinfo.rmode()) || | 2276 DCHECK(RelocInfo::IsDebugBreakSlot(rinfo.rmode()) || |
2265 RelocInfo::IsJSReturn(rinfo.rmode()) || | 2277 RelocInfo::IsJSReturn(rinfo.rmode()) || |
2266 RelocInfo::IsComment(rinfo.rmode()) || | 2278 RelocInfo::IsComment(rinfo.rmode()) || |
2267 RelocInfo::IsPosition(rinfo.rmode())); | 2279 RelocInfo::IsPosition(rinfo.rmode())); |
2268 } | 2280 } |
2269 if (!RelocInfo::IsNone(rinfo.rmode())) { | 2281 if (!RelocInfo::IsNone(rinfo.rmode())) { |
2270 // Don't record external references unless the heap will be serialized. | 2282 // Don't record external references unless the heap will be serialized. |
2271 if (rinfo.rmode() == RelocInfo::EXTERNAL_REFERENCE) { | 2283 if (rinfo.rmode() == RelocInfo::EXTERNAL_REFERENCE) { |
2272 if (!serializer_enabled() && !emit_debug_code()) { | 2284 if (!serializer_enabled() && !emit_debug_code()) { |
2273 return; | 2285 return; |
2274 } | 2286 } |
2275 } | 2287 } |
2276 DCHECK(buffer_space() >= kMaxRelocSize); // too late to grow buffer here | |
2277 if (rinfo.rmode() == RelocInfo::CODE_TARGET_WITH_ID) { | 2288 if (rinfo.rmode() == RelocInfo::CODE_TARGET_WITH_ID) { |
2278 RelocInfo reloc_info_with_ast_id(rinfo.pc(), rinfo.rmode(), | 2289 DeferredRelocInfo reloc_info_with_ast_id(rinfo.position(), rinfo.rmode(), |
2279 RecordedAstId().ToInt(), NULL); | 2290 RecordedAstId().ToInt()); |
2280 ClearRecordedAstId(); | 2291 ClearRecordedAstId(); |
2281 reloc_info_writer.Write(&reloc_info_with_ast_id); | 2292 relocations_.push_back(reloc_info_with_ast_id); |
2282 } else { | 2293 } else { |
2283 reloc_info_writer.Write(&rinfo); | 2294 relocations_.push_back(rinfo); |
2284 } | 2295 } |
2285 } | 2296 } |
2286 } | 2297 } |
2287 | 2298 |
2288 | 2299 |
| 2300 void Assembler::EmitRelocations() { |
| 2301 EnsureSpaceFor(relocations_.size() * kMaxRelocSize); |
| 2302 |
| 2303 for (std::vector<DeferredRelocInfo>::iterator it = relocations_.begin(); |
| 2304 it != relocations_.end(); it++) { |
| 2305 RelocInfo::Mode rmode = it->rmode(); |
| 2306 RelocInfo rinfo(buffer_ + it->position(), rmode, it->data(), NULL); |
| 2307 |
| 2308 // Fix up internal references now that they are guaranteed to be bound. |
| 2309 if (RelocInfo::IsInternalReference(rmode) || |
| 2310 RelocInfo::IsInternalReferenceEncoded(rmode)) { |
| 2311 intptr_t pos = |
| 2312 reinterpret_cast<intptr_t>(rinfo.target_internal_reference()); |
| 2313 rinfo.set_target_internal_reference(buffer_ + pos); |
| 2314 } |
| 2315 |
| 2316 reloc_info_writer.Write(&rinfo); |
| 2317 } |
| 2318 |
| 2319 reloc_info_writer.Finish(); |
| 2320 } |
| 2321 |
| 2322 |
2289 void Assembler::BlockTrampolinePoolFor(int instructions) { | 2323 void Assembler::BlockTrampolinePoolFor(int instructions) { |
2290 BlockTrampolinePoolBefore(pc_offset() + instructions * kInstrSize); | 2324 BlockTrampolinePoolBefore(pc_offset() + instructions * kInstrSize); |
2291 } | 2325 } |
2292 | 2326 |
2293 | 2327 |
2294 void Assembler::CheckTrampolinePool() { | 2328 void Assembler::CheckTrampolinePool() { |
2295 // Some small sequences of instructions must not be broken up by the | 2329 // Some small sequences of instructions must not be broken up by the |
2296 // insertion of a trampoline pool; such sequences are protected by setting | 2330 // insertion of a trampoline pool; such sequences are protected by setting |
2297 // either trampoline_pool_blocked_nesting_ or no_trampoline_pool_before_, | 2331 // either trampoline_pool_blocked_nesting_ or no_trampoline_pool_before_, |
2298 // which are both checked here. Also, recursive calls to CheckTrampolinePool | 2332 // which are both checked here. Also, recursive calls to CheckTrampolinePool |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2346 } | 2380 } |
2347 | 2381 |
2348 | 2382 |
2349 void Assembler::PopulateConstantPool(ConstantPoolArray* constant_pool) { | 2383 void Assembler::PopulateConstantPool(ConstantPoolArray* constant_pool) { |
2350 DCHECK(!FLAG_enable_ool_constant_pool); | 2384 DCHECK(!FLAG_enable_ool_constant_pool); |
2351 } | 2385 } |
2352 } | 2386 } |
2353 } // namespace v8::internal | 2387 } // namespace v8::internal |
2354 | 2388 |
2355 #endif // V8_TARGET_ARCH_PPC | 2389 #endif // V8_TARGET_ARCH_PPC |
OLD | NEW |