1
package org.perl6.nqp.sixmodel;
3
import java.nio.ByteBuffer;
4
import java.nio.ByteOrder;
5
import java.util.ArrayList;
6
import java.util.HashMap;
10
import org.perl6.nqp.runtime.Base64;
11
import org.perl6.nqp.runtime.CallFrame;
12
import org.perl6.nqp.runtime.CodeRef;
13
import org.perl6.nqp.runtime.ExceptionHandling;
14
import org.perl6.nqp.runtime.ThreadContext;
15
import org.perl6.nqp.sixmodel.reprs.CallCapture;
16
import org.perl6.nqp.sixmodel.reprs.IOHandle;
17
import org.perl6.nqp.sixmodel.reprs.MultiCache;
19
public class SerializationWriter {
20
/* The current version of the serialization format. */
21
private final int CURRENT_VERSION = 8;
23
/* Various sizes (in bytes). */
24
private final int HEADER_SIZE = 4 * 16;
25
private final int STABLES_TABLE_ENTRY_SIZE = 12;
26
private final int OBJECTS_TABLE_ENTRY_SIZE = 16;
27
private final int CLOSURES_TABLE_ENTRY_SIZE = 24;
28
private final int CONTEXTS_TABLE_ENTRY_SIZE = 16;
29
private final int REPOS_TABLE_ENTRY_SIZE = 16;
31
/* Possible reference types we can serialize. */
32
private final short REFVAR_NULL = 1;
33
private final short REFVAR_OBJECT = 2;
34
private final short REFVAR_VM_NULL = 3;
35
private final short REFVAR_VM_INT = 4;
36
private final short REFVAR_VM_NUM = 5;
37
private final short REFVAR_VM_STR = 6;
38
private final short REFVAR_VM_ARR_VAR = 7;
39
private final short REFVAR_VM_ARR_STR = 8;
40
private final short REFVAR_VM_ARR_INT = 9;
41
private final short REFVAR_VM_HASH_STR_VAR = 10;
42
private final short REFVAR_STATIC_CODEREF = 11;
43
private final short REFVAR_CLONED_CODEREF = 12;
45
private ThreadContext tc;
46
private SerializationContext sc;
47
private ArrayList<String> sh;
48
private HashMap<String, Integer> stringMap;
50
private ArrayList<SerializationContext> dependentSCs;
51
private ArrayList<CallFrame> contexts;
53
private static final int DEPS = 0;
54
private static final int STABLES = 1;
55
private static final int STABLE_DATA = 2;
56
private static final int OBJECTS = 3;
57
private static final int OBJECT_DATA = 4;
58
private static final int CLOSURES = 5;
59
private static final int CONTEXTS = 6;
60
private static final int CONTEXT_DATA = 7;
61
private static final int REPOS = 8;
62
private ByteBuffer[] outputs;
63
private int currentBuffer;
65
private int numClosures;
66
private int sTablesListPos;
67
private int objectsListPos;
68
private int contextsListPos;
70
public SerializationWriter(ThreadContext tc, SerializationContext sc, ArrayList<String> sh) {
74
this.stringMap = new HashMap<String, Integer>();
75
this.dependentSCs = new ArrayList<SerializationContext>();
76
this.contexts = new ArrayList<CallFrame>();
77
this.outputs = new ByteBuffer[9];
78
this.outputs[DEPS] = ByteBuffer.allocate(128);
79
this.outputs[STABLES] = ByteBuffer.allocate(512);
80
this.outputs[STABLE_DATA] = ByteBuffer.allocate(1024);
81
this.outputs[OBJECTS] = ByteBuffer.allocate(2048);
82
this.outputs[OBJECT_DATA] = ByteBuffer.allocate(8912);
83
this.outputs[CLOSURES] = ByteBuffer.allocate(128);
84
this.outputs[CONTEXTS] = ByteBuffer.allocate(128);
85
this.outputs[CONTEXT_DATA] = ByteBuffer.allocate(1024);
86
this.outputs[REPOS] = ByteBuffer.allocate(64);
87
this.outputs[DEPS].order(ByteOrder.LITTLE_ENDIAN);
88
this.outputs[STABLES].order(ByteOrder.LITTLE_ENDIAN);
89
this.outputs[STABLE_DATA].order(ByteOrder.LITTLE_ENDIAN);
90
this.outputs[OBJECTS].order(ByteOrder.LITTLE_ENDIAN);
91
this.outputs[OBJECT_DATA].order(ByteOrder.LITTLE_ENDIAN);
92
this.outputs[CLOSURES].order(ByteOrder.LITTLE_ENDIAN);
93
this.outputs[CONTEXTS].order(ByteOrder.LITTLE_ENDIAN);
94
this.outputs[CONTEXT_DATA].order(ByteOrder.LITTLE_ENDIAN);
95
this.outputs[REPOS].order(ByteOrder.LITTLE_ENDIAN);
96
this.currentBuffer = 0;
98
this.sTablesListPos = 0;
99
this.objectsListPos = 0;
100
this.contextsListPos = 0;
103
public String serialize() {
104
/* Initialize string heap so first entry is the NULL string. */
107
/* Start serializing. */
110
/* Build a single result string out of the serialized data. */
111
return concatenateOutputs();
114
private int addStringToHeap(String s) {
115
/* We ensured that the first entry in the heap represents the null string,
116
* so can just hand back 0 here. */
120
/* Did we already see it? */
121
Integer idx = stringMap.get(s);
125
/* Otherwise, need to add it to the heap. */
126
int newIdx = sh.size();
128
stringMap.put(s, newIdx);
132
/* Gets the ID of a serialization context. Returns 0 if it's the current
133
* one, or its dependency table offset (base-1) otherwise. Note that if
134
* it is not yet in the dependency table, it will be added. */
135
private int getSCId(SerializationContext sc) {
136
/* Easy if it's in the current SC. */
140
/* If not, try to find it in our dependencies list. */
141
int found = dependentSCs.indexOf(sc);
145
/* Otherwise, need to add it to our dependencies list. */
146
dependentSCs.add(sc);
148
outputs[DEPS].putInt(addStringToHeap(sc.handle));
149
outputs[DEPS].putInt(addStringToHeap(sc.description));
150
return dependentSCs.size(); /* Deliberately index + 1. */
153
/* Takes an STable. If it's already in an SC, returns information on how
154
* to reference it. Otherwise, adds it to the current SC, effectively
155
* placing it onto the work list. */
156
private int[] getSTableRefInfo(STable st) {
157
/* Add to this SC if needed. */
160
this.sc.root_stables.add(st);
163
/* Work out SC reference. */
164
int[] result = new int[2];
165
result[0] = getSCId(st.sc);
166
result[1] = st.sc.root_stables.indexOf(st);
170
/* Writing function for native integers. */
171
public void writeInt(long value) {
172
this.growToHold(currentBuffer, 8);
173
outputs[currentBuffer].putLong(value);
176
/* Writing function for 32-bit native integers. */
177
public void writeInt32(int value) {
178
this.growToHold(currentBuffer, 4);
179
outputs[currentBuffer].putInt(value);
182
/* Writing function for native numbers. */
183
public void writeNum(double value) {
184
this.growToHold(currentBuffer, 8);
185
outputs[currentBuffer].putDouble(value);
188
/* Writing function for native strings. */
189
public void writeStr(String value) {
190
int heapLoc = addStringToHeap(value);
191
this.growToHold(currentBuffer, 4);
192
outputs[currentBuffer].putInt(heapLoc);
195
/* Writes an object reference. */
196
public void writeObjRef(SixModelObject ref) {
197
if (ref.sc == null) {
198
/* This object doesn't belong to an SC yet, so it must be serialized as part of
199
* this compilation unit. Add it to the work list. */
201
this.sc.root_objects.add(ref);
204
/* Write SC index, then object index. */
205
this.growToHold(currentBuffer, 8);
206
outputs[currentBuffer].putInt(getSCId(ref.sc));
207
outputs[currentBuffer].putInt(ref.sc.root_objects.indexOf(ref));
210
public void writeList(List<SixModelObject> list) {
211
growToHold(currentBuffer, 6);
212
outputs[currentBuffer].putShort(REFVAR_VM_ARR_VAR);
213
outputs[currentBuffer].putInt(list.size());
214
for (SixModelObject item : list)
218
public void writeHash(Map<String, SixModelObject> hash) {
219
growToHold(currentBuffer, 6);
220
outputs[currentBuffer].putShort(REFVAR_VM_HASH_STR_VAR);
221
outputs[currentBuffer].putInt(hash.size());
222
for (String key : hash.keySet()) {
224
writeRef(hash.get(key));
228
public void writeIntHash(HashMap<String, Integer> hash) {
229
growToHold(currentBuffer, 6);
230
outputs[currentBuffer].putShort(REFVAR_VM_HASH_STR_VAR);
231
outputs[currentBuffer].putInt(hash.size());
232
for (String key : hash.keySet()) {
234
growToHold(currentBuffer, 10);
235
outputs[currentBuffer].putShort(REFVAR_VM_INT);
236
outputs[currentBuffer].putLong((int)hash.get(key));
240
private void writeCodeRef(SixModelObject ref) {
241
SerializationContext codeSC = ref.sc;
242
int scId = getSCId(codeSC);
243
int idx = codeSC.root_codes.indexOf(ref);
244
growToHold(currentBuffer, 8);
245
outputs[currentBuffer].putInt(scId);
246
outputs[currentBuffer].putInt(idx);
249
/* Writing function for references to things. */
250
public void writeRef(SixModelObject ref) {
251
/* Work out what kind of thing we have and determine the discriminator. */
254
discrim = REFVAR_VM_NULL;
256
else if (ref.st.REPR instanceof IOHandle) {
257
/* Can't serialize handles. */
258
discrim = REFVAR_VM_NULL;
260
else if (ref.st.REPR instanceof CallCapture) {
261
/* This is a hack for Rakudo's sake; it keeps a CallCapture around in
262
* the lexpad, for no really good reason. */
263
discrim = REFVAR_VM_NULL;
265
else if (ref.st.REPR instanceof MultiCache) {
266
/* These are re-computed each time. */
267
discrim = REFVAR_VM_NULL;
269
else if (ref.st.WHAT == tc.gc.BOOTInt) {
270
discrim = REFVAR_VM_INT;
272
else if (ref.st.WHAT == tc.gc.BOOTNum) {
273
discrim = REFVAR_VM_NUM;
275
else if (ref.st.WHAT == tc.gc.BOOTStr) {
276
discrim = REFVAR_VM_STR;
278
else if (ref.st.WHAT == tc.gc.BOOTArray) {
279
discrim = REFVAR_VM_ARR_VAR;
281
else if (ref.st.WHAT == tc.gc.BOOTIntArray) {
282
discrim = REFVAR_VM_ARR_INT;
284
else if (ref.st.WHAT == tc.gc.BOOTStrArray) {
285
discrim = REFVAR_VM_ARR_STR;
287
else if (ref.st.WHAT == tc.gc.BOOTHash) {
288
discrim = REFVAR_VM_HASH_STR_VAR;
290
else if (ref instanceof CodeRef) {
291
if (ref.sc != null && ((CodeRef)ref).isStaticCodeRef) {
292
/* Static code reference. */
293
discrim = REFVAR_STATIC_CODEREF;
295
else if (ref.sc != null) {
296
/* Closure, but already seen and serialization already handled. */
297
discrim = REFVAR_CLONED_CODEREF;
300
/* Closure but didn't see it yet. Take care of it serialization, which
301
* gets it marked with this SC. Then it's just a normal code ref that
302
* needs serializing. */
303
serializeClosure((CodeRef)ref);
304
discrim = REFVAR_CLONED_CODEREF;
308
/* Just a normal object, with no special serialization needs. */
309
discrim = REFVAR_OBJECT;
312
/* Write the discriminator. */
313
growToHold(currentBuffer, 2);
314
outputs[currentBuffer].putShort(discrim);
316
/* Now take appropriate action. */
320
/* Nothing to do for these. */
326
writeInt(ref.get_int(tc));
329
writeNum(ref.get_num(tc));
332
writeStr(ref.get_str(tc));
334
case REFVAR_VM_ARR_VAR:
335
case REFVAR_VM_ARR_INT:
336
case REFVAR_VM_ARR_STR:
337
case REFVAR_VM_HASH_STR_VAR:
338
/* These all delegate to the REPR. */
339
ref.st.REPR.serialize(tc, this, ref);
341
case REFVAR_STATIC_CODEREF:
342
case REFVAR_CLONED_CODEREF:
346
throw new RuntimeException("Serialization Error: Unimplemented object type writeRef");
350
/* Writing function for references to STables. */
351
public void writeSTableRef(STable st) {
352
int[] idxs = getSTableRefInfo(st);
353
growToHold(currentBuffer, 8);
354
outputs[currentBuffer].putInt(idxs[0]);
355
outputs[currentBuffer].putInt(idxs[1]);
358
/* Concatenates the various output segments into a single binary string. */
359
private String concatenateOutputs() {
363
/* Calculate total size. */
364
output_size += HEADER_SIZE;
365
output_size += outputs[DEPS].position();
366
output_size += outputs[STABLES].position();
367
output_size += outputs[STABLE_DATA].position();
368
output_size += outputs[OBJECTS].position();
369
output_size += outputs[OBJECT_DATA].position();
370
output_size += outputs[CLOSURES].position();
371
output_size += outputs[CONTEXTS].position();
372
output_size += outputs[CONTEXT_DATA].position();
373
output_size += outputs[REPOS].position();
375
/* Allocate a buffer that size. */
376
ByteBuffer output = ByteBuffer.allocate(output_size);
377
output.order(ByteOrder.LITTLE_ENDIAN);
379
/* Write version into header. */
380
output.putInt(CURRENT_VERSION);
381
offset += HEADER_SIZE;
383
/* Put dependencies table in place and set location/rows in header. */
384
output.putInt(offset);
385
output.putInt(this.dependentSCs.size());
386
output.position(offset);
387
output.put(usedBytes(outputs[DEPS]));
388
offset += outputs[DEPS].position();
390
/* Put STables table in place, and set location/rows in header. */
392
output.putInt(offset);
393
output.putInt(this.sc.root_stables.size());
394
output.position(offset);
395
output.put(usedBytes(outputs[STABLES]));
396
offset += outputs[STABLES].position();
398
/* Put STables data in place. */
400
output.putInt(offset);
401
output.position(offset);
402
output.put(usedBytes(outputs[STABLE_DATA]));
403
offset += outputs[STABLE_DATA].position();
405
/* Put objects table in place, and set location/rows in header. */
407
output.putInt(offset);
408
output.putInt(this.sc.root_objects.size());
409
output.position(offset);
410
output.put(usedBytes(outputs[OBJECTS]));
411
offset += outputs[OBJECTS].position();
413
/* Put objects data in place. */
415
output.putInt(offset);
416
output.position(offset);
417
output.put(usedBytes(outputs[OBJECT_DATA]));
418
offset += outputs[OBJECT_DATA].position();
420
/* Put closures table in place, and set location/rows in header. */
422
output.putInt(offset);
423
output.putInt(this.numClosures);
424
output.position(offset);
425
output.put(usedBytes(outputs[CLOSURES]));
426
offset += outputs[CLOSURES].position();
428
/* Put contexts table in place, and set location/rows in header. */
430
output.putInt(offset);
431
output.putInt(this.contexts.size());
432
output.position(offset);
433
output.put(usedBytes(outputs[CONTEXTS]));
434
offset += outputs[CONTEXTS].position();
436
/* Put contexts data in place. */
438
output.putInt(offset);
439
output.position(offset);
440
output.put(usedBytes(outputs[CONTEXT_DATA]));
441
offset += outputs[CONTEXT_DATA].position();
443
/* Put repossessions table in place, and set location/rows in header. */
445
output.putInt(offset);
446
output.putInt(this.sc.rep_scs.size());
447
output.position(offset);
448
output.put(usedBytes(outputs[REPOS]));
449
offset += outputs[REPOS].position();
452
if (offset != output_size)
453
throw new RuntimeException("Serialization sanity check failed: offset != output_size");
455
/* Base 64 encode and return. */
456
return Base64.encode(output);
459
/* Grabs an array of the bytes actually populated in the specified buffer. */
460
private byte[] usedBytes(ByteBuffer bb) {
461
byte[] result = new byte[bb.position()];
464
bb.position(result.length);
468
/* This handles the serialization of an object, which largely involves a
469
* delegation to its representation. */
470
private void serializeObject(SixModelObject obj) {
471
/* Get index of SC that holds the STable and its index. */
472
int[] ref = getSTableRefInfo(obj.st);
476
/* Ensure there's space in the objects table; grow if not. */
477
growToHold(OBJECTS, OBJECTS_TABLE_ENTRY_SIZE);
479
/* Make objects table entry. */
480
outputs[OBJECTS].putInt(sc);
481
outputs[OBJECTS].putInt(sc_idx);
482
outputs[OBJECTS].putInt(outputs[OBJECT_DATA].position());
483
outputs[OBJECTS].putInt(obj instanceof TypeObject ? 0 : 1);
485
/* Make sure we're going to write to the correct place. */
486
currentBuffer = OBJECT_DATA;
488
/* Delegate to its serialization REPR function. */
489
if (!(obj instanceof TypeObject))
490
obj.st.REPR.serialize(tc, this, obj);
493
private void serializeStable(STable st) {
494
/* Ensure there's space in the STables table. */
495
growToHold(STABLES, STABLES_TABLE_ENTRY_SIZE);
497
/* Make STables table entry. */
498
outputs[STABLES].putInt(addStringToHeap(st.REPR.name));
499
outputs[STABLES].putInt(outputs[STABLE_DATA].position());
501
/* Make sure we're going to write to the correct place. */
502
currentBuffer = STABLE_DATA;
504
/* Write HOW, WHAT and WHO. */
506
writeObjRef(st.WHAT);
509
/* Method cache and v-table. */
510
growToHold(currentBuffer, 2);
511
if (st.MethodCache != null) {
512
writeHash(st.MethodCache);
515
outputs[currentBuffer].putShort(REFVAR_VM_NULL);
517
int vtl = st.VTable == null ? 0 : st.VTable.length;
519
for (int i = 0; i < vtl; i++)
520
writeRef(st.VTable[i]);
522
/* Type check cache. */
523
int tcl = st.TypeCheckCache == null ? 0 : st.TypeCheckCache.length;
525
for (int i = 0; i < tcl; i++)
526
writeRef(st.TypeCheckCache[i]);
529
writeInt(st.ModeFlags);
531
/* Boolification spec. */
532
writeInt(st.BoolificationSpec == null ? 0 : 1);
533
if (st.BoolificationSpec != null) {
534
writeInt(st.BoolificationSpec.Mode);
535
writeRef(st.BoolificationSpec.Method);
538
/* Container spec. */
539
writeInt(st.ContainerSpec == null ? 0 : 1);
540
if (st.ContainerSpec != null) {
541
writeStr(st.ContainerSpec.name());
542
st.ContainerSpec.serialize(tc, st, this);
545
/* Invocation spec. */
546
writeInt(st.InvocationSpec == null ? 0 : 1);
547
if (st.InvocationSpec != null) {
548
writeRef(st.InvocationSpec.ClassHandle);
549
writeStr(st.InvocationSpec.AttrName);
550
writeInt(st.InvocationSpec.Hint);
551
writeRef(st.InvocationSpec.InvocationHandler);
555
writeStr(st.hllOwner == null ? "" : st.hllOwner.name);
556
writeInt(st.hllRole);
558
/* Location of REPR data. */
559
outputs[STABLES].putInt(outputs[STABLE_DATA].position());
561
/* If the REPR has a function to serialize representation data, call it. */
562
st.REPR.serialize_repr_data(tc, st, this);
565
private SixModelObject closureToStaticCodeRef(CodeRef closure, boolean fatal) {
566
SixModelObject staticCode = ((CodeRef)closure).staticInfo.staticCode;
567
if (staticCode == null)
570
throw ExceptionHandling.dieInternal(tc,
571
"Serialization Error: missing static code ref for closure " +
572
((CodeRef)staticCode).name);
576
if (staticCode.sc == null) {
578
throw ExceptionHandling.dieInternal(tc,
579
"Serialization Error: could not locate static code ref for closure " +
580
((CodeRef)staticCode).name);
587
private void serializeClosure(CodeRef closure) {
588
/* Locate the static code object. */
589
SixModelObject staticCodeRef = closureToStaticCodeRef(closure, true);
590
SerializationContext staticCodeSC = staticCodeRef.sc;
592
/* Ensure there's space in the closures table; grow if not. */
593
growToHold(CLOSURES, CLOSURES_TABLE_ENTRY_SIZE);
595
/* Get the index of the context (which will add it to the todo list if
597
int contextIdx = getSerializedOuterContextIdx(closure);
599
/* Add an entry to the closures table. */
600
int staticSCId = getSCId(staticCodeSC);
601
int staticIdx = staticCodeSC.root_codes.indexOf(staticCodeRef);
602
outputs[CLOSURES].putInt(staticSCId);
603
outputs[CLOSURES].putInt(staticIdx);
604
outputs[CLOSURES].putInt(contextIdx);
606
/* Check if it has a static code object. */
607
if (closure.codeObject != null) {
608
outputs[CLOSURES].putInt(1);
609
if (closure.codeObject.sc == null) {
610
closure.codeObject.sc = this.sc;
611
this.sc.root_objects.add(closure.codeObject);
613
outputs[CLOSURES].putInt(getSCId(closure.codeObject.sc));
614
outputs[CLOSURES].putInt(closure.codeObject.sc.root_objects.indexOf(closure.codeObject));
617
outputs[CLOSURES].putInt(0);
618
outputs[CLOSURES].putInt(0); // pad
619
outputs[CLOSURES].putInt(0); // pad
622
/* Increment count of closures in the table. */
625
/* Add the closure to this SC, and mark it as as being in it. */
626
this.sc.root_codes.add((CodeRef)closure);
627
closure.sc = this.sc;
630
private int getSerializedOuterContextIdx(CodeRef closure) {
631
if (closure.isCompilerStub)
633
if (closure.outer == null)
635
return getSerializedContextIdx(closure.outer);
638
private int getSerializedContextIdx(CallFrame cf) {
640
/* Make sure we should chase a level down. */
641
if (closureToStaticCodeRef(cf.codeRef, false) == null) {
647
return contexts.size();
651
if (cf.sc != this.sc)
652
ExceptionHandling.dieInternal(tc,
653
"Serialization Error: reference to context outside of SC");
654
int idx = contexts.indexOf(cf);
656
ExceptionHandling.dieInternal(tc,
657
"Serialization Error: could not locate outer context in current SC");
662
private void serializeContext(CallFrame cf) {
663
/* Locate the static code ref this context points to. */
664
SixModelObject staticCodeRef = closureToStaticCodeRef(cf.codeRef, true);
665
SerializationContext staticCodeSC = staticCodeRef.sc;
666
if (staticCodeSC == null)
667
ExceptionHandling.dieInternal(tc,
668
"Serialization Error: closure outer is a code object not in an SC");
669
int staticSCId = getSCId(staticCodeSC);
670
int staticIdx = staticCodeSC.root_codes.indexOf(staticCodeRef);
672
/* Ensure there's space in the contexts table; grow if not. */
673
growToHold(CONTEXTS, CONTEXTS_TABLE_ENTRY_SIZE);
675
/* Make contexts table entry. */
676
outputs[CONTEXTS].putInt(staticSCId);
677
outputs[CONTEXTS].putInt(staticIdx);
678
outputs[CONTEXTS].putInt(outputs[CONTEXT_DATA].position());
680
/* See if there's any relevant outer context, and if so set it up to
682
if (cf.outer != null)
683
outputs[CONTEXTS].putInt(getSerializedContextIdx(cf.outer));
685
outputs[CONTEXTS].putInt(0);
688
currentBuffer = CONTEXT_DATA;
690
/* Serialize lexicals. */
692
numLexicals += cf.oLex == null ? 0 : cf.oLex.length;
693
numLexicals += cf.iLex == null ? 0 : cf.iLex.length;
694
numLexicals += cf.nLex == null ? 0 : cf.nLex.length;
695
numLexicals += cf.sLex == null ? 0 : cf.sLex.length;
696
writeInt(numLexicals);
697
if (cf.oLex != null) {
698
String[] names = cf.codeRef.staticInfo.oLexicalNames;
699
for (int i = 0; i < cf.oLex.length; i++) {
701
writeRef(cf.oLex[i]);
704
if (cf.iLex != null) {
705
String[] names = cf.codeRef.staticInfo.iLexicalNames;
706
for (int i = 0; i < cf.iLex.length; i++) {
708
writeInt(cf.iLex[i]);
711
if (cf.nLex != null) {
712
String[] names = cf.codeRef.staticInfo.nLexicalNames;
713
for (int i = 0; i < cf.nLex.length; i++) {
715
writeNum(cf.nLex[i]);
718
if (cf.sLex != null) {
719
String[] names = cf.codeRef.staticInfo.sLexicalNames;
720
for (int i = 0; i < cf.sLex.length; i++) {
722
writeStr(cf.sLex[i]);
727
/* Grows a buffer as needed to hold more data. */
728
private void growToHold(int idx, int required) {
729
ByteBuffer check = this.outputs[idx];
730
int position = check.position();
731
if (position + required >= check.capacity()) {
732
ByteBuffer replacement = ByteBuffer.allocate(
733
Math.max(check.capacity() * 2, position + required));
734
replacement.order(ByteOrder.LITTLE_ENDIAN);
736
replacement.put(check);
737
replacement.position(position);
738
this.outputs[idx] = replacement;
742
/* Goes through the list of repossessions and serializes them all. */
743
private void serializeRepossessions() {
744
/* Allocate table space, provided we've actually something to do. */
745
int numRepos = sc.rep_indexes.size();
748
growToHold(REPOS, numRepos * REPOS_TABLE_ENTRY_SIZE);
751
for (int i = 0; i < numRepos; i++) {
752
int objIdx = sc.rep_indexes.get(i) >> 1;
753
int isST = sc.rep_indexes.get(i) & 1;
754
SerializationContext origSC = sc.rep_scs.get(i);
756
/* Work out original object's SC location. */
757
int origSCIdx = getSCId(origSC);
758
int origIdx = isST != 0
759
? origSC.root_stables.indexOf(sc.root_stables.get(objIdx))
760
: origSC.root_objects.indexOf(sc.root_objects.get(objIdx));
762
throw new RuntimeException(
763
"Could not find object when writing repossessions; " +
766
: "REPR = " + sc.root_objects.get(objIdx).st.REPR.name));
768
/* Write table row. */
769
outputs[REPOS].putInt(isST);
770
outputs[REPOS].putInt(objIdx);
771
outputs[REPOS].putInt(origSCIdx);
772
outputs[REPOS].putInt(origIdx);
776
/* This is the overall serialization loop. It keeps an index into the list of
777
* STables and objects in the SC. As we discover new ones, they get added. We
778
* finished when we've serialized everything. */
779
private void serializationLoop() {
780
boolean workTodo = true;
782
/* Current work list sizes. */
783
int sTablesTodo = sc.root_stables.size();
784
int objectsTodo = sc.root_objects.size();
785
int contextsTodo = contexts.size();
787
/* Reset todo flag - if we do some work we'll go round again as it
788
* may have generated more. */
791
/* Serialize any STables on the todo list. */
792
while (sTablesListPos < sTablesTodo) {
793
serializeStable(sc.root_stables.get(sTablesListPos));
798
/* Serialize any objects on the todo list. */
799
while (objectsListPos < objectsTodo) {
800
serializeObject(sc.root_objects.get(objectsListPos));
805
/* Serialize any contexts on the todo list. */
806
while (contextsListPos < contextsTodo) {
807
serializeContext(contexts.get(contextsListPos));
813
/* Finally, serialize repossessions table (this can't make any more
814
* work, so is done as a separate step here at the end). */
815
serializeRepossessions();