Skip to content

Instantly share code, notes, and snippets.

@zoffixznet
Created June 21, 2018 00:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zoffixznet/725ea622bf0bebfce25c54e0364d5deb to your computer and use it in GitHub Desktop.
Save zoffixznet/725ea622bf0bebfce25c54e0364d5deb to your computer and use it in GitHub Desktop.
diff --git a/src/Perl6/Actions.nqp b/src/Perl6/Actions.nqp
index 8f8b8d750..4ced01e8c 100644
--- a/src/Perl6/Actions.nqp
+++ b/src/Perl6/Actions.nqp
@@ -2814,9 +2814,17 @@ class Perl6::Actions is HLL::Actions does STDActions {
if +@name > 1 {
$*W.throw($/, 'X::Dynamic::Package', symbol => ~$/);
}
+ # Try to get the var, if it's not there, look for it in a couple
+ # more places by calling &DYNAMIC. The `ifnull`/`getlexdyn`
+ # call is not part of &DYNAMIC because with such a setup, it
+ # is larger than the spesh inline limit in MoarVM and dynvars
+ # are fairly common, for us to want them to be fast
+ my $sVal-name := $*W.add_string_constant: $name;
$past := QAST::Op.new(
- :op('call'), :name('&DYNAMIC'),
- $*W.add_string_constant($name));
+ :op<ifnull>,
+ QAST::Op.new(:op<getlexdyn>, $sVal-name),
+ QAST::Op.new: :op<call>, :name<&DYNAMIC>, $sVal-name
+ ).annotate_self: '&DYNAMIC', $name;
}
elsif $twigil eq '?' && $*IN_DECL eq 'variable' && !$*COMPILING_CORE_SETTING {
$*W.throw($/, 'X::Syntax::Variable::Twigil',
@@ -6576,10 +6584,8 @@ class Perl6::Actions is HLL::Actions does STDActions {
# first item is a hash (%foo or %!foo)
$is_hash := 1;
}
- elsif nqp::istype($elem, QAST::Op) && $elem.name eq '&DYNAMIC' &&
- nqp::istype($elem[0], QAST::Want) && $elem[0][1] eq 'Ss' &&
- nqp::istype($elem[0][2], QAST::SVal)
- && nqp::eqat($elem[0][2].value, '%', 0) {
+ elsif nqp::istype($elem, QAST::Op)
+ && nqp::eqat($elem.ann('&DYNAMIC'), '%', 0) {
# first item is a hash (%*foo)
$is_hash := 1;
}
@@ -7159,14 +7165,13 @@ class Perl6::Actions is HLL::Actions does STDActions {
$source
));
}
- elsif nqp::istype($target, QAST::Op) && $target.op eq 'call'
- && $target.name eq '&DYNAMIC' && $target[0][1] eq 'Ss' {
+ elsif nqp::istype($target, QAST::Op) && $target.has_ann('&DYNAMIC') {
my $complain := QAST::Op.new(
:op('die_s'),
- QAST::SVal.new( :value('Contextual ' ~ ~$/ ~ ' not found') )
+ QAST::SVal.new( :value('Contextual ' ~ $/ ~ ' not found') )
);
my $contextual := QAST::VarWithFallback.new(
- :name($target[0][2].value), :scope('contextual'), :fallback($complain) );
+ :name($target.ann: '&DYNAMIC'), :scope('contextual'), :fallback($complain) );
my $dynbind := QAST::Op.new( :op('bind'), $contextual, $source);
$dynbind.nosink(1);
make $dynbind;
diff --git a/src/Perl6/Grammar.nqp b/src/Perl6/Grammar.nqp
index c6658d46d..98aba19ad 100644
--- a/src/Perl6/Grammar.nqp
+++ b/src/Perl6/Grammar.nqp
@@ -414,11 +414,24 @@ role STD {
}
method check_variable($var) {
+ return self if $*IN_DECL;
my $varast := $var.ast;
- if nqp::istype($varast, QAST::Op) && $varast.op eq 'ifnull' {
- $varast := $varast[0];
+
+ if nqp::istype($varast, QAST::Op) {
+ if $varast.has_ann('&DYNAMIC') {
+ my $lex := $*W.cur_lexpad();
+ my $au := $lex.ann('also_uses');
+ $lex.annotate('also_uses', $au := {}) unless $au;
+ $au{$varast.ann: '&DYNAMIC'} := 1;
+ return self
+ }
+
+ # do this here, because `&DYNAMIC`'s QAST we're looking at
+ # above is an `ifnull` op, but we don't want to unwrap it
+ $varast := $varast[0] if $varast.op eq 'ifnull';
}
- if !$*IN_DECL && nqp::istype($varast, QAST::Var) && $varast.scope eq 'lexical' {
+
+ if nqp::istype($varast, QAST::Var) && $varast.scope eq 'lexical' {
my $name := $varast.name;
if $name ne '%_' && $name ne '@_' && !$*W.is_lexical($name) {
@@ -453,14 +466,6 @@ role STD {
self.mark_variable_used($name);
}
}
- if !$*IN_DECL && nqp::istype($varast, QAST::Op) && $varast.name eq '&DYNAMIC' {
- my $lex := $*W.cur_lexpad();
- if nqp::istype($varast[0], QAST::Want) && nqp::istype($varast[0][2], QAST::SVal) {
- my $au := $lex.ann('also_uses');
- $lex.annotate('also_uses', $au := {}) unless $au;
- $au{$varast[0][2].value} := 1;
- }
- }
self
}
diff --git a/src/core/stubs.pm6 b/src/core/stubs.pm6
index 7388a84a7..e4daebcd4 100644
--- a/src/core/stubs.pm6
+++ b/src/core/stubs.pm6
@@ -31,25 +31,29 @@ my class Lock is repr('ReentrantMutex') { ... }
my class Lock::Async { ... }
sub DYNAMIC(\name) is raw {
- nqp::ifnull(
- nqp::getlexdyn(name),
- nqp::stmts(
- nqp::unless(
- nqp::isnull(my $prom := nqp::getlexdyn('$*PROMISE')),
- (my Mu $x := nqp::getlexreldyn(
- nqp::getattr($prom,Promise,'$!dynamic_context'),name)
- )
- ),
- nqp::ifnull(
- $x,
- nqp::stmts(
- (my str $pkgname = nqp::replace(name,1,1,'')),
+ # When we gen dynvar lookup, in Actions, we first do this:
+ # nqp::ifnull(
+ # nqp::getlexdyn(name),
+ # And the call to this sub is in the "else" branch of that `ifnull`.
+ # The reason that stuff lives outside this sub is because all together
+ # the code is above the spesh inline limit (in MoarVM) and dynvar lookup
+ # is fairly common for us to want it very fast
+ nqp::stmts(
+ nqp::unless(
+ nqp::isnull(my $prom := nqp::getlexdyn('$*PROMISE')),
+ (my Mu $x := nqp::getlexreldyn(
+ nqp::getattr($prom,Promise,'$!dynamic_context'),name)
+ )
+ ),
+ nqp::ifnull(
+ $x,
+ nqp::stmts(
+ (my str $pkgname = nqp::replace(name,1,1,'')),
+ nqp::ifnull(
+ nqp::atkey(GLOBAL.WHO,$pkgname),
nqp::ifnull(
- nqp::atkey(GLOBAL.WHO,$pkgname),
- nqp::ifnull(
- nqp::atkey(PROCESS.WHO,$pkgname),
- Rakudo::Internals.INITIALIZE-DYNAMIC(name)
- )
+ nqp::atkey(PROCESS.WHO,$pkgname),
+ Rakudo::Internals.INITIALIZE-DYNAMIC(name)
)
)
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment