2 JPC-RR: A x86 PC Hardware Emulator
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
;
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
;
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
;
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
) {
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()];
80 if(buf2
.length
> 1024)
81 throw new IOException("Class name length of 1024 bytes exceeded");
87 static class ObjectListEntry
91 public ObjectListEntry next
;
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
);
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
>();
118 constructors
= new java
.util
.HashSet
<String
>();
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
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
;
157 public void dumpInt(int x
, boolean ensure
) throws IOException
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
;
174 public void dumpLong(long x
, boolean ensure
) throws IOException
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
;
196 public void dumpString(String x
) throws IOException
198 ensureBufferSpace(2);
199 buffer
[bufferStart
++] = TYPE_STRING
;
201 buffer
[bufferStart
++] = 1;
203 int characters
= x
.length();
204 for(int i
= 0; i
< characters
; i
++) {
205 char ch
= x
.charAt(i
);
215 dumpShort((short)bytes
, true);
216 for(int i
= 0; i
< characters
; i
++) {
217 char ch
= x
.charAt(i
);
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);
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);
237 buffer
[bufferStart
++] = 0;
240 public void dumpArray(boolean[] x
) throws IOException
242 ensureBufferSpace(2);
243 buffer
[bufferStart
++] = TYPE_BOOLEAN_ARRAY
;
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;
253 buffer
[bufferStart
++] = 0;
256 public void dumpArray(byte[] x
) throws IOException
258 ensureBufferSpace(2);
259 buffer
[bufferStart
++] = TYPE_BYTE_ARRAY
;
261 buffer
[bufferStart
++] = 1;
262 dumpInt(x
.length
, true);
263 int remaining
= x
.length
;
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
;
276 buffer
[bufferStart
++] = 0;
279 public void dumpArray(short[] x
) throws IOException
281 ensureBufferSpace(2);
282 buffer
[bufferStart
++] = TYPE_SHORT_ARRAY
;
284 buffer
[bufferStart
++] = 1;
285 dumpInt(x
.length
, true);
286 int remaining
= x
.length
;
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);
299 buffer
[bufferStart
++] = 0;
302 public void dumpArray(int[] x
) throws IOException
304 ensureBufferSpace(2);
305 buffer
[bufferStart
++] = TYPE_INT_ARRAY
;
307 buffer
[bufferStart
++] = 1;
308 dumpInt(x
.length
, true);
309 int remaining
= x
.length
;
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);
322 buffer
[bufferStart
++] = 0;
325 public void dumpArray(long[] x
) throws IOException
327 ensureBufferSpace(2);
328 buffer
[bufferStart
++] = TYPE_LONG_ARRAY
;
330 buffer
[bufferStart
++] = 1;
331 dumpInt(x
.length
, true);
332 int remaining
= x
.length
;
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);
345 buffer
[bufferStart
++] = 0;
348 public void dumpArray(double[] x
) throws IOException
350 ensureBufferSpace(2);
351 buffer
[bufferStart
++] = TYPE_DOUBLE_ARRAY
;
353 buffer
[bufferStart
++] = 1;
354 dumpInt(x
.length
, true);
355 int remaining
= x
.length
;
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);
368 buffer
[bufferStart
++] = 0;
371 public void dumpObject(SRDumpable o
) throws IOException
373 ensureBufferSpace(1);
374 buffer
[bufferStart
++] = TYPE_OBJECT
;
375 dumpInt(objectNumber(o
));
381 public void specialObject(SRDumpable o
) throws IOException
383 int assigned
= objectNumber(o
);
384 ensureBufferSpace(1);
385 buffer
[bufferStart
++] = TYPE_SPECIAL_OBJECT
;
387 firstUnseenObject
= assigned
+ 1;
390 private void builtinDumpSR(SRDumpable obj
) throws IOException
395 obj
.dumpSRPartial(this);
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
)
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
)
412 throw new IOException("Unknown exception while invoking dumper: " + e2
);
416 public int dumpedObjects()
421 private void addObject(Object O
, int n
)
423 Integer hcode
= new Integer(System
.identityHashCode(O
));
424 ObjectListEntry e
= new ObjectListEntry();
428 if(!chainingLists
.containsKey(hcode
)) {
429 chainingLists
.put(hcode
, e
);
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
))
441 ObjectListEntry e
= chainingLists
.get(hcode
);
450 public int objectNumber(Object O
)
453 boolean isNew
= false;
458 assignedNum
= lookupObject(O
);
459 if(assignedNum
== -1)
463 assignedNum
= nextObjectNumber
++;
464 addObject(O
, assignedNum
);
469 public boolean dumped(Object O
) throws IOException
472 Integer obj
= new Integer(objn
= objectNumber(O
));
474 if(objn
>= firstUnseenObject
) {
475 firstUnseenObject
= objn
+ 1;
477 ensureBufferSpace(1);
478 buffer
[bufferStart
++] = TYPE_OBJECT_START
;
479 dumpString(O
.getClass().getName());
480 constructors
.add(O
.getClass().getName());
481 objectStack
.push(obj
);
484 ensureBufferSpace(1);
485 buffer
[bufferStart
++] = TYPE_OBJECT_NOT_PRESENT
;
490 public void endObject() throws IOException
492 ensureBufferSpace(1);
493 buffer
[bufferStart
++] = TYPE_OBJECT_END
;