Raku / nqp

NQP
Other
345 stars 131 forks source link

[JVM] nqp::null as value for class attribute is changed to NQPMu after serialization+deserialization #828

Open usev6 opened 4 hours ago

usev6 commented 4 hours ago

If I'm not mistaken, the following code (adjusted from t/serialization/01-basics.t shows that serialization+deserialization wrongly changes a class attributes with the value nqp::null to NQPMu on the JVM backend:

sub add_to_sc($sc, $idx, $obj) {
  nqp::scsetobj($sc, $idx, $obj);
  nqp::setobjsc($obj, $sc);
}

my $in_sc := -1;
sub fresh_in_sc() {
  $in_sc := $in_sc + 1;
  'TEST_SC_' ~ $in_sc ~ '_IN';
}

my $out_sc := -1;
sub fresh_out_sc() {
  $out_sc := $out_sc + 1;
  'TEST_SC_' ~ $out_sc ~ '_OUT';
};

my $sc := nqp::createsc(fresh_in_sc());
my $sh := nqp::list_s();
class T1 {
  has $!a;
  method new() {
    my $obj := nqp::create(self);
    $obj.BUILD();
    $obj;
  }
  method BUILD() {
    $!a := nqp::null;
  }
  method a() { $!a }
}

my $v := T1.new();
add_to_sc($sc, 0, $v);
my $serialized := nqp::serialize($sc, $sh);
my $dsc := nqp::createsc(fresh_out_sc());
nqp::deserialize($serialized, $dsc, $sh, nqp::list(), nqp::null());

nqp::say('Before serialization+deserialization');
nqp::say('$!a is nqp::null: ' ~ nqp::isnull($v.a));
nqp::say('$!a is NQPMu:     ' ~ nqp::eqaddr($v.a, NQPMu));
nqp::say('After serialization+deserialization');
nqp::say('$!a is nqp::null: ' ~ nqp::isnull(nqp::scgetobj($dsc, 0).a));
nqp::say('$!a is NQPMu:     ' ~ nqp::eqaddr(nqp::scgetobj($dsc, 0).a, NQPMu));

Running this code gives the following output: On MoarVM:

Before serialization+deserialization
$!a is nqp::null: 1
$!a is NQPMu:     0
After serialization+deserialization
$!a is nqp::null: 1
$!a is NQPMu:     0

On the JVM:

Before serialization+deserialization
$!a is nqp::null: 1
$!a is NQPMu:     0
After serialization+deserialization
$!a is nqp::null: 0
$!a is NQPMu:     1

I think that this causes different problems for Raku on the JVM backend. AFAIU compiling the setting and using it later for rakudo-j involves a serialization+deserialization cycle. (And I'm quite happy that I found a way to golf this to plain NQP code.)

At least in one case I recently added a workaround to unbreak module loading: https://github.com/rakudo/rakudo/commit/9f41d2c61a. But I noticed more problems of this type, so we really should fix the underlying problem.

I'm trying to dig into this, but at this point it seems to make sense to have an issue as a reference.

usev6 commented 4 hours ago

This is probably related to https://github.com/rakudo/rakudo/issues/1613.

usev6 commented 4 hours ago

Seems also related to https://github.com/Raku/nqp/pull/605, which introduced a VMNull for the JVM backend. Probably that needs to be added to serialization and deserialization.