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
|
/* vi: set ft=c : */
static bool op_is_const(OP *o)
{
switch(o->op_type) {
case OP_CONST:
return true;
case OP_LIST:
{
OP *oelem = cLISTOPo->op_first;
if(oelem->op_type == OP_PUSHMARK)
oelem = OpSIBLING(oelem);
for(; oelem; oelem = OpSIBLING(oelem))
if(oelem->op_type != OP_CONST)
return false;
return true;
}
default:
return false;
}
}
static OP *ckcall_constfold(pTHX_ OP *o, GV *namegv, SV *ckobj)
{
assert(o->op_type == OP_ENTERSUB);
OP *kid = cUNOPo->op_first;
/* The first kid is usually an ex-list whose ->op_first begins the actual args list */
if(kid->op_type == OP_NULL && kid->op_targ == OP_LIST)
kid = cUNOPx(kid)->op_first;
/* First actual arg is likely a OP_PUSHMARK */
if(kid->op_type == OP_PUSHMARK)
kid = OpSIBLING(kid);
OP *firstarg = kid;
for(; kid && OpSIBLING(kid); kid = OpSIBLING(kid)) {
if(op_is_const(kid))
continue;
return o;
}
CV *cv = GvCV(namegv);
assert(SvTYPE(cv) == SVt_PVCV);
/* We've not rejected it now, so lets invoke it and inline the result */
/* TODO: I tried invoking the actual optree by linking it, setting it as
* PL_op and invoking CALLRUNOPS(), but it seems the pad isn't set up
* correctly yet to permit this for OP_PADCV ops.
* Instead, we'll simulated it by PUSHs()ing ourselves
*/
dSP;
ENTER;
SAVETMPS;
PUSHMARK(SP);
for(OP *oarg = firstarg; oarg && OpSIBLING(oarg); oarg = OpSIBLING(oarg)) {
switch(oarg->op_type) {
case OP_CONST:
PUSHs(cSVOPx(oarg)->op_sv);
break;
case OP_LIST:
{
OP *oelem = cUNOPx(oarg)->op_first;
if(oelem->op_type == OP_PUSHMARK)
oelem = OpSIBLING(oelem);
for(; oelem; oelem = OpSIBLING(oelem)) {
assert(oelem->op_type == OP_CONST);
PUSHs(cSVOPx(oelem)->op_sv);
}
break;
}
}
}
PUTBACK;
/* TODO: Currently always presume scalar context */
I32 count = call_sv((SV *)cv, G_SCALAR|G_EVAL);
bool got_err = SvTRUE(GvSV(PL_errgv));
SPAGAIN;
SV *retval = SvREFCNT_inc(POPs);
PUTBACK;
FREETMPS;
LEAVE;
if(got_err)
/* Error was raised; abort */
return o;
op_free(o);
o = newSVOP(OP_CONST, 0, retval);
return o;
}
|