File: BeginLift.xs

package info (click to toggle)
libdevel-beginlift-perl 0.001003-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd, wheezy
  • size: 156 kB
  • ctags: 101
  • sloc: perl: 1,092; makefile: 2
file content (142 lines) | stat: -rw-r--r-- 3,285 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#define PERL_CORE
#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include <stdio.h>
#include <string.h>

#include "hook_op_check_entersubforcv.h"

/* lifted from op.c */

#define LINKLIST(o) ((o)->op_next ? (o)->op_next : linklist((OP*)o))

#ifndef linklist
# define linklist(o) THX_linklist(aTHX_ o)
STATIC OP *THX_linklist(pTHX_ OP *o) {
  OP *first;
  if(o->op_next)
    return o->op_next;
  first = cUNOPo->op_first;
  if (first) {
    OP *kid;
    o->op_next = LINKLIST(first);
    kid = first;
    for (;;) {
      if (kid->op_sibling) {
   kid->op_next = LINKLIST(kid->op_sibling);
   kid = kid->op_sibling;
      } else {
   kid->op_next = o;
   break;
      }
    }
  } else {
    o->op_next = o;
  }
  return o->op_next;
}
#endif /* !linklist */

STATIC OP *lift_cb(pTHX_ OP *o, CV *cv, void *user_data) {
  dSP;
  SV *sv;
  SV **stack_save;
  OP *curop, *kid, *saved_next;
  I32 type = o->op_type;

  /* shamelessly lifted from fold_constants in op.c */

  stack_save = SP;

  curop = LINKLIST(o);

  if (0) { /* call as macro */
    OP *arg;
    OP *gv;
    /* this means the argument pushing ops are not executed, only the GV to
     * resolve the call is, and B::OP objects will be made of all the opcodes
     * */
    PUSHMARK(SP); /* push a mark for the arguments */

    /* push an arg for every sibling op */
    for ( arg = curop->op_sibling; arg->op_sibling; arg = arg->op_sibling ) {
      XPUSHs(sv_bless(newRV_inc(newSViv(PTR2IV(arg))), gv_stashpv("B::LISTOP", 0)));
    }

    /* find the last non null before the lifted entersub */
    for ( kid = curop; kid->op_next != o; kid = kid->op_next ) {
      if ( kid->op_type == OP_GV )
          gv = kid;
    }

    PL_op = gv; /* make the call to our sub without evaluating the arg ops */
  } else {
    PL_op = curop;
  }

  /* stop right after the call */
  saved_next = o->op_next;
  o->op_next = NULL;

  PUTBACK;
  SAVETMPS;
  CALLRUNOPS(aTHX);
  SPAGAIN;

  if (SP > stack_save) { /* sub returned something */
    sv = POPs;
    if (o->op_targ && sv == PAD_SV(o->op_targ)) /* grab pad temp? */
      pad_swipe(o->op_targ,  FALSE);
    else if (SvTEMP(sv)) {      /* grab mortal temp? */
      (void)SvREFCNT_inc(sv);
      SvTEMP_off(sv);
    }

    if (SvROK(sv) && sv_derived_from(sv, "B::OP")) {
      OP *new = INT2PTR(OP *,SvIV((SV *)SvRV(sv)));
      new->op_sibling = NULL;

      /* FIXME this is bullshit */
      if ( (PL_opargs[new->op_type] & OA_CLASS_MASK) != OA_SVOP ) {
        new->op_next = saved_next;
      } else {
        new->op_next = new;
      }

      return new;
    }

    if (type == OP_RV2GV)
      return newGVOP(OP_GV, 0, (GV*)sv);

	if (SvTYPE(sv) == SVt_NULL) {
		op_free(o);
		return newOP(OP_NULL, 0);
	}

    return newSVOP(OP_CONST, 0, sv);
  } else {
    /* this bit not lifted, handles the 'sub doesn't return stuff' case
       which fold_constants can ignore */
    op_free(o);
    return newOP(OP_NULL, 0);
  }
}

MODULE = Devel::BeginLift  PACKAGE = Devel::BeginLift

PROTOTYPES: DISABLE

UV
setup_for_cv (class, CV *cv)
  CODE:
    RETVAL = (UV)hook_op_check_entersubforcv (cv, lift_cb, NULL);
  OUTPUT:
    RETVAL

void
teardown_for_cv (class, UV id)
  CODE:
    hook_op_check_entersubforcv_remove ((hook_op_check_id)id);