001    /*
002     *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003     *
004     *  This file is licensed to You under the Eclipse Public License (EPL);
005     *  You may not use this file except in compliance with the License. You
006     *  may obtain a copy of the License at
007     *
008     *      http://www.opensource.org/licenses/eclipse-1.0.php
009     *
010     *  See the COPYRIGHT.txt file distributed with this work for information
011     *  regarding copyright ownership.
012     */
013    package org.jikesrvm.compilers.common.assembler;
014    
015    import org.jikesrvm.VM;
016    
017    /**
018     *
019     *  A forward reference has a machine-code-index source and optionally
020     *  a bytecode-index target.  The idea is to fix up the instruction at
021     *  the source when the machine-code-index of the target is known.
022     *  There need not be an explicit target, if the reference is used (by
023     *  the compiler) within the machine-code for one bytecode.
024     *  <p>
025     *  There are three kinds of forward reference:
026     *  <ol>
027     *    <li>unconditional branches
028     *    <li>conditional branches
029     *    <li>switch cases
030     *  </ol>
031     *  Each subclass must be able to resolve itself.
032     *  <p>
033     *  This class also includes the machinery for maintaining a priority
034     *  queue of forward references, priorities being target bytecode
035     *  addresses.  The head of this priority queue is maintained by a
036     *  Assembler object.
037     *  <p>
038     *  The priority queue is implemented as a one-way linked list of forward
039     *  references with strictly increasing targets.  The link for this list
040     *  is "next".  A separate linked list ("other" is the link) contains all
041     *  forward references with the same target.
042     */
043    public abstract class ForwardReference {
044    
045      final int sourceMachinecodeIndex;
046      final int targetBytecodeIndex;     // optional
047    
048      /* Support for priority queue of forward references */
049    
050      /** Has next larger targetBytecodeIndex */
051      ForwardReference next;
052      /** Has the same targetBytecodeIndex */
053      ForwardReference other;
054    
055      protected ForwardReference(int source, int btarget) {
056        sourceMachinecodeIndex = source;
057        targetBytecodeIndex = btarget;
058      }
059    
060      /**
061       * No target; for use within cases of the main compiler loop
062       */
063      protected ForwardReference(int source) {
064        sourceMachinecodeIndex = source;
065        targetBytecodeIndex = 0;
066      }
067    
068      /**
069       * Rewrite source to reference current machine code (in asm's machineCodes)
070       */
071      public abstract void resolve(AbstractAssembler asm);
072    
073      /**
074       * Add a new reference r to a priority queue q
075       * @return the updated queue
076       */
077      public static ForwardReference enqueue(ForwardReference q, ForwardReference r) {
078        if (q == null) return r;
079        if (r.targetBytecodeIndex < q.targetBytecodeIndex) {
080          r.next = q;
081          return r;
082        } else if (r.targetBytecodeIndex == q.targetBytecodeIndex) {
083          r.other = q.other;
084          q.other = r;
085          return q;
086        }
087        ForwardReference s = q;
088        while (s.next != null && r.targetBytecodeIndex > s.next.targetBytecodeIndex) {
089          s = s.next;
090        }
091        s.next = enqueue(s.next, r);
092        return q;
093    
094      }
095    
096      /**
097       * Resolve any forward references on priority queue q to bytecode index bi
098       * @return queue of unresolved references
099       */
100      public static ForwardReference resolveMatching(AbstractAssembler asm, ForwardReference q, int bi) {
101        if (q == null) return null;
102        if (VM.VerifyAssertions) VM._assert(bi <= q.targetBytecodeIndex);
103        if (bi != q.targetBytecodeIndex) return q;
104        ForwardReference r = q.next;
105        while (q != null) {
106          q.resolve(asm);
107          q = q.other;
108        }
109        return r;
110      }
111    
112      public static final class UnconditionalBranch extends ForwardReference {
113    
114        public UnconditionalBranch(int source, int btarget) {
115          super(source, btarget);
116        }
117    
118        @Override
119        public void resolve(AbstractAssembler asm) {
120          asm.patchUnconditionalBranch(sourceMachinecodeIndex);
121        }
122      }
123    
124      public static final class ConditionalBranch extends ForwardReference {
125    
126        public ConditionalBranch(int source, int btarget) {
127          super(source, btarget);
128        }
129    
130        @Override
131        public void resolve(AbstractAssembler asm) {
132          asm.patchConditionalBranch(sourceMachinecodeIndex);
133        }
134      }
135    
136      // Cannot be made final; subclassed for PPC
137      public static class ShortBranch extends ForwardReference {
138    
139        public ShortBranch(int source) {
140          super(source);
141        }
142    
143        public ShortBranch(int source, int btarget) {
144          super(source, btarget);
145        }
146    
147        @Override
148        public void resolve(AbstractAssembler asm) {
149          asm.patchShortBranch(sourceMachinecodeIndex);
150        }
151      }
152    
153      public static final class SwitchCase extends ForwardReference {
154    
155        public SwitchCase(int source, int btarget) {
156          super(source, btarget);
157        }
158    
159        @Override
160        public void resolve(AbstractAssembler asm) {
161          asm.patchSwitchCase(sourceMachinecodeIndex);
162        }
163      }
164    
165      public static final class LoadReturnAddress extends ForwardReference {
166    
167        public LoadReturnAddress(int source) {
168          super(source);
169        }
170    
171        public LoadReturnAddress(int source, int btarget) {
172          super(source, btarget);
173        }
174    
175        @Override
176        public void resolve(AbstractAssembler asm) {
177          asm.patchLoadReturnAddress(sourceMachinecodeIndex);
178        }
179      }
180    }