Skip to content

Commit

Permalink
[JVM] Deserialize native arrays as such
Browse files Browse the repository at this point in the history
There is a long standing issue with Rakudo on the JVM backend:
If one declares a native array (like 'my int @arr;') this comes
out as a non-native array after precompilation.
(Compare rakudo/rakudo#1666.)

I think I figured out what happened: Both, native and non-native
arrays have the REPR 'VMArray'. They differ in native arrays having
a non-null REPRData in their STable. When an array is serialized, a
string representing the REPR is put into the string heap. During the
first pass of deserialization, this string is used to create a stub
object (of the given REPR). At this moment the REPRData is not yet
known -- so a plain (non-native) VMArray is created. Only during the
second pass of deserialization, the REPRData is added to the STable
(in deserialize_repr_data). But that's too late to change the object.

My patch tweaks the string that is put into the string heap, so that
the correct stub object can be created. If I'm not mistaken, this fake
REPR name isn't used in another place and it is corrected during the
first pass of deserialization. This doesn't feel clean, but it seems
to work.
  • Loading branch information
usev6 committed May 8, 2021
1 parent 05b06f9 commit f3dc977
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 2 deletions.
9 changes: 9 additions & 0 deletions src/vm/jvm/runtime/org/raku/nqp/sixmodel/REPRRegistry.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,15 @@ private static void addREPR(String name, REPR REPR) {
addREPR("P6opaque", new P6Opaque());
addREPR("VMHash", new VMHash());
addREPR("VMArray", new VMArray());
addREPR("VMArray_i8", new VMArray());
addREPR("VMArray_u8", new VMArray());
addREPR("VMArray_i16", new VMArray());
addREPR("VMArray_u16", new VMArray());
addREPR("VMArray_i32", new VMArray());
addREPR("VMArray_u32", new VMArray());
addREPR("VMArray_i", new VMArray());
addREPR("VMArray_n", new VMArray());
addREPR("VMArray_s", new VMArray());
addREPR("VMIter", new VMIter());
addREPR("P6str", new P6str());
addREPR("P6int", new P6int());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import org.raku.nqp.sixmodel.reprs.CallCapture;
import org.raku.nqp.sixmodel.reprs.IOHandle;
import org.raku.nqp.sixmodel.reprs.MultiCache;
import org.raku.nqp.sixmodel.reprs.VMArrayREPRData;

public class SerializationWriter {
/* The current version of the serialization format. */
Expand Down Expand Up @@ -549,7 +550,45 @@ private void serializeStable(STable st) {
growToHold(STABLES, STABLES_TABLE_ENTRY_SIZE);

/* Make STables table entry. */
outputs[STABLES].putInt(addStringToHeap(st.REPR.name));
if (st.REPRData instanceof VMArrayREPRData) {
/* Workaround for native arrays. If they end up as VMArray in the
* string heap, a plain VMArray will be created in deserialize_stub.
* So we cheat and add a suffix to the real REPR name. */
String reprNameForSerialization;
StorageSpec ss = ((VMArrayREPRData)st.REPRData).ss;
switch (ss.boxed_primitive) {
case StorageSpec.BP_INT:
if (ss.bits == 64)
reprNameForSerialization = "VMArray_i";
else if (ss.bits == 8)
reprNameForSerialization = ss.is_unsigned == 0
? "VMArray_i8"
: "VMArray_u8";
else if (ss.bits == 16)
reprNameForSerialization = ss.is_unsigned == 0
? "VMArray_i16"
: "VMArray_u16";
else if (ss.bits == 32)
reprNameForSerialization = ss.is_unsigned == 0
? "VMArray_i32"
: "VMArray_u32";
else
reprNameForSerialization = "VMArray_i";
break;
case StorageSpec.BP_NUM:
reprNameForSerialization = "VMArray_n";
break;
case StorageSpec.BP_STR:
reprNameForSerialization = "VMArray_s";
break;
default:
throw ExceptionHandling.dieInternal(tc, "Invalid REPR data for VMArray");
}
outputs[STABLES].putInt(addStringToHeap(reprNameForSerialization));
}
else {
outputs[STABLES].putInt(addStringToHeap(st.REPR.name));
}
outputs[STABLES].putInt(outputs[STABLE_DATA].position());

/* Make sure we're going to write to the correct place. */
Expand Down
38 changes: 37 additions & 1 deletion src/vm/jvm/runtime/org/raku/nqp/sixmodel/reprs/VMArray.java
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,43 @@ public void compose(ThreadContext tc, STable st, SixModelObject repr_info) {
public SixModelObject deserialize_stub(ThreadContext tc, STable st) {
SixModelObject obj;
if (st.REPRData == null) {
obj = new VMArrayInstance();
// Either a real VMArray or REPRData not yet known.
switch (st.REPR.name) {
case "VMArray":
obj = new VMArrayInstance();
break;
case "VMArray_i8":
obj = new VMArrayInstance_i8();
break;
case "VMArray_u8":
obj = new VMArrayInstance_u8();
break;
case "VMArray_i16":
obj = new VMArrayInstance_i16();
break;
case "VMArray_u16":
obj = new VMArrayInstance_u16();
break;
case "VMArray_i32":
obj = new VMArrayInstance_i32();
break;
case "VMArray_u32":
obj = new VMArrayInstance_u32();
break;
case "VMArray_i":
obj = new VMArrayInstance_i();
break;
case "VMArray_n":
obj = new VMArrayInstance_n();
break;
case "VMArray_s":
obj = new VMArrayInstance_s();
break;
default:
throw ExceptionHandling.dieInternal(tc, "Invalid REPR name for VMArray");
}
// Set real REPR name (we cheated during serialization).
st.REPR.name = "VMArray";
}
else {
StorageSpec ss = ((VMArrayREPRData)st.REPRData).ss;
Expand Down

0 comments on commit f3dc977

Please sign in to comment.