File Coverage

Wanted.xs
Criterion Covered Total %
statement 284 338 84.0
branch 214 324 66.0
condition n/a
subroutine n/a
pod n/a
total 498 662 75.2


line stmt bran cond sub pod time code
1             /*
2             *----------------------------------------------------------------------------
3             * Wanted - ~/Wanted.xs
4             * Version v0.1.2
5             * Copyright(c) 2025 DEGUEST Pte. Ltd.
6             * Original author: Robin Houston
7             * Modified by: Jacques Deguest
8             * Created 2025/05/16
9             * Modified 2025/06/14
10             * All rights reserved
11             *
12             * This program is free software; you can redistribute it and/or modify it
13             * under the same terms as Perl itself.
14             *
15             * Description:
16             * XS implementation for the Wanted Perl module, providing low-level
17             * functions to inspect and manipulate Perl's context stack and op tree.
18             *----------------------------------------------------------------------------
19             */
20             #include "EXTERN.h"
21             #include "perl.h"
22             #include "XSUB.h"
23              
24             /* Between 5.9.1 and 5.9.2 the retstack was removed, and the return op is now stored on the cxstack. */
25             #define HAS_RETSTACK (\
26             PERL_REVISION < 5 || \
27             (PERL_REVISION == 5 && PERL_VERSION < 9) || \
28             (PERL_REVISION == 5 && PERL_VERSION == 9 && PERL_SUBVERSION < 2) \
29             )
30              
31             /* Define PERL_VERSION_GE, PERL_VERSION_LT, PERL_VERSION_LE if not already defined (Perl < 5.24.0) */
32             #ifndef PERL_VERSION_GE
33             #define PERL_VERSION_GE(major, minor, patch) \
34             (PERL_REVISION > (major) || \
35             (PERL_REVISION == (major) && (PERL_VERSION > (minor) || \
36             (PERL_VERSION == (minor) && PERL_SUBVERSION >= (patch)))))
37             #endif
38              
39             #ifndef PERL_VERSION_LT
40             #define PERL_VERSION_LT(major, minor, patch) \
41             (PERL_REVISION < (major) || \
42             (PERL_REVISION == (major) && (PERL_VERSION < (minor) || \
43             (PERL_VERSION == (minor) && PERL_SUBVERSION < (patch)))))
44             #endif
45              
46             #ifndef PERL_VERSION_LE
47             #define PERL_VERSION_LE(major, minor, patch) \
48             (PERL_REVISION < (major) || \
49             (PERL_REVISION == (major) && (PERL_VERSION < (minor) || \
50             (PERL_VERSION == (minor) && PERL_SUBVERSION <= (patch)))))
51             #endif
52              
53             #define PERL_HAS_FREE_OS_BUG (PERL_VERSION_GE(5, 22, 0) && PERL_VERSION_LE(5, 24, 0))
54              
55             #define ENABLE_DOUBLE_RETURN_HACKS 1
56              
57             /* After 5.10, the CxLVAL macro was added. */
58             #ifndef CxLVAL
59             # define CxLVAL(cx) cx->blk_sub.lval
60             #endif
61              
62             #ifndef OpSIBLING
63             # define OpSIBLING(o) o->op_sibling
64             #endif
65              
66             /* Stolen from B.xs */
67             #ifdef PERL_OBJECT
68             #undef PL_op_name
69             #undef PL_opargs
70             #undef PL_op_desc
71             #define PL_op_name (get_op_names())
72             #define PL_opargs (get_opargs())
73             #define PL_op_desc (get_op_descs())
74             #endif
75              
76             /* Define oplist and numop types */
77             #define OPLIST_MAX 50
78             typedef struct {
79             U16 numop_num;
80             OP* numop_op;
81             } numop;
82              
83             typedef struct {
84             U16 length;
85             numop ops[OPLIST_MAX];
86             } oplist;
87              
88             #define new_oplist (oplist*) malloc(sizeof(oplist))
89             #define init_oplist(l) l->length = 0
90              
91             /* Function declarations */
92             numop* lastnumop(oplist* l);
93             OP* lastop(oplist* l);
94             oplist* pushop(oplist* l, OP* o, U16 i);
95             oplist* find_ancestors_from(OP* start, OP* next, oplist* l);
96             I32 count_list (OP* parent, OP* returnop);
97             I32 count_slice (OP* o);
98              
99             /* Stolen from pp_ctl.c (with modifications) */
100             /*
101             * dopoptosub_at - Scans the given context stack for the nearest subroutine or format block.
102             *
103             * Arguments:
104             * PERL_CONTEXT *cxstk - The context stack to search.
105             * I32 startingblock - The starting index from which to scan downward.
106             *
107             * Return:
108             * I32 - The index of the found subroutine or format block, or -1 if none is found.
109             *
110             * Description:
111             * This is a helper function to locate the closest CXt_SUB or CXt_FORMAT in a given stack.
112             * It is used in walking the context stack and is central to call depth resolution.
113             *
114             * Internal:
115             * Used by dopoptosub() to implement context stack traversal.
116             */
117             I32
118 9475           dopoptosub_at(pTHX_ PERL_CONTEXT *cxstk, I32 startingblock)
119             {
120             dTHR;
121             I32 i;
122             PERL_CONTEXT *cx;
123 9475 50         if (!cxstk) return -1;
124 14472 100         for (i = startingblock; i >= 0; i--)
125             {
126 12966           cx = &cxstk[i];
127 12966 100         switch (CxTYPE(cx))
128             {
129 4997           default:
130 4997           continue;
131 7969           case CXt_SUB:
132             case CXt_FORMAT:
133             DEBUG_l( Perl_deb(aTHX_ "(Found sub #%ld)\n", (long)i));
134 7969           return i;
135             }
136             }
137 1506           return i;
138             }
139              
140             /*
141             * dopoptosub - Convenience wrapper around dopoptosub_at using the current cxstack.
142             *
143             * Arguments:
144             * I32 startingblock - Start index into cxstack to scan for a subroutine context.
145             *
146             * Return:
147             * I32 - The index of the found subroutine or format block, or -1 if not found.
148             *
149             * Description:
150             * This function uses the current 'cxstack' and is typically used to locate
151             * the active subroutine context for the current execution stack.
152             *
153             * Internal:
154             * Used by upcontext() and upcontext_plus() to traverse the context stack.
155             */
156             I32
157 1735           dopoptosub(pTHX_ I32 startingblock)
158             {
159             dTHR;
160 1735 50         if (!cxstack) return -1;
161 1735           return dopoptosub_at(aTHX_ cxstack, startingblock);
162             }
163              
164             /*
165             * upcontext - Retrieves the subroutine context 'count' levels up the stack.
166             *
167             * Arguments:
168             * I32 count - The number of subroutine contexts to go up.
169             *
170             * Return:
171             * PERL_CONTEXT* - Pointer to the located context or NULL if not found.
172             *
173             * Description:
174             * This searches up through the Perl call stack, accounting for DB::sub wrappers,
175             * and returns the context frame corresponding to the requested call depth.
176             *
177             * Internal:
178             * Used by want_gimme(), want_lvalue(), find_return_op(), and other context-inspection functions.
179             */
180             PERL_CONTEXT*
181 1007           upcontext(pTHX_ I32 count)
182             {
183 1007           PERL_SI *top_si = PL_curstackinfo;
184 1007           I32 cxix = dopoptosub(aTHX_ cxstack_ix);
185             PERL_CONTEXT *cx;
186 1007           PERL_CONTEXT *ccstack = cxstack;
187             I32 dbcxix;
188              
189 1007 50         if (!top_si || !ccstack || cxix < 0)
    50          
    50          
190             {
191 0           return (PERL_CONTEXT *)0;
192             }
193              
194             for (;;)
195             {
196 4267 100         while (cxix < 0 && top_si->si_type != PERLSI_MAIN)
    50          
197             {
198 0           top_si = top_si->si_prev;
199 0 0         if (!top_si)
200             {
201 0           return (PERL_CONTEXT *)0;
202             }
203 0           ccstack = top_si->si_cxstack;
204 0           cxix = dopoptosub_at(aTHX_ ccstack, top_si->si_cxix);
205             }
206 4267 100         if (cxix < 0)
207             {
208 5           return (PERL_CONTEXT *)0;
209             }
210 4262 50         if (PL_DBsub && cxix >= 0 &&
    50          
211 4262 50         ccstack[cxix].blk_sub.cv == GvCV(PL_DBsub))
212 0           count++;
213 4262 100         if (!count--)
214 1002           break;
215 3260           cxix = dopoptosub_at(aTHX_ ccstack, cxix - 1);
216             }
217 1002           cx = &ccstack[cxix];
218 1002 50         if (CxTYPE(cx) == CXt_SUB || CxTYPE(cx) == CXt_FORMAT)
    0          
219             {
220 1002           dbcxix = dopoptosub_at(aTHX_ ccstack, cxix - 1);
221 1002 50         if (PL_DBsub && dbcxix >= 0 && ccstack[dbcxix].blk_sub.cv == GvCV(PL_DBsub))
    100          
    50          
222             {
223 0           cx = &ccstack[dbcxix];
224             }
225             }
226 1002           return cx;
227             }
228              
229             /*
230             * upcontext_plus - Retrieves the block or loop context enclosing the subroutine at the given depth.
231             *
232             * Arguments:
233             * I32 count - Number of subroutine levels up to inspect.
234             * bool end_of_block - Whether to return the context at the end of the enclosing block.
235             *
236             * Return:
237             * PERL_CONTEXT* - The identified context or NULL.
238             *
239             * Description:
240             * This is a more sophisticated version of 'upcontext', considering debugger issues,
241             * tie/tied ops, and whether the block context is required instead of the sub context.
242             *
243             * Internal:
244             * Used by find_start_cop() to locate the starting context op for a subroutine or block.
245             */
246             PERL_CONTEXT*
247 728           upcontext_plus(pTHX_ I32 count, bool end_of_block)
248             {
249 728           PERL_SI *top_si = PL_curstackinfo;
250 728           I32 cxix = dopoptosub(aTHX_ cxstack_ix);
251             PERL_CONTEXT *cx, *tcx;
252 728           PERL_CONTEXT *ccstack = cxstack;
253             I32 dbcxix, i;
254             bool debugger_trouble;
255              
256 728 50         if (!top_si || !ccstack || cxix < 0)
    50          
    50          
257             {
258 0           return (PERL_CONTEXT *)0;
259             }
260              
261 728 50         if (PL_op && (PL_op->op_type == OP_TIE || PL_op->op_type == OP_TIED))
    50          
    50          
262             {
263             I32 i;
264 0 0         for (i = cxix; i >= 0; i--)
265             {
266 0           cx = &ccstack[i];
267 0 0         if (CxTYPE(cx) == CXt_SUB || CxTYPE(cx) == CXt_BLOCK)
    0          
268             {
269 0 0         OP *op = cx->blk_oldcop ? (OP*)cx->blk_oldcop : PL_op;
270 0 0         if (op && (op->op_type == OP_LIST || op->op_type == OP_AASSIGN))
    0          
    0          
271             {
272 0           cx->blk_gimme = G_ARRAY;
273             }
274 0           return cx;
275             }
276             }
277 0           return (PERL_CONTEXT *)0;
278             }
279              
280             for (;;)
281             {
282 3480 100         while (cxix < 0 && top_si->si_type != PERLSI_MAIN)
    50          
283             {
284 0           top_si = top_si->si_prev;
285 0 0         if (!top_si)
286             {
287 0           return (PERL_CONTEXT *)0;
288             }
289 0           ccstack = top_si->si_cxstack;
290 0           cxix = dopoptosub_at(aTHX_ ccstack, top_si->si_cxix);
291             }
292 3480 100         if (cxix < 0)
293             {
294 2           return (PERL_CONTEXT *)0;
295             }
296 3478 50         if (PL_DBsub && cxix >= 0 &&
    50          
297 3478 50         ccstack[cxix].blk_sub.cv == GvCV(PL_DBsub))
298 0           count++;
299 3478 100         if (!count--)
300 726           break;
301 2752           cxix = dopoptosub_at(aTHX_ ccstack, cxix - 1);
302             }
303 726           cx = &ccstack[cxix];
304 726 50         if (CxTYPE(cx) == CXt_SUB || CxTYPE(cx) == CXt_FORMAT)
    0          
305             {
306 726           dbcxix = dopoptosub_at(aTHX_ ccstack, cxix - 1);
307 726 50         if (PL_DBsub && dbcxix >= 0 && ccstack[dbcxix].blk_sub.cv == GvCV(PL_DBsub))
    100          
    50          
308             {
309 0           cxix = dbcxix;
310 0           cx = &ccstack[dbcxix];
311             }
312             }
313              
314 726 50         debugger_trouble = (cx->blk_oldcop && cx->blk_oldcop->op_type == OP_DBSTATE);
    50          
315              
316 1348 100         for (i = cxix-1; i>=0 ; i--)
317             {
318 832           tcx = &ccstack[i];
319 832           switch (CxTYPE(tcx))
320             {
321 599           case CXt_BLOCK:
322 599 50         if (debugger_trouble && i > 0) return tcx;
    0          
323             default:
324 622           continue;
325             #ifdef CXt_LOOP_PLAIN
326 114           case CXt_LOOP_PLAIN:
327             #endif
328             #ifdef CXt_LOOP_FOR
329             case CXt_LOOP_FOR:
330             #endif
331             #ifdef CXt_LOOP_LIST
332             case CXt_LOOP_LIST:
333             #endif
334             #ifdef CXt_LOOP_ARY
335             case CXt_LOOP_ARY:
336             #endif
337             #ifdef CXt_LOOP
338             case CXt_LOOP:
339             #endif
340 114           return tcx;
341 96           case CXt_SUB:
342             case CXt_FORMAT:
343 96           return cx;
344             }
345             }
346 516 100         return ((end_of_block && cxix > 1) ? &ccstack[cxix-1] : cx);
    50          
347             }
348              
349             /*
350             * want_gimme - Returns the context type (void, scalar, or array) at the given call stack level.
351             *
352             * Arguments:
353             * I32 uplevel - The number of call frames up to check.
354             *
355             * Return:
356             * U8 - One of G_VOID, G_SCALAR, or G_ARRAY.
357             *
358             * Description:
359             * This uses the PERL_CONTEXT retrieved by 'upcontext' to determine the evaluation context
360             * of the caller. It is a low-level helper for functions like wantarray_up().
361             *
362             * Internal:
363             * Used by wantarray_up(), want_count(), and Perl-side context inspection.
364             */
365             U8
366 96           want_gimme (I32 uplevel)
367             {
368 96           PERL_CONTEXT* cx = upcontext(aTHX_ uplevel);
369 96 100         if (!cx) return G_VOID;
370 95           return cx->blk_gimme;
371             }
372              
373             /*
374             * lastnumop - Retrieves the last meaningful 'numop' from an 'oplist'.
375             *
376             * Arguments:
377             * oplist* l - Pointer to an 'oplist' structure containing a sequence of 'numop' entries.
378             *
379             * Return:
380             * numop* - A pointer to the last 'numop' whose op is not of type 'OP_NULL' or 'OP_SCOPE',
381             * or NULL if no such entry exists.
382             *
383             * Description:
384             * This function scans backward through the list of 'numop' entries and returns the last
385             * one that corresponds to a significant operation. It is used to find the operative
386             * instruction before a return or assignment analysis.
387             *
388             * Internal:
389             * Used by 'want_assign()' to determine the final operational node before returning values.
390             */
391             numop*
392 23           lastnumop(oplist* l)
393             {
394             U16 i;
395             numop* ret;
396              
397 23 50         if (!l) return (numop*)0;
398 23           i = l->length;
399 25 50         while (i-- > 0)
400             {
401 25           ret = &(l->ops)[i];
402 25 100         if (ret->numop_op->op_type != OP_NULL && ret->numop_op->op_type != OP_SCOPE)
    50          
403             {
404 23           return ret;
405             }
406             }
407 0           return (numop*)0;
408             }
409              
410             /*
411             * lastop - Returns the last significant OP from a given oplist.
412             *
413             * Arguments:
414             * oplist* l - The list of operations to search.
415             *
416             * Return:
417             * OP* - The last non-NULL, non-SCOPE, non-LEAVE op, or Nullop if none found.
418             *
419             * Description:
420             * This function scans backwards through an oplist to find the last significant operation,
421             * ignoring NULL, SCOPE, and LEAVE ops. It is used to determine the most relevant op at
422             * the end of an op chain, typically for context or assignment analysis.
423             *
424             * Internal:
425             * Used by parent_op() to identify the final operation in an op chain.
426             */
427             OP*
428 632           lastop(oplist* l)
429             {
430             U16 i;
431             OP* ret;
432              
433 632 100         if (!l) return Nullop;
434 565           i = l->length;
435 834 100         while (i-- > 0)
436             {
437 779           ret = (l->ops)[i].numop_op;
438 779 100         if (ret->op_type != OP_NULL
439 599 50         && ret->op_type != OP_SCOPE
440 599 100         && ret->op_type != OP_LEAVE)
441             {
442 510           free(l);
443 510           return ret;
444             }
445             }
446 55           free(l);
447 55           return Nullop;
448             }
449              
450             /*
451             * pushop - Adds an operation to an oplist with an associated index.
452             *
453             * Arguments:
454             * oplist* l - The oplist to modify.
455             * OP* o - The op to push.
456             * U16 i - The op’s index or position.
457             *
458             * Return:
459             * oplist* - The modified list.
460             *
461             * Description:
462             * This utility is used during op tree traversal to maintain a list of encountered operations.
463             *
464             * Internal:
465             * Used by find_ancestors_from() to build the list of parent ops.
466             */
467             oplist*
468 2833           pushop(oplist* l, OP* o, U16 i)
469             {
470 2833           I16 len = l->length;
471 2833 100         if (o && len < OPLIST_MAX)
    50          
472             {
473 2177           ++ l->length;
474 2177           l->ops[len].numop_op = o;
475 2177           l->ops[len].numop_num = -1;
476             }
477 2833 100         if (len > 0)
478 2177           l->ops[len-1].numop_num = i;
479              
480 2833           return l;
481             }
482              
483             /*
484             * find_ancestors_from - Recursively traverses an op tree to find a path to a target op.
485             *
486             * Arguments:
487             * OP* start - Starting op for the tree walk.
488             * OP* next - Target op to find.
489             * oplist* l - The oplist to accumulate ops into (can be NULL).
490             *
491             * Return:
492             * oplist* - A list of parent ops leading to the target op, or NULL if not found.
493             *
494             * Description:
495             * This function recursively traverses the op tree starting from 'start' to find a path
496             * to the 'next' op, accumulating parent ops in an oplist. It is used to trace a path
497             * through the abstract syntax tree (AST) from a COP to a return op.
498             *
499             * Notes:
500             * The caller is responsible for freeing the oplist if the function returns NULL.
501             *
502             * Internal:
503             * Used by ancestor_ops() to build the list of ancestor ops for context analysis.
504             */
505             oplist*
506 2833           find_ancestors_from(OP* start, OP* next, oplist* l)
507             {
508             OP *o, *p;
509 2833           U16 cn = 0;
510             U16 ll;
511 2833           bool outer_call = FALSE;
512              
513 2833 50         if (!start || !next)
    50          
514             {
515             /* Do not free l here; let the caller handle it */
516 0           return (oplist*)0;
517             }
518              
519 2833 100         if (!l)
520             {
521 656           outer_call = TRUE;
522 656           l = new_oplist;
523 656           init_oplist(l);
524 656           ll = 0;
525             }
526 2177           else ll = l->length;
527              
528 5432 100         for (o = start; o; p = o, o = OpSIBLING(o), ++cn)
    100          
529             {
530 4839 100         if (o->op_type == OP_ENTERSUB && o->op_next == next)
    100          
531 656           return pushop(l, Nullop, cn);
532              
533 4183 100         if (o->op_flags & OPf_KIDS)
534             {
535 2177           U16 ll = l->length;
536            
537 2177           pushop(l, o, cn);
538 2177 100         if (find_ancestors_from(cUNOPo->op_first, next, l))
539 1584           return l;
540             else
541 593           l->length = ll;
542             }
543             }
544             /* Not found. Free the list only if it was allocated in this outermost frame;
545             recursive frames borrow the caller's list and must not free it. */
546 593 50         if (outer_call)
547             {
548 0           free(l);
549             }
550             /* Do not free l here; let the caller handle it */
551 593           return (oplist*)0;
552             }
553              
554             /*
555             * find_return_op - Resolves the return OP for the subroutine at a given depth.
556             *
557             * Arguments:
558             * I32 uplevel - The number of frames up to inspect.
559             *
560             * Return:
561             * OP* - The op that is used to return from the subroutine, or Nullop if not found.
562             *
563             * Description:
564             * This inspects the current cxstack or PL_retstack to find the return point for a sub.
565             *
566             * Internal:
567             * Used by ancestor_ops() to determine the return op for context analysis.
568             */
569             OP*
570 728           find_return_op(pTHX_ I32 uplevel)
571             {
572 728           PERL_CONTEXT *cx = upcontext(aTHX_ uplevel);
573 728 100         if (!cx)
574             {
575 2           return Nullop;
576             }
577             #if HAS_RETSTACK
578             return PL_retstack[cx->blk_oldretsp - 1];
579             #else
580 726           return cx->blk_sub.retop;
581             #endif
582             }
583              
584             /*
585             * find_start_cop - Returns the start COP (context op) for the subroutine frame.
586             *
587             * Arguments:
588             * I32 uplevel - Call stack depth to inspect.
589             * bool end_of_block - If true, return the enclosing block cop.
590             *
591             * Return:
592             * OP* - The starting COP for the sub or block context, or Nullop if not found.
593             *
594             * Description:
595             * This function determines the starting COP (context op) for a subroutine or block
596             * at the specified call stack depth, helping to identify where execution begins.
597             *
598             * Internal:
599             * Used by ancestor_ops() to find the starting point for op tree traversal.
600             */
601             OP*
602 728           find_start_cop(pTHX_ I32 uplevel, bool end_of_block)
603             {
604 728           PERL_CONTEXT* cx = upcontext_plus(aTHX_ uplevel, end_of_block);
605 728 100         if (!cx)
606             {
607 2           return Nullop;
608             }
609 726           return (OP*) cx->blk_oldcop;
610             }
611              
612             /*
613             * ancestor_ops - Produces a list of ancestor ops from sub start to return.
614             *
615             * Arguments:
616             * I32 uplevel - Stack level to inspect.
617             * OP** return_op_out - Optional pointer to capture return op.
618             *
619             * Return:
620             * oplist* - A list of operations between sub entry and return, or NULL if not found.
621             *
622             * Description:
623             * This function walks the op tree using 'find_start_cop' and 'find_return_op',
624             * storing the trace path in an oplist. It is used to analyse the operations
625             * between a subroutine's entry and return points.
626             *
627             * Notes:
628             * The caller is responsible for freeing the returned oplist.
629             *
630             * Internal:
631             * Used by want_boolean() and want_assign() for context analysis.
632             */
633             oplist*
634 728           ancestor_ops (I32 uplevel, OP** return_op_out)
635             {
636 728           OP* return_op = find_return_op(aTHX_ uplevel);
637 728           OP* start_cop = find_start_cop(aTHX_ uplevel,
638 728 100         return_op ? return_op->op_type == OP_LEAVE : FALSE);
    100          
639              
640 728 100         if (!return_op || !start_cop)
    50          
641             {
642 72 100         if (return_op_out) *return_op_out = Nullop;
643 72           return (oplist*)0;
644             }
645              
646 656 100         if (return_op_out)
647 588           *return_op_out = return_op;
648              
649             /* return find_ancestors_from(start_cop, return_op, 0); */
650 656           oplist* result = find_ancestors_from(start_cop, return_op, 0);
651 656 50         if (!result)
652             {
653             /* Free the oplist if find_ancestors_from allocated it but failed */
654 0           free(result); // This will be a no-op since result is NULL
655 0           return (oplist*)0;
656             }
657 656           return result;
658             }
659              
660             /*
661             * parent_op - Retrieves the parent OP of the current OP in the call stack.
662             *
663             * Arguments:
664             * I32 uplevel - Stack level to begin inspection.
665             * OP **retop - A pointer to receive the resolved OP.
666             *
667             * Return:
668             * OP* - The parent operation at the given level.
669             *
670             * Description:
671             * This walks the OP tree upward from the caller’s stack frame to find the relevant parent.
672             *
673             * Internal:
674             * Used by parent_op_name() and first_multideref_type().
675             */
676             OP*
677 632           parent_op (I32 uplevel, OP** return_op_out)
678             {
679 632           return lastop(ancestor_ops(uplevel, return_op_out));
680             }
681              
682             /*
683             * count_slice - Calculates the number of elements in a slice op.
684             *
685             * Arguments:
686             * OP* o - The slice op (e.g., OP_HSLICE or OP_ASLICE).
687             *
688             * Return:
689             * I32 - The number of elements being sliced, or -999 on error.
690             *
691             * Description:
692             * Recursively walks the op tree to count list elements involved in slicing,
693             * such as in array or hash slice operations.
694             *
695             * Internal:
696             * Used by count_list() to determine the size of sliced elements in assignments.
697             */
698             I32
699 9           count_slice (OP* o)
700             {
701             OP* pm;
702 9           OP* l = Nullop;
703              
704 9 50         if (!o) return -999;
705 9           pm = cUNOPo->op_first;
706 9 50         if (!pm || pm->op_type != OP_PUSHMARK)
    50          
707 0           die("%s", "Wanted panicked: slice doesn't start with pushmark\n");
708              
709 9 50         if ( (l = OpSIBLING(pm)) && (l->op_type == OP_LIST || (l->op_type == OP_NULL && l->op_targ == OP_LIST)))
    50          
    50          
    100          
    50          
710 4           return count_list(l, Nullop);
711              
712 5 50         else if (l)
713 5           switch (l->op_type)
714             {
715 1           case OP_RV2AV:
716             case OP_PADAV:
717             case OP_PADHV:
718             case OP_RV2HV:
719 1           return 0;
720 2           case OP_HSLICE:
721             case OP_ASLICE:
722 2           return count_slice(l);
723 2           case OP_STUB:
724 2           return 1;
725 0           default:
726 0           die("Wanted panicked: Unexpected op in slice (%s)\n", PL_op_name[l->op_type]);
727             }
728              
729             else
730 0           die("Wanted panicked: Nothing follows pushmark in slice\n");
731              
732             return -999;
733             }
734              
735             /*
736             * count_list - Counts the number of elements in a list op.
737             *
738             * Arguments:
739             * OP* parent - The parent list op.
740             * OP* returnop - Optional terminator to stop early.
741             *
742             * Return:
743             * I32 - The number of child ops, or 0 if none.
744             *
745             * Description:
746             * This function counts the number of child ops in a list op, helping to determine
747             * the number of left-hand-side variables in assignments (e.g., my( $a, $b ) = ...).
748             *
749             * Internal:
750             * Used by want_count() and want_assign() for assignment analysis.
751             */
752             I32
753 39           count_list (OP* parent, OP* returnop)
754             {
755             OP* o;
756 39           I32 i = 0;
757              
758 39 50         if (!parent || ! (parent->op_flags & OPf_KIDS))
    50          
759 0           return 0;
760              
761 117 100         for(o = cUNOPx(parent)->op_first; o; o=OpSIBLING(o))
    100          
762             {
763 96 50         if (returnop && o->op_type == OP_ENTERSUB && o->op_next == returnop)
    0          
    0          
764 0           return i;
765 96 100         if (o->op_type == OP_RV2AV || o->op_type == OP_RV2HV
    100          
766 90 100         || o->op_type == OP_PADAV || o->op_type == OP_PADHV
    100          
767 79 50         || o->op_type == OP_ENTERSUB)
768 17           return 0;
769            
770 79 100         if (o->op_type == OP_HSLICE || o->op_type == OP_ASLICE)
    100          
771 6           {
772 7           I32 slice_length = count_slice(o);
773 7 100         if (slice_length == 0)
774 1           return 0;
775             else
776 6           i += slice_length - 1;
777             }
778 72           else ++i;
779             }
780              
781 21           return i;
782             }
783              
784             /*
785             * countstack - Counts the number of stack values passed to a subroutine.
786             *
787             * Arguments:
788             * I32 uplevel - Stack frame level to inspect.
789             *
790             * Return:
791             * I32 - Number of items between oldmarksp and current mark, or -1 if context not found.
792             *
793             * Description:
794             * This function counts the number of values on the stack between the old mark and
795             * the current mark, used to estimate how many right-hand-side values exist in an assignment.
796             *
797             * Internal:
798             * Used by want_count() to analyse assignment contexts.
799             */
800             I32
801 35           countstack(I32 uplevel)
802             {
803 35           PERL_CONTEXT* cx = upcontext(aTHX_ uplevel);
804             I32 oldmarksp;
805             I32 mark_from;
806             I32 mark_to;
807              
808 35 50         if (!cx) return -1;
809              
810 35           oldmarksp = cx->blk_oldmarksp;
811 35           mark_from = PL_markstack[oldmarksp];
812 35           mark_to = PL_markstack[oldmarksp+1];
813 35           return (mark_to - mark_from);
814             }
815              
816             /*
817             * copy_rvals - Returns an array of stack values passed to a subroutine.
818             *
819             * Arguments:
820             * I32 uplevel - Stack level to inspect.
821             * I32 skip - Number of items to skip from the start.
822             *
823             * Return:
824             * AV* - An array of values beyond the 'skip' threshold, or Nullav if context not found.
825             *
826             * Description:
827             * This copies the right-hand-side values passed to an assignment into an AV for Perl-side use.
828             *
829             * Internal:
830             * Used by want_assign() to retrieve assignment values.
831             */
832             AV*
833 0           copy_rvals(I32 uplevel, I32 skip)
834             {
835 0           PERL_CONTEXT* cx = upcontext(aTHX_ uplevel);
836             I32 oldmarksp;
837             I32 mark_from;
838             I32 mark_to;
839             I32 i;
840             AV* a;
841              
842 0 0         if (!cx) return Nullav;
843              
844 0           oldmarksp = cx->blk_oldmarksp;
845 0           mark_from = PL_markstack[oldmarksp-1];
846 0           mark_to = PL_markstack[oldmarksp];
847              
848 0           a = newAV();
849 0 0         for(i=mark_from+1; i<=mark_to; ++i)
850 0 0         if (skip-- <= 0) av_push(a, newSVsv(PL_stack_base[i]));
851              
852 0           return a;
853             }
854              
855             /*
856             * copy_rval - Retrieves a single scalar value passed to a subroutine.
857             *
858             * Arguments:
859             * I32 uplevel - Stack level to inspect.
860             *
861             * Return:
862             * AV* - An array containing one value, or Nullav if context not found.
863             *
864             * Description:
865             * This function retrieves the last scalar value from the stack, wrapping it in an AV
866             * for Perl-side use. It is used in OP_SASSIGN cases to retrieve the sole value.
867             *
868             * Internal:
869             * Used by want_assign() for scalar assignment contexts.
870             */
871             AV*
872 21           copy_rval(I32 uplevel)
873             {
874 21           PERL_CONTEXT* cx = upcontext(aTHX_ uplevel);
875             I32 oldmarksp;
876             AV* a;
877              
878 21 50         if (!cx) return Nullav;
879              
880 21           oldmarksp = cx->blk_oldmarksp;
881 21           a = newAV();
882 21           av_push(a, newSVsv(PL_stack_base[PL_markstack[oldmarksp+1]]));
883              
884 21           return a;
885             }
886              
887             // NOTE: Module
888              
889             MODULE = Wanted PACKAGE = Wanted
890             PROTOTYPES: ENABLE
891              
892             =begin comment
893             // NOTE: wantarray_up
894             /*
895             * wantarray_up - Wrapper for Perl's wantarray at a given stack level.
896             *
897             * Arguments:
898             * I32 uplevel - Call stack level offset to use.
899             *
900             * Return:
901             * SV* - Returns &PL_sv_yes (true) for list context, &PL_sv_no (false) for scalar
902             * context, or &PL_sv_undef for void context.
903             *
904             * Description:
905             * This provides a consistent interface to Perl’s context detection at various call
906             * depths.
907             *
908             * Internal:
909             * Used by context(), want(), and _wantone().
910             */
911             =cut
912             SV*
913             wantarray_up(uplevel)
914             I32 uplevel;
915             PREINIT:
916 50           U8 gimme = want_gimme(uplevel);
917             CODE:
918 50           switch(gimme)
919             {
920 10           case G_ARRAY:
921 10           RETVAL = &PL_sv_yes;
922 10           break;
923 34           case G_SCALAR:
924 34           RETVAL = &PL_sv_no;
925 34           break;
926 6           default:
927 6           RETVAL = &PL_sv_undef;
928             }
929             OUTPUT:
930             RETVAL
931              
932             =begin comment
933             // NOTE: want_lvalue
934             /*
935             * want_lvalue - Detects if the current subroutine is being called in lvalue context.
936             *
937             * Arguments:
938             * I32 uplevel - Number of levels up the call stack to check.
939             *
940             * Return:
941             * int - Returns true (non-zero) if in lvalue context, false (0) otherwise.
942             *
943             * Description:
944             * This checks whether the subroutine is being evaluated in a context where the result
945             * can be assigned to, such as in `foo() = 42`.
946             *
947             * Usage:
948             * Called internally by Perl subroutines via want('LVALUE').
949             *
950             * Internal:
951             * Used by wantassign(), lnoreturn().
952             */
953             =cut
954             U8
955             want_lvalue(uplevel)
956             I32 uplevel;
957             PREINIT:
958             PERL_CONTEXT* cx;
959             CODE:
960 81           cx = upcontext(aTHX_ uplevel);
961 81 50         if (!cx)
962             {
963 0           RETVAL = 0;
964             }
965 81 50         else if (!cx->blk_sub.cv)
966             {
967 0           RETVAL = 0;
968             }
969 81 100         else if (CvLVALUE(cx->blk_sub.cv))
970             {
971 62           RETVAL = CxLVAL(cx);
972             }
973             else
974             {
975 19           RETVAL = 0;
976             }
977             OUTPUT:
978             RETVAL
979              
980             =begin comment
981             // NOTE: parent_op_name
982             /*
983             * parent_op_name - Returns the name of the parent OP at the requested level.
984             *
985             * Arguments:
986             * I32 uplevel - How far up the call stack to look.
987             *
988             * Return:
989             * In scalar context: The stringified parent op name (e.g., "aassign", "method_call", "(none)").
990             * In list context: A two-element list containing the parent op name and the return op name.
991             *
992             * Description:
993             * This function resolves the parent op name by examining the OP tree.
994             * If the op is a `leavesub`, this typically means the context is not well-defined.
995             *
996             * Internal:
997             * Used by wantref(), bump_level(), and debugging tools.
998             */
999             =cut
1000             void
1001             parent_op_name(uplevel)
1002             I32 uplevel;
1003             PREINIT:
1004             OP *r;
1005 579           OP *o = parent_op(uplevel, &r);
1006             OP *first, *second;
1007             char *retval;
1008             PPCODE:
1009 579 100         if (!o || !r)
    50          
1010             {
1011 118 50         EXTEND(SP, 2);
1012 118           PUSHs(sv_2mortal(newSVpv("(none)", 0)));
1013 118           PUSHs(sv_2mortal(newSVpv("(none)", 0)));
1014             }
1015             else
1016             {
1017 461 100         if (o->op_type == OP_ENTERSUB && (first = cUNOPx(o)->op_first)
    50          
1018 30 100         && (second = OpSIBLING(first)) && OpSIBLING(second) != Nullop)
    100          
    50          
    50          
1019 7           retval = "method_call";
1020             else
1021 454           retval = (char *)PL_op_name[o->op_type];
1022 461 50         if (GIMME == G_ARRAY)
    100          
1023             {
1024 283 50         EXTEND(SP, 2);
1025 283           PUSHs(sv_2mortal(newSVpv(retval, 0)));
1026 283           PUSHs(sv_2mortal(newSVpv(PL_op_name[r->op_type], 0)));
1027             }
1028             else
1029             {
1030 178 50         EXTEND(SP, 1);
1031 178           PUSHs(sv_2mortal(newSVpv(retval, 0)));
1032             }
1033             }
1034              
1035             =begin comment
1036             // NOTE: want_count
1037             /*
1038             * want_count - Determines how many return values are expected by the caller.
1039             *
1040             * Arguments:
1041             * I32 uplevel - Number of levels up to look for the list evaluation context.
1042             *
1043             * Return:
1044             * int - A count of expected return items. Returns -1 if unlimited, 0 for void, or a positive count.
1045             *
1046             * Description:
1047             * This enables subs to detect how many return values the caller is expecting,
1048             * like in `my ($a, $b) = sub();`.
1049             *
1050             * Internal:
1051             * Used by howmany(), want('COUNT'), and _wantone().
1052             */
1053             =cut
1054             I32
1055             want_count(uplevel)
1056             I32 uplevel;
1057             PREINIT:
1058             OP* returnop;
1059 46           OP* o = parent_op(uplevel, &returnop);
1060 46           U8 gimme = want_gimme(uplevel);
1061             CODE:
1062 46 100         if (!o)
1063             {
1064 4 50         RETVAL = (gimme == G_SCALAR ? 1 : gimme == G_ARRAY ? -1 : 0);
    50          
1065             }
1066 42 100         else if (o->op_type == OP_AASSIGN)
1067             {
1068 35           I32 lhs = count_list(cBINOPo->op_last, Nullop );
1069 35           I32 rhs = countstack(uplevel);
1070 35 100         if (lhs == 0) RETVAL = -1;
1071 17 100         else if (rhs >= lhs-1) RETVAL = 0;
1072 13           else RETVAL = lhs - rhs - 1;
1073             }
1074 7           else switch(gimme)
1075             {
1076 1           case G_ARRAY:
1077 1           RETVAL = -1;
1078 1           break;
1079 6           case G_SCALAR:
1080 6           RETVAL = 1;
1081 6           break;
1082 0           default:
1083 0           RETVAL = 0;
1084             }
1085             OUTPUT:
1086             RETVAL
1087              
1088             =begin comment
1089             // NOTE: want_boolean
1090             /*
1091             * want_boolean - Determines whether the current expression is evaluated in boolean context.
1092             *
1093             * Arguments:
1094             * I32 uplevel - Stack level to examine.
1095             *
1096             * Return:
1097             * int - Boolean true/false indicating if this is boolean context.
1098             *
1099             * Description:
1100             * This inspects the op tree to determine if the result of the function is
1101             * being evaluated as a truth value (e.g., `if(foo())` or `foo() && 1`).
1102             *
1103             * Internal:
1104             * Used by want('BOOL').
1105             */
1106             =cut
1107             bool
1108             want_boolean(uplevel)
1109             I32 uplevel;
1110             PREINIT:
1111 73           oplist* l = ancestor_ops(uplevel, 0);
1112             U16 i;
1113 73           bool truebool = FALSE, pseudobool = FALSE;
1114             CODE:
1115 73 100         if (!l)
1116             {
1117 5           RETVAL = FALSE;
1118             }
1119             else
1120             {
1121 267 100         for( i=0; i < l->length; ++i )
1122             {
1123 199           OP* o = l->ops[i].numop_op;
1124 199           U16 n = l->ops[i].numop_num;
1125 199 100         bool v = (OP_GIMME(o, -1) == G_VOID);
    100          
1126 199           switch(o->op_type)
1127             {
1128 13           case OP_NOT:
1129             case OP_XOR:
1130 13           truebool = TRUE;
1131 13           break;
1132 34           case OP_AND:
1133 34 100         if (truebool || v)
    100          
1134 30           truebool = TRUE;
1135             else
1136 4 50         pseudobool = (pseudobool || n == 0);
    100          
1137 34           break;
1138 15           case OP_OR:
1139 15 100         if (truebool || v)
    100          
1140 12           truebool = TRUE;
1141             else
1142 3           truebool = FALSE;
1143 15           break;
1144 6           case OP_COND_EXPR:
1145 6 100         truebool = (truebool || n == 0);
    100          
1146 6           break;
1147 64           case OP_NULL:
1148 64           break;
1149 67           default:
1150 67           truebool = FALSE;
1151 67           pseudobool = FALSE;
1152             }
1153             }
1154 68           free(l);
1155 68 100         RETVAL = truebool || pseudobool;
    100          
1156             }
1157             OUTPUT:
1158             RETVAL
1159              
1160             =begin comment
1161             // NOTE: want_assign
1162             /*
1163             * want_assign - Retrieves the right-hand-side values in an assignment context.
1164             *
1165             * Arguments:
1166             * I32 uplevel - Number of levels up the call stack to inspect.
1167             *
1168             * Return:
1169             * SV* - A reference to an array containing the right-hand-side (RHS) values,
1170             * or &PL_sv_undef if not in assignment context.
1171             *
1172             * Description:
1173             * This XS function inspects the current call context to determine if a subroutine is
1174             * being assigned to. If so, it captures and returns the values being assigned.
1175             *
1176             * Internal:
1177             * Used by wantassign() to expose assignment RHS values to Perl.
1178             */
1179             =cut
1180             SV*
1181             want_assign(uplevel)
1182             U32 uplevel;
1183             PREINIT:
1184             AV* r;
1185             OP* returnop;
1186 23           oplist* os = ancestor_ops(uplevel, &returnop);
1187 23 50         numop* lno = os ? lastnumop(os) : (numop*)0;
1188             OPCODE type;
1189             PPCODE:
1190 23 50         if (!lno)
1191             {
1192 0           r = Nullav;
1193             }
1194             else
1195             {
1196 23           type = lno->numop_op->op_type;
1197 23 50         if (lno && (type == OP_AASSIGN || type == OP_SASSIGN) && lno->numop_num == 1)
    50          
    100          
    50          
1198             {
1199 21 50         if (type == OP_AASSIGN)
1200             {
1201 0           I32 lhs_count = count_list(cBINOPx(lno->numop_op)->op_last, returnop);
1202 0 0         if (lhs_count == 0) r = newAV();
1203             else
1204             {
1205 0           r = copy_rvals(uplevel, lhs_count-1);
1206             }
1207             }
1208 21           else r = copy_rval(uplevel);
1209             }
1210             else
1211             {
1212 2           r = Nullav;
1213             }
1214             }
1215 23 50         if (os) free(os);
1216              
1217 23 50         EXTEND(SP, 1);
1218 23 100         PUSHs(r ? sv_2mortal(newRV_noinc((SV*) r)) : &PL_sv_undef);
1219              
1220             =begin comment
1221             // NOTE: double_return
1222             /*
1223             * double_return - Restores nested return context.
1224             *
1225             * Description:
1226             * This function simulates a return from a subroutine by manipulating the context stack.
1227             * It is tightly coupled to Perl's internal context stack and was originally implemented
1228             * in version 1 of Want. It has been retained as-is for compatibility.
1229             *
1230             * Notes:
1231             * Wrapped in PERL_VERSION_GE(5, 8, 8) and ENABLE_DOUBLE_RETURN_HACKS for safety.
1232             * ⚠️ Do not modify unless you deeply understand the implications, as changes can
1233             * lead to crashes or undefined behaviour.
1234             *
1235             * Internal:
1236             * Used by rreturn() and lnoreturn() to implement early returns in Perl code.
1237             */
1238             =cut
1239             void
1240             double_return(...)
1241             PREINIT:
1242             PERL_CONTEXT *ourcx, *cx;
1243             PPCODE:
1244             # if PERL_VERSION_GE(5, 8, 8) && ENABLE_DOUBLE_RETURN_HACKS
1245 23           ourcx = upcontext(aTHX_ 0);
1246 23           cx = upcontext(aTHX_ 1);
1247 23 100         if (!cx)
1248 2           Perl_croak(aTHX_ "Can't return outside a subroutine");
1249             #ifdef POPBLOCK
1250             ourcx->cx_type = CXt_NULL;
1251             CvDEPTH(ourcx->blk_sub.cv)--;
1252             # if HAS_RETSTACK
1253             if (PL_retstack_ix > 0)
1254             --PL_retstack_ix;
1255             # endif
1256             #else
1257             /* In 5.23.8 or later, PL_curpad is saved in the context stack and
1258             * restored by cx_popsub(), rather than being saved on the savestack
1259             * and restored by LEAVE; so just CXt_NULLing the parent sub
1260             * skips the PL_curpad restore and so everything done during the
1261             * second part of the return will have the wrong PL_curpad.
1262             * So instead, fix up the first return so that it thinks the
1263             * op to continue at is iteself, forcing it to do a double return.
1264             */
1265             assert(PL_op->op_next->op_type == OP_RETURN);
1266             /* force the op following the 'return' to be 'return' again */
1267 21           ourcx->blk_sub.retop = PL_op->op_next;
1268             assert(PL_markstack + ourcx->blk_oldmarksp + 1 == PL_markstack_ptr);
1269 21           ourcx->blk_oldmarksp++;
1270 21           ourcx->blk_gimme = cx->blk_gimme;
1271             #endif
1272              
1273 21           return;
1274             # else
1275             Perl_croak(aTHX_ "double_return not supported on Perl %d.%d.%d (requires >= 5.8.8)",
1276             PERL_REVISION, PERL_VERSION, PERL_SUBVERSION);
1277             # endif /* PERL_VERSION_GE && ENABLE_DOUBLE_RETURN_HACKS */
1278              
1279             =begin comment
1280             // NOTE: disarm_temp
1281             /*
1282             * disarm_temp - Prevents premature destruction of temporary SVs.
1283             *
1284             * Arguments:
1285             * SV* sv - A scalar value which would normally be discarded or freed.
1286             *
1287             * Return:
1288             * SV* - A new scalar that holds the value of the temporary, protected from auto-cleanup.
1289             *
1290             * Description:
1291             * This is used to hold a temporary value in a persistent form for use in lvalue context.
1292             * It ensures the SV is detached from temporary cleanup scopes.
1293             *
1294             * Usage:
1295             * return disarm_temp(newSViv(0)); // safe to return from XS
1296             *
1297             * Internal:
1298             * Used by lnoreturn() to safely return placeholder values.
1299             */
1300             =cut
1301             SV *
1302             disarm_temp(sv)
1303             SV *sv;
1304             CODE:
1305 9           RETVAL = sv_2mortal(SvREFCNT_inc(SvREFCNT_inc(sv)));
1306             OUTPUT:
1307             RETVAL
1308              
1309             INCLUDE: FirstMultideref.xsh