Skip to content

Commit

Permalink
Fix overzealous autothreading of Junctions even on Mu parameters
Browse files Browse the repository at this point in the history
A Mu type constraint on a parameter is supposed to avoid autothreading of
junctions for that parameter. Usually this is ensured by the the dispatcher
only considering autothreading on bind failures. However when there are
multiple Junction arguments, it's possible that some should be passed through
(i.e. Mu type constraints on the parameters) and some should be autothreaded.

AUTOTHREAD did not take this into account and blindly threaded over all
Junction arguments. This led to errors when what was passed was actually a
scalar container holding a Junction and the routine wanted to assign into this
container.

Fix by checking each parameter's type before deciding to autothread. Sadly
this does not yet work for protos as auto-generated protos will report Mu as
type constraint for all parameter. But it's at least a step in the right
direction.

Adding the additional check to AUTOTHREAD required us to avoid it for method
calls on Junctions and CALL-ME as for the invocant or callee respectively we
do want to autothread, despite the permissive type constraints. Anyway, having
specialized code for those cases is better for performance anyway.
  • Loading branch information
niner authored and jnthn committed Sep 28, 2021
1 parent 605cd8e commit 61f6984
Showing 1 changed file with 31 additions and 7 deletions.
38 changes: 31 additions & 7 deletions src/core.c/Junction.pm6
Expand Up @@ -282,9 +282,16 @@ my class Junction { # declared in BOOTSTRAP
}

method CALL-ME(|c) {
self.AUTOTHREAD(
-> $obj, |c { $obj(|c) },
self, |c);
my \storage := nqp::getattr(self, Junction, '$!eigenstates');
my int $elems = nqp::elems(storage);
my \result := nqp::setelems(nqp::list, $elems);
my int $i = -1;
nqp::while(
nqp::islt_i(($i = nqp::add_i($i, 1)), $elems),
nqp::bindpos(result, $i, nqp::atpos(storage, $i)(|c))
);
nqp::p6bindattrinvres(
nqp::clone(self), Junction, '$!eigenstates', result)
}

method sink(Junction:D: --> Nil) {
Expand Down Expand Up @@ -337,10 +344,17 @@ my class Junction { # declared in BOOTSTRAP
my int $first_any_one = -1;
my int $elems = nqp::elems(positionals);
my int $i = -1;
my @params := &call.signature.params;
while nqp::islt_i(++$i,$elems) {
# Junctional positional argument?
my Mu $arg := nqp::atpos(positionals, $i);
if nqp::istype($arg,Junction) {
if nqp::istype($arg, Junction) and (
# No auto-threading for Mu or Junction parameters necessary
not nqp::istype(Junction, @params[$i].type)
# Can't handle protos yet because auto-generated protos
# will report Mu as parameter type
or &call.?is_dispatcher
) {
my str $type = nqp::getattr_s(nqp::decont($arg),Junction,'$!type');
nqp::iseq_s($type,'any') || nqp::iseq_s($type,'one')
?? $first_any_one == -1
Expand Down Expand Up @@ -542,9 +556,19 @@ nqp::p6setautothreader( -> |c {
Junction.AUTOTHREAD(|c)
} );
Mu.HOW.setup_junction_fallback(Junction, -> $name, |c {
Junction.AUTOTHREAD(
-> \obj, |c { obj."$name"(|c) },
|c);
my \positionals := nqp::getattr(nqp::decont(c), Capture, '@!list');
my \junction := nqp::decont(nqp::atpos(positionals, 0));
my \storage := nqp::getattr(junction, Junction, '$!eigenstates');
my int $elems = nqp::elems(storage);
my \result := nqp::setelems(nqp::list, $elems);
my int $i = -1;
nqp::shift(positionals); # remove Junction
nqp::while(
nqp::islt_i(($i = nqp::add_i($i, 1)), $elems),
nqp::bindpos(result, $i, nqp::atpos(storage, $i)."$name"(|c))
);
nqp::p6bindattrinvres(
nqp::clone(junction), Junction, '$!eigenstates', result)
} );

# vim: expandtab shiftwidth=4

0 comments on commit 61f6984

Please sign in to comment.