>Мне-то кажется, что именно этот метод и есть правильный, но навязывать ничего 
>не хочу )))

Получилось сделать локализацию вручную с помощью модуля Hook::Scope. Но 
дополнительно выкинул из него код 'use optimizer 'sub-detect' => \&optimizer;' 
потому, что модуль уж совсем старый и некорректно работает с новыми версиями 
perl.

use Hook::Scope;

sub sub_returns {
        # если  стек есть...
        if( defined $DB::deep ) { # когда функции ещё не вызывались, то 
$DB::deep == undef
                $#DB::stack =  $DB::deep;
                $DB::single =  $DB::stack[-1]{ single };
        }

}

sub sub {
    if( $DB::sub eq 'DB::sub_returns' ) { # предотвращаем segfault
        return &$DB::sub;
    }

        # register hook to restore value when out of scope
        Hook::Scope::POST( \&sub_returns );
        # relocate space and save value
        $#DB::stack =  $DB::deep;
        $DB::stack[-1] =  { single => $DB::single };

    local $DB::deep = $DB::deep +1;
    return &$DB::sub;
}
07.01.2016, 01:56, "Vladimir Timofeev" <[email protected]>:
> 2016-01-07 6:19 GMT+03:00 Eugen Konkov <[email protected]>:
>>  Спасибо! Очень много интересной информации вы мне дали. Пойду изучать...
>>  Не могли бы вы мне подсказать файл, в котором перл генерирует обком для 
>> goto?
>
> Ну это просто. Все OP в файлах op*.c, так что ack 'pp_goto' op*.c и 
> получаем...
> pp_ctl.c:2768 OP(pp_goto)
>
> А вот дальше... текст там забавный )))
>
>>> Во втором случае никакой local работать не будет, вернее будет...
>>  local $DB::single = $DB::single +0; работал и работает отлично и в дебаг 
>> режиме тоже (см. ниже)
>
> Ух ты, я и не знал ))
> Интересно почему, но быстрый просмотр показал, что чтобы понять,
> придётся много времени потратить, которого нет...
> По идее магия для DB::single get/set очень простая, просто сохраняет
> значения ещё и в глобальном массивчике PL_DBcontrol (там для каждой
> переменной single, trace... по слоту). Хендлеры в конце mg.c, функции
> Perl_magic_setdebugvar и Perl_magic_getdebugvar.
>
>>> Мне кажется, что для хранения текущего состояния в своём дебаггере
>>  Как раз не текущее состояние было нужно, а n фреймов назад...
>>
>>  У меня в дебагере что-то наподобие:
>>  sub sub {
>>       local $DB::single = $DB::single +0; # без 0 не работает :?
>>       return &$DB::sub;
>>   }
>>
>>  Где-то внутри вызываемой функции с именем "$DB::sub" я делаю $DB::single = 
>> 0 и автоматом останавливаюсь на первом операторе вне этой функции. Т.е. для 
>> кода:
>>  sub t{ $DB::single = 0; }
>>  t();
>>  $x++; <<< останавливаюсь тут
>>
>>  Останавливаюсь потому, что после того как отработает 'return &$DB::sub' 
>> перл восстановит старое локализированное значение $DB::single в TRUE
>>  и вызовется DB::DB на первом опкоде после возврата, те. '$x++'
>>
>>  Но если бы мы хотели выйти на 2 фрейма вверх?
>>  То нам нужно, чтобы старое локализированное значение $DB::single 
>> восстановилось в FALSE
>>
>>  Как поменять старое локализированное значение? - Взять ссылку на него...
>>  Получается примерно такое:
>>  sub sub {
>>       $#DB::stack = $DB::deep;
>>       $DB::stack[-1] = { single => \$DB::single };
>>
>>       local $DB::single = $DB::single +0;
>>       local $DB::deep = $DB::deep +1;
>>       return &$DB::sub;
>>  }
>>
>>  sub t1 { $DB::stack[-1]{ single } = 0; $DB::single = 0; } #DEEP 2
>>  sub t2 { t1(); $y++; } # DEEP 1
>>  t2(); #DEEP 0
>>  $x++;
>>
>>  Если бы мы шли в функцию t1 пошагово, то было бы локализировано 2 значения 
>> $DB::single, это единицы.
>>  [
>>     { single => \1 }
>>     { single => \1 }
>>  ]
>>
>>  после выполнения t1 стэк выгледел был бы так:
>>  [
>>     { single => \1 }
>>     { single => \0 }
>>  ]
>>
>>  Соответственно после выхода из t1 перл бы востанавливал в $DB::single не в 
>> единицу, а в 0, а это бы позволило нам выйти из t2 тоже и остановиться на 
>> $x++
>>
>>  И теперь мне понятно (благодаря вашему объяснению), что из-за магии 
>> $DB::single, когда мы делаем ${ $DB::stack[-1]{single} } = 0, то меняются 
>> все значения в стеке, а не только указанное, т.е. получаем:
>>  [
>>     { single => \0 }
>>     { single => \0 }
>>  ]
>>
>>  соответственно вываливаемся полностью из программы...
>
> А не может ли быть того, что просто нет никакого стека там (в месте,
> где хранится реальное значение и куда дебаггер смотрит) в слоте
> PL_DBControl? ;-)
>
>>  Я предпологаю, что должна быть возможность через XS обойти магию и 
>> присвоить 0 в правильную ссылку. Не могли бы вы порекомендовать какие нибудь 
>> хорошие мануалы по XS?
>
> Мысль на вскидку (не проверял). В XS API есть SvIV_nomg(sv), типа
> возвращает iv из sv и не вызывает магию. Пример использования в той же
> mg.c:Perl_magic_setdebugvar ну и вообще по коду перла этого добра
> раскиданно в достатке.
>
>>  PS. Сейчас пока обхожусь костылём. Завожу переменную, в которой хранится 
>> значение на сколько уровней нужно поднятся и в sub DB::DB делаю
>>  sub DB {
>>     if( $DB::level-- != 1 ) {
>>         $DB::single = 0;
>>         return;
>>     }
>>  }
>>
>>  Соответсвенно в t1:
>>  sub t1 { $DB::level = 2; $DB::single = 0; }
>>  Недостаток этого метода, наверное, небольшой проигрыш в скорости работы, по 
>> сравнению с "правильным" методом, но выбирать не приходиться (((
>
> Мне-то кажется, что именно этот метод и есть правильный, но навязывать
> ничего не хочу )))
>
>>  PSS. Тут для наглядности и простоты примеров я изменял значения из DB:: 
>> прям в коде скрипта, но в боевом примере этого добиваюсь с помощью комманд 
>> дебагера s n r
>>
>>  Вы писали 6 января 2016 г., 18:45:53:
>>
>>  VT> Ну вот это уже интереснее )
>>
>>  VT> Так вот:
>>  VT> 1. Без дебаггера, $DB::single обычный скаляр, с ним всё происходит как
>>  VT> надо (в вашем случае это был $DB::x, об этом чуть ниже).
>>  VT> $ perl -MDevel::Peek -e'Dump($DB::single)'
>>  VT> SV = NULL(0x0) at 0x7f882b82dc60
>>  VT> REFCNT = 1
>>  VT> FLAGS = ()
>>
>>  VT> 2. С подключенным дебаггером.
>>  VT> $ perl -MDevel::Peek -d -e'Dump($DB::single)'
>>  VT> DB<1> c
>>  VT> SV = PVMG(0x7fc78a025460) at 0x7fc78a004a30
>>  VT> REFCNT = 1
>>  VT> FLAGS = (GMG,SMG,IOK,pIOK)
>>  VT> IV = 0
>>  VT> NV = 0
>>  VT> PV = 0
>>  VT> MAGIC = 0x7fc789c052e0
>>  VT> MG_VIRTUAL = &PL_vtbl_debugvar
>>  VT> MG_TYPE = PERL_MAGIC_debugvar(*)
>>
>>  VT> Во втором случае никакой local работать не будет, вернее будет... в
>>  VT> штатном режиме (это можно увидеть, если вставить Dump в ваш код), но
>>  VT> толку нет, потому что к значениям из слотов SV не будет доступа,
>>  VT> вместо этого будет вызываться метод из VTBL магический, который...
>>  VT> возвращает актуальное значение. (это примерное объяснение, я редко
>>  VT> лазил в эту область и внимательно сейчас читать исходники нет ни
>>  VT> времени ни желания :-)
>>
>>  VT> Всю магию, которую вешает дебаггер можно посмотреть в perl.c где-то в
>>  VT> р-не строки 4000, функция Perl_init_debugger. Соотвественно, те
>>  VT> символы, на которых магия могут работать не нормально: DB::single,
>>  VT> DB::trace, DB::signal.
>>
>>  VT> Мне кажется, что для хранения текущего состояния в своём дебаггере,
>>  VT> можно использовать нормальные свои переменные в пакете DB, главное не
>>  VT> пересечься с уже используемыми перлом.
>>
>>  VT> 2016-01-06 22:38 GMT+03:00 KES <[email protected]>:
>>>>  Я извиняюсь. Упустил важный момент. Вот полный код:
>>>>  $ cat Devel/DB.pm
>>>>  package DB;
>>
>>>>  sub DB::DB {
>>>>  }
>>
>>>>  sub sub {
>>>>      {
>>>>          $DB::single = 7; my $x = \$DB::single;
>>>>          print "Before: ". \$DB::single ." <<$x $$x\n";
>>>>          local $DB::single = 0;
>>>>          print "After: ". \$DB::single ." <<$x $$x\n";
>>>>      }
>>
>>>>      return &$DB::sub;
>>>>  }
>>
>>>>  1;
>>
>>>>  $ perl -d:DB -e 'sub t{} t()'
>>
>>>>  $ perl -v
>>>>  This is perl 5, version 22, subversion 0 (v5.22.0) built for x86_64-linux
>>
>>>>  PS. Думаю в ближайшее мне придется очень глубоко копнуть в исходники 
>>>> перл, т.к. в дебаг режиме шероховатость на шероховатости :`-(
>>>>  --
>>>>  Moscow.pm mailing list
>>>>  [email protected] | http://moscow.pm.org
>>
>>  VT> --
>>  VT> Vladimir Timofeev <[email protected]>
>>
>>  --
>>  С уважением,
>>   Eugen mailto:[email protected]
>
> --
> Vladimir Timofeev <[email protected]>
-- 
Moscow.pm mailing list
[email protected] | http://moscow.pm.org

Ответить