/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Common Public License (CPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/cpl1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.compilers.common.assembler;
import org.jikesrvm.VM;
/**
*
* A forward reference has a machine-code-index source and optionally
* a bytecode-index target. The idea is to fix up the instruction at
* the source when the machine-code-index of the target is known.
* There need not be an explicit target, if the reference is used (by
* the compiler) within the machine-code for one bytecode.
*
* There are three kinds of forward reference:
* 1) unconditional branches
* 2) conditional branches
* 3) switch cases
* Each subclass must be able to resolve itself.
*
* This class also includes the machinery for maintaining a priority
* queue of forward references, priorities being target bytecode
* addresses. The head of this priority queue is maintained by a
* VM_Assembler object.
*
* The priority queue is implemented as a one-way linked list of forward
* references with strictly increasing targets. The link for this list
* is "next". A separate linked list ("other" is the link) contains all
* forward references with the same target.
*/
public abstract class VM_ForwardReference {
int sourceMachinecodeIndex;
int targetBytecodeIndex; // optional
/* support for priority queue of forward references */ VM_ForwardReference next; // has next larger targetBytecodeIndex
VM_ForwardReference other; // has the same targetBytecodeIndex
protected VM_ForwardReference(int source, int btarget) {
sourceMachinecodeIndex = source;
targetBytecodeIndex = btarget;
}
/* no target;
* for use within cases of the main compiler loop
*/
protected VM_ForwardReference(int source) {
sourceMachinecodeIndex = source;
}
// rewrite source to reference current machine code (in asm's machineCodes)
//
public abstract void resolve(VM_AbstractAssembler asm);
// add a new reference r to a priority queue q
// return the updated queue
//
public static VM_ForwardReference enqueue(VM_ForwardReference q, VM_ForwardReference r) {
if (q == null) return r;
if (r.targetBytecodeIndex < q.targetBytecodeIndex) {
r.next = q;
return r;
} else if (r.targetBytecodeIndex == q.targetBytecodeIndex) {
r.other = q.other;
q.other = r;
return q;
}
VM_ForwardReference s = q;
while (s.next != null && r.targetBytecodeIndex > s.next.targetBytecodeIndex) {
s = s.next;
}
s.next = enqueue(s.next, r);
return q;
}
// resolve any forward references on priority queue q to bytecode index bi
// return queue of unresolved references
//
public static VM_ForwardReference resolveMatching(VM_AbstractAssembler asm, VM_ForwardReference q, int bi) {
if (q == null) return null;
if (VM.VerifyAssertions) VM._assert(bi <= q.targetBytecodeIndex);
if (bi != q.targetBytecodeIndex) return q;
VM_ForwardReference r = q.next;
while (q != null) {
q.resolve(asm);
q = q.other;
}
return r;
}
public static class UnconditionalBranch extends VM_ForwardReference {
public UnconditionalBranch(int source, int btarget) {
super(source, btarget);
}
public void resolve(VM_AbstractAssembler asm) {
asm.patchUnconditionalBranch(sourceMachinecodeIndex);
}
}
public static class ConditionalBranch extends VM_ForwardReference {
public ConditionalBranch(int source, int btarget) {
super(source, btarget);
}
public void resolve(VM_AbstractAssembler asm) {
asm.patchConditionalBranch(sourceMachinecodeIndex);
}
}
public static class ShortBranch extends VM_ForwardReference {
public ShortBranch(int source) {
super(source);
}
public ShortBranch(int source, int btarget) {
super(source, btarget);
}
public void resolve(VM_AbstractAssembler asm) {
asm.patchShortBranch(sourceMachinecodeIndex);
}
}
public static class SwitchCase extends VM_ForwardReference {
public SwitchCase(int source, int btarget) {
super(source, btarget);
}
public void resolve(VM_AbstractAssembler asm) {
asm.patchSwitchCase(sourceMachinecodeIndex);
}
}
public static class LoadReturnAddress extends VM_ForwardReference {
public LoadReturnAddress(int source) {
super(source);
}
public LoadReturnAddress(int source, int btarget) {
super(source, btarget);
}
public void resolve(VM_AbstractAssembler asm) {
asm.patchLoadReturnAddress(sourceMachinecodeIndex);
}
}
}