void CodeSection::relocate(address at, RelocationHolder const& spec, int format) { Relocation* reloc = spec.reloc(); relocInfo::relocType rtype = (relocInfo::relocType) reloc->type(); if (rtype == relocInfo::none) return; // The assertion below has been adjusted, to also work for // relocation for fixup. Sometimes we want to put relocation // information for the next instruction, since it will be patched // with a call. assert(start() <= at && at <= end()+1, "cannot relocate data outside code boundaries"); if (!has_locs()) { // no space for relocation information provided => code cannot be // relocated. Make sure that relocate is only called with rtypes // that can be ignored for this kind of code. assert(rtype == relocInfo::none || rtype == relocInfo::runtime_call_type || rtype == relocInfo::internal_word_type|| rtype == relocInfo::section_word_type || rtype == relocInfo::external_word_type, "code needs relocation information"); // leave behind an indication that we attempted a relocation DEBUG_ONLY(_locs_start = _locs_limit = (relocInfo*)badAddress); return; } // Advance the point, noting the offset we'll have to record. csize_t offset = at - locs_point(); set_locs_point(at); // Test for a couple of overflow conditions; maybe expand the buffer. relocInfo* end = locs_end(); relocInfo* req = end + relocInfo::length_limit; // Check for (potential) overflow if (req >= locs_limit() || offset >= relocInfo::offset_limit()) { req += (uint)offset / (uint)relocInfo::offset_limit(); if (req >= locs_limit()) { // Allocate or reallocate. expand_locs(locs_count() + (req - end)); // reload pointer end = locs_end(); } } // If the offset is giant, emit filler relocs, of type 'none', but // each carrying the largest possible offset, to advance the locs_point. while (offset >= relocInfo::offset_limit()) { assert(end < locs_limit(), "adjust previous paragraph of code"); *end++ = filler_relocInfo(); offset -= filler_relocInfo().addr_offset(); } // If it's a simple reloc with no data, we'll just write (rtype | offset). (*end) = relocInfo(rtype, offset, format); // If it has data, insert the prefix, as (data_prefix_tag | data1), data2. end->initialize(this, reloc); }
void relocInfo::set_type(relocType t) { int old_offset = addr_offset(); int old_format = format(); (*this) = relocInfo(t, old_offset, old_format); assert(type()==(int)t, "sanity check"); assert(addr_offset()==old_offset, "sanity check"); assert(format()==old_format, "sanity check"); }
relocInfo::relocInfo(relocType t, int off, int f) { assert(t != data_prefix_tag, "cannot build a prefix this way"); assert((t & type_mask) == t, "wrong type"); assert((f & format_mask) == f, "wrong format"); assert(off >= 0 && off < offset_limit(), "offset out off bounds"); assert((off & (offset_unit-1)) == 0, "misaligned offset"); int bits = (off / (unsigned)offset_unit) | (f << offset_width); (*this) = relocInfo(t, RAW_BITS, bits); }
csize_t CodeBuffer::copy_relocations_to(CodeBlob* dest) const { address buf = NULL; csize_t buf_offset = 0; csize_t buf_limit = 0; if (dest != NULL) { buf = (address)dest->relocation_begin(); buf_limit = (address)dest->relocation_end() - buf; assert((uintptr_t)buf % HeapWordSize == 0, "buf must be fully aligned"); assert(buf_limit % HeapWordSize == 0, "buf must be evenly sized"); } // if dest == NULL, this is just the sizing pass csize_t code_end_so_far = 0; csize_t code_point_so_far = 0; for (int n = (int) SECT_FIRST; n < (int)SECT_LIMIT; n++) { // pull relocs out of each section const CodeSection* cs = code_section(n); assert(!(cs->is_empty() && cs->locs_count() > 0), "sanity"); if (cs->is_empty()) continue; // skip trivial section relocInfo* lstart = cs->locs_start(); relocInfo* lend = cs->locs_end(); csize_t lsize = (csize_t)( (address)lend - (address)lstart ); csize_t csize = cs->size(); code_end_so_far = cs->align_at_start(code_end_so_far); if (lsize > 0) { // Figure out how to advance the combined relocation point // first to the beginning of this section. // We'll insert one or more filler relocs to span that gap. // (Don't bother to improve this by editing the first reloc's offset.) csize_t new_code_point = code_end_so_far; for (csize_t jump; code_point_so_far < new_code_point; code_point_so_far += jump) { jump = new_code_point - code_point_so_far; relocInfo filler = filler_relocInfo(); if (jump >= filler.addr_offset()) { jump = filler.addr_offset(); } else { // else shrink the filler to fit filler = relocInfo(relocInfo::none, jump); } if (buf != NULL) { assert(buf_offset + (csize_t)sizeof(filler) <= buf_limit, "filler in bounds"); *(relocInfo*)(buf+buf_offset) = filler; } buf_offset += sizeof(filler); } // Update code point and end to skip past this section: csize_t last_code_point = code_end_so_far + cs->locs_point_off(); assert(code_point_so_far <= last_code_point, "sanity"); code_point_so_far = last_code_point; // advance past this guy's relocs } code_end_so_far += csize; // advance past this guy's instructions too // Done with filler; emit the real relocations: if (buf != NULL && lsize != 0) { assert(buf_offset + lsize <= buf_limit, "target in bounds"); assert((uintptr_t)lstart % HeapWordSize == 0, "sane start"); if (buf_offset % HeapWordSize == 0) { // Use wordwise copies if possible: Copy::disjoint_words((HeapWord*)lstart, (HeapWord*)(buf+buf_offset), (lsize + HeapWordSize-1) / HeapWordSize); } else { Copy::conjoint_jbytes(lstart, buf+buf_offset, lsize); } } buf_offset += lsize; } // Align end of relocation info in target. while (buf_offset % HeapWordSize != 0) { if (buf != NULL) { relocInfo padding = relocInfo(relocInfo::none, 0); assert(buf_offset + (csize_t)sizeof(padding) <= buf_limit, "padding in bounds"); *(relocInfo*)(buf+buf_offset) = padding; } buf_offset += sizeof(relocInfo); } assert(code_end_so_far == total_content_size(), "sanity"); // Account for index: if (buf != NULL) { RelocIterator::create_index(dest->relocation_begin(), buf_offset / sizeof(relocInfo), dest->relocation_end()); } return buf_offset; }