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