Как взаимодействуют mro, goto и set_subname? - PullRequest
3 голосов
/ 03 ноября 2019

Это сложный вопрос в отношении mro.pm и взаимодействия с set_subname и goto

При устранении проблемы, я думаю, ядро ​​моейнедоразумение относится к тому, как работает mro.pm, особенно в отношении set_subname.

В чем разница между этими тремя конструкциями,

  1. Простой вызов set_subname

    *Foo::bar = set_subname( 'Foo::bar', $codeRef );
    
  2. Anon subкоторый включает set_subname

    *Foo::bar = sub {
      my $codeRef2 = set_subname('Foo::bar', $codeRef);
      goto $codeRef2
    };
    
  3. Anon sub, имя которого установлено с set_subname

    *Foo::bar = set_subname(
      'Foo::bar',
      sub { goto $codeRef }
    );
    

В частности,Тестовые комплекты Mojo не срабатывают ни с одной из этих модификаций, если к Mojo::Utils * monkey_patch применены сабвуферы, запустив два вышеуказанных варианта против t/mojo/websocket_proxy.t,

  • С опцией 2 (второй) у меня есть

    *{"${class}::$k"} = sub {                                                                                                                          
      my $cr = set_subname("${class}::$k", $patch{$k});                                                                                                
      goto $cr;                                                                                                                                        
    }; 
    

    И я получаю

    Mojo::Reactor::Poll: Timer failed: Can't locate object method "send" via package "Mojo::Transaction::HTTP" at t/mojo/websocket_proxy.t line 66.
    
  • С опцией 3 (третьей) у меня

    *{"${class}::$k"} = set_subname("${class}::$k", sub { goto $patch{$k} })
    

    И я получаю

    No next::method 'new' found for Mojolicious::Routes at /usr/lib/x86_64-linux-gnu/perl/5.28/mro.pm line 30.
    

Очевидно, первая версия работает (это из кода, который я связал), вопрос в том, почему два других варианта дают мне разныеошибки (особенно второй вариант) и что там происходит - почему они не работают?

Ответы [ 3 ]

2 голосов
/ 04 ноября 2019

Ваш второй вариант не работает, потому что сабвуфер, который вы используете в качестве оболочки, не соответствует прототипу внутреннего сабвуфера. monkey_patch используется не только для методов, и это меняет способ анализа некоторых функций. В частности, Mojo::Util::steady_time имеет пустой прототип и часто вызывается без использования скобок.

*{"${class}::$k"} = Sub::Util::set_prototype(
  Sub::Util::prototype( $patch{$k} ),
  Sub::Util::set_subname(
    "${class}::$k",
    sub {
      my $cr = Sub::Util::set_subname("${class}::$k", $patch{$k});
      goto $cr;
    }
  )
);

Третья конструкция не работает, потому что вы используете goto для удаления переименованной подпрограммы-оболочки из стека вызовов. , оставляя только внутреннюю подпрограмму, которая не имеет имени. Это нарушает способность next::method найти правильное имя метода.

2 голосов
/ 03 ноября 2019

Это действительно сложно, но, может быть, вы это слишком усложнили?

Помните, что MRO занимается только поиском метода, который является просто записью таблицы символов в coderef, через определенный порядок имен пакетов. Внутреннее имя пользователя имеет отношение только к тому, что caller () сообщает AFAIK.

От: Mojo

*{"${class}::$_"} =          ## symbol table entry
set_subname("${class}::$_",  ## an internal name
   $patch{$_})               ## for a code ref
for keys %patch;

HTH

Редактировать после просмотра сообщений об ошибках:

Подпрограммы не были правильно установлены. Я подозреваю, что, поскольку в вариантах 2 и 3 вы откладываете вызовы set_subname () для вызова времени, coderef $ patch {$ k} никогда не имеет назначенного ему имени, и это разрывает ссылку в цепочке mro :: _ nextcan() XS magic. Особенно, если $ patch {$ k} вызывает метод next ::. Тем не менее, кажется, что замыкания действительны.

Хотя я должен сказать, что мое тестирование показало, что вариант 2 действителен.

Enter command: my ($class, $k) = qw/W S/; my %patch = (S =>
sub {print "patch here\n"; decall;}); *{"${class}::$k"} = 
sub { print "goto'r here\n";  my $cr = set_subname("${class}::$k",
$patch{$k}); goto $cr;};


Enter command: decall
0       "console"
1       "console.pl"
2       "114"
3       "(eval)"
4       "0"
5       0
6       "package W; decall"
7       ""
8       "256"
9       "\020\001\000\000\000P\004\000\000\000\000\000\000U\025U\005"
10      0

Enter command: S
goto'r here
patch here
0       "W"
1       "(eval 110)"
2       "1"
3       "W::S"
4       "1"
5       0
6       0
7       0
8       "256"
9       "\020\001\000\000\000P\004\000\000\000\000\000\000U\025U\005"
10      0

Возможно, вам придется начать искать вдали от проблемы свариант 2.

0 голосов
/ 04 ноября 2019

После изменения Mojo / Util.pm с помощью

  foreach my $k (keys %patch) {
    *{"${class}::$k"} = sub {
      my $cr = set_subname("${class}::$k", $patch{$k});
      goto $cr;
    };
   }

и изоляции тестового примера я получаю:

$ perl -MCarp::Always t/mojo/websocket_proxy2.t
Mojo::Reactor::Poll: Timer failed: Can't locate object method "send" via package "Mojo::Transaction::HTTP" at t/mojo/websocket_proxy2.t line 59.
        main::__ANON__(Mojo::UserAgent=HASH(0x60280dad0), Mojo::Transaction::HTTP=HASH(0x6029ee7b0)) called at blib/lib/Mojo/UserAgent.pm line 252
        Mojo::UserAgent::_finish(Mojo::UserAgent=HASH(0x60280dad0), "927210c53042c6142eda3f4010c8b17c", 1) called at blib/lib/Mojo/UserAgent.pm line 220
        Mojo::UserAgent::_error(Mojo::UserAgent=HASH(0x60280dad0), "927210c53042c6142eda3f4010c8b17c", "Connect timeout") called at blib/lib/Mojo/UserAgent.pm line 128
        Mojo::UserAgent::__ANON__(Mojo::IOLoop=HASH(0x601f9abb8), "Connect timeout", undef) called at blib/lib/Mojo/IOLoop.pm line 63
        Mojo::IOLoop::__ANON__(Mojo::IOLoop::Client=HASH(0x601e34598)) called at blib/lib/Mojo/EventEmitter.pm line 15
        Mojo::EventEmitter::emit(Mojo::IOLoop::Client=HASH(0x601e34598), "error", "Connect timeout") called at blib/lib/Mojo/IOLoop/Client.pm line 39
        Mojo::IOLoop::Client::__ANON__(Mojo::Reactor::Poll=HASH(0x6001a8390)) called at blib/lib/Mojo/Reactor/Poll.pm line 143
        eval {...} called at blib/lib/Mojo/Reactor/Poll.pm line 143
        Mojo::Reactor::Poll::_try(Mojo::Reactor::Poll=HASH(0x6001a8390), "Timer", CODE(0x601e24ca0)) called at blib/lib/Mojo/Reactor/Poll.pm line 81
        Mojo::Reactor::Poll::one_tick(Mojo::Reactor::Poll=HASH(0x6001a8390)) called at blib/lib/Mojo/Reactor/Poll.pm line 99
        Mojo::Reactor::Poll::start(Mojo::Reactor::Poll=HASH(0x6001a8390)) called at blib/lib/Mojo/IOLoop.pm line 134
        Mojo::IOLoop::start("Mojo::IOLoop") called at t/mojo/websocket_proxy2.t line 62
 at blib/lib/Mojo/IOLoop.pm line 23.
        Mojo::IOLoop::__ANON__(Mojo::Reactor::Poll=HASH(0x6001a8390), "Timer failed: Can't locate object method \"send\" via package \"Mojo::Transaction::HTTP\" at t/mojo/websocket_proxy2.t line 59.\x{a}\x{9}main::__ANON__(Mojo::UserAgent=HASH(0x60280dad0), Mojo::Transaction::HTTP=HASH(0x6029ee7b0)) called at blib/lib/Mojo/UserAgent.pm line 252\x{a}\x{9}Mojo::UserAgent::_finish(Mojo::UserAgent=HASH(0x60280dad0), \"927210c53042c6142eda3f4010c8b17c\", 1) called at blib/lib/Mojo/UserAgent.pm line 220\x{a}\x{9}Mojo::UserAgent::_error(Mojo::UserAgent=HASH(0x60280dad0), \"927210c53042c6142eda3f4010c8b17c\", \"Connect timeout\") called at blib/lib/Mojo/UserAgent.pm line 128\x{a}\x{9}Mojo::UserAgent::__ANON__(Mojo::IOLoop=HASH(0x601f9abb8), \"Connect timeout\", undef) called at blib/lib/Mojo/IOLoop.pm line 63\x{a}\x{9}Mojo::IOLoop::__ANON__(Mojo::IOLoop::Client=HASH(0x601e34598)) called at blib/lib/Mojo/EventEmitter.pm line 15\x{a}\x{9}Mojo::EventEmitter::emit(Mojo::IOLoop::Client=HASH(0x601e34598), \"error\", \"Connect timeout\") called at blib/lib/Mojo/IOLoop/Client.pm line 39\x{a}\x{9}Mojo::IOLoop::Client::__ANON__(Mojo::Reactor::Poll=HASH(0x6001a8390)) called at blib/lib/Mojo/Reactor/Poll.pm line 143\x{a}\x{9}eval {...} called at blib/lib/Mojo/Reactor/Poll.pm line 143\x{a}\x{9}Mojo::Reactor::Poll::_try(Mojo::Reactor::Poll=HASH(0x6001a8390), \"Timer\", CODE(0x601e24ca0)) called at blib/lib/Mojo/Reactor/Poll.pm line 81\x{a}\x{9}Mojo::Reactor::Poll::one_tick(Mojo::Reactor::Poll=HASH(0x6001a8390)) called at blib/lib/Mojo/Reactor/Poll.pm line 99\x{a}\x{9}Mojo::Reactor::Poll::start(Mojo::Reactor::Poll=HASH(0x6001a8390)) called at blib/lib/Mojo/IOLoop.pm line 134\x{a}\x{9}Mojo::IOLoop::start(\"Mojo::IOLoop\") called at t/mojo/websocket_proxy2.t line 62\x{a}") called at blib/lib/Mojo/EventEmitter.pm line 15
        Mojo::EventEmitter::emit(Mojo::Reactor::Poll=HASH(0x6001a8390), "error", "Timer failed: Can't locate object method \"send\" via package \"Mojo::Transaction::HTTP\" at t/mojo/websocket_proxy2.t line 59.\x{a}\x{9}main::__ANON__(Mojo::UserAgent=HASH(0x60280dad0), Mojo::Transaction::HTTP=HASH(0x6029ee7b0)) called at blib/lib/Mojo/UserAgent.pm line 252\x{a}\x{9}Mojo::UserAgent::_finish(Mojo::UserAgent=HASH(0x60280dad0), \"927210c53042c6142eda3f4010c8b17c\", 1) called at blib/lib/Mojo/UserAgent.pm line 220\x{a}\x{9}Mojo::UserAgent::_error(Mojo::UserAgent=HASH(0x60280dad0), \"927210c53042c6142eda3f4010c8b17c\", \"Connect timeout\") called at blib/lib/Mojo/UserAgent.pm line 128\x{a}\x{9}Mojo::UserAgent::__ANON__(Mojo::IOLoop=HASH(0x601f9abb8), \"Connect timeout\", undef) called at blib/lib/Mojo/IOLoop.pm line 63\x{a}\x{9}Mojo::IOLoop::__ANON__(Mojo::IOLoop::Client=HASH(0x601e34598)) called at blib/lib/Mojo/EventEmitter.pm line 15\x{a}\x{9}Mojo::EventEmitter::emit(Mojo::IOLoop::Client=HASH(0x601e34598), \"error\", \"Connect timeout\") called at blib/lib/Mojo/IOLoop/Client.pm line 39\x{a}\x{9}Mojo::IOLoop::Client::__ANON__(Mojo::Reactor::Poll=HASH(0x6001a8390)) called at blib/lib/Mojo/Reactor/Poll.pm line 143\x{a}\x{9}eval {...} called at blib/lib/Mojo/Reactor/Poll.pm line 143\x{a}\x{9}Mojo::Reactor::Poll::_try(Mojo::Reactor::Poll=HASH(0x6001a8390), \"Timer\", CODE(0x601e24ca0)) called at blib/lib/Mojo/Reactor/Poll.pm line 81\x{a}\x{9}Mojo::Reactor::Poll::one_tick(Mojo::Reactor::Poll=HASH(0x6001a8390)) called at blib/lib/Mojo/Reactor/Poll.pm line 99\x{a}\x{9}Mojo::Reactor::Poll::start(Mojo::Reactor::Poll=HASH(0x6001a8390)) called at blib/lib/Mojo/IOLoop.pm line 134\x{a}\x{9}Mojo::IOLoop::start(\"Mojo::IOLoop\") called at t/mojo/websocket_proxy2.t line 62\x{a}") called at blib/lib/Mojo/Reactor/Poll.pm line 143
        Mojo::Reactor::Poll::_try(Mojo::Reactor::Poll=HASH(0x6001a8390), "Timer", CODE(0x601e24ca0)) called at blib/lib/Mojo/Reactor/Poll.pm line 81
        Mojo::Reactor::Poll::one_tick(Mojo::Reactor::Poll=HASH(0x6001a8390)) called at blib/lib/Mojo/Reactor/Poll.pm line 99
        Mojo::Reactor::Poll::start(Mojo::Reactor::Poll=HASH(0x6001a8390)) called at blib/lib/Mojo/IOLoop.pm line 134
        Mojo::IOLoop::start("Mojo::IOLoop") called at t/mojo/websocket_proxy2.t line 62

Я также могу подтвердить, что установка прототипа исправляет его.

...