handle long conditional immediate branches properly on PowerPC

Due to encoding limitations, the immediate operand of conditional
branches can be no more than 32KB forward or backward.  Since the
JIT-compiled form of some methods can be larger than 32KB, and we also
do conditional jumps to code outside the current method in some cases,
we must work around this limitation.

The strategy of this commit is to provide inline, intermediate jump
tables where necessary.  A given conditional branch whose target is
too far for a direct jump will instead point to an unconditional
branch in the nearest jump table which points to the actual target.

Unconditional immediate branches are also limited on PowerPC, but this
limit is 32MB, which is not an impediment in practice.  If it does
become a problem, we'll need to encode such branches using multiple
instructions.
This commit is contained in:
Joel Dice
2011-02-27 23:03:13 -07:00
parent 5f50226ae0
commit 255fc9f9d3
7 changed files with 377 additions and 109 deletions

View File

@ -670,7 +670,9 @@ padding(MyBlock* b, unsigned offset)
unsigned total = 0;
for (PoolEvent* e = b->poolEventHead; e; e = e->next) {
if (e->offset <= offset) {
total += BytesPerWord;
if (b->next) {
total += BytesPerWord;
}
for (PoolOffset* o = e->poolOffsetHead; o; o = o->next) {
total += BytesPerWord;
}
@ -2333,9 +2335,12 @@ class MyAssembler: public Assembler {
}
}
virtual void writeTo(uint8_t* dst) {
virtual void setDestination(uint8_t* dst) {
c.result = dst;
}
virtual void write() {
uint8_t* dst = c.result;
unsigned dstOffset = 0;
for (MyBlock* b = c.firstBlock; b; b = b->next) {
if (DebugPool) {
@ -2356,10 +2361,12 @@ class MyAssembler: public Assembler {
o, o->offset, b);
}
poolSize += BytesPerWord;
unsigned entry = dstOffset + poolSize;
if (b->next) {
entry += BytesPerWord;
}
o->entry->address = dst + entry;
unsigned instruction = o->block->start
@ -2370,9 +2377,13 @@ class MyAssembler: public Assembler {
int32_t* p = reinterpret_cast<int32_t*>(dst + instruction);
*p = (v & PoolOffsetMask) | ((~PoolOffsetMask) & *p);
poolSize += BytesPerWord;
}
write4(dst + dstOffset, ::b((poolSize + BytesPerWord - 8) >> 2));
if (b->next) {
write4(dst + dstOffset, ::b((poolSize + BytesPerWord - 8) >> 2));
}
dstOffset += poolSize + BytesPerWord;
}