File Coverage

blib/lib/Acme/Perl/VM.pm
Criterion Covered Total %
statement 302 519 58.1
branch 53 176 30.1
condition 7 29 24.1
subroutine 82 111 73.8
pod 0 81 0.0
total 444 916 48.4


line stmt bran cond sub pod time code
1             package Acme::Perl::VM;
2              
3 22     22   736848 use 5.008_001;
  22         373  
  22         1032  
4 22     22   141 use strict;
  22         54  
  22         1710  
5 22     22   373 use warnings;
  22         47  
  22         2014  
6              
7             our $VERSION = '0.006';
8              
9 22   50 22   131 use constant APVM_DEBUG => ( $ENV{APVM} || $ENV{APVM_DEBUG} || 0 );
  22         41  
  22         6456  
10             use constant {
11 22         2482 APVM_TRACE => scalar(APVM_DEBUG =~ /\b trace \b/xmsi),
12             APVM_SCOPE => scalar(APVM_DEBUG =~ /\b scope \b/xmsi),
13             APVM_CX => scalar(APVM_DEBUG =~ /\b (?: cx | context ) \b/xmsi),
14             APVM_STACK => scalar(APVM_DEBUG =~ /\b stack \b/xmsi),
15              
16             APVM_DUMMY => scalar(APVM_DEBUG =~ /\b dummy \b/xmsi),
17 22     22   132 };
  22         48  
18              
19 22     22   127 use Exporter qw(import);
  22         44  
  22         7253  
20              
21             BEGIN{
22 22     22   75 our @EXPORT = qw(run_block call_sv);
23 22         296 our @EXPORT_OK = qw(
24             $PL_op $PL_curcop
25             @PL_stack @PL_markstack @PL_cxstack @PL_scopestack @PL_savestack @PL_tmps
26             $PL_tmps_floor
27             $PL_comppad $PL_comppad_name @PL_curpad
28             $PL_last_in_gv
29             $PL_runops
30             @PL_ppaddr
31              
32             PUSHMARK POPMARK TOPMARK
33             PUSH POP TOP SET SETval
34             mPUSH
35             GET_TARGET
36             GET_TARGETSTACKED
37             GET_ATARGET
38             MAXARG
39              
40             PUSHBLOCK POPBLOCK TOPBLOCK
41             PUSHSUB POPSUB
42             PUSHLOOP POPLOOP
43              
44             dounwind
45              
46             ENTER LEAVE LEAVE_SCOPE
47             SAVETMPS FREETMPS
48             SAVE SAVECOMPPAD SAVECLEARSV
49             SAVEPADSV
50             save_scalar save_ary save_hash
51              
52             OP_GIMME GIMME_V LVRET
53              
54             PAD_SV PAD_SET_CUR_NOSAVE PAD_SET_CUR
55             CX_CURPAD_SAVE CX_CURPAD_SV
56              
57             dopoptosub dopoptoloop dopoptolabel
58              
59             deb apvm_warn apvm_die croak ddx
60              
61             GVOP_gv
62              
63             vivify_ref
64             sv_newmortal sv_mortalcopy sv_2mortal
65             SvPV SvNV SvIV SvTRUE
66             av_assign av_store
67             hv_store hv_store_ent hv_scalar
68              
69             defoutgv
70             gv_fullname
71              
72             looks_like_number
73             sv_defined is_null is_not_null
74             mark_list
75             not_implemented
76             dump_object dump_value dump_stack dump_si
77              
78             apvm_extern
79             cv_external
80              
81             APVM_DEBUG APVM_DUMMY
82             APVM_SCOPE APVM_TRACE
83             );
84 22         90 our %EXPORT_TAGS = (
85             perl_h => \@EXPORT_OK,
86             );
87              
88 22         46 if(APVM_DEBUG && -t *STDERR){
89             require Term::ANSIColor;
90              
91             *deb = \&_deb_colored;
92             }
93             else{
94 22         678 *deb = \&_deb;
95             }
96             }
97              
98 22     22   155 use Scalar::Util qw(looks_like_number refaddr);
  22         56  
  22         3655  
99 22     22   206 use Carp ();
  22         344  
  22         1039  
100              
101 22     22   18222 use Acme::Perl::VM::Context;
  22         5894  
  22         1442  
102 22     22   23416 use Acme::Perl::VM::Scope;
  22         2729  
  22         1085  
103 22     22   20952 use Acme::Perl::VM::PP;
  22         93  
  22         1177  
104 22     22   2817 use Acme::Perl::VM::B;
  22         54  
  22         186843  
105              
106             our $PL_runops = (APVM_TRACE || APVM_STACK)
107             ? \&runops_debug
108             : \&runops_standard;
109              
110             our $PL_op;
111             our $PL_curcop;
112              
113             our @PL_stack;
114             our @PL_markstack;
115             our @PL_cxstack;
116             our @PL_scopestack;
117             our @PL_savestack;
118             our @PL_tmps;
119              
120             our $PL_tmps_floor;
121              
122             our $PL_comppad;
123             our $PL_comppad_name;
124             our @PL_curpad;
125              
126             our $PL_last_in_gv;
127              
128             our @PL_ppaddr;
129              
130             our $color = 'GREEN BOLD'; # for debugging log
131              
132             sub not_implemented;
133              
134             {
135             my $i = 0;
136             while(my $ppname = B::ppname($i)){
137             my $ppaddr = \$Acme::Perl::VM::PP::{$ppname};
138              
139             if(ref($ppaddr) eq 'GLOB'){
140             $PL_ppaddr[$i] = *{$ppaddr}{CODE};
141             }
142              
143             $PL_ppaddr[$i] ||= sub{ not_implemented($ppname) };
144              
145             $i++;
146             }
147             }
148              
149             sub runops_standard{ # run.c
150 101     101 0 135 1 while(${ $PL_op = &{$PL_ppaddr[ $PL_op->type ]} });
  1141         1309  
  1141         5510  
151 88         532 return;
152             }
153              
154             sub _op_trace{
155 0     0   0 my $flags = $PL_op->flags;
156 0         0 my $name = $PL_op->name;
157              
158 0         0 deb '.%s', $name;
159 0 0 0     0 if(ref($PL_op) eq 'B::COP'){
    0          
    0          
    0          
    0          
160 0 0       0 deb '(%s%s %s:%d)',
161             ($PL_op->label ? $PL_op->label.': ' : ''),
162             $PL_op->stashpv,
163             $PL_op->file, $PL_op->line,
164             ;
165             }
166             elsif($name eq 'entersub'){
167 0         0 my $gv = TOP;
168 0 0       0 if(!$gv->isa('B::GV')){
169 0         0 $gv = $gv->GV;
170             }
171 0         0 deb '(%s)', gv_fullname($gv, '&');
172             }
173             elsif($name eq 'aelemfast'){
174 0         0 my $name;
175 0 0       0 if($flags & OPf_SPECIAL){
176 0         0 my $padname = $PL_comppad_name->ARRAYelt($PL_op->targ);
177 0 0       0 $name = $padname->POK ? '@'.$padname->PVX : '[...]';
178             }
179             else{
180 0         0 $name = gv_fullname(GVOP_gv($PL_op), '@');
181             }
182 0         0 deb '[%s[%s]]', $name, $PL_op->private;
183             }
184             elsif($PL_op->targ && $name !~ /leave/){
185 0 0 0     0 if($name eq 'const' || $name eq 'method_named'){
186 0         0 my $sv = PAD_SV($PL_op->targ);
187              
188 0 0       0 if(is_scalar($sv)){
189 0 0       0 deb '(%s)', $sv->POK ? B::perlstring($sv->PVX) : $sv->as_string;
190             }
191             else{
192 0         0 deb '(%s)', ddx([$sv->object_2svref])->Indent(0)->Dump;
193             }
194             }
195             else{
196 0         0 my $padname = $PL_comppad_name->ARRAYelt($PL_op->targ);
197 0 0       0 if($padname->POK){
198 0         0 deb '(%s)', $padname->PVX;
199 0 0       0 deb ' INTRO' if $PL_op->private & OPpLVAL_INTRO;
200             }
201             }
202             }
203             elsif($PL_op->can('sv')){
204 0         0 my $sv = SVOP_sv($PL_op);
205 0 0       0 if($sv->class eq 'GV'){
206 0 0       0 my $prefix = $name eq 'gvsv' ? '$' : '*';
207 0         0 deb '(%s)', gv_fullname($sv, $prefix);
208 0 0       0 deb ' INTRO' if $PL_op->private & OPpLVAL_INTRO;
209             }
210             else{
211 0         0 deb '(%s)', B::perlstring(SvPV(SVOP_sv($PL_op)));
212             }
213             }
214              
215 0 0       0 deb ' VOID' if( ($flags & OPf_WANT) == OPf_WANT_VOID );
216 0 0       0 deb ' SCALAR' if( ($flags & OPf_WANT) == OPf_WANT_SCALAR );
217 0 0       0 deb ' LIST' if( ($flags & OPf_WANT) == OPf_WANT_LIST );
218              
219 0 0       0 deb ' KIDS' if $flags & OPf_KIDS;
220 0 0       0 deb ' PARENS' if $flags & OPf_PARENS;
221 0 0       0 deb ' REF' if $flags & OPf_REF;
222 0 0       0 deb ' MOD' if $flags & OPf_MOD;
223 0 0       0 deb ' STACKED' if $flags & OPf_STACKED;
224 0 0       0 deb ' SPECIAL' if $flags & OPf_SPECIAL;
225              
226 0         0 deb "\n";
227             }
228              
229             sub runops_debug{
230 0     0 0 0 _op_trace();
231 0         0 while(${ $PL_op = &{$PL_ppaddr[$PL_op->type]} }){
  0         0  
  0         0  
232 0         0 if(APVM_STACK){
233             dump_stack();
234             }
235              
236 0         0 _op_trace();
237             }
238 0         0 if(APVM_STACK){
239             dump_stack();
240             }
241 0         0 return;
242             }
243              
244             sub _deb_colored{
245 0     0   0 my($fmt, @args) = @_;
246 0         0 printf STDERR Term::ANSIColor::colored($fmt, $color), @args;
247 0         0 return;
248             }
249             sub _deb{
250 0     0   0 my($fmt, @args) = @_;
251 0         0 printf STDERR $fmt, @args;
252 0         0 return;
253             }
254              
255             sub mess{ # util.c
256 0     0 0 0 my($fmt, @args) = @_;
257 0         0 my $msg = sprintf $fmt, @args;
258 0         0 return sprintf "[APVM] %s in %s at %s line %d.\n",
259             $msg, $PL_op->desc, $PL_curcop->file, $PL_curcop->line;
260             }
261              
262             sub longmess{
263 0     0 0 0 my $msg = mess(@_);
264 0         0 my $cxix = $#PL_cxstack;
265 0         0 while( ($cxix = dopoptosub($cxix)) >= 0 ){
266 0         0 my $cx = $PL_cxstack[$cxix];
267 0         0 my $cop = $cx->oldcop;
268              
269 0         0 my $args;
270              
271 0 0       0 if($cx->argarray){
272 0 0       0 $args = sprintf '(%s)', join q{,},
273 0         0 map{ defined($_) ? qq{'$_'} : 'undef' }
274 0         0 @{ $cx->argarray->object_2svref };
275             }
276             else{
277 0         0 $args = '';
278             }
279              
280 0         0 my $cvgv = $cx->cv->GV;
281 0         0 $msg .= sprintf qq{[APVM] %s%s called at %s line %d.\n},
282             gv_fullname($cvgv), $args,
283             $cop->file, $cop->line;
284              
285 0         0 $cxix--;
286             }
287 0         0 return $msg;
288             }
289              
290             sub apvm_warn{
291             #warn APVM_DEBUG ? longmess(@_) : mess(@_);
292 0     0 0 0 print STDERR longmess(@_);
293             }
294             sub apvm_die{
295             # not yet implemented completely
296             # cf.
297             # die_where() in pp_ctl.c
298             # vdie() in util.c
299 0     0 0 0 die APVM_DEBUG ? longmess(@_) : mess(@_);
300             }
301             sub croak{
302 0     0 0 0 die APVM_DEBUG ? longmess(@_) : mess(@_);
303             }
304              
305             sub PUSHMARK(){
306 188     188 0 375 push @PL_markstack, $#PL_stack;
307 188         453 return;
308             }
309             sub POPMARK(){
310 180     180 0 477 return pop @PL_markstack;
311             }
312             sub TOPMARK(){
313 115     115 0 314 return $PL_markstack[-1];
314             }
315              
316             sub PUSH{
317 632     632   1042 push @PL_stack, @_;
318 632         1071 return;
319             }
320             sub mPUSH{
321 11     11 0 25 PUSH(map{ sv_2mortal($_) } @_);
  12         32  
322 11         25 return;
323             }
324             sub POP(){
325 225     225   643 return pop @PL_stack;
326             }
327             sub TOP(){
328 156     156 0 449 return $PL_stack[-1];
329             }
330             sub SET{
331 71     71 0 109 my($sv) = @_;
332 71         99 $PL_stack[-1] = $sv;
333 71         168 return;
334             }
335             sub SETval{
336 2     2 0 3 my($val) = @_;
337 2         15 $PL_stack[-1] = PAD_SV( $PL_op->targ )->setval($val);
338 2         6 return;
339             }
340              
341             sub GET_TARGET{
342 115     115 0 509 return PAD_SV($PL_op->targ);
343             }
344             sub GET_TARGETSTACKED{
345 5 50   5 0 183 return $PL_op->flags & OPf_STACKED ? POP : PAD_SV($PL_op->targ);
346             }
347             sub GET_ATARGET{
348 31 100   31 0 197 return $PL_op->flags & OPf_STACKED ? $PL_stack[$#PL_stack-1] : PAD_SV($PL_op->targ);
349             }
350              
351             sub MAXARG{
352 0     0 0 0 return $PL_op->private & 0x0F;
353             }
354              
355             sub PUSHBLOCK{
356 154     154 0 2574 my($type, %args) = @_;
357              
358 154         327 $args{oldcop} = $PL_curcop;
359 154         299 $args{oldmarksp} = $#PL_markstack;
360 154         305 $args{oldscopesp} = $#PL_scopestack;
361              
362 154         2285 my $cx = "Acme::Perl::VM::Context::$type"->new(\%args);
363 154         895 push @PL_cxstack, $cx;
364              
365 154         184 if(APVM_CX){
366             deb "%s" . "Entering %s\n", (q{>} x @PL_cxstack), $type;
367             }
368              
369 154         627 return $cx;
370             }
371              
372             sub POPBLOCK{
373 132     132 0 228 my $cx = pop @PL_cxstack;
374              
375 132         440 $PL_curcop = $cx->oldcop;
376 132         475 $#PL_markstack = $cx->oldmarksp;
377 132         399 $#PL_scopestack = $cx->oldscopesp;
378              
379 132         161 if(APVM_CX){
380             deb "%s" . "Leaving %s\n", (q{>} x (@PL_cxstack+1)), $cx->type;
381             }
382              
383 132         341 return $cx;
384             }
385             sub TOPBLOCK{
386 0     0 0 0 my $cx = $PL_cxstack[-1];
387              
388 0         0 $#PL_stack = $cx->oldsp;
389 0         0 $#PL_markstack = $cx->oldmarksp;
390 0         0 $#PL_scopestack = $cx->oldscopesp;
391              
392 0         0 return $cx;
393             }
394              
395             sub POPSUB{
396 116     116 0 165 my($cx) = @_;
397 116 100       403 if($cx->hasargs){
398 19         57 *_ = $cx->savearray;
399              
400 19         23 @{ $cx->argarray->object_2svref } = ();
  19         109  
401             }
402 116         248 return;
403             }
404              
405             sub POPLOOP{
406 5     5 0 7 my($cx) = @_;
407              
408 5 100       19 if($cx->ITERVAR){
409 2 50       11 if($cx->padvar){
410 0         0 my $padix = $cx->iterdata;
411             #my $curpad = $PL_comppad->object_2svref;
412              
413             #delete $curpad->[$padix];
414             #$curpad->[$padix] = $cx->itersave;
415             #dump_object($PL_curpad[$padix], $cx->itersave);
416 0         0 $PL_curpad[$padix] = $cx->itersave;
417             }
418             }
419 5         12 return;
420             }
421              
422             sub dounwind{
423 6     6 0 9 my($cxix) = @_;
424              
425 6         17 while($#PL_cxstack > $cxix){
426 6         11 my $cx = pop @PL_cxstack;
427 6         18 my $type = $cx->type;
428              
429 6 50       79 if($type eq 'SUBST'){
    50          
    50          
    50          
430 0         0 POPSUBST($cx);
431             }
432             elsif($type eq 'SUB'){
433 0         0 POPSUB($cx);
434             }
435             elsif($type eq 'EVAL'){
436 0         0 POPEVAL($cx);
437             }
438             elsif($type eq 'LOOP'){
439 0         0 POPLOOP($cx);
440             }
441             }
442 6         16 return;
443             }
444              
445             sub ENTER{
446 264     264 0 8668 push @PL_scopestack, $#PL_savestack;
447 264         324 if(APVM_SCOPE){
448             deb "%s" . "ENTER\n", ('>' x @PL_scopestack);
449             }
450 264         470 return;
451             }
452              
453             sub LEAVE{
454 225     225 0 377 my $oldsave = pop @PL_scopestack;
455 225         577 LEAVE_SCOPE($oldsave);
456              
457 225         217 if(APVM_SCOPE){
458             deb "%s" . "LEAVE\n", ('>' x (@PL_scopestack+1));
459             }
460 225         359 return;
461             }
462             sub LEAVE_SCOPE{
463 246     246 0 300 my($oldsave) = @_;
464              
465 246         624 while( $oldsave < $#PL_savestack ){
466 374         521 my $ss = pop @PL_savestack;
467              
468 374         504 if(APVM_SCOPE){
469             deb "%s" . "leave %s %s\n",
470             ('>' x (@PL_cxstack+1)), $ss->type, $ss->saved_state;
471             }
472 374         1243 $ss->leave();
473             }
474 246         390 return;
475             }
476              
477             sub SAVETMPS{
478 258     258 0 3061 push @PL_savestack, Acme::Perl::VM::Scope::Tmps->new(
479             value => $PL_tmps_floor,
480             value_ref => \$PL_tmps_floor,
481             );
482 258         3634 $PL_tmps_floor = $#PL_tmps;
483 258         497 return;
484             }
485             sub FREETMPS{
486 319     319 0 624 $#PL_tmps = $PL_tmps_floor;
487 319         577 return;
488             }
489              
490             sub SAVE{
491 2     2 0 23 push @PL_savestack, Acme::Perl::VM::Scope::Value->new(
492             value => $_[0],
493             value_ref => \$_[0],
494             );
495 2         72 return;
496             }
497             sub SAVECOMPPAD{
498 131     131 0 1240 push @PL_savestack, Acme::Perl::VM::Scope::Comppad->new(
499             comppad => $PL_comppad,
500             comppad_name => $PL_comppad_name,
501             );
502 131         1715 return;
503             }
504             sub SAVECLEARSV{
505 23     23 0 40 my($sv) = @_;
506 23         242 push @PL_savestack, Acme::Perl::VM::Scope::Clearsv->new(
507             sv => $sv,
508             );
509 23         624 return;
510             }
511             sub SAVEPADSV{
512 0     0 0 0 my($off) = @_;
513 0         0 push @PL_savestack, Acme::Perl::VM::Scope::Padsv->new(
514             off => $off,
515 0         0 value => ${$PL_curpad[$off]->object_2svref},
516             comppad => $PL_comppad,
517             );
518 0         0 return;
519             }
520             sub save_scalar{
521 3     3 0 4 my($gv) = @_;
522 3         35 push @PL_savestack, Acme::Perl::VM::Scope::Scalar->new(gv => $gv);
523 3         13 return $PL_savestack[-1]->sv;
524             }
525             sub save_ary{
526 1     1 0 2 my($gv) = @_;
527 1         17 push @PL_savestack, Acme::Perl::VM::Scope::Array->new(gv => $gv);
528 1         5 return $PL_savestack[-1]->sv;
529             }
530             sub save_hash{
531 1     1 0 2 my($gv) = @_;
532 1         14 push @PL_savestack, Acme::Perl::VM::Scope::Hash->new(gv => $gv);
533 1         5 return $PL_savestack[-1]->sv;
534             }
535              
536             sub PAD_SET_CUR_NOSAVE{
537 131     131 0 195 my($padlist, $nth) = @_;
538              
539 131         623 $PL_comppad_name = $padlist->ARRAYelt(0);
540 131         437 $PL_comppad = $padlist->ARRAYelt($nth);
541 131         805 @PL_curpad = ($PL_comppad->ARRAY);
542              
543 131         232 return;
544             }
545             sub PAD_SET_CUR{
546 131     131 0 217 my($padlist, $nth) = @_;
547              
548 131         312 SAVECOMPPAD();
549 131         313 PAD_SET_CUR_NOSAVE($padlist, $nth);
550              
551 131         269 return;
552             }
553              
554             sub PAD_SV{
555             #my($targ) = @_;
556              
557 153     153 0 474 return $PL_curpad[ $_[0] ];
558             }
559              
560             sub dopoptosub{
561 72     72 0 164 my($startingblock) = @_;
562              
563 72         245 for(my $i = $startingblock; $i >= 0; $i--){
564 86         403 my $type = $PL_cxstack[$i]->type;
565              
566 86 100 66     523 if($type eq 'EVAL' or $type eq 'SUB'){
567 72         298 return $i;
568             }
569             }
570 0         0 return -1;
571             }
572              
573             my %loop;
574             @loop{qw(SUBST SUB EVAL NULL)} = ();
575             $loop{LOOP} = TRUE;
576              
577             sub dopoptoloop{
578 0     0 0 0 my($startingblock) = @_;
579              
580 0         0 for(my $i = $startingblock; $i >= 0; --$i){
581 0         0 my $cx = $PL_cxstack[$i];
582 0         0 my $type = $cx->type;
583              
584 0 0       0 if(exists $loop{$type}){
585 0 0       0 if(!$loop{$type}){
586 0         0 apvm_warn 'Exsiting %s via %s', $type, $PL_op->name;
587 0 0       0 $i = -1 if $type eq 'NULL';
588             }
589 0         0 return $i;
590             }
591             }
592 0         0 return -1;
593             }
594             sub dopoptolabel{
595 0     0 0 0 my($label) = @_;
596              
597 0         0 for(my $i = $#PL_cxstack; $i >= 0; --$i){
598 0         0 my $cx = $PL_cxstack[$i];
599 0         0 my $type = $cx->type;
600              
601 0 0       0 if(exists $loop{$type}){
602 0 0 0     0 if(!$loop{$type}){
    0          
603 0         0 apvm_warn 'Exsiting %s via %s', $type, $PL_op->name;
604 0 0       0 return $type eq 'NULL' ? -1 : $i;
605             }
606             elsif($cx->label && $cx->label eq $label){
607 0         0 return $i;
608             }
609             }
610             }
611 0         0 return -1;
612             }
613              
614             sub OP_GIMME{ # op.h
615 209     209 0 334 my($op, $default) = @_;
616 209         703 my $op_gimme = $op->flags & OPf_WANT;
617 209 100       927 return $op_gimme == OPf_WANT_VOID ? G_VOID
    100          
    100          
618             : $op_gimme == OPf_WANT_SCALAR ? G_SCALAR
619             : $op_gimme == OPf_WANT_LIST ? G_ARRAY
620             : $default;
621             }
622              
623             sub OP_GIMME_REVERSE{ # op.h
624 101     101 0 155 my($flags) = @_;
625 101         141 $flags &= G_WANT;
626 101 100       1446 return $flags == G_VOID ? OPf_WANT_VOID
    100          
627             : $flags == G_SCALAR ? OPf_WANT_SCALAR
628             : OPf_WANT_LIST;
629             }
630              
631             sub gimme2want{
632 0     0 0 0 my($gimme) = @_;
633 0         0 $gimme &= G_WANT;
634 0 0       0 return $gimme == G_VOID ? undef
    0          
635             : $gimme == G_SCALAR ? 0
636             : 1;
637             }
638             sub want2gimme{
639 101     101 0 207 my($wantarray) = @_;
640              
641 101 100       440 return !defined($wantarray) ? G_VOID
    100          
642             : !$wantarray ? G_SCALAR
643             : G_ARRAY;
644             }
645              
646             sub block_gimme{
647 52     52 0 178 my $cxix = dopoptosub($#PL_cxstack);
648              
649 52 50       218 if($cxix < 0){
650 0         0 return G_VOID;
651             }
652              
653 52         315 return $PL_cxstack[$cxix]->gimme;
654             }
655              
656             sub GIMME_V(){ # op.h
657 181     181 0 485 my $gimme = OP_GIMME($PL_op, -1);
658 181 100       629 return $gimme != -1 ? $gimme : block_gimme();
659             }
660              
661             sub LVRET(){ # cf. is_lvalue_sub() in pp_ctl.h
662 14 100   14 0 67 if($PL_op->flags & OPpMAYBE_LVSUB){
663 1         4 my $cxix = dopoptosub($#PL_cxstack);
664              
665 1 50 33     8 if($PL_cxstack[$cxix]->lval && $PL_cxstack[$cxix]->cv->CvFLAGS & CVf_LVALUE){
666 0         0 not_implemented 'lvalue';
667 0         0 return TRUE;
668             }
669             }
670 14         63 return FALSE;
671             }
672              
673             sub SVOP_sv{
674 0     0 0 0 my($op) = @_;
675 0         0 return USE_ITHREADS ? PAD_SV($op->padix) : $op->sv;
676             }
677             sub GVOP_gv{
678 47     47 0 74 my($op) = @_;
679 47         251 return USE_ITHREADS ? PAD_SV($op->padix) : $op->gv;
680             }
681              
682             sub vivify_ref{
683 0     0 0 0 not_implemented 'vivify_ref';
684             }
685              
686             sub sv_newmortal{
687 38     38 0 40 my $sv;
688 38         55 push @PL_tmps, \$sv;
689 38         158 return B::svref_2object(\$sv);
690             }
691             sub sv_mortalcopy{
692 162     162 0 223 my($sv) = @_;
693              
694 162 50       353 if(!defined $sv){
695 0         0 Carp::confess('sv_mortalcopy(NULL)');
696             }
697              
698 162         174 my $newsv =${$sv->object_2svref};
  162         535  
699 162         279 push @PL_tmps, \$newsv;
700 162         971 return B::svref_2object(\$newsv);
701             }
702             sub sv_2mortal{
703 13     13 0 23 my($sv) = @_;
704              
705 13 50       40 if(!defined $sv){
706 0         0 Carp::confess('sv_2mortal(NULL)');
707             }
708              
709 13         47 push @PL_tmps, $sv->object_2svref;
710 13         44 return $sv;
711             }
712              
713             sub SvTRUE{
714 27     27 0 34 my($sv) = @_;
715              
716 27 100       30 return ${ $sv->object_2svref } ? TRUE : FALSE;
  27         139  
717             }
718              
719             sub SvPV{
720 19     19 0 24 my($sv) = @_;
721 19         60 my $ref = $sv->object_2svref;
722              
723 19 50       26 if(!defined ${$ref}){
  19         52  
724 0         0 apvm_warn 'Use of uninitialized value';
725 0         0 return q{};
726             }
727              
728 19         27 return "${$ref}";
  19         86  
729             }
730              
731             sub SvNV{
732 59     59 0 75 my($sv) = @_;
733 59         381 my $ref = $sv->object_2svref;
734              
735 58 50       60 if(!defined ${$ref}){
  58         145  
736 0         0 apvm_warn 'Use of uninitialized value';
737 0         0 return 0;
738             }
739              
740 58         57 return ${$ref} + 0;
  58         192  
741             }
742              
743             sub SvIV{
744 4     4 0 6 my($sv) = @_;
745 4         10 my $ref = $sv->object_2svref;
746              
747 4 50       6 if(!defined ${$ref}){
  4         20  
748 0         0 apvm_warn 'Use of uninitialized value';
749 0         0 return 0;
750             }
751              
752 4         4 return int(${$ref});
  4         33  
753             }
754              
755             sub av_assign{
756 24     24 0 35 my $av = shift;
757 24         88 my $ref = $av->object_2svref;
758 24         38 $#{$ref} = $#_;
  24         65  
759 24         84 for(my $i = 0; $i < @_; $i++){
760 40         276 tie $ref->[$i], 'Acme::Perl::VM::Alias', $_[$i]->object_2svref;
761             }
762 24         66 return;
763             }
764              
765             sub av_store{
766 0     0 0 0 my($av, $ix, $sv) = @_;
767 0         0 tie $av->object_2svref->[$ix],
768             'Acme::Perl::VM::Alias', $sv->object_2svref;
769 0         0 return;
770             }
771              
772             sub hv_store{
773 0     0 0 0 my($hv, $key, $sv) = @_;
774 0         0 tie $hv->object_2svref->{$key},
775             'Acme::Perl::VM::Alias', $sv->object_2svref;
776 0         0 return;
777             }
778              
779             sub hv_store_ent{
780 0     0 0 0 my($hv, $key, $sv) = @_;
781 0         0 tie $hv->object_2svref->{ ${$key->object_2svref} },
  0         0  
782             'Acme::Perl::VM::Alias', $sv->object_2svref;
783 0         0 return;
784             }
785              
786             sub hv_scalar{
787 1     1 0 2 my($hv) = @_;
788 1         5 my $sv = sv_newmortal();
789 1         2 $sv->setval(scalar %{ $hv->object_2svref });
  1         23  
790 1         5 return $sv;
791             }
792              
793             sub defoutgv{
794 22     22   316 no strict 'refs';
  22         52  
  22         15756  
795 6     6 0 5 return \*{ select() };
  6         33  
796             }
797              
798             sub gv_fullname{
799 0     0 0 0 my($gv, $prefix) = @_;
800 0 0       0 $prefix = '' unless defined $prefix;
801              
802 0         0 my $stashname = $gv->STASH->NAME;
803 0 0       0 if($stashname eq 'main'){
804 0         0 $prefix .= $gv->SAFENAME;
805             }
806             else{
807 0         0 $prefix .= join q{::}, $stashname, $gv->SAFENAME;
808             }
809 0         0 return $prefix;
810             }
811              
812             # Utilities
813              
814             sub sv_defined{
815 14     14 0 19 my($sv) = @_;
816              
817 14   33     55 return $sv && ${$sv} && defined(${ $sv->object_2svref });
818             }
819              
820             sub is_not_null{
821 163     163 0 246 my($sv) = @_;
822 163         184 return ${$sv};
  163         1145  
823             }
824             sub is_null{
825 134     134 0 211 my($sv) = @_;
826 134         168 return !${$sv};
  134         595  
827             }
828              
829             my %not_a_scalar;
830             @not_a_scalar{qw(AV HV CV IO)} = ();
831             sub is_scalar{
832 0     0 0 0 my($sv) = @_;
833 0         0 return !exists $not_a_scalar{ $sv->class };
834             }
835              
836             sub mark_list{
837 98     98 0 158 my($mark) = @_;
838 98         295 return map{ ${ $_->object_2svref } } splice @PL_stack, $mark+1;
  136         190  
  136         577  
839             }
840              
841              
842             our %external;
843              
844             sub apvm_extern{
845 5     5 0 53 foreach my $arg(@_){
846 6 100       25 if(ref $arg){
847 2 50       8 if(ref($arg) ne 'CODE'){
848 0         0 Carp::croak('Not a CODE reference for apvm_extern()');
849             }
850 2         15 $external{refaddr $arg} = 1;
851             }
852             else{
853 22     22   170 my $stash = do{ no strict 'refs'; \%{$arg .'::'} };
  22         53  
  22         1533  
  4         10  
  4         9  
  4         29  
854 4         11 while(my $name = each %{$stash}){
  216         511  
855 22     22   121 my $code_ref = do{ no strict 'refs'; *{$arg . '::' . $name}{CODE} };
  22         58  
  22         11563  
  212         186  
  212         190  
  212         534  
856 212 100       398 if(defined $code_ref){
857 156         498 $external{refaddr $code_ref} = 1;
858             }
859             }
860             }
861             }
862 5         17 return;
863             }
864              
865             sub cv_external{
866 134     134 0 210 my($cv) = @_;
867 134   66     773 return $cv->XSUB || $external{ ${$cv} };
868             }
869              
870             sub ddx{
871 0     0 0 0 require Data::Dumper;
872 0         0 my $ddx = Data::Dumper->new(@_);
873 0         0 $ddx->Indent(1);
874 0         0 $ddx->Terse(TRUE);
875 0         0 $ddx->Quotekeys(FALSE);
876 0         0 $ddx->Useqq(TRUE);
877 0 0       0 return $ddx if defined wantarray;
878              
879 0         0 my $name = ( split '::', (caller 2)[3] )[-1];
880 0         0 print STDERR $name, ': ', $ddx->Dump(), "\n";
881 0         0 return;
882             }
883             sub dump_object{
884 0 0   0 0 0 ddx([[ map{ $_ ? $_->object_2svref : $_ } @_ ]]);
  0         0  
885             }
886              
887             sub dump_value{
888 0     0 0 0 ddx([\@_]);
889             }
890              
891              
892             sub dump_stack{
893 0     0 0 0 require Data::Dumper;
894 22     22   173 no warnings 'once';
  22         56  
  22         34601  
895              
896 0         0 local $Data::Dumper::Indent = 0;
897 0         0 local $Data::Dumper::Terse = TRUE;
898 0         0 local $Data::Dumper::Quotekeys = FALSE;
899 0         0 local $Data::Dumper::Useqq = TRUE;
900              
901 0         0 deb "(%s)\n", join q{,}, map{
902             # find variable name
903 0         0 my $varname = '';
904 0         0 my $class = $_->class;
905              
906 0 0       0 if($class eq 'SPECIAL'){
    0          
907 0         0 ($varname = $_->special_name) =~ s/^\&PL_//;
908 0         0 $varname;
909             }
910             elsif($class eq 'CV'){
911 0         0 $varname = '&' . gv_fullname($_->GV);
912             }
913             else{
914 0         0 for(my $padix = 0; $padix < @PL_curpad; $padix++){
915 0         0 my $padname;
916 0 0 0     0 if(${ $PL_curpad[$padix] } == ${ $_ }){
  0 0       0  
  0         0  
  0         0  
917 0         0 $padname = $PL_comppad_name->ARRAYelt($padix);
918             }
919 0         0 elsif($_->ROK && ${$PL_curpad[$padix]} == ${ $_->RV }){
920 0         0 $padname = $PL_comppad_name->ARRAYelt($padix);
921 0         0 $varname .= '\\';
922             }
923              
924 0 0       0 if($padname){
925 0 0       0 if($padname->POK){
926 0         0 $varname .= $padname->PVX . ' ';
927             }
928 0         0 last;
929             }
930             }
931 0 0       0 $varname . Data::Dumper->Dump([is_scalar($_) ? ${$_->object_2svref} : $_->object_2svref], [$_->ROK ? 'SV' : '*SV']);
  0 0       0  
932             }
933              
934             } @PL_stack;
935              
936 0         0 return;
937             }
938             sub _dump_stack{
939 0     0   0 my $warn;
940             my $ddx = ddx([[map{
941 0 0       0 if(ref $_){
  0         0  
942 0 0       0 is_scalar($_) ? ${$_->object_2svref} : $_->object_2svref;
  0         0  
943             }
944             else{
945 0         0 $warn++;
946 0         0 $_;
947             }
948             } @PL_stack]], ['*PL_stack']);
949 0         0 $ddx->Indent(0);
950 0         0 deb " %s\n", $ddx->Dump();
951              
952 0 0       0 if($warn){
953 0         0 apvm_die 'No sv found (%d)', $warn;
954             }
955 0         0 return;
956             }
957              
958             sub dump_si{
959 0     0 0 0 my %stack_info = (
960             stack => \@PL_stack,
961             markstack => \@PL_markstack,
962             cxstack => \@PL_cxstack,
963             scopstack => \@PL_scopestack,
964             savestack => \@PL_savestack,
965             tmps => \@PL_tmps,
966             );
967              
968 0         0 ddx([\%stack_info]);
969             }
970              
971             sub not_implemented{
972 11 50   11 0 52 if(!@_){
973 0 0 0     0 if($PL_op && is_not_null($PL_op)){
974 0         0 @_ = ($PL_op->name);
975             }
976             else{
977 0         0 @_ = (caller 0)[3];
978             }
979             }
980              
981 11         34 push @_, ' is not implemented';
982 11         3661 goto &Carp::confess;
983             }
984              
985              
986             sub call_sv{ # perl.h
987 101     101 0 202 my($sv, $flags) = @_;
988              
989 101 50       379 if($flags & G_DISCARD){
990 0         0 ENTER;
991 0         0 SAVETMPS;
992             }
993              
994 101         457 my $cv = $sv->toCV();
995              
996 101         174 my $old_op = $PL_op;
997 101         172 my $old_cop = $PL_curcop;
998              
999 101         329 $PL_op = Acme::Perl::VM::OP_CallSV->new(
1000             cv => $cv,
1001             next => NULL,
1002             flags => OP_GIMME_REVERSE($flags),
1003             );
1004 101         2184 $PL_curcop = $PL_op;
1005              
1006 101         240 PUSH($cv);
1007 101         245 my $oldmark = TOPMARK;
1008              
1009 101         280 $PL_runops->();
1010              
1011 88         180 my $retval = $#PL_stack - $oldmark;
1012              
1013 88 50       256 if($flags & G_DISCARD){
1014 0         0 $#PL_stack = $oldmark;
1015 0         0 $retval = 0;
1016 0         0 FREETMPS;
1017 0         0 LEAVE;
1018             }
1019              
1020 88         132 $PL_op = $old_op;
1021 88         114 $PL_curcop = $old_cop;
1022              
1023 88         483 return $retval;
1024             }
1025              
1026             sub run_block(&@){
1027 101     101 0 34219 my($code, @args) = @_;
1028              
1029 101         173 if(APVM_DUMMY){
1030             return $code->(@args);
1031             }
1032 101         133 local $SIG{__DIE__} = \&Carp::confess if APVM_DEBUG;
1033 101         146 local $SIG{__WARN__} = \&Carp::cluck if APVM_DEBUG;
1034              
1035 101         306 ENTER;
1036 101         253 SAVETMPS;
1037              
1038 101         281 PUSHMARK;
1039 101         284 PUSH(@args);
1040              
1041 101         273 my $gimme = want2gimme(wantarray);
1042 101         737 my $mark = $#PL_stack - call_sv(B::svref_2object($code), $gimme);
1043 88         296 my @retval = mark_list($mark);
1044              
1045 88         225 FREETMPS;
1046 88         170 LEAVE;
1047              
1048 88 100       306 if($gimme == G_SCALAR){
    100          
1049 31         171 return $retval[-1];
1050             }
1051             elsif($gimme == G_ARRAY){
1052 46         333 return @retval;
1053             }
1054              
1055 11         29 return;
1056             }
1057              
1058             package
1059             Acme::Perl::VM::OP_CallSV;
1060              
1061 22     22   185 use Mouse;
  22         51  
  22         265  
1062              
1063             has cv => (
1064             is => 'ro',
1065             isa => 'B::CV',
1066              
1067             required => 1,
1068             );
1069              
1070             has next => (
1071             is => 'ro',
1072             isa => 'B::OBJECT',
1073              
1074             required => 1,
1075             );
1076              
1077             has flags => (
1078             is => 'ro',
1079             isa => 'Int',
1080              
1081             required => 1,
1082             );
1083              
1084             use constant {
1085 22         4143 class => 'OP',
1086             type => B::opnumber('entersub'),
1087             name => 'entersub',
1088             desc => 'subroutine entry',
1089              
1090             file => __FILE__,
1091             line => 0,
1092 22     22   15547 };
  22         53  
1093              
1094             sub isa{
1095 101     101   3418 shift;
1096 101         2163 return B::COP->isa(@_);
1097             }
1098              
1099 22     22   127 no Mouse;
  22         49  
  22         190  
1100             __PACKAGE__->meta->make_immutable();
1101              
1102             package
1103             Acme::Perl::VM::Alias;
1104              
1105              
1106             sub TIESCALAR{
1107 40     40   58 my($class, $scalar_ref) = @_;
1108 40         204 return bless [$scalar_ref], $class;
1109             }
1110             sub FETCH{
1111 16     16   49 return ${ $_[0]->[0] }
  16         62  
1112             }
1113             sub STORE{
1114 0     0     ${ $_[0]->[0] } = $_[1];
  0            
1115 0           return;
1116             }
1117              
1118              
1119             1;
1120             __END__