Skip to content

Commit

Permalink
Restructure handling of wrapping
Browse files Browse the repository at this point in the history
Previously, we would handle wrapping in `raku-invoke`. This included the
situation where a `proto` was wrapped. This resulted in:

* Wrong semantics: if we did a `callwith` in the wrapper, we failed to
  honor its change of arguments from the original ones given to the
  `proto`, which in turn meant that they weren't accounted for in the
  dispatch. (This showed up in the DateTime::Timezones module.)
* Inconsistency: a proto that would ordinarily have its invocation
  elided would be invoked if the proto was wrapped
* A slight slowdown, for the same reason

Now we handle it at the point we call a routine. This simplifies things
a bit in `raku-invoke-wrapped` too, because it no longer has to try and
pick a correct dispatcher to delegate to, but can always use the same
one for both the wrappers and the original routine.
  • Loading branch information
jnthn committed Sep 28, 2021
1 parent ebd0305 commit 3e5e217
Showing 1 changed file with 43 additions and 25 deletions.
68 changes: 43 additions & 25 deletions src/vm/moar/dispatchers.nqp
Expand Up @@ -609,11 +609,16 @@ nqp::dispatch('boot-syscall', 'dispatcher-register', 'raku-call', -> $capture {
$with-name);
}
elsif nqp::istype_nd($callee, Routine) {
nqp::dispatch('boot-syscall', 'dispatcher-guard-literal',
nqp::dispatch('boot-syscall', 'dispatcher-track-attr',
$track_callee, Routine, '@!dispatchees'));
nqp::dispatch('boot-syscall', 'dispatcher-delegate',
$callee.is_dispatcher ?? 'raku-multi' !! 'raku-invoke', $capture);
if nqp::can($callee, 'WRAPPERS') {
nqp::dispatch('boot-syscall', 'dispatcher-delegate', 'raku-invoke-wrapped', $capture);
}
else {
nqp::dispatch('boot-syscall', 'dispatcher-guard-literal',
nqp::dispatch('boot-syscall', 'dispatcher-track-attr',
$track_callee, Routine, '@!dispatchees'));
nqp::dispatch('boot-syscall', 'dispatcher-delegate',
$callee.is_dispatcher ?? 'raku-multi' !! 'raku-invoke', $capture);
}
}
else {
nqp::dispatch('boot-syscall', 'dispatcher-delegate', 'raku-invoke', $capture);
Expand Down Expand Up @@ -851,8 +856,17 @@ nqp::dispatch('boot-syscall', 'dispatcher-register', 'raku-meth-call-resolved',
my $delegate_capture := nqp::dispatch('boot-syscall', 'dispatcher-drop-arg',
nqp::dispatch('boot-syscall', 'dispatcher-drop-arg', $capture, 1), 1);
my $method := nqp::captureposarg($delegate_capture, 0);
if nqp::istype($method, Routine) && $method.is_dispatcher {
nqp::dispatch('boot-syscall', 'dispatcher-delegate', 'raku-multi', $delegate_capture);
if nqp::istype($method, Routine) {
if nqp::can($method, 'WRAPPERS') {
nqp::dispatch('boot-syscall', 'dispatcher-delegate', 'raku-invoke-wrapped',
$delegate_capture);
}
elsif $method.is_dispatcher {
nqp::dispatch('boot-syscall', 'dispatcher-delegate', 'raku-multi', $delegate_capture);
}
else {
nqp::dispatch('boot-syscall', 'dispatcher-delegate', 'raku-invoke', $delegate_capture);
}
}
else {
nqp::dispatch('boot-syscall', 'dispatcher-delegate', 'raku-invoke', $delegate_capture);
Expand Down Expand Up @@ -1084,13 +1098,23 @@ sub method-deferral-step($chain-head, int $kind, $args) {
# to the invoke dispatcher.
my $delegate_capture := nqp::dispatch('boot-syscall',
'dispatcher-insert-arg-literal-obj', $args, 0, $next_method);
if nqp::istype($next_method, Routine) && $next_method.is_dispatcher {
nqp::dispatch('boot-syscall', 'dispatcher-delegate', 'raku-multi',
if nqp::istype($next_method, Routine) {
if nqp::can($next_method, 'WRAPPERS') {
nqp::dispatch('boot-syscall', 'dispatcher-delegate', 'raku-invoke-wrapped',
$delegate_capture);
}
elsif $next_method.is_dispatcher {
nqp::dispatch('boot-syscall', 'dispatcher-delegate', 'raku-multi',
$delegate_capture);
}
else {
nqp::dispatch('boot-syscall', 'dispatcher-delegate', 'raku-invoke',
$delegate_capture);
}
}
else {
nqp::dispatch('boot-syscall', 'dispatcher-delegate', 'raku-invoke',
$delegate_capture);
$delegate_capture);
}
}
elsif $kind == nqp::const::DISP_NEXTCALLEE {
Expand Down Expand Up @@ -1118,7 +1142,7 @@ nqp::dispatch('boot-syscall', 'dispatcher-register', 'raku-multi',
my $callee := nqp::captureposarg($capture, 0);
my int $onlystar := nqp::getattr_i($callee, Routine, '$!onlystar');
my int $simple := $onlystar && simple-args-proto($callee, $capture);
if $simple && !nqp::can($callee, 'WRAPPERS') {
if $simple {
# Don't need to invoke the proto itself, so just get on with the
# candidate dispatch.
nqp::dispatch('boot-syscall', 'dispatcher-delegate', 'raku-multi-core', $capture);
Expand Down Expand Up @@ -1920,10 +1944,12 @@ nqp::dispatch('boot-syscall', 'dispatcher-register', 'raku-multi-core',
# Trivial multi dispatch. Set dispatch state for resumption, and
# then delegate to raku-invoke to run it.
nqp::dispatch('boot-syscall', 'dispatcher-set-resume-init-args', $capture);
my $candidate := $dispatch-plan.candidate;
my $capture-delegate := nqp::dispatch('boot-syscall',
'dispatcher-insert-arg-literal-obj', $arg-capture, 0,
$dispatch-plan.candidate);
nqp::dispatch('boot-syscall', 'dispatcher-delegate', 'raku-invoke',
$candidate);
nqp::dispatch('boot-syscall', 'dispatcher-delegate',
nqp::can($candidate, 'WRAPPERS') ?? 'raku-invoke-wrapped' !! 'raku-invoke',
$capture-delegate);
}
elsif nqp::istype($dispatch-plan, MultiDispatchNonScalar) {
Expand Down Expand Up @@ -2206,8 +2232,9 @@ sub raku-multi-non-trivial-step(int $kind, $track-cur-state, $cur-state, $orig-c
# Set up the call.
my $capture-delegate := nqp::dispatch('boot-syscall', 'dispatcher-insert-arg',
$arg-capture, 0, $track-candidate);
my $candidate := $cur-state.candidate;
my str $disp := $try || $kind != nqp::const::DISP_NEXTCALLEE
?? 'raku-invoke'
?? (nqp::can($candidate, 'WRAPPERS') ?? 'raku-invoke-wrapped' !! 'raku-invoke')
!! 'boot-value';
nqp::dispatch('boot-syscall', 'dispatcher-delegate', $disp, $capture-delegate);
}
Expand Down Expand Up @@ -2386,13 +2413,6 @@ nqp::dispatch('boot-syscall', 'dispatcher-register', 'raku-invoke', -> $capture
$delegate);
}

# If it's a routine that has wrappers (the guard on the type covers this,
# since such a routine will have been mxied in to).
elsif nqp::istype($code, Routine) && nqp::can($code, 'WRAPPERS') {
nqp::dispatch('boot-syscall', 'dispatcher-delegate', 'raku-invoke-wrapped',
$capture);
}

# If it's a code object...
elsif nqp::istype($code, Code) {
# Concrete code object: extract the $!do, replace the code object,
Expand Down Expand Up @@ -2649,8 +2669,7 @@ nqp::dispatch('boot-syscall', 'dispatcher-register', 'raku-wrapper-deferral',
my $code := $cur_deferral.code;
my $delegate_capture := nqp::dispatch('boot-syscall', 'dispatcher-insert-arg-literal-obj',
$args, 0, $code);
my str $dispatcher := $cur_deferral.next ?? 'raku-call-simple' !! 'raku-invoke';
nqp::dispatch('boot-syscall', 'dispatcher-delegate', $dispatcher, $delegate_capture);
nqp::dispatch('boot-syscall', 'dispatcher-delegate', 'raku-call-simple', $delegate_capture);
},
# Resumption.
-> $capture {
Expand Down Expand Up @@ -2725,11 +2744,10 @@ nqp::dispatch('boot-syscall', 'dispatcher-register', 'raku-wrapper-deferral',
# treat as Raku calls, since it's possible somebody decided to wrap
# some code up with a multi.
my $code := $cur_deferral.code;
my str $dispatcher := $cur_deferral.next ?? 'raku-call-simple' !! 'raku-invoke';
my $delegate_capture := nqp::dispatch('boot-syscall', 'dispatcher-insert-arg-literal-obj',
nqp::dispatch('boot-syscall', 'dispatcher-drop-arg', $init, 0),
0, $code);
nqp::dispatch('boot-syscall', 'dispatcher-delegate', $dispatcher,
nqp::dispatch('boot-syscall', 'dispatcher-delegate', 'raku-call-simple',
$delegate_capture);
}
elsif $kind == nqp::const::DISP_NEXTCALLEE {
Expand Down

0 comments on commit 3e5e217

Please sign in to comment.