1 #define PERL_NO_GET_CONTEXT /* we want efficiency */
8 /* ... op => info map ................................................. */
15 #define PTABLE_NAME ptable_map
16 #define PTABLE_VAL_FREE(V) PerlMemShared_free(V)
18 #define ptable_map_store(T, K, V) ptable_map_store(aPTBLMS_ (T), (K), (V))
20 STATIC ptable *ab_op_map = NULL;
23 STATIC perl_mutex ab_op_map_mutex;
26 STATIC const ab_op_info *ab_map_fetch(const OP *o, ab_op_info *oi) {
27 const ab_op_info *val;
30 MUTEX_LOCK(&ab_op_map_mutex);
33 val = (ab_op_info *)ptable_fetch(ab_op_map, o);
40 MUTEX_UNLOCK(&ab_op_map_mutex);
46 STATIC const ab_op_info *ab_map_store_locked(
47 pPTBLMS_ const OP *o, OP *(*old_pp)(pTHX), IV base
49 #define ab_map_store_locked(O, PP, B) \
50 ab_map_store_locked(aPTBLMS_ (O), (PP), (B))
53 if (!(oi = (ab_op_info *)ptable_fetch(ab_op_map, o))) {
54 oi = (ab_op_info *)PerlMemShared_malloc(sizeof *oi);
55 ptable_map_store(ab_op_map, o, oi);
63 STATIC void ab_map_store(
64 pPTBLMS_ const OP *o, OP *(*old_pp)(pTHX), IV base)
66 #define ab_map_store(O, PP, B) ab_map_store(aPTBLMS_ (O),(PP),(B))
69 MUTEX_LOCK(&ab_op_map_mutex);
72 ab_map_store_locked(o, old_pp, base);
75 MUTEX_UNLOCK(&ab_op_map_mutex);
79 STATIC void ab_map_delete(pTHX_ const OP *o) {
80 #define ab_map_delete(O) ab_map_delete(aTHX_ (O))
82 MUTEX_LOCK(&ab_op_map_mutex);
85 ptable_map_store(ab_op_map, o, NULL);
88 MUTEX_UNLOCK(&ab_op_map_mutex);
92 /* ... $[ Implementation .............................................. */
95 #define hintkey_len (sizeof(hintkey)-1)
97 STATIC SV * ab_hint(pTHX_ const bool create) {
98 #define ab_hint(c) ab_hint(aTHX_ c)
101 = hv_fetch(GvHV(PL_hintgv), hintkey, hintkey_len, create);
107 /* current base at compile time */
108 STATIC IV current_base(pTHX) {
109 #define current_base() current_base(aTHX)
110 SV *hsv = ab_hint(0);
111 assert(FEATURE_ARYBASE_IS_ENABLED);
112 if (!hsv || !SvOK(hsv)) return 0;
116 STATIC void set_arybase_to(pTHX_ IV base) {
117 #define set_arybase_to(base) set_arybase_to(aTHX_ (base))
119 SV *hsv = ab_hint(1);
120 sv_setiv_mg(hsv, base);
123 #define old_ck(opname) STATIC OP *(*ab_old_ck_##opname)(pTHX_ OP *) = 0
138 STATIC bool ab_op_is_dollar_bracket(pTHX_ OP *o) {
139 #define ab_op_is_dollar_bracket(o) ab_op_is_dollar_bracket(aTHX_ (o))
141 return o->op_type == OP_RV2SV && (o->op_flags & OPf_KIDS)
142 && (c = cUNOPx(o)->op_first)
143 && c->op_type == OP_GV
144 && GvSTASH(cGVOPx_gv(c)) == PL_defstash
145 && strEQ(GvNAME(cGVOPx_gv(c)), "[");
148 STATIC void ab_neuter_dollar_bracket(pTHX_ OP *o) {
149 #define ab_neuter_dollar_bracket(o) ab_neuter_dollar_bracket(aTHX_ (o))
152 * Must replace the core's $[ with something that can accept assignment
153 * of non-zero value and can be local()ised. Simplest thing is a
154 * different global variable.
156 oldc = cUNOPx(o)->op_first;
157 newc = newGVOP(OP_GV, 0,
158 gv_fetchpvs("arybase::leftbrack", GV_ADDMULTI, SVt_PVGV));
159 cUNOPx(o)->op_first = newc;
163 STATIC void ab_process_assignment(pTHX_ OP *left, OP *right) {
164 #define ab_process_assignment(l, r) \
165 ab_process_assignment(aTHX_ (l), (r))
166 if (ab_op_is_dollar_bracket(left) && right->op_type == OP_CONST) {
167 set_arybase_to(SvIV(cSVOPx_sv(right)));
168 ab_neuter_dollar_bracket(left);
169 Perl_ck_warner_d(aTHX_
170 packWARN(WARN_DEPRECATED), "Use of assignment to $[ is deprecated"
175 STATIC OP *ab_ck_sassign(pTHX_ OP *o) {
176 o = (*ab_old_ck_sassign)(aTHX_ o);
177 if (o->op_type == OP_SASSIGN && FEATURE_ARYBASE_IS_ENABLED) {
178 OP *right = cBINOPx(o)->op_first;
179 OP *left = right->op_sibling;
180 if (left) ab_process_assignment(left, right);
185 STATIC OP *ab_ck_aassign(pTHX_ OP *o) {
186 o = (*ab_old_ck_aassign)(aTHX_ o);
187 if (o->op_type == OP_AASSIGN && FEATURE_ARYBASE_IS_ENABLED) {
188 OP *right = cBINOPx(o)->op_first;
189 OP *left = cBINOPx(right->op_sibling)->op_first->op_sibling;
190 right = cBINOPx(right)->op_first->op_sibling;
191 ab_process_assignment(left, right);
197 tie(pTHX_ SV * const sv, SV * const obj, HV *const stash)
199 SV *rv = newSV_type(SVt_RV);
201 SvRV_set(rv, obj ? SvREFCNT_inc_simple_NN(obj) : newSV(0));
205 sv_unmagic((SV *)sv, PERL_MAGIC_tiedscalar);
206 sv_magic((SV *)sv, rv, PERL_MAGIC_tiedscalar, NULL, 0);
207 SvREFCNT_dec(rv); /* As sv_magic increased it by one. */
210 /* This function converts from base-based to 0-based an index to be passed
213 adjust_index(IV index, IV base)
215 if (index >= base || index > -1) return index-base;
218 /* This function converts from 0-based to base-based an index to
221 adjust_index_r(IV index, IV base)
226 #define replace_sv(sv,base) \
227 ((sv) = sv_2mortal(newSViv(adjust_index(SvIV(sv),base))))
228 #define replace_sv_r(sv,base) \
229 ((sv) = sv_2mortal(newSViv(adjust_index_r(SvIV(sv),base))))
231 static OP *ab_pp_basearg(pTHX) {
237 ab_map_fetch(PL_op, &oi);
239 switch (PL_op->op_type) {
244 firstp = PL_stack_base + TOPMARK + 1;
248 firstp = PL_stack_base + *(PL_markstack_ptr-1)+1;
249 count = TOPMARK - *(PL_markstack_ptr-1);
250 if (GIMME != G_ARRAY) {
256 if (SP - PL_stack_base - TOPMARK >= 2)
257 firstp = PL_stack_base + TOPMARK + 2;
261 firstp = SP-(PL_op->op_private & 7)+2;
265 "panic: invalid op type for arybase.xs:ab_pp_basearg: %d",
269 while (count--) replace_sv(*svp,oi.base), svp++;
270 return (*oi.old_pp)(aTHX);
273 static OP *ab_pp_av2arylen(pTHX) {
278 ab_map_fetch(PL_op, &oi);
279 ret = (*oi.old_pp)(aTHX);
280 if (PL_op->op_flags & OPf_MOD || LVRET) {
282 tie(aTHX_ sv, TOPs, gv_stashpv("arybase::mg",1));
287 if (SvOK(TOPs)) replace_sv_r(TOPs, oi.base);
292 static OP *ab_pp_keys(pTHX) {
296 const I32 offset = SP - PL_stack_base;
298 ab_map_fetch(PL_op, &oi);
299 retval = (*oi.old_pp)(aTHX);
300 if (GIMME_V == G_SCALAR) return retval;
302 svp = PL_stack_base + offset;
303 while (svp <= SP) replace_sv_r(*svp,oi.base), ++svp;
307 static OP *ab_pp_each(pTHX) {
311 const I32 offset = SP - PL_stack_base;
312 ab_map_fetch(PL_op, &oi);
313 retval = (*oi.old_pp)(aTHX);
315 if (GIMME_V == G_SCALAR) {
316 if (SvOK(TOPs)) replace_sv_r(TOPs,oi.base);
318 else if (offset < SP - PL_stack_base) replace_sv_r(TOPm1s,oi.base);
322 static OP *ab_pp_index(pTHX) {
326 ab_map_fetch(PL_op, &oi);
327 if (MAXARG == 3 && TOPs) replace_sv(TOPs,oi.base);
328 retval = (*oi.old_pp)(aTHX);
330 replace_sv_r(TOPs,oi.base);
334 static OP *ab_ck_base(pTHX_ OP *o)
336 OP * (*old_ck)(pTHX_ OP *o) = 0;
337 OP * (*new_pp)(pTHX) = ab_pp_basearg;
338 switch (o->op_type) {
339 case OP_AELEM : old_ck = ab_old_ck_aelem ; break;
340 case OP_ASLICE : old_ck = ab_old_ck_aslice ; break;
341 case OP_LSLICE : old_ck = ab_old_ck_lslice ; break;
342 case OP_AV2ARYLEN: old_ck = ab_old_ck_av2arylen; break;
343 case OP_SPLICE : old_ck = ab_old_ck_splice ; break;
344 case OP_KEYS : old_ck = ab_old_ck_keys ; break;
345 case OP_EACH : old_ck = ab_old_ck_each ; break;
346 case OP_SUBSTR : old_ck = ab_old_ck_substr ; break;
347 case OP_RINDEX : old_ck = ab_old_ck_rindex ; break;
348 case OP_INDEX : old_ck = ab_old_ck_index ; break;
349 case OP_POS : old_ck = ab_old_ck_pos ; break;
352 "panic: invalid op type for arybase.xs:ab_ck_base: %d",
355 o = (*old_ck)(aTHX_ o);
356 if (!FEATURE_ARYBASE_IS_ENABLED) return o;
357 /* We need two switch blocks, as the type may have changed. */
358 switch (o->op_type) {
363 case OP_SUBSTR : break;
365 case OP_AV2ARYLEN: new_pp = ab_pp_av2arylen ; break;
366 case OP_AKEYS : new_pp = ab_pp_keys ; break;
367 case OP_AEACH : new_pp = ab_pp_each ; break;
369 case OP_INDEX : new_pp = ab_pp_index ; break;
373 IV const base = current_base();
375 ab_map_store(o, o->op_ppaddr, base);
376 o->op_ppaddr = new_pp;
377 /* Break the aelemfast optimisation */
378 if (o->op_type == OP_AELEM &&
379 cBINOPo->op_first->op_sibling->op_type == OP_CONST) {
380 cBINOPo->op_first->op_sibling
381 = newUNOP(OP_NULL,0,cBINOPo->op_first->op_sibling);
384 else ab_map_delete(o);
390 STATIC U32 ab_initialized = 0;
392 /* --- XS ------------------------------------------------------------- */
394 MODULE = arybase PACKAGE = arybase
399 GV *const gv = gv_fetchpvn("[", 1, GV_ADDMULTI|GV_NOTQUAL, SVt_PV);
400 sv_unmagic(GvSV(gv), PERL_MAGIC_sv); /* This is *our* scalar now! */
401 tie(aTHX_ GvSV(gv), NULL, GvSTASH(CvGV(cv)));
403 if (!ab_initialized++) {
404 ab_op_map = ptable_new();
406 MUTEX_INIT(&ab_op_map_mutex);
408 #define check(uc,lc,ck) \
409 wrap_op_checker(OP_##uc, ab_ck_##ck, &ab_old_ck_##lc)
410 check(SASSIGN, sassign, sassign);
411 check(AASSIGN, aassign, aassign);
412 check(AELEM, aelem, base);
413 check(ASLICE, aslice, base);
414 check(LSLICE, lslice, base);
415 check(AV2ARYLEN,av2arylen,base);
416 check(SPLICE, splice, base);
417 check(KEYS, keys, base);
418 check(EACH, each, base);
419 check(SUBSTR, substr, base);
420 check(RINDEX, rindex, base);
421 check(INDEX, index, base);
422 check(POS, pos, base);
429 SV *ret = FEATURE_ARYBASE_IS_ENABLED
430 ? cop_hints_fetch_pvs(PL_curcop, "$[", 0)
433 if (!ret || !SvOK(ret)) mXPUSHi(0);
437 STORE(SV *sv, IV newbase)
439 if (FEATURE_ARYBASE_IS_ENABLED) {
440 SV *base = cop_hints_fetch_pvs(PL_curcop, "$[", 0);
441 if (SvOK(base) ? SvIV(base) == newbase : !newbase) XSRETURN_EMPTY;
442 Perl_croak(aTHX_ "That use of $[ is unsupported");
445 Perl_croak(aTHX_ "Assigning non-zero to $[ is no longer possible");
448 MODULE = arybase PACKAGE = arybase::mg
454 if (!SvROK(sv) || SvTYPE(SvRV(sv)) >= SVt_PVAV)
455 Perl_croak(aTHX_ "Not a SCALAR reference");
457 SV *base = FEATURE_ARYBASE_IS_ENABLED
458 ? cop_hints_fetch_pvs(PL_curcop, "$[", 0)
460 SvGETMAGIC(SvRV(sv));
461 if (!SvOK(SvRV(sv))) XSRETURN_UNDEF;
462 mXPUSHi(adjust_index_r(
463 SvIV_nomg(SvRV(sv)), base&&SvOK(base)?SvIV(base):0
468 STORE(SV *sv, SV *newbase)
470 if (!SvROK(sv) || SvTYPE(SvRV(sv)) >= SVt_PVAV)
471 Perl_croak(aTHX_ "Not a SCALAR reference");
473 SV *base = FEATURE_ARYBASE_IS_ENABLED
474 ? cop_hints_fetch_pvs(PL_curcop, "$[", 0)
477 if (!SvOK(newbase)) SvSetMagicSV(SvRV(sv),&PL_sv_undef);
482 SvIV_nomg(newbase), base&&SvOK(base)?SvIV(base):0