Add wait for PC to stop function to Lua
[jpcrr.git] / org / jpc / emulator / SRDumper.java
blobdba039f492e65fa14aebd4db95d5b363d575a817
1 /*
2 JPC-RR: A x86 PC Hardware Emulator
3 Release 1
5 Copyright (C) 2007-2009 Isis Innovation Limited
6 Copyright (C) 2009 H. Ilari Liusvaara
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License version 2 as published by
10 the Free Software Foundation.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 Based on JPC x86 PC Hardware emulator,
22 A project from the Physics Dept, The University of Oxford
24 Details about original JPC can be found at:
26 www-jpc.physics.ox.ac.uk
30 package org.jpc.emulator;
32 import java.io.*;
33 import java.nio.*;
34 import java.nio.charset.*;
36 public final class SRDumper
38 public static final byte TYPE_BOOLEAN = 1;
39 public static final byte TYPE_BYTE = 2;
40 public static final byte TYPE_SHORT = 3;
41 public static final byte TYPE_INT = 4;
42 public static final byte TYPE_LONG = 5;
43 public static final byte TYPE_STRING = 6;
44 public static final byte TYPE_BOOLEAN_ARRAY = 7;
45 public static final byte TYPE_BYTE_ARRAY = 8;
46 public static final byte TYPE_SHORT_ARRAY = 9;
47 public static final byte TYPE_INT_ARRAY = 10;
48 public static final byte TYPE_LONG_ARRAY = 11;
49 public static final byte TYPE_DOUBLE_ARRAY = 12;
50 public static final byte TYPE_OBJECT = 13;
51 public static final byte TYPE_OBJECT_START = 14;
52 public static final byte TYPE_OBJECT_END = 15;
53 public static final byte TYPE_SPECIAL_OBJECT = 16;
54 public static final byte TYPE_OBJECT_NOT_PRESENT = 19;
56 OutputStream underlyingOutput;
57 int nextObjectNumber;
58 static final Boolean FALSE;
59 static final Boolean TRUE;
60 private java.util.Stack<Integer> objectStack;
61 private int firstUnseenObject;
62 java.util.HashMap<Integer, ObjectListEntry> chainingLists;
63 java.util.HashSet<String> constructors;
64 int objectsCount;
65 private int bufferStart;
66 private byte[] buffer;
67 private static final int BUFFER_MAXSIZE = 4096; //MUST BE MULTIPLE OF 8.
69 public void writeConstructorManifest(OutputStream out) throws IOException
71 for(String clazz : constructors) {
72 ByteBuffer buf;
73 try {
74 buf = Charset.forName("UTF-8").newEncoder().encode(CharBuffer.wrap(clazz));
75 } catch(CharacterCodingException e) {
76 throw new IOException("WTF??? UTF-8 can't encode String???");
78 byte[] buf2 = new byte[buf.remaining()];
79 buf.get(buf2);
80 if(buf2.length > 1024)
81 throw new IOException("Class name length of 1024 bytes exceeded");
82 out.write(buf2);
83 out.write(10);
87 static class ObjectListEntry
89 public Object object;
90 public int num;
91 public ObjectListEntry next;
94 static
96 FALSE = new Boolean(false);
97 TRUE = new Boolean(true);
100 private void ensureBufferSpace(int minSpace) throws IOException
102 if(minSpace > BUFFER_MAXSIZE)
103 throw new IllegalStateException("ensureBufferSpace: Buffer overflow.");
104 while(minSpace > BUFFER_MAXSIZE - bufferStart) {
105 underlyingOutput.write(buffer, 0, bufferStart);
106 bufferStart = 0;
110 public SRDumper(OutputStream ps)
112 nextObjectNumber = 0;
113 underlyingOutput = ps;
114 firstUnseenObject = 0;
115 chainingLists = new java.util.HashMap<Integer, ObjectListEntry>();
116 objectStack = new java.util.Stack<Integer>();
117 objectsCount = 0;
118 constructors = new java.util.HashSet<String>();
119 bufferStart = 0;
120 buffer = new byte[BUFFER_MAXSIZE];
123 public void flush() throws IOException
125 ensureBufferSpace(BUFFER_MAXSIZE);
128 public void dumpBoolean(boolean x) throws IOException
130 ensureBufferSpace(2);
131 buffer[bufferStart++] = TYPE_BOOLEAN;
132 buffer[bufferStart++] = x ? (byte)1 : (byte)0;
135 public void dumpByte(byte x) throws IOException
137 ensureBufferSpace(2);
138 buffer[bufferStart++] = TYPE_BYTE;
139 buffer[bufferStart++] = x;
142 public void dumpShort(short x, boolean ensure) throws IOException
144 if(ensure)
145 ensureBufferSpace(2);
146 buffer[bufferStart++] = (byte)(x >>> 8);
147 buffer[bufferStart++] = (byte)x;
150 public void dumpShort(short x) throws IOException
152 ensureBufferSpace(3);
153 buffer[bufferStart++] = TYPE_SHORT;
154 dumpShort(x, false);
157 public void dumpInt(int x, boolean ensure) throws IOException
159 if(ensure)
160 ensureBufferSpace(4);
161 buffer[bufferStart++] = (byte)(x >>> 24);
162 buffer[bufferStart++] = (byte)(x >>> 16);
163 buffer[bufferStart++] = (byte)(x >>> 8);
164 buffer[bufferStart++] = (byte)x;
167 public void dumpInt(int x) throws IOException
169 ensureBufferSpace(5);
170 buffer[bufferStart++] = TYPE_INT;
171 dumpInt(x, false);
174 public void dumpLong(long x, boolean ensure) throws IOException
176 if(ensure)
177 ensureBufferSpace(8);
178 buffer[bufferStart++] = (byte)(x >>> 56);
179 buffer[bufferStart++] = (byte)(x >>> 48);
180 buffer[bufferStart++] = (byte)(x >>> 40);
181 buffer[bufferStart++] = (byte)(x >>> 32);
182 buffer[bufferStart++] = (byte)(x >>> 24);
183 buffer[bufferStart++] = (byte)(x >>> 16);
184 buffer[bufferStart++] = (byte)(x >>> 8);
185 buffer[bufferStart++] = (byte)x;
189 public void dumpLong(long x) throws IOException
191 ensureBufferSpace(9);
192 buffer[bufferStart++] = TYPE_LONG;
193 dumpLong(x, false);
196 public void dumpString(String x) throws IOException
198 ensureBufferSpace(2);
199 buffer[bufferStart++] = TYPE_STRING;
200 if(x != null) {
201 buffer[bufferStart++] = 1;
202 int bytes = 0;
203 int characters = x.length();
204 for(int i = 0; i < characters; i++) {
205 char ch = x.charAt(i);
206 if(ch == 0)
207 bytes += 2;
208 else if(ch < 128)
209 bytes += 1;
210 else if(ch < 2048)
211 bytes += 2;
212 else
213 bytes += 3;
215 dumpShort((short)bytes, true);
216 for(int i = 0; i < characters; i++) {
217 char ch = x.charAt(i);
218 if(ch == 0) {
219 ensureBufferSpace(2);
220 buffer[bufferStart++] = (byte)192;
221 buffer[bufferStart++] = (byte)128;
222 } else if(ch < 128) {
223 ensureBufferSpace(1);
224 buffer[bufferStart++] = (byte)ch;
225 } else if(ch < 2048) {
226 ensureBufferSpace(2);
227 buffer[bufferStart++] = (byte)((ch >> 6) + 192);
228 buffer[bufferStart++] = (byte)(128 + ch & 0x3F);
229 } else {
230 ensureBufferSpace(3);
231 buffer[bufferStart++] = (byte)((ch >> 12) + 224);
232 buffer[bufferStart++] = (byte)(128 + (ch >> 6) & 0x3F);
233 buffer[bufferStart++] = (byte)(128 + ch & 0x3F);
236 } else
237 buffer[bufferStart++] = 0;
240 public void dumpArray(boolean[] x) throws IOException
242 ensureBufferSpace(2);
243 buffer[bufferStart++] = TYPE_BOOLEAN_ARRAY;
244 if(x != null) {
245 buffer[bufferStart++] = 1;
246 dumpInt(x.length, true);
247 for(int i = 0; i < x.length; i++) {
248 if(bufferStart > BUFFER_MAXSIZE - 1)
249 ensureBufferSpace(1);
250 buffer[bufferStart++] = x[i] ? (byte)1 : (byte)0;
252 } else
253 buffer[bufferStart++] = 0;
256 public void dumpArray(byte[] x) throws IOException
258 ensureBufferSpace(2);
259 buffer[bufferStart++] = TYPE_BYTE_ARRAY;
260 if(x != null) {
261 buffer[bufferStart++] = 1;
262 dumpInt(x.length, true);
263 int remaining = x.length;
264 int index = 0;
265 while(remaining > 0) {
266 int tocopy = remaining;
267 if(tocopy > BUFFER_MAXSIZE)
268 tocopy = BUFFER_MAXSIZE;
269 ensureBufferSpace(tocopy);
270 System.arraycopy(x, index, buffer, bufferStart, tocopy);
271 bufferStart += tocopy;
272 remaining -= tocopy;
273 index += tocopy;
275 } else
276 buffer[bufferStart++] = 0;
279 public void dumpArray(short[] x) throws IOException
281 ensureBufferSpace(2);
282 buffer[bufferStart++] = TYPE_SHORT_ARRAY;
283 if(x != null) {
284 buffer[bufferStart++] = 1;
285 dumpInt(x.length, true);
286 int remaining = x.length;
287 int index = 0;
288 while(remaining > 0) {
289 int tocopy = remaining;
290 if(tocopy > BUFFER_MAXSIZE / 2)
291 tocopy = BUFFER_MAXSIZE / 2;
292 ensureBufferSpace(2 * tocopy);
293 for(int i = 0; i < tocopy; i++)
294 dumpShort(x[index + i], false);
295 remaining -= tocopy;
296 index += tocopy;
298 } else
299 buffer[bufferStart++] = 0;
302 public void dumpArray(int[] x) throws IOException
304 ensureBufferSpace(2);
305 buffer[bufferStart++] = TYPE_INT_ARRAY;
306 if(x != null) {
307 buffer[bufferStart++] = 1;
308 dumpInt(x.length, true);
309 int remaining = x.length;
310 int index = 0;
311 while(remaining > 0) {
312 int tocopy = remaining;
313 if(tocopy > BUFFER_MAXSIZE / 4)
314 tocopy = BUFFER_MAXSIZE / 4;
315 ensureBufferSpace(4 * tocopy);
316 for(int i = 0; i < tocopy; i++)
317 dumpInt(x[index + i], false);
318 remaining -= tocopy;
319 index += tocopy;
321 } else
322 buffer[bufferStart++] = 0;
325 public void dumpArray(long[] x) throws IOException
327 ensureBufferSpace(2);
328 buffer[bufferStart++] = TYPE_LONG_ARRAY;
329 if(x != null) {
330 buffer[bufferStart++] = 1;
331 dumpInt(x.length, true);
332 int remaining = x.length;
333 int index = 0;
334 while(remaining > 0) {
335 int tocopy = remaining;
336 if(tocopy > BUFFER_MAXSIZE / 8)
337 tocopy = BUFFER_MAXSIZE / 8;
338 ensureBufferSpace(8 * tocopy);
339 for(int i = 0; i < tocopy; i++)
340 dumpLong(x[index + i], false);
341 remaining -= tocopy;
342 index += tocopy;
344 } else
345 buffer[bufferStart++] = 0;
348 public void dumpArray(double[] x) throws IOException
350 ensureBufferSpace(2);
351 buffer[bufferStart++] = TYPE_DOUBLE_ARRAY;
352 if(x != null) {
353 buffer[bufferStart++] = 1;
354 dumpInt(x.length, true);
355 int remaining = x.length;
356 int index = 0;
357 while(remaining > 0) {
358 int tocopy = remaining;
359 if(tocopy > BUFFER_MAXSIZE / 8)
360 tocopy = BUFFER_MAXSIZE / 8;
361 ensureBufferSpace(8 * tocopy);
362 for(int i = 0; i < tocopy; i++)
363 dumpLong(Double.doubleToLongBits(x[index + i]), false);
364 remaining -= tocopy;
365 index += tocopy;
367 } else
368 buffer[bufferStart++] = 0;
371 public void dumpObject(SRDumpable o) throws IOException
373 ensureBufferSpace(1);
374 buffer[bufferStart++] = TYPE_OBJECT;
375 dumpInt(objectNumber(o));
376 if(o != null) {
377 builtinDumpSR(o);
381 public void specialObject(SRDumpable o) throws IOException
383 int assigned = objectNumber(o);
384 ensureBufferSpace(1);
385 buffer[bufferStart++] = TYPE_SPECIAL_OBJECT;
386 dumpInt(assigned);
387 firstUnseenObject = assigned + 1;
390 private void builtinDumpSR(SRDumpable obj) throws IOException
392 try {
393 if(dumped(obj))
394 return;
395 obj.dumpSRPartial(this);
396 endObject();
397 } catch(Throwable e) {
398 Throwable e2 = e.getCause();
399 //If the exception is something unchecked, just pass it through.
400 if(e2 instanceof RuntimeException)
401 throw (RuntimeException)e2;
402 if(e2 instanceof Error)
403 throw (Error)e2;
404 //Also pass IOException through.
405 if(e2 instanceof IOException)
406 throw (IOException)e2;
407 //What the heck is that?
408 if(e instanceof RuntimeException)
409 throw (RuntimeException)e;
410 if(e instanceof Error)
411 throw (Error)e;
412 throw new IOException("Unknown exception while invoking dumper: " + e2);
416 public int dumpedObjects()
418 return objectsCount;
421 private void addObject(Object O, int n)
423 Integer hcode = new Integer(System.identityHashCode(O));
424 ObjectListEntry e = new ObjectListEntry();
425 e.object = O;
426 e.num = n;
427 e.next = null;
428 if(!chainingLists.containsKey(hcode)) {
429 chainingLists.put(hcode, e);
430 } else {
431 e.next = chainingLists.get(hcode);
432 chainingLists.put(hcode, e);
436 private int lookupObject(Object O)
438 Integer hcode = new Integer(System.identityHashCode(O));
439 if(!chainingLists.containsKey(hcode))
440 return -1;
441 ObjectListEntry e = chainingLists.get(hcode);
442 while(e != null) {
443 if(e.object == O)
444 return e.num;
445 e = e.next;
447 return -1;
450 public int objectNumber(Object O)
452 int assignedNum;
453 boolean isNew = false;
455 if(O == null)
456 return -1;
458 assignedNum = lookupObject(O);
459 if(assignedNum == -1)
460 isNew = true;
462 if(isNew) {
463 assignedNum = nextObjectNumber++;
464 addObject(O, assignedNum);
466 return assignedNum;
469 public boolean dumped(Object O) throws IOException
471 int objn;
472 Integer obj = new Integer(objn = objectNumber(O));
474 if(objn >= firstUnseenObject) {
475 firstUnseenObject = objn + 1;
476 objectsCount++;
477 ensureBufferSpace(1);
478 buffer[bufferStart++] = TYPE_OBJECT_START;
479 dumpString(O.getClass().getName());
480 constructors.add(O.getClass().getName());
481 objectStack.push(obj);
482 return false;
483 } else {
484 ensureBufferSpace(1);
485 buffer[bufferStart++] = TYPE_OBJECT_NOT_PRESENT;
486 return true;
490 public void endObject() throws IOException
492 ensureBufferSpace(1);
493 buffer[bufferStart++] = TYPE_OBJECT_END;