Skip to content

Commit 06ae7d2

Browse files
committed
[js] Progress on serializing P6opaque and object references.
1 parent bd77bf7 commit 06ae7d2

File tree

4 files changed

+257
-3
lines changed

4 files changed

+257
-3
lines changed

src/vm/js/nqp-runtime/deserialization.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,8 +232,7 @@ BinaryCursor.prototype.varint = function() {
232232

233233
/** Read a variant reference */
234234
BinaryCursor.prototype.variant = function() {
235-
var type = this.buffer.readInt8(this.offset);
236-
this.offset += 1;
235+
var type = this.I8();
237236
switch (type) {
238237
case 2:
239238
return this.objRef();
@@ -619,6 +618,12 @@ BinaryCursor.prototype.U32 = function() {
619618
return ret;
620619
};
621620

621+
BinaryCursor.prototype.I8 = function() {
622+
var ret = this.buffer.readInt8(this.offset);
623+
this.offset += 1;
624+
return ret;
625+
};
626+
622627

623628
function int64(high, low) {
624629
return new Int64(high, low).toNumber();

src/vm/js/nqp-runtime/reprs.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,17 @@ P6opaque.prototype.deserialize_repr_data = function(cursor, STable) {
140140
P6opaque.prototype.deserialize_finish = function(object, data) {
141141
var attrs = [];
142142

143+
var names = {};
144+
145+
for (var i in this.name_to_index_mapping) {
146+
for (var j in this.name_to_index_mapping[i].slots) {
147+
var name = this.name_to_index_mapping[i].names[j];
148+
var slot = this.name_to_index_mapping[i].slots[j];
149+
// TODO take class key into account with attribute storage
150+
names[slot] = name;
151+
}
152+
}
153+
143154
for (var i = 0; i < this.flattened_stables.length; i++) {
144155
if (this.flattened_stables[i]) {
145156
var STable = this.flattened_stables[i];
@@ -151,6 +162,7 @@ P6opaque.prototype.deserialize_finish = function(object, data) {
151162
attrs.push(data.variant());
152163
}
153164
}
165+
154166
for (var i in this.name_to_index_mapping) {
155167
for (var j in this.name_to_index_mapping[i].slots) {
156168
var name = this.name_to_index_mapping[i].names[j];
@@ -161,6 +173,41 @@ P6opaque.prototype.deserialize_finish = function(object, data) {
161173
}
162174
};
163175

176+
P6opaque.prototype.serialize = function(cursor, obj) {
177+
var flattened = obj._STable.REPR.flattened_stables;
178+
var nqp = require('nqp-runtime');
179+
if (!flattened) {
180+
throw 'Representation must be composed before it can be serialized';
181+
}
182+
183+
var attrs = [];
184+
185+
var names = [];
186+
187+
for (var i in this.name_to_index_mapping) {
188+
for (var j in this.name_to_index_mapping[i].slots) {
189+
var name = this.name_to_index_mapping[i].names[j];
190+
var slot = this.name_to_index_mapping[i].slots[j];
191+
192+
// TODO take class key into account with attribute storage
193+
attrs[slot] = obj[name];
194+
names[slot] = name;
195+
}
196+
}
197+
198+
for (var i = 0; i < flattened.length; i++) {
199+
if (flattened[i] == null || !flattened[i]) {
200+
// TODO - think about what happens when we get an undefined value here
201+
cursor.ref(attrs[i]);
202+
}
203+
else {
204+
// HACK different kinds of numbers etc.
205+
var attr = typeof attrs[i] == 'object' ? attrs[i] : {value: attrs[i]}; // HACK - think if that's a correct way of serializing a native attribute
206+
this.flattened_stables[i].REPR.serialize(cursor, attr);
207+
}
208+
}
209+
};
210+
164211
P6opaque.prototype.type_object_for = basic_type_object_for;
165212

166213

src/vm/js/nqp-runtime/runtime.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,12 @@ exports.to_str = function(arg, ctx) {
8181
return "";
8282
} else if (arg.Str) {
8383
return arg.Str(ctx);
84+
} else if (arg.$$get_str) {
85+
return arg.$$get_str();
86+
} else if (arg.$$get_num) {
87+
return arg.$$get_num().toString();
88+
} else if (arg.$$get_int) {
89+
return arg.$$get_int().toString();
8490
} else {
8591
console.log(arg);
8692
throw "Can't convert to str";
@@ -100,6 +106,10 @@ exports.to_num = function(arg, ctx) {
100106
return 0;
101107
} else if (arg.Num) {
102108
return arg.Num(ctx);
109+
} else if (arg.$$get_num) {
110+
return arg.$$get_num();
111+
} else if (arg.$$get_int) {
112+
return arg.$$get_int();
103113
} else {
104114
console.log(arg);
105115
throw "Can't convert to num";

src/vm/js/nqp-runtime/serialization.js

Lines changed: 193 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
var Hash = require('./hash.js');
2+
var CodeRef = require('./code-ref.js');
13

24
var op = {};
35
exports.op = op;
@@ -11,6 +13,20 @@ var OBJECTS_TABLE_ENTRY_SC_SHIFT = 20;
1113
var OBJECTS_TABLE_ENTRY_SC_OVERFLOW = 0x7FF;
1214
var OBJECTS_TABLE_ENTRY_IS_CONCRETE = 0x80000000;
1315

16+
/* Possible reference types we can serialize. */
17+
var REFVAR_NULL = 1;
18+
var REFVAR_OBJECT = 2;
19+
var REFVAR_VM_NULL = 3;
20+
var REFVAR_VM_INT = 4;
21+
var REFVAR_VM_NUM = 5;
22+
var REFVAR_VM_STR = 6;
23+
var REFVAR_VM_ARR_VAR = 7;
24+
var REFVAR_VM_ARR_STR = 8;
25+
var REFVAR_VM_ARR_INT = 9;
26+
var REFVAR_VM_HASH_STR_VAR = 10;
27+
var REFVAR_STATIC_CODEREF = 11;
28+
var REFVAR_CLONED_CODEREF = 12;
29+
1430
function BinaryWriteCursor(writer) {
1531
this.buffer = new Buffer(1024);
1632
this.writer = writer;
@@ -78,7 +94,7 @@ BinaryWriteCursor.prototype.varint = function(value) {
7894
|| (nybble >> 3) == ~0);
7995

8096
this.I8((rest << 4) | (nybble & 0xF));
81-
console.log("TODO - writing varints that take 2-8 bytes");
97+
console.log("TODO - writing varints that take 2-8 bytes", value, storage_needed);
8298
//memcpy(buffer + offset, &value, rest);
8399
}
84100
};
@@ -175,6 +191,182 @@ SerializationWriter.prototype.serializeObject = function(obj) {
175191
this.objects.I32(obj._type_object ? 0 : 1);*/
176192
};
177193

194+
var PACKED_SC_IDX_MASK = 0x000FFFFF;
195+
var PACKED_SC_MAX = 0xFFE;
196+
var PACKED_SC_IDX_MAX = 0x000FFFFF;
197+
var PACKED_SC_SHIFT = 20;
198+
var PACKED_SC_OVERFLOW = 0xFFF;
199+
200+
/* Writes the ID, index pair that identifies an entry in a Serialization
201+
context. */
202+
BinaryWriteCursor.prototype.idIdx = function(sc_id, idx) {
203+
//static void write_sc_id_idx(MVMThreadContext *tc, MVMSerializationWriter *writer, MVMint32 sc_id, MVMint32 idx) {
204+
if (sc_id <= PACKED_SC_MAX && idx <= PACKED_SC_IDX_MAX) {
205+
var packed = (sc_id << PACKED_SC_SHIFT) | (idx & PACKED_SC_IDX_MASK);
206+
this.I32(packed);
207+
} else {
208+
var packed = PACKED_SC_OVERFLOW << PACKED_SC_SHIFT;
209+
210+
this.I32(packed);
211+
this.I32(sc_id);
212+
this.I32(idx);
213+
/*write_int32(*(writer->cur_write_buffer), *(writer->cur_write_offset), packed);
214+
write_int32(*(writer->cur_write_buffer), *(writer->cur_write_offset), sc_id);
215+
write_int32(*(writer->cur_write_buffer), *(writer->cur_write_offset), idx);*/
216+
}
217+
}
218+
219+
BinaryWriteCursor.prototype.objRef = function(ref) {
220+
var writer_sc = this.writer.sc;
221+
if (!ref._STable) {
222+
console.log(ref);
223+
console.trace("can't serialize this for sure");
224+
console.log(typeof ref);
225+
console.log(ref.code_ref);
226+
process.exit();
227+
}
228+
if (!ref._SC) {
229+
/* This object doesn't belong to an SC yet, so it must be serialized
230+
* as part of this compilation unit. Add it to the work list. */
231+
ref._SC = 123;
232+
ref._SC = writer_sc;
233+
234+
this.writer.sc.root_objects.push(ref);
235+
}
236+
237+
var sc = ref._SC;
238+
if (!sc) {
239+
console.log('!sc', !ref._SC, ref._SC);
240+
console.trace('!sc');
241+
//process.exit();
242+
}
243+
/* Write SC index, then object index. */
244+
this.idIdx(this.writer.getSCId(sc), sc.root_objects.indexOf(ref));
245+
};
246+
247+
BinaryWriteCursor.prototype.ref = function(ref) {
248+
/* Work out what kind of thing we have and determine the discriminator. */
249+
// cnsole.log('got to ref',value);
250+
var discrim = 0;
251+
252+
if (ref == null) {
253+
discrim = REFVAR_VM_NULL;
254+
}
255+
// else if (ref.st.REPR instanceof IOHandle) {
256+
// /* Can't serialize handles. */
257+
// discrim = REFVAR_VM_NULL;
258+
// }
259+
// else if (ref.st.REPR instanceof CallCapture) {
260+
// /* This is a hack for Rakudo's sake; it keeps a CallCapture around in
261+
// * the lexpad, for no really good reason. */
262+
// discrim = REFVAR_VM_NULL;
263+
// }
264+
// else if (ref.st.REPR instanceof MultiCache) {
265+
// /* These are re-computed each time. */
266+
// discrim = REFVAR_VM_NULL;
267+
// }
268+
// else if (ref.st.WHAT == tc.gc.BOOTInt) {
269+
// discrim = REFVAR_VM_INT;
270+
// }
271+
else if (typeof ref == 'number') {
272+
discrim = REFVAR_VM_NUM;
273+
}
274+
else if (typeof ref == 'string') {
275+
discrim = REFVAR_VM_STR;
276+
}
277+
else if (ref instanceof Array) {
278+
discrim = REFVAR_VM_ARR_VAR;
279+
}
280+
// else if (ref.st.WHAT == tc.gc.BOOTIntArray) {
281+
// discrim = REFVAR_VM_ARR_INT;
282+
// }
283+
// else if (ref.st.WHAT == tc.gc.BOOTStrArray) {
284+
// discrim = REFVAR_VM_ARR_STR;
285+
// }
286+
else if (ref instanceof Hash) {
287+
discrim = REFVAR_VM_HASH_STR_VAR;
288+
}
289+
else if (ref instanceof CodeRef || typeof ref == 'function') {
290+
// console.log("serializing code ref");
291+
discrim = REFVAR_VM_NULL;
292+
if (ref._SC && ref.isStaticCodeRef) {
293+
/* Static code reference. */
294+
discrim = REFVAR_STATIC_CODEREF;
295+
}
296+
else if (ref._SC) {
297+
/* Closure, but already seen and serialization already handled. */
298+
discrim = REFVAR_CLONED_CODEREF;
299+
}
300+
else {
301+
/* Closure but didn't see it yet. Take care of it serialization, which
302+
* gets it marked with this SC. Then it's just a normal code ref that
303+
* needs serializing. */
304+
this.writer.serializeClosure(ref);
305+
discrim = REFVAR_CLONED_CODEREF;
306+
}
307+
}
308+
else {
309+
/* Just a normal object, with no special serialization needs. */
310+
discrim = REFVAR_OBJECT;
311+
}
312+
313+
314+
this.I8(discrim);
315+
316+
/* Now take appropriate action. */
317+
switch (discrim) {
318+
case REFVAR_NULL:
319+
case REFVAR_VM_NULL:
320+
/* Nothing to do for these. */
321+
break;
322+
case REFVAR_OBJECT:
323+
this.objRef(ref);
324+
break;
325+
case REFVAR_VM_INT:
326+
this.I64(ref);
327+
break;
328+
case REFVAR_VM_NUM:
329+
this.double(ref);
330+
// writeNum(ref.get_num(tc));
331+
break;
332+
case REFVAR_VM_STR:
333+
this.str(ref);
334+
break;
335+
// case REFVAR_VM_ARR_INT:
336+
// case REFVAR_VM_ARR_STR:
337+
// ref.st.REPR.serialize(tc, this, ref);
338+
case REFVAR_VM_ARR_VAR:
339+
this.I32(ref.length);
340+
for (var i = 0; i < ref.length; i++) {
341+
this.ref(ref[i]);
342+
}
343+
break;
344+
case REFVAR_VM_HASH_STR_VAR:
345+
var count = 0;
346+
for (var key in ref) {
347+
count++;
348+
}
349+
this.I32(count);
350+
for (var key in ref) {
351+
if (key === undefined) {
352+
console.log(ref);
353+
}
354+
this.string(key);
355+
this.ref(ref[key]);
356+
}
357+
break;
358+
case REFVAR_STATIC_CODEREF:
359+
case REFVAR_CLONED_CODEREF:
360+
var scId = this.writer.getSCId(ref._SC);
361+
var idx = ref._SC.root_codes.indexOf(ref);
362+
this.I32(scId);
363+
this.I32(idx);
364+
break;
365+
default:
366+
throw 'Serialization Error: Unimplemented object type: ' + discrim;
367+
}
368+
};
369+
178370
/* This is the overall serialization loop. It keeps an index into the list of
179371
* STables and objects in the SC. As we discover new ones, they get added. We
180372
* finished when we've serialized everything. */

0 commit comments

Comments
 (0)