Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: Allocator/RuntimeCodeAllocator.java


1   // RuntimeCodeAllocator.java, created Tue Feb 27  2:53:11 2001 by joewhaley
2   // Copyright (C) 2001-3 John Whaley <jwhaley@alum.mit.edu>
3   // Licensed under the terms of the GNU LGPL; see COPYING for details.
4   package Allocator;
5   
6   import java.util.List;
7   
8   import Clazz.jq_BytecodeMap;
9   import Clazz.jq_CompiledCode;
10  import Clazz.jq_Method;
11  import Clazz.jq_TryCatch;
12  import Memory.Address;
13  import Memory.CodeAddress;
14  import Run_Time.ExceptionDeliverer;
15  import Run_Time.SystemInterface;
16  import Util.Assert;
17  import Util.Strings;
18  
19  /**
20   * RuntimeCodeAllocator
21   *
22   * @author  John Whaley <jwhaley@alum.mit.edu>
23   * @version $Id: RuntimeCodeAllocator.java,v 1.19 2003/05/12 10:04:52 joewhaley Exp $
24   */
25  public class RuntimeCodeAllocator extends CodeAllocator {
26  
27      // Memory layout:
28      //
29      // start:   |   next ptr   |---->
30      //          |   end ptr    |
31      //          |.....data.....|
32      // current: |.....free.....|
33      // end:     | current ptr  |
34  
35      /** Size of blocks allocated from the OS.
36       */
37      public static final int BLOCK_SIZE = 131072;
38      
39      /** Pointers to the start, current, and end of the heap.
40       */
41      private CodeAddress heapStart, heapCurrent, heapEnd;
42      
43      /** Pointer to the first block.
44       */
45      private CodeAddress heapFirst;
46      
47      /** Max memory free in all allocated blocks.
48       */
49      private int maxFreePrevious;
50      
51      volatile boolean isGenerating = false;
52      
53      public void init()
54      throws OutOfMemoryError {
55          heapStart = heapFirst = (CodeAddress)SystemInterface.syscalloc(BLOCK_SIZE);
56          if (heapStart.isNull())
57              HeapAllocator.outOfMemory();
58          heapStart.poke(null);
59          heapEnd = (CodeAddress)heapStart.offset(BLOCK_SIZE - CodeAddress.size());
60          heapStart.offset(CodeAddress.size()).poke(heapEnd);
61          heapCurrent = (CodeAddress)heapStart.offset(CodeAddress.size() * 2);
62          heapEnd.poke(heapCurrent);
63      }
64      
65      /** Allocate a code buffer of the given estimated size, such that the given
66       * offset will have the given alignment.
67       * It is legal for code to exceed the estimated size, but the cost may be
68       * high (i.e. it may require recopying of the buffer.)
69       *
70       * @param estimatedSize  estimated size, in bytes, of desired code buffer
71       * @param offset  desired offset to align to
72       * @param alignment  desired alignment, or 0 if don't care
73       * @return  the new code buffer
74       */
75      public x86CodeBuffer getCodeBuffer(int estimatedSize,
76                                         int offset,
77                                         int alignment) {
78          // should not be called recursively.
79          Assert._assert(!isGenerating);
80          if (TRACE) SystemInterface.debugwriteln("Code generation started: "+this);
81          isGenerating = true;
82          // align pointer
83          CodeAddress entrypoint = (CodeAddress)heapCurrent.offset(offset);
84          if (alignment > 0) entrypoint.align(alignment);
85          if (entrypoint.offset(estimatedSize - offset).difference(heapEnd) <= 0) {
86              return new Runtimex86CodeBuffer((CodeAddress)entrypoint.offset(-offset), heapEnd);
87          }
88          if (estimatedSize < maxFreePrevious) {
89              // use a prior block's unused space.
90              if (TRACE) SystemInterface.debugwriteln("Estimated size ("+Strings.hex(estimatedSize)+" fits within a prior block: maxfreeprev="+Strings.hex(maxFreePrevious));
91              // start searching at the first block
92              CodeAddress start_ptr = heapFirst;
93              for (;;) {
94                  // start_ptr:   points to start of current block
95                  // end_ptr:     points to end of current block
96                  // current_ptr: current pointer for current block
97                  Assert._assert(!start_ptr.isNull());
98                  CodeAddress end_ptr = (CodeAddress)start_ptr.offset(CodeAddress.size()).peek();
99                  CodeAddress current_ptr = (CodeAddress)end_ptr.peek();
100                 if (end_ptr.difference(current_ptr) >= estimatedSize) {
101                     return new Runtimex86CodeBuffer(current_ptr, end_ptr);
102                 }
103                 start_ptr = (CodeAddress)start_ptr.peek(); // go to the next block
104             }
105         }
106         // allocate new block.
107         allocateNewBlock(Math.max(estimatedSize, BLOCK_SIZE));
108         return new Runtimex86CodeBuffer(heapCurrent, heapEnd);
109     }
110     
111     private void allocateNewBlock(int blockSize)
112     throws OutOfMemoryError {
113         heapStart.offset(CodeAddress.size()).poke(heapCurrent);
114         CodeAddress newBlock = (CodeAddress)SystemInterface.syscalloc(blockSize);
115         if (newBlock.isNull())
116             HeapAllocator.outOfMemory();
117         heapStart.poke(newBlock);
118         heapStart = newBlock;
119         heapStart.poke(null);
120         heapEnd = (CodeAddress)newBlock.offset(blockSize - CodeAddress.size());
121         heapStart.offset(CodeAddress.size()).poke(heapEnd);
122         heapCurrent = (CodeAddress)newBlock.offset(CodeAddress.size() * 2);
123         heapEnd.poke(heapCurrent);
124     }
125     
126     public void patchAbsolute(Address addr1, Address addr2) {
127         addr1.poke(addr2);
128     }
129     public void patchRelativeOffset(CodeAddress code, CodeAddress target) {
130         code.poke4(target.difference(code)-4);
131     }
132     
133     public class Runtimex86CodeBuffer extends CodeAllocator.x86CodeBuffer {
134 
135         private CodeAddress startAddress;
136         private CodeAddress entrypointAddress;
137         private CodeAddress currentAddress;
138         private CodeAddress endAddress;
139 
140         Runtimex86CodeBuffer(CodeAddress startAddress, CodeAddress endAddress) {
141             this.startAddress = startAddress;
142             this.endAddress = endAddress;
143             this.currentAddress = (CodeAddress)startAddress.offset(-1);
144         }
145         
146         public int getCurrentOffset() { return currentAddress.difference(startAddress) + 1; }
147         public CodeAddress getStartAddress() { return startAddress; }
148         public CodeAddress getCurrentAddress() { return (CodeAddress)currentAddress.offset(1); }
149         
150         public CodeAddress getStart() { return startAddress; }
151         public CodeAddress getCurrent() { return (CodeAddress)currentAddress.offset(1); }
152         public CodeAddress getEntry() { return entrypointAddress; }
153         public CodeAddress getEnd() { return endAddress; }
154         
155         public void setEntrypoint() { this.entrypointAddress = getCurrent(); }
156         
157         public void checkSize(int size) {
158             if (currentAddress.offset(size).difference(endAddress) < 0) return;
159             // overflow!
160             int newEstimatedSize = endAddress.difference(startAddress) << 1;
161             allocateNewBlock(Math.max(BLOCK_SIZE, newEstimatedSize));
162             Assert._assert(currentAddress.difference(startAddress)+size < heapEnd.difference(heapCurrent));
163             SystemInterface.mem_cpy(heapCurrent, startAddress, currentAddress.difference(startAddress));
164             if (!entrypointAddress.isNull())
165                 entrypointAddress = (CodeAddress)heapCurrent.offset(entrypointAddress.difference(startAddress));
166             currentAddress = (CodeAddress)heapCurrent.offset(currentAddress.difference(startAddress));
167             startAddress = heapCurrent;
168             endAddress = heapEnd;
169         }
170         
171         public void add1(byte i) {
172             checkSize(1);
173             currentAddress = (CodeAddress)currentAddress.offset(1);
174             currentAddress.poke1(i);
175         }
176         public void add2_endian(int i) {
177             checkSize(2);
178             currentAddress.offset(1).poke2((short)i);
179             currentAddress = (CodeAddress)currentAddress.offset(2);
180         }
181         public void add2(int i) {
182             checkSize(2);
183             currentAddress.offset(1).poke2(endian2(i));
184             currentAddress = (CodeAddress)currentAddress.offset(2);
185         }
186         public void add3(int i) {
187             checkSize(3);
188             currentAddress.offset(1).poke1((byte)(i >> 16));
189             currentAddress.offset(2).poke2(endian2(i));
190             currentAddress = (CodeAddress)currentAddress.offset(3);
191         }
192         public void add4_endian(int i) {
193             checkSize(4);
194             currentAddress.offset(1).poke4(i);
195             currentAddress = (CodeAddress)currentAddress.offset(4);
196         }
197 
198         public byte get1(int k) {
199             return startAddress.offset(k).peek1();
200         }
201         public int get4_endian(int k) {
202             return startAddress.offset(k).peek4();
203         }
204 
205         public void put1(int k, byte instr) {
206             startAddress.offset(k).poke1(instr);
207         }
208         public void put4_endian(int k, int instr) {
209             startAddress.offset(k).poke4(instr);
210         }
211 
212         public void skip(int nbytes) {
213             currentAddress = (CodeAddress)currentAddress.offset(nbytes);
214         }
215         
216         public jq_CompiledCode allocateCodeBlock(jq_Method m, jq_TryCatch[] ex,
217                                                  jq_BytecodeMap bcm, ExceptionDeliverer exd,
218                                                  int stackframesize,
219                                                  List code_relocs, List data_relocs) {
220             Assert._assert(isGenerating);
221             CodeAddress start = getStart();
222             CodeAddress entrypoint = getEntry();
223             CodeAddress current = getCurrent();
224             CodeAddress end = getEnd();
225             Assert._assert(current.difference(end) <= 0);
226             if (end != heapEnd) {
227                 if (TRACE) SystemInterface.debugwriteln("Prior block, recalculating maxfreeprevious (was "+Strings.hex(maxFreePrevious)+")");
228                 // prior block
229                 end.poke(current);
230                 // recalculate max free previous
231                 maxFreePrevious = 0;
232                 CodeAddress start_ptr = heapFirst;
233                 while (!start_ptr.isNull()) {
234                     CodeAddress end_ptr = (CodeAddress)start_ptr.offset(CodeAddress.size());
235                     CodeAddress current_ptr = (CodeAddress)end_ptr.peek();
236                     int temp = end_ptr.difference(current_ptr);
237                     maxFreePrevious = Math.max(maxFreePrevious, temp);
238                     start_ptr = (CodeAddress)start_ptr.peek();
239                 }
240                 if (TRACE) SystemInterface.debugwriteln("New maxfreeprevious: "+Strings.hex(maxFreePrevious));
241             } else {
242                 // current block
243                 heapCurrent = current;
244                 heapEnd.poke(heapCurrent);
245             }
246             isGenerating = false;
247             if (TRACE) SystemInterface.debugwriteln("Code generation completed: "+this);
248             jq_CompiledCode cc = new jq_CompiledCode(m, start, current.difference(start), entrypoint, ex, bcm, exd, stackframesize, code_relocs, data_relocs);
249             CodeAllocator.registerCode(cc);
250             return cc;
251         }
252     }
253 
254     public static short endian2(int k) {
255         return (short)(((k>>8)&0xFF) | (k<<8));
256     }
257 }