File: ref.xs

package info (click to toggle)
libuniversal-ref-perl 0.14-9
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 560 kB
  • sloc: perl: 149; makefile: 3
file content (170 lines) | stat: -rw-r--r-- 5,443 bytes parent folder | download | duplicates (4)
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"

typedef OP	*B__OP;

int init_done = 0;

#if 0
#define UNIVERSAL_REF_DEBUG(x) x
#else
#define UNIVERSAL_REF_DEBUG(x)
#endif

OP* (*real_pp_ref)(pTHX);
PP(pp_universal_ref) { 
    dSP; dTARG;
    SV* thing;
    SV* result;
    int count;

    if ( OP_REF != PL_op->op_type ) {
        /* WTF called us? Whatever it is, I don't want to screw with it. */
        return real_pp_ref(aTHX);
    }

    /* Delegate to the pre-existing function if it isn't an object. */
    if ( ! sv_isobject( TOPs ) ) {
        /* I only mess with objects. */
        return real_pp_ref(aTHX);
    }

    /* Start our scope. */
    thing = POPs;
    ENTER;
    SAVETMPS;

    /* Pass that as an argument to the callback. */
    /* TODO: list context. */
    PUSHMARK(SP);
    XPUSHs(thing);
    PUTBACK;
    count = call_pv( "UNIVERSAL::ref::_hook", G_SCALAR );
    if ( 1 != count )
        croak("UNIVERSAL::ref::_hook returned %d elements, expected 1", count);

    /* Get our result and increase its refcount so it won't be reaped
       by closing this scope. */
    /* TODO: list context. */
    SPAGAIN;
    result = POPs;
    SvREFCNT_inc(result);

    /* Close our scope. */
    FREETMPS;
    LEAVE;
    
    /* Just return whatever the callback returned. */
    assert( 1 == SvREFCNT(result));
    XPUSHs(result);
    RETURN;
}

void universal_ref_fixupop( OP* o ) {
  /* I'm seeing completely fruity ->op_sibling pointers and I think
     perhaps I shouldn't be looking at some ops. I'm hoping that
     requiring that I have a valid sort of class will prevent me
     from wandering into places I shouldn't be. */
  U32 opclass;

  UNIVERSAL_REF_DEBUG(printf( "fixing op=%x\n", o ));
  opclass = (OA_CLASS_MASK & PL_opargs[o->op_type]) >> OCSHIFT;
  if ( opclass < OA_UNOP ) {
    return;
  }
  
  /* printf("# OP=%x\n",o); */
  if ( o->op_type == OP_REF || o->op_ppaddr == real_pp_ref ) {
    UNIVERSAL_REF_DEBUG(printf("# XXX\n"));
    o->op_ppaddr = Perl_pp_universal_ref;
  }

  UNIVERSAL_REF_DEBUG(printf("# op_type=%d\n",o->op_type));
  UNIVERSAL_REF_DEBUG(printf("# opargs=%x\n",PL_opargs[o->op_type] & ~OA_CLASS_MASK));
  UNIVERSAL_REF_DEBUG(printf("# class=%x\n", opclass));

  if ( cUNOPx(o)->op_first ) {
    UNIVERSAL_REF_DEBUG(printf("# ->first=%x\n",cUNOPx(o)->op_first));
    universal_ref_fixupop(cUNOPx(o)->op_first);
  }

  if ( OpHAS_SIBLING(o) ) {
    UNIVERSAL_REF_DEBUG(printf("# ->sibling=%x\n",OpSIBLING(o)));
    universal_ref_fixupop(OpSIBLING(o));
  }
}

void universal_ref_fixupworld () {
    I32 i = 0;

    /* TODO: This finds all existing code and replaces ppaddr with the
       new pointer. */

    /* Fixup stuff that exists. */
/*
    if ( PL_main_root ) {
        UNIVERSAL_REF_DEBUG(printf("# FIXING PL_main_root\n"));
        universal_ref_fixupop( PL_main_root );
    }
    if ( PL_eval_root ) {
        UNIVERSAL_REF_DEBUG(printf("# FIXING PL_eval_root\n"));
        universal_ref_fixupop(PL_eval_root);
    }
    if ( PL_main_cv && CvROOT(PL_main_cv) ) {
        UNIVERSAL_REF_DEBUG(printf("# FIXING PL_main_cv\n"));
        universal_ref_fixupop(CvROOT(PL_main_cv));
    }
    if ( PL_compcv && CvROOT(PL_compcv) ) {
        UNIVERSAL_REF_DEBUG(printf("# FIXING PL_compcv\n"));
        universal_ref_fixupop(CvROOT(PL_compcv));
    }
*/

    /* Is this too sneaky to live? Dunno. */
/*    for ( i = 2; i < PL_savestack_max; i += 2 ) {
        if ( PL_savestack[i].any_i32 == SAVEt_SPTR
             && (    &PL_compcv  == PL_savestack[i-1].any_ptr
                  || &PL_main_cv == PL_savestack[i-1].any_ptr )
             && PL_savestack[i-2].any_ptr ) {
            UNIVERSAL_REF_DEBUG(printf("# PL_compcv=%x\n", PL_savestack[i-2].any_ptr));
            UNIVERSAL_REF_DEBUG(printf("#   file=%s\n",CvFILE((CV*)(PL_savestack[i-2].any_ptr))));
            UNIVERSAL_REF_DEBUG(printf("#   root=%x\n",CvROOT((CV*)(PL_savestack[i-2].any_ptr))));
            UNIVERSAL_REF_DEBUG(printf("#   gv=%x\n",CvGV((CV*)(PL_savestack[i-2].any_ptr))));
            UNIVERSAL_REF_DEBUG(printf("#   xsubany=%x\n",CvXSUBANY((CV*)(PL_savestack[i-2].any_ptr))));
            UNIVERSAL_REF_DEBUG(printf("#   xsub=%x\n",CvXSUB((CV*)(PL_savestack[i-2].any_ptr))));
            UNIVERSAL_REF_DEBUG(printf("#   start=%x\n",CvSTART((CV*)(PL_savestack[i-2].any_ptr))));
            UNIVERSAL_REF_DEBUG(printf("#   stash=%x\n",CvSTASH((CV*)(PL_savestack[i-2].any_ptr))));
            UNIVERSAL_REF_DEBUG(printf("#   depth=%x\n",CvDEPTH((CV*)(PL_savestack[i-2].any_ptr))));
            UNIVERSAL_REF_DEBUG(printf("#   padlist=%x\n",CvPADLIST((CV*)(PL_savestack[i-2].any_ptr))));
            UNIVERSAL_REF_DEBUG(printf("#   outside=%x\n",CvOUTSIDE((CV*)(PL_savestack[i-2].any_ptr))));
            UNIVERSAL_REF_DEBUG(printf("#   flags=%x\n",CvFLAGS((CV*)(PL_savestack[i-2].any_ptr)))); */
            /* universal_ref_fixupop(CvROOT((CV*)(PL_savestack[i-2].any_ptr))); */
/*        }
    } */
}

MODULE = UNIVERSAL::ref	PACKAGE = UNIVERSAL::ref PREFIX = universal_ref_

PROTOTYPES: ENABLE

BOOT:
if ( ! init_done++  ) {
    /* Is this a race in threaded perl? */
    real_pp_ref = PL_ppaddr[OP_REF];
    PL_ppaddr[OP_REF] = Perl_pp_universal_ref;
/*    universal_ref_fixupworld(); */
}

void
universal_ref__fixupop( o )
        B::OP o
    CODE:
        universal_ref_fixupop( o );

void
universal_ref__fixupworld()
    CODE:
        universal_ref_fixupworld();