File Coverage

lib/XS/JIT/xs_jit_builder.c
Criterion Covered Total %
statement 2846 3116 91.3
branch 298 472 63.1
condition n/a
subroutine n/a
pod n/a
total 3144 3588 87.6


line stmt bran cond sub pod time code
1             /*
2             * xs_jit_builder.c - C implementation for XS::JIT code builder
3             *
4             * This provides a fluent C API for generating C code strings dynamically.
5             */
6              
7             #define PERL_NO_GET_CONTEXT
8             #include "xs_jit_builder.h"
9             #include
10              
11             /* ============================================
12             * Internal helpers
13             * ============================================ */
14              
15 12928           static void add_indent(pTHX_ XS_JIT_Builder* b) {
16             int i;
17 12928 100         if (b->use_tabs) {
18 46 100         for (i = 0; i < b->indent; i++) {
19 28           sv_catpvs(b->code, "\t");
20             }
21             } else {
22 12910           int spaces = b->indent * b->indent_width;
23 80978 100         for (i = 0; i < spaces; i++) {
24 68068           sv_catpvs(b->code, " ");
25             }
26             }
27 12928           }
28              
29             /* ============================================
30             * Lifecycle
31             * ============================================ */
32              
33 369           XS_JIT_Builder* xs_jit_builder_new(pTHX) {
34             XS_JIT_Builder* b;
35 369           Newxz(b, 1, XS_JIT_Builder);
36 369           b->code = newSVpvs("");
37 369           b->indent = 0;
38 369           b->indent_width = 4;
39 369           b->use_tabs = 0;
40 369           b->in_function = 0;
41 369           b->enums = newHV();
42 369           b->memoized = newHV();
43 369           return b;
44             }
45              
46 369           void xs_jit_builder_free(pTHX_ XS_JIT_Builder* b) {
47             /* Note: does NOT free code SV - caller should get it first if needed */
48 369 50         if (b) {
49 369           SvREFCNT_dec(b->code);
50 369 50         if (b->enums) SvREFCNT_dec((SV*)b->enums);
51 369 50         if (b->memoized) SvREFCNT_dec((SV*)b->memoized);
52 369           Safefree(b);
53             }
54 369           }
55              
56 416           SV* xs_jit_builder_code(pTHX_ XS_JIT_Builder* b) {
57 416           SvREFCNT_inc(b->code);
58 416           return b->code;
59             }
60              
61 0           const char* xs_jit_builder_cstr(pTHX_ XS_JIT_Builder* b) {
62 0           return SvPV_nolen(b->code);
63             }
64              
65 74           void xs_jit_builder_reset(pTHX_ XS_JIT_Builder* b) {
66 74           SvREFCNT_dec(b->code);
67 74           b->code = newSVpvs("");
68 74           b->indent = 0;
69 74           b->in_function = 0;
70 74           }
71              
72             /* ============================================
73             * Low-level output
74             * ============================================ */
75              
76 12056           void xs_jit_line(pTHX_ XS_JIT_Builder* b, const char* fmt, ...) {
77             va_list args;
78            
79 12056           add_indent(aTHX_ b);
80            
81 12056           va_start(args, fmt);
82 12056           sv_vcatpvf(b->code, fmt, &args);
83 12056           va_end(args);
84            
85 12056           sv_catpvs(b->code, "\n");
86 12056           }
87              
88 93           void xs_jit_raw(pTHX_ XS_JIT_Builder* b, const char* fmt, ...) {
89             va_list args;
90            
91 93           va_start(args, fmt);
92 93           sv_vcatpvf(b->code, fmt, &args);
93 93           va_end(args);
94 93           }
95              
96 872           void xs_jit_comment(pTHX_ XS_JIT_Builder* b, const char* text) {
97 872           add_indent(aTHX_ b);
98 872           sv_catpvf(b->code, "/* %s */\n", text);
99 872           }
100              
101 759           void xs_jit_blank(pTHX_ XS_JIT_Builder* b) {
102 759           sv_catpvs(b->code, "\n");
103 759           }
104              
105             /* ============================================
106             * Indentation control
107             * ============================================ */
108              
109 93           void xs_jit_indent(XS_JIT_Builder* b) {
110 93           b->indent++;
111 93           }
112              
113 90           void xs_jit_dedent(XS_JIT_Builder* b) {
114 90 50         if (b->indent > 0) {
115 90           b->indent--;
116             }
117 90           }
118              
119 369           void xs_jit_set_indent_width(XS_JIT_Builder* b, int width) {
120 369           b->indent_width = width;
121 369           }
122              
123 369           void xs_jit_set_use_tabs(XS_JIT_Builder* b, int use_tabs) {
124 369           b->use_tabs = use_tabs;
125 369           }
126              
127             /* ============================================
128             * Blocks and structure
129             * ============================================ */
130              
131 16           void xs_jit_block_start(pTHX_ XS_JIT_Builder* b) {
132 16           xs_jit_line(aTHX_ b, "{");
133 16           b->indent++;
134 16           }
135              
136 16           void xs_jit_block_end(pTHX_ XS_JIT_Builder* b) {
137 16           b->indent--;
138 16           xs_jit_line(aTHX_ b, "}");
139 16           }
140              
141             /* ============================================
142             * XS Function structure
143             * ============================================ */
144              
145 581           void xs_jit_xs_function(pTHX_ XS_JIT_Builder* b, const char* name) {
146 581           xs_jit_line(aTHX_ b, "XS_EUPXS(%s) {", name);
147 581           b->indent++;
148 581           b->in_function = 1;
149 581           }
150              
151 518           void xs_jit_xs_preamble(pTHX_ XS_JIT_Builder* b) {
152 518           xs_jit_line(aTHX_ b, "dVAR; dXSARGS;");
153 518           xs_jit_line(aTHX_ b, "PERL_UNUSED_VAR(cv);");
154 518           }
155              
156 578           void xs_jit_xs_end(pTHX_ XS_JIT_Builder* b) {
157 578           b->indent--;
158 578           xs_jit_line(aTHX_ b, "}");
159 578           b->in_function = 0;
160 578           }
161              
162 442           void xs_jit_xs_return(pTHX_ XS_JIT_Builder* b, int count) {
163 442           xs_jit_line(aTHX_ b, "XSRETURN(%d);", count);
164 442           }
165              
166 25           void xs_jit_xs_return_undef(pTHX_ XS_JIT_Builder* b) {
167 25           xs_jit_line(aTHX_ b, "ST(0) = &PL_sv_undef;");
168 25           xs_jit_line(aTHX_ b, "XSRETURN(1);");
169 25           }
170              
171 112           void xs_jit_croak_usage(pTHX_ XS_JIT_Builder* b, const char* usage) {
172 112           xs_jit_line(aTHX_ b, "croak_xs_usage(cv, \"%s\");", usage);
173 112           }
174              
175             /* ============================================
176             * Control flow
177             * ============================================ */
178              
179 846           void xs_jit_if(pTHX_ XS_JIT_Builder* b, const char* cond) {
180 846           xs_jit_line(aTHX_ b, "if (%s) {", cond);
181 846           b->indent++;
182 846           }
183              
184 122           void xs_jit_elsif(pTHX_ XS_JIT_Builder* b, const char* cond) {
185 122           b->indent--;
186 122           xs_jit_line(aTHX_ b, "} else if (%s) {", cond);
187 122           b->indent++;
188 122           }
189              
190 257           void xs_jit_else(pTHX_ XS_JIT_Builder* b) {
191 257           b->indent--;
192 257           xs_jit_line(aTHX_ b, "} else {");
193 257           b->indent++;
194 257           }
195              
196 846           void xs_jit_endif(pTHX_ XS_JIT_Builder* b) {
197 846           b->indent--;
198 846           xs_jit_line(aTHX_ b, "}");
199 846           }
200              
201 105           void xs_jit_for(pTHX_ XS_JIT_Builder* b, const char* init, const char* cond, const char* incr) {
202 105           xs_jit_line(aTHX_ b, "for (%s; %s; %s) {", init, cond, incr);
203 105           b->indent++;
204 105           }
205              
206 52           void xs_jit_while(pTHX_ XS_JIT_Builder* b, const char* cond) {
207 52           xs_jit_line(aTHX_ b, "while (%s) {", cond);
208 52           b->indent++;
209 52           }
210              
211 156           void xs_jit_endloop(pTHX_ XS_JIT_Builder* b) {
212 156           b->indent--;
213 156           xs_jit_line(aTHX_ b, "}");
214 156           }
215              
216             /* ============================================
217             * Variable declarations
218             * ============================================ */
219              
220 619           void xs_jit_declare(pTHX_ XS_JIT_Builder* b, const char* type, const char* name, const char* value) {
221 619 100         if (value && *value) {
    50          
222 552           xs_jit_line(aTHX_ b, "%s %s = %s;", type, name, value);
223             } else {
224 67           xs_jit_line(aTHX_ b, "%s %s;", type, name);
225             }
226 619           }
227              
228 238           void xs_jit_declare_sv(pTHX_ XS_JIT_Builder* b, const char* name, const char* value) {
229 238           xs_jit_declare(aTHX_ b, "SV*", name, value);
230 238           }
231              
232 236           void xs_jit_declare_hv(pTHX_ XS_JIT_Builder* b, const char* name, const char* value) {
233 236           xs_jit_declare(aTHX_ b, "HV*", name, value);
234 236           }
235              
236 29           void xs_jit_declare_av(pTHX_ XS_JIT_Builder* b, const char* name, const char* value) {
237 29           xs_jit_declare(aTHX_ b, "AV*", name, value);
238 29           }
239              
240 3           void xs_jit_declare_int(pTHX_ XS_JIT_Builder* b, const char* name, const char* value) {
241 3           xs_jit_declare(aTHX_ b, "int", name, value);
242 3           }
243              
244 68           void xs_jit_declare_iv(pTHX_ XS_JIT_Builder* b, const char* name, const char* value) {
245 68           xs_jit_declare(aTHX_ b, "IV", name, value);
246 68           }
247              
248 16           void xs_jit_declare_nv(pTHX_ XS_JIT_Builder* b, const char* name, const char* value) {
249 16           xs_jit_declare(aTHX_ b, "NV", name, value);
250 16           }
251              
252 5           void xs_jit_declare_pv(pTHX_ XS_JIT_Builder* b, const char* name, const char* value) {
253 5           xs_jit_declare(aTHX_ b, "const char*", name, value);
254 5           }
255              
256 504           void xs_jit_assign(pTHX_ XS_JIT_Builder* b, const char* var, const char* value) {
257 504           xs_jit_line(aTHX_ b, "%s = %s;", var, value);
258 504           }
259              
260             /* ============================================
261             * Common XS patterns
262             * ============================================ */
263              
264 8           void xs_jit_get_self(pTHX_ XS_JIT_Builder* b) {
265 8           xs_jit_declare_sv(aTHX_ b, "self", "ST(0)");
266 8           }
267              
268 145           void xs_jit_get_self_hv(pTHX_ XS_JIT_Builder* b) {
269 145           xs_jit_declare_sv(aTHX_ b, "self", "ST(0)");
270 145           xs_jit_declare_hv(aTHX_ b, "hv", "(HV*)SvRV(self)");
271 145           }
272              
273 2           void xs_jit_get_self_av(pTHX_ XS_JIT_Builder* b) {
274 2           xs_jit_declare_sv(aTHX_ b, "self", "ST(0)");
275 2           xs_jit_declare_av(aTHX_ b, "av", "(AV*)SvRV(self)");
276 2           }
277              
278             /* ============================================
279             * Hash operations
280             * ============================================ */
281              
282 158           void xs_jit_hv_fetch(pTHX_ XS_JIT_Builder* b, const char* hv, const char* key, STRLEN len, const char* result_var) {
283 158           xs_jit_line(aTHX_ b, "SV** %s = hv_fetch(%s, \"%s\", %lu, 0);", result_var, hv, key, (unsigned long)len);
284 158           }
285              
286 2           void xs_jit_hv_fetch_sv(pTHX_ XS_JIT_Builder* b, const char* hv, const char* key_expr, const char* len_expr, const char* result_var) {
287 2           xs_jit_line(aTHX_ b, "SV** %s = hv_fetch(%s, %s, %s, 0);", result_var, hv, key_expr, len_expr);
288 2           }
289              
290 39           void xs_jit_hv_store(pTHX_ XS_JIT_Builder* b, const char* hv, const char* key, STRLEN len, const char* value) {
291 39           xs_jit_line(aTHX_ b, "(void)hv_store(%s, \"%s\", %lu, %s, 0);", hv, key, (unsigned long)len, value);
292 39           }
293              
294 2           void xs_jit_hv_store_sv(pTHX_ XS_JIT_Builder* b, const char* hv, const char* key_expr, const char* len_expr, const char* value) {
295 2           xs_jit_line(aTHX_ b, "(void)hv_store(%s, %s, %s, %s, 0);", hv, key_expr, len_expr, value);
296 2           }
297              
298 3           void xs_jit_hv_fetch_return(pTHX_ XS_JIT_Builder* b, const char* hv, const char* key, STRLEN len) {
299 3           xs_jit_line(aTHX_ b, "SV** valp = hv_fetch(%s, \"%s\", %lu, 0);", hv, key, (unsigned long)len);
300 3           xs_jit_line(aTHX_ b, "ST(0) = (valp && *valp) ? *valp : &PL_sv_undef;");
301 3           xs_jit_line(aTHX_ b, "XSRETURN(1);");
302 3           }
303              
304             /* ============================================
305             * Array operations
306             * ============================================ */
307              
308 14           void xs_jit_av_fetch(pTHX_ XS_JIT_Builder* b, const char* av, const char* index, const char* result_var) {
309 14           xs_jit_line(aTHX_ b, "SV** %s = av_fetch(%s, %s, 0);", result_var, av, index);
310 14           }
311              
312 3           void xs_jit_av_store(pTHX_ XS_JIT_Builder* b, const char* av, const char* index, const char* value) {
313 3           xs_jit_line(aTHX_ b, "av_store(%s, %s, %s);", av, index, value);
314 3           }
315              
316 11           void xs_jit_av_push(pTHX_ XS_JIT_Builder* b, const char* av, const char* value) {
317 11           xs_jit_line(aTHX_ b, "av_push(%s, %s);", av, value);
318 11           }
319              
320 4           void xs_jit_av_len(pTHX_ XS_JIT_Builder* b, const char* av, const char* result_var) {
321 4           xs_jit_line(aTHX_ b, "I32 %s = av_len(%s);", result_var, av);
322 4           }
323              
324             /* ============================================
325             * SV creation
326             * ============================================ */
327              
328 3           void xs_jit_new_sv_iv(pTHX_ XS_JIT_Builder* b, const char* result_var, const char* value) {
329 3           xs_jit_line(aTHX_ b, "SV* %s = newSViv(%s);", result_var, value);
330 3           }
331              
332 3           void xs_jit_new_sv_nv(pTHX_ XS_JIT_Builder* b, const char* result_var, const char* value) {
333 3           xs_jit_line(aTHX_ b, "SV* %s = newSVnv(%s);", result_var, value);
334 3           }
335              
336 3           void xs_jit_new_sv_pv(pTHX_ XS_JIT_Builder* b, const char* result_var, const char* str, STRLEN len) {
337 3           xs_jit_line(aTHX_ b, "SV* %s = newSVpvn(\"%s\", %lu);", result_var, str, (unsigned long)len);
338 3           }
339              
340 6           void xs_jit_mortal(pTHX_ XS_JIT_Builder* b, const char* sv) {
341 6           xs_jit_line(aTHX_ b, "%s = sv_2mortal(%s);", sv, sv);
342 6           }
343              
344             /* ============================================
345             * Type checking
346             * ============================================ */
347              
348 107           void xs_jit_check_items(pTHX_ XS_JIT_Builder* b, int min, int max, const char* usage) {
349             char cond[128];
350 107 100         if (min == max) {
351 102           snprintf(cond, sizeof(cond), "items != %d", min);
352 5 100         } else if (max < 0) {
353 2           snprintf(cond, sizeof(cond), "items < %d", min);
354             } else {
355 3           snprintf(cond, sizeof(cond), "items < %d || items > %d", min, max);
356             }
357 107           xs_jit_if(aTHX_ b, cond);
358 107           xs_jit_croak_usage(aTHX_ b, usage);
359 107           xs_jit_endif(aTHX_ b);
360 107           }
361              
362 3           void xs_jit_check_defined(pTHX_ XS_JIT_Builder* b, const char* sv, const char* error_msg) {
363             char cond[128];
364 3           snprintf(cond, sizeof(cond), "!SvOK(%s)", sv);
365 3           xs_jit_if(aTHX_ b, cond);
366 3           xs_jit_croak(aTHX_ b, error_msg);
367 3           xs_jit_endif(aTHX_ b);
368 3           }
369              
370 6           void xs_jit_check_ref_type(pTHX_ XS_JIT_Builder* b, const char* sv, const char* type, const char* error_msg) {
371             char cond[256];
372 6           snprintf(cond, sizeof(cond), "!SvROK(%s) || SvTYPE(SvRV(%s)) != %s", sv, sv, type);
373 6           xs_jit_if(aTHX_ b, cond);
374 6           xs_jit_croak(aTHX_ b, error_msg);
375 6           xs_jit_endif(aTHX_ b);
376 6           }
377              
378 3           void xs_jit_check_hashref(pTHX_ XS_JIT_Builder* b, const char* sv, const char* error_msg) {
379 3           xs_jit_check_ref_type(aTHX_ b, sv, "SVt_PVHV", error_msg);
380 3           }
381              
382 3           void xs_jit_check_arrayref(pTHX_ XS_JIT_Builder* b, const char* sv, const char* error_msg) {
383 3           xs_jit_check_ref_type(aTHX_ b, sv, "SVt_PVAV", error_msg);
384 3           }
385              
386             /* ============================================
387             * SV conversion (extract values from SV)
388             * ============================================ */
389              
390 3           void xs_jit_sv_to_iv(pTHX_ XS_JIT_Builder* b, const char* result_var, const char* sv) {
391 3           xs_jit_line(aTHX_ b, "IV %s = SvIV(%s);", result_var, sv);
392 3           }
393              
394 0           void xs_jit_sv_to_uv(pTHX_ XS_JIT_Builder* b, const char* result_var, const char* sv) {
395 0           xs_jit_line(aTHX_ b, "UV %s = SvUV(%s);", result_var, sv);
396 0           }
397              
398 3           void xs_jit_sv_to_nv(pTHX_ XS_JIT_Builder* b, const char* result_var, const char* sv) {
399 3           xs_jit_line(aTHX_ b, "NV %s = SvNV(%s);", result_var, sv);
400 3           }
401              
402 5           void xs_jit_sv_to_pv(pTHX_ XS_JIT_Builder* b, const char* result_var, const char* len_var, const char* sv) {
403 5 100         if (len_var && *len_var) {
    50          
404 3           xs_jit_line(aTHX_ b, "STRLEN %s;", len_var);
405 3           xs_jit_line(aTHX_ b, "const char* %s = SvPV(%s, %s);", result_var, sv, len_var);
406             } else {
407 2           xs_jit_line(aTHX_ b, "const char* %s = SvPV_nolen(%s);", result_var, sv);
408             }
409 5           }
410              
411 3           void xs_jit_sv_to_bool(pTHX_ XS_JIT_Builder* b, const char* result_var, const char* sv) {
412 3           xs_jit_line(aTHX_ b, "int %s = SvTRUE(%s);", result_var, sv);
413 3           }
414              
415             /* ============================================
416             * Return helpers
417             * ============================================ */
418              
419 127           void xs_jit_return_iv(pTHX_ XS_JIT_Builder* b, const char* value) {
420 127           xs_jit_line(aTHX_ b, "ST(0) = sv_2mortal(newSViv(%s));", value);
421 127           xs_jit_xs_return(aTHX_ b, 1);
422 127           }
423              
424 0           void xs_jit_return_uv(pTHX_ XS_JIT_Builder* b, const char* value) {
425 0           xs_jit_line(aTHX_ b, "ST(0) = sv_2mortal(newSVuv(%s));", value);
426 0           xs_jit_xs_return(aTHX_ b, 1);
427 0           }
428              
429 13           void xs_jit_return_nv(pTHX_ XS_JIT_Builder* b, const char* value) {
430 13           xs_jit_line(aTHX_ b, "ST(0) = sv_2mortal(newSVnv(%s));", value);
431 13           xs_jit_xs_return(aTHX_ b, 1);
432 13           }
433              
434 22           void xs_jit_return_pv(pTHX_ XS_JIT_Builder* b, const char* str, const char* len) {
435             /* str is used as-is - caller must quote literal strings with \" */
436 22 100         if (len && *len) {
    50          
437 3           xs_jit_line(aTHX_ b, "ST(0) = sv_2mortal(newSVpvn(%s, %s));", str, len);
438             } else {
439 19           xs_jit_line(aTHX_ b, "ST(0) = sv_2mortal(newSVpv(%s, 0));", str);
440             }
441 22           xs_jit_xs_return(aTHX_ b, 1);
442 22           }
443              
444 53           void xs_jit_return_sv(pTHX_ XS_JIT_Builder* b, const char* sv) {
445 53           xs_jit_line(aTHX_ b, "ST(0) = %s;", sv);
446 53           xs_jit_xs_return(aTHX_ b, 1);
447 53           }
448              
449 59           void xs_jit_return_yes(pTHX_ XS_JIT_Builder* b) {
450 59           xs_jit_line(aTHX_ b, "ST(0) = &PL_sv_yes;");
451 59           xs_jit_xs_return(aTHX_ b, 1);
452 59           }
453              
454 90           void xs_jit_return_no(pTHX_ XS_JIT_Builder* b) {
455 90           xs_jit_line(aTHX_ b, "ST(0) = &PL_sv_no;");
456 90           xs_jit_xs_return(aTHX_ b, 1);
457 90           }
458              
459 45           void xs_jit_return_self(pTHX_ XS_JIT_Builder* b) {
460 45           xs_jit_line(aTHX_ b, "ST(0) = self;");
461 45           xs_jit_xs_return(aTHX_ b, 1);
462 45           }
463              
464             /* ============================================
465             * Common method patterns
466             * ============================================ */
467              
468 2           void xs_jit_method_start(pTHX_ XS_JIT_Builder* b, const char* func_name, int min_args, int max_args, const char* usage) {
469 2           xs_jit_xs_function(aTHX_ b, func_name);
470 2           xs_jit_xs_preamble(aTHX_ b);
471 2 50         if (min_args > 0 || max_args >= 0) {
    0          
472 2           xs_jit_check_items(aTHX_ b, min_args, max_args, usage);
473             }
474 2           xs_jit_get_self_hv(aTHX_ b);
475 2           }
476              
477             /* Predicate (returns true/false based on attribute existence) */
478 4           void xs_jit_predicate(pTHX_ XS_JIT_Builder* b, const char* func_name, const char* attr_name, STRLEN attr_len) {
479 4           xs_jit_xs_function(aTHX_ b, func_name);
480 4           xs_jit_xs_preamble(aTHX_ b);
481 4           xs_jit_get_self_hv(aTHX_ b);
482 4           xs_jit_line(aTHX_ b, "SV** valp = hv_fetch(hv, \"%s\", %lu, 0);", attr_name, (unsigned long)attr_len);
483 4           xs_jit_if(aTHX_ b, "valp != NULL");
484 4           xs_jit_return_yes(aTHX_ b);
485 4           xs_jit_else(aTHX_ b);
486 4           xs_jit_return_no(aTHX_ b);
487 4           xs_jit_endif(aTHX_ b);
488 4           xs_jit_xs_end(aTHX_ b);
489 4           }
490              
491             /* Clearer (deletes an attribute) */
492 4           void xs_jit_clearer(pTHX_ XS_JIT_Builder* b, const char* func_name, const char* attr_name, STRLEN attr_len) {
493 4           xs_jit_xs_function(aTHX_ b, func_name);
494 4           xs_jit_xs_preamble(aTHX_ b);
495 4           xs_jit_get_self_hv(aTHX_ b);
496 4           xs_jit_line(aTHX_ b, "(void)hv_delete(hv, \"%s\", %lu, G_DISCARD);", attr_name, (unsigned long)attr_len);
497 4           xs_jit_return_self(aTHX_ b);
498 4           xs_jit_xs_end(aTHX_ b);
499 4           }
500              
501             /* ============================================
502             * Error handling
503             * ============================================ */
504              
505 114           void xs_jit_croak(pTHX_ XS_JIT_Builder* b, const char* message) {
506 114           xs_jit_line(aTHX_ b, "croak(\"%s\");", message);
507 114           }
508              
509 3           void xs_jit_warn(pTHX_ XS_JIT_Builder* b, const char* message) {
510 3           xs_jit_line(aTHX_ b, "warn(\"%s\");", message);
511 3           }
512              
513             /* ============================================
514             * Prebuilt patterns
515             * ============================================ */
516              
517 5           void xs_jit_ro_accessor(pTHX_ XS_JIT_Builder* b, const char* func_name, const char* attr_name, STRLEN attr_len) {
518 5           xs_jit_xs_function(aTHX_ b, func_name);
519 5           xs_jit_line(aTHX_ b, "dXSARGS;");
520 5           xs_jit_line(aTHX_ b, "PERL_UNUSED_VAR(cv); PERL_UNUSED_VAR(items);");
521              
522             /* Use hv_fetch for reliable hash lookup */
523 5           xs_jit_line(aTHX_ b, "SV** valp = hv_fetch((HV*)SvRV(ST(0)), \"%s\", %lu, 0);",
524             attr_name, (unsigned long)attr_len);
525 5           xs_jit_line(aTHX_ b, "ST(0) = (valp && *valp) ? *valp : &PL_sv_undef;");
526 5           xs_jit_line(aTHX_ b, "XSRETURN(1);");
527              
528 5           xs_jit_xs_end(aTHX_ b);
529 5           }
530              
531 42           void xs_jit_rw_accessor(pTHX_ XS_JIT_Builder* b, const char* func_name, const char* attr_name, STRLEN attr_len) {
532 42           xs_jit_xs_function(aTHX_ b, func_name);
533 42           xs_jit_line(aTHX_ b, "dXSARGS;");
534 42           xs_jit_line(aTHX_ b, "PERL_UNUSED_VAR(cv);");
535              
536 42           xs_jit_line(aTHX_ b, "HV* hv = (HV*)SvRV(ST(0));");
537              
538 42           xs_jit_if(aTHX_ b, "items > 1");
539             /* Setter: use hv_store */
540 42           xs_jit_line(aTHX_ b, "SV* val = newSVsv(ST(1));");
541 42           xs_jit_line(aTHX_ b, "SV** slot = hv_store(hv, \"%s\", %lu, val, 0);",
542             attr_name, (unsigned long)attr_len);
543 42           xs_jit_line(aTHX_ b, "ST(0) = slot ? *slot : val;");
544 42           xs_jit_line(aTHX_ b, "XSRETURN(1);");
545 42           xs_jit_endif(aTHX_ b);
546              
547             /* Getter: use hv_fetch */
548 42           xs_jit_line(aTHX_ b, "SV** valp = hv_fetch(hv, \"%s\", %lu, 0);",
549             attr_name, (unsigned long)attr_len);
550 42           xs_jit_line(aTHX_ b, "ST(0) = (valp && *valp) ? *valp : &PL_sv_undef;");
551 42           xs_jit_line(aTHX_ b, "XSRETURN(1);");
552              
553 42           xs_jit_xs_end(aTHX_ b);
554 42           }
555              
556 6           void xs_jit_constructor(pTHX_ XS_JIT_Builder* b, const char* func_name, const char* class_name, XS_JIT_Attr* attrs, int num_attrs) {
557             int i;
558            
559 6           xs_jit_xs_function(aTHX_ b, func_name);
560 6           xs_jit_xs_preamble(aTHX_ b);
561            
562 6           xs_jit_comment(aTHX_ b, "Get class name");
563 6           xs_jit_declare_sv(aTHX_ b, "class_sv", "ST(0)");
564 6           xs_jit_line(aTHX_ b, "const char* classname = SvPV_nolen(class_sv);");
565 6           xs_jit_blank(aTHX_ b);
566            
567 6           xs_jit_comment(aTHX_ b, "Parse args hash if provided");
568 6           xs_jit_declare_hv(aTHX_ b, "args", "NULL");
569 6           xs_jit_if(aTHX_ b, "items > 1 && SvROK(ST(1)) && SvTYPE(SvRV(ST(1))) == SVt_PVHV");
570 6           xs_jit_line(aTHX_ b, "args = (HV*)SvRV(ST(1));");
571 6           xs_jit_endif(aTHX_ b);
572 6           xs_jit_blank(aTHX_ b);
573            
574 6           xs_jit_comment(aTHX_ b, "Create new hash for object");
575 6           xs_jit_declare_hv(aTHX_ b, "hv", "newHV()");
576 6           xs_jit_blank(aTHX_ b);
577            
578 6           xs_jit_comment(aTHX_ b, "Process attributes");
579 14 100         for (i = 0; i < num_attrs; i++) {
580 8           const char* name = attrs[i].name;
581 8           STRLEN len = attrs[i].len;
582            
583 8           xs_jit_line(aTHX_ b, "{");
584 8           b->indent++;
585 8           xs_jit_line(aTHX_ b, "SV** %s_valp = args ? hv_fetch(args, \"%s\", %lu, 0) : NULL;", name, name, (unsigned long)len);
586             /* Build condition string for if */
587 8           SV* cond_sv = newSVpvf("%s_valp && SvOK(*%s_valp)", name, name);
588 8           xs_jit_if(aTHX_ b, SvPV_nolen(cond_sv));
589 8           SvREFCNT_dec(cond_sv);
590 8           xs_jit_line(aTHX_ b, "(void)hv_store(hv, \"%s\", %lu, newSVsv(*%s_valp), 0);", name, (unsigned long)len, name);
591 8           xs_jit_endif(aTHX_ b);
592 8           b->indent--;
593 8           xs_jit_line(aTHX_ b, "}");
594             }
595 6           xs_jit_blank(aTHX_ b);
596            
597 6           xs_jit_comment(aTHX_ b, "Bless and return");
598 6           xs_jit_declare_sv(aTHX_ b, "self", "newRV_noinc((SV*)hv)");
599 6           xs_jit_line(aTHX_ b, "sv_bless(self, gv_stashpv(classname, GV_ADD));");
600 6           xs_jit_line(aTHX_ b, "ST(0) = sv_2mortal(self);");
601 6           xs_jit_line(aTHX_ b, "XSRETURN(1);");
602            
603 6           xs_jit_xs_end(aTHX_ b);
604 6           }
605              
606             /* ============================================
607             * New constructor variants
608             * ============================================ */
609              
610 3           void xs_jit_new_simple(pTHX_ XS_JIT_Builder* b, const char* func_name) {
611 3           xs_jit_xs_function(aTHX_ b, func_name);
612 3           xs_jit_line(aTHX_ b, "dXSARGS;");
613 3           xs_jit_line(aTHX_ b, "PERL_UNUSED_VAR(cv); PERL_UNUSED_VAR(items);");
614            
615 3           xs_jit_line(aTHX_ b, "SV* class_sv = ST(0);");
616 3           xs_jit_line(aTHX_ b, "const char* classname = SvPV_nolen(class_sv);");
617 3           xs_jit_line(aTHX_ b, "HV* hv = newHV();");
618 3           xs_jit_line(aTHX_ b, "SV* self = newRV_noinc((SV*)hv);");
619 3           xs_jit_line(aTHX_ b, "sv_bless(self, gv_stashpv(classname, GV_ADD));");
620 3           xs_jit_line(aTHX_ b, "ST(0) = sv_2mortal(self);");
621 3           xs_jit_line(aTHX_ b, "XSRETURN(1);");
622            
623 3           xs_jit_xs_end(aTHX_ b);
624 3           }
625              
626 28           void xs_jit_new_hash(pTHX_ XS_JIT_Builder* b, const char* func_name) {
627 28           xs_jit_xs_function(aTHX_ b, func_name);
628 28           xs_jit_xs_preamble(aTHX_ b);
629            
630 28           xs_jit_comment(aTHX_ b, "Get class name");
631 28           xs_jit_line(aTHX_ b, "SV* class_sv = ST(0);");
632 28           xs_jit_line(aTHX_ b, "const char* classname = SvPV_nolen(class_sv);");
633 28           xs_jit_blank(aTHX_ b);
634            
635 28           xs_jit_comment(aTHX_ b, "Create object hash");
636 28           xs_jit_line(aTHX_ b, "HV* hv = newHV();");
637 28           xs_jit_line(aTHX_ b, "HV* args;");
638 28           xs_jit_line(aTHX_ b, "HE* entry;");
639 28           xs_jit_line(aTHX_ b, "STRLEN klen;");
640 28           xs_jit_line(aTHX_ b, "const char* key;");
641 28           xs_jit_line(aTHX_ b, "SV* val;");
642 28           xs_jit_line(aTHX_ b, "int i;");
643 28           xs_jit_blank(aTHX_ b);
644              
645 28           xs_jit_comment(aTHX_ b, "Parse args - accept hashref or flat list");
646 28           xs_jit_if(aTHX_ b, "items > 1");
647 28           xs_jit_if(aTHX_ b, "SvROK(ST(1)) && SvTYPE(SvRV(ST(1))) == SVt_PVHV");
648 28           xs_jit_comment(aTHX_ b, "Hashref: Class->new(\\%args)");
649 28           xs_jit_assign(aTHX_ b, "args", "(HV*)SvRV(ST(1))");
650 28           xs_jit_line(aTHX_ b, "hv_iterinit(args);");
651 28           xs_jit_while(aTHX_ b, "(entry = hv_iternext(args)) != NULL");
652 28           xs_jit_assign(aTHX_ b, "key", "HePV(entry, klen)");
653 28           xs_jit_assign(aTHX_ b, "val", "HeVAL(entry)");
654 28           xs_jit_line(aTHX_ b, "hv_store(hv, key, klen, newSVsv(val), 0);");
655 28           xs_jit_endloop(aTHX_ b);
656 28           xs_jit_else(aTHX_ b);
657 28           xs_jit_comment(aTHX_ b, "Flat list: Class->new(key => val, ...)");
658 28           xs_jit_if(aTHX_ b, "(items - 1) % 2 != 0");
659 28           xs_jit_croak(aTHX_ b, "Odd number of arguments to new()");
660 28           xs_jit_endif(aTHX_ b);
661 28           xs_jit_for(aTHX_ b, "i = 1", "i < items", "i += 2");
662 28           xs_jit_assign(aTHX_ b, "key", "SvPV(ST(i), klen)");
663 28           xs_jit_assign(aTHX_ b, "val", "ST(i + 1)");
664 28           xs_jit_line(aTHX_ b, "hv_store(hv, key, klen, newSVsv(val), 0);");
665 28           xs_jit_endloop(aTHX_ b);
666 28           xs_jit_endif(aTHX_ b);
667 28           xs_jit_endif(aTHX_ b);
668 28           xs_jit_blank(aTHX_ b);
669            
670 28           xs_jit_comment(aTHX_ b, "Bless and return");
671 28           xs_jit_line(aTHX_ b, "SV* self = newRV_noinc((SV*)hv);");
672 28           xs_jit_line(aTHX_ b, "sv_bless(self, gv_stashpv(classname, GV_ADD));");
673 28           xs_jit_line(aTHX_ b, "ST(0) = sv_2mortal(self);");
674 28           xs_jit_line(aTHX_ b, "XSRETURN(1);");
675            
676 28           xs_jit_xs_end(aTHX_ b);
677 28           }
678              
679 1           void xs_jit_new_array(pTHX_ XS_JIT_Builder* b, const char* func_name, int num_slots) {
680 1           xs_jit_xs_function(aTHX_ b, func_name);
681 1           xs_jit_line(aTHX_ b, "dXSARGS;");
682 1           xs_jit_line(aTHX_ b, "PERL_UNUSED_VAR(cv); PERL_UNUSED_VAR(items);");
683            
684 1           xs_jit_comment(aTHX_ b, "Get class name");
685 1           xs_jit_line(aTHX_ b, "SV* class_sv = ST(0);");
686 1           xs_jit_line(aTHX_ b, "const char* classname = SvPV_nolen(class_sv);");
687 1           xs_jit_blank(aTHX_ b);
688            
689 1           xs_jit_comment(aTHX_ b, "Create array with pre-extended size");
690 1           xs_jit_line(aTHX_ b, "AV* av = newAV();");
691 1 50         if (num_slots > 0) {
692             char cond_buf[64];
693 1           xs_jit_line(aTHX_ b, "av_extend(av, %d);", num_slots - 1);
694 1           xs_jit_comment(aTHX_ b, "Initialize slots to undef");
695 1           xs_jit_line(aTHX_ b, "int i;");
696 1           snprintf(cond_buf, sizeof(cond_buf), "i < %d", num_slots);
697 1           xs_jit_for(aTHX_ b, "i = 0", cond_buf, "i++");
698 1           xs_jit_line(aTHX_ b, "av_store(av, i, newSV(0));");
699 1           xs_jit_endloop(aTHX_ b);
700             }
701 1           xs_jit_blank(aTHX_ b);
702            
703 1           xs_jit_comment(aTHX_ b, "Bless and return");
704 1           xs_jit_line(aTHX_ b, "SV* self = newRV_noinc((SV*)av);");
705 1           xs_jit_line(aTHX_ b, "sv_bless(self, gv_stashpv(classname, GV_ADD));");
706 1           xs_jit_line(aTHX_ b, "ST(0) = sv_2mortal(self);");
707 1           xs_jit_line(aTHX_ b, "XSRETURN(1);");
708            
709 1           xs_jit_xs_end(aTHX_ b);
710 1           }
711              
712 2           void xs_jit_new_with_build(pTHX_ XS_JIT_Builder* b, const char* func_name) {
713 2           xs_jit_xs_function(aTHX_ b, func_name);
714 2           xs_jit_xs_preamble(aTHX_ b);
715            
716 2           xs_jit_comment(aTHX_ b, "Get class name");
717 2           xs_jit_line(aTHX_ b, "SV* class_sv = ST(0);");
718 2           xs_jit_line(aTHX_ b, "const char* classname = SvPV_nolen(class_sv);");
719 2           xs_jit_blank(aTHX_ b);
720            
721 2           xs_jit_comment(aTHX_ b, "Create object hash and args hash");
722 2           xs_jit_line(aTHX_ b, "HV* hv = newHV();");
723 2           xs_jit_line(aTHX_ b, "HV* args = newHV();");
724 2           xs_jit_line(aTHX_ b, "HV* src;");
725 2           xs_jit_line(aTHX_ b, "HE* entry;");
726 2           xs_jit_line(aTHX_ b, "STRLEN klen;");
727 2           xs_jit_line(aTHX_ b, "const char* key;");
728 2           xs_jit_line(aTHX_ b, "SV* val;");
729 2           xs_jit_line(aTHX_ b, "int i;");
730 2           xs_jit_blank(aTHX_ b);
731              
732 2           xs_jit_comment(aTHX_ b, "Parse args - accept hashref or flat list");
733 2           xs_jit_if(aTHX_ b, "items > 1");
734 2           xs_jit_if(aTHX_ b, "SvROK(ST(1)) && SvTYPE(SvRV(ST(1))) == SVt_PVHV");
735 2           xs_jit_comment(aTHX_ b, "Hashref: Class->new(\\%args)");
736 2           xs_jit_assign(aTHX_ b, "src", "(HV*)SvRV(ST(1))");
737 2           xs_jit_line(aTHX_ b, "hv_iterinit(src);");
738 2           xs_jit_while(aTHX_ b, "(entry = hv_iternext(src)) != NULL");
739 2           xs_jit_assign(aTHX_ b, "key", "HePV(entry, klen)");
740 2           xs_jit_assign(aTHX_ b, "val", "newSVsv(HeVAL(entry))");
741 2           xs_jit_line(aTHX_ b, "hv_store(hv, key, klen, val, 0);");
742 2           xs_jit_line(aTHX_ b, "hv_store(args, key, klen, newSVsv(val), 0);");
743 2           xs_jit_endloop(aTHX_ b);
744 2           xs_jit_else(aTHX_ b);
745 2           xs_jit_comment(aTHX_ b, "Flat list: Class->new(key => val, ...)");
746 2           xs_jit_if(aTHX_ b, "(items - 1) % 2 != 0");
747 2           xs_jit_croak(aTHX_ b, "Odd number of arguments to new()");
748 2           xs_jit_endif(aTHX_ b);
749 2           xs_jit_for(aTHX_ b, "i = 1", "i < items", "i += 2");
750 2           xs_jit_assign(aTHX_ b, "key", "SvPV(ST(i), klen)");
751 2           xs_jit_assign(aTHX_ b, "val", "newSVsv(ST(i + 1))");
752 2           xs_jit_line(aTHX_ b, "hv_store(hv, key, klen, val, 0);");
753 2           xs_jit_line(aTHX_ b, "hv_store(args, key, klen, newSVsv(val), 0);");
754 2           xs_jit_endloop(aTHX_ b);
755 2           xs_jit_endif(aTHX_ b);
756 2           xs_jit_endif(aTHX_ b);
757 2           xs_jit_blank(aTHX_ b);
758            
759 2           xs_jit_comment(aTHX_ b, "Bless object");
760 2           xs_jit_line(aTHX_ b, "SV* self = newRV_noinc((SV*)hv);");
761 2           xs_jit_line(aTHX_ b, "HV* stash = gv_stashpv(classname, GV_ADD);");
762 2           xs_jit_line(aTHX_ b, "sv_bless(self, stash);");
763 2           xs_jit_blank(aTHX_ b);
764            
765 2           xs_jit_comment(aTHX_ b, "Call BUILD if it exists");
766 2           xs_jit_line(aTHX_ b, "GV* build_gv = gv_fetchmeth(stash, \"BUILD\", 5, 0);");
767 2           xs_jit_if(aTHX_ b, "build_gv");
768 2           xs_jit_line(aTHX_ b, "dSP;");
769 2           xs_jit_line(aTHX_ b, "ENTER;");
770 2           xs_jit_line(aTHX_ b, "SAVETMPS;");
771 2           xs_jit_line(aTHX_ b, "PUSHMARK(SP);");
772 2           xs_jit_line(aTHX_ b, "XPUSHs(self);");
773 2           xs_jit_line(aTHX_ b, "XPUSHs(newRV_noinc((SV*)args));");
774 2           xs_jit_line(aTHX_ b, "PUTBACK;");
775 2           xs_jit_line(aTHX_ b, "call_sv((SV*)GvCV(build_gv), G_DISCARD);");
776 2           xs_jit_line(aTHX_ b, "FREETMPS;");
777 2           xs_jit_line(aTHX_ b, "LEAVE;");
778 2           xs_jit_else(aTHX_ b);
779 2           xs_jit_line(aTHX_ b, "SvREFCNT_dec((SV*)args);");
780 2           xs_jit_endif(aTHX_ b);
781 2           xs_jit_blank(aTHX_ b);
782            
783 2           xs_jit_line(aTHX_ b, "ST(0) = sv_2mortal(self);");
784 2           xs_jit_line(aTHX_ b, "XSRETURN(1);");
785            
786 2           xs_jit_xs_end(aTHX_ b);
787 2           }
788              
789             /* ============================================
790             * Constructor validation
791             * ============================================ */
792              
793 6           void xs_jit_new_with_required(pTHX_ XS_JIT_Builder* b, const char* func_name,
794             const char** required_attrs, STRLEN* required_lens,
795             int num_required) {
796             int i;
797            
798 6           xs_jit_xs_function(aTHX_ b, func_name);
799 6           xs_jit_xs_preamble(aTHX_ b);
800            
801 6           xs_jit_comment(aTHX_ b, "Get class name");
802 6           xs_jit_line(aTHX_ b, "SV* class_sv = ST(0);");
803 6           xs_jit_line(aTHX_ b, "const char* classname = SvPV_nolen(class_sv);");
804 6           xs_jit_blank(aTHX_ b);
805            
806 6           xs_jit_comment(aTHX_ b, "Create object hash");
807 6           xs_jit_line(aTHX_ b, "HV* hv = newHV();");
808 6           xs_jit_line(aTHX_ b, "HV* src;");
809 6           xs_jit_line(aTHX_ b, "HE* entry;");
810 6           xs_jit_line(aTHX_ b, "STRLEN klen;");
811 6           xs_jit_line(aTHX_ b, "const char* key;");
812 6           xs_jit_line(aTHX_ b, "SV* val;");
813 6           xs_jit_line(aTHX_ b, "int i;");
814 6           xs_jit_blank(aTHX_ b);
815              
816 6           xs_jit_comment(aTHX_ b, "Parse args - accept hashref or flat list");
817 6           xs_jit_if(aTHX_ b, "items > 1");
818 6           xs_jit_if(aTHX_ b, "SvROK(ST(1)) && SvTYPE(SvRV(ST(1))) == SVt_PVHV");
819 6           xs_jit_comment(aTHX_ b, "Hashref: Class->new(\\%args)");
820 6           xs_jit_assign(aTHX_ b, "src", "(HV*)SvRV(ST(1))");
821 6           xs_jit_line(aTHX_ b, "hv_iterinit(src);");
822 6           xs_jit_while(aTHX_ b, "(entry = hv_iternext(src)) != NULL");
823 6           xs_jit_assign(aTHX_ b, "key", "HePV(entry, klen)");
824 6           xs_jit_assign(aTHX_ b, "val", "newSVsv(HeVAL(entry))");
825 6           xs_jit_line(aTHX_ b, "hv_store(hv, key, klen, val, 0);");
826 6           xs_jit_endloop(aTHX_ b);
827 6           xs_jit_else(aTHX_ b);
828 6           xs_jit_comment(aTHX_ b, "Flat list: Class->new(key => val, ...)");
829 6           xs_jit_if(aTHX_ b, "(items - 1) % 2 != 0");
830 6           xs_jit_croak(aTHX_ b, "Odd number of arguments to new()");
831 6           xs_jit_endif(aTHX_ b);
832 6           xs_jit_for(aTHX_ b, "i = 1", "i < items", "i += 2");
833 6           xs_jit_assign(aTHX_ b, "key", "SvPV(ST(i), klen)");
834 6           xs_jit_assign(aTHX_ b, "val", "newSVsv(ST(i + 1))");
835 6           xs_jit_line(aTHX_ b, "hv_store(hv, key, klen, val, 0);");
836 6           xs_jit_endloop(aTHX_ b);
837 6           xs_jit_endif(aTHX_ b);
838 6           xs_jit_endif(aTHX_ b);
839 6           xs_jit_blank(aTHX_ b);
840              
841             /* Validate required attributes */
842 6 50         if (num_required > 0) {
843 6           xs_jit_comment(aTHX_ b, "Validate required attributes");
844 15 100         for (i = 0; i < num_required; i++) {
845 9           xs_jit_line(aTHX_ b, "{");
846 9           xs_jit_indent(b);
847 9           xs_jit_line(aTHX_ b, "SV** valp = hv_fetch(hv, \"%s\", %d, 0);",
848 9           required_attrs[i], (int)required_lens[i]);
849 9           xs_jit_if(aTHX_ b, "!valp || !SvOK(*valp)");
850 9           xs_jit_line(aTHX_ b, "SvREFCNT_dec((SV*)hv);");
851 9           xs_jit_line(aTHX_ b, "croak(\"Missing required attribute '%s'\");",
852 9           required_attrs[i]);
853 9           xs_jit_endif(aTHX_ b);
854 9           xs_jit_dedent(b);
855 9           xs_jit_line(aTHX_ b, "}");
856             }
857 6           xs_jit_blank(aTHX_ b);
858             }
859            
860 6           xs_jit_comment(aTHX_ b, "Bless object");
861 6           xs_jit_line(aTHX_ b, "SV* self = newRV_noinc((SV*)hv);");
862 6           xs_jit_line(aTHX_ b, "HV* stash = gv_stashpv(classname, GV_ADD);");
863 6           xs_jit_line(aTHX_ b, "sv_bless(self, stash);");
864 6           xs_jit_blank(aTHX_ b);
865            
866 6           xs_jit_line(aTHX_ b, "ST(0) = sv_2mortal(self);");
867 6           xs_jit_line(aTHX_ b, "XSRETURN(1);");
868            
869 6           xs_jit_xs_end(aTHX_ b);
870 6           }
871              
872 10           void xs_jit_rw_accessor_typed(pTHX_ XS_JIT_Builder* b, const char* func_name,
873             const char* attr_name, STRLEN attr_len,
874             int type, const char* error_msg) {
875 10           xs_jit_xs_function(aTHX_ b, func_name);
876 10           xs_jit_xs_preamble(aTHX_ b);
877            
878 10           xs_jit_line(aTHX_ b, "SV* self = ST(0);");
879 10           xs_jit_line(aTHX_ b, "HV* hv = (HV*)SvRV(self);");
880 10           xs_jit_blank(aTHX_ b);
881            
882 10           xs_jit_comment(aTHX_ b, "Setter with type validation");
883 10           xs_jit_if(aTHX_ b, "items > 1");
884 10           xs_jit_line(aTHX_ b, "SV* val = ST(1);");
885            
886             /* Type checking - only check if value is defined (undef bypasses unless TYPE_DEFINED) */
887 10 100         if (type == 1) { /* TYPE_DEFINED */
888 1           xs_jit_if(aTHX_ b, "!SvOK(val)");
889 1           xs_jit_croak(aTHX_ b, error_msg);
890 1           xs_jit_endif(aTHX_ b);
891 9 100         } else if (type == 2) { /* TYPE_INT */
892 3           xs_jit_if(aTHX_ b, "SvOK(val) && !SvIOK(val) && !(SvNOK(val) && SvNV(val) == (NV)(IV)SvNV(val))");
893 3           xs_jit_croak(aTHX_ b, error_msg);
894 3           xs_jit_endif(aTHX_ b);
895 6 100         } else if (type == 3) { /* TYPE_NUM */
896 1           xs_jit_if(aTHX_ b, "SvOK(val) && !SvNOK(val) && !SvIOK(val) && !looks_like_number(val)");
897 1           xs_jit_croak(aTHX_ b, error_msg);
898 1           xs_jit_endif(aTHX_ b);
899 5 100         } else if (type == 4) { /* TYPE_STR */
900 1           xs_jit_if(aTHX_ b, "SvOK(val) && SvROK(val)");
901 1           xs_jit_croak(aTHX_ b, error_msg);
902 1           xs_jit_endif(aTHX_ b);
903 4 50         } else if (type == 5) { /* TYPE_REF */
904 0           xs_jit_if(aTHX_ b, "SvOK(val) && !SvROK(val)");
905 0           xs_jit_croak(aTHX_ b, error_msg);
906 0           xs_jit_endif(aTHX_ b);
907 4 100         } else if (type == 6) { /* TYPE_ARRAYREF */
908 1           xs_jit_if(aTHX_ b, "SvOK(val) && !(SvROK(val) && SvTYPE(SvRV(val)) == SVt_PVAV)");
909 1           xs_jit_croak(aTHX_ b, error_msg);
910 1           xs_jit_endif(aTHX_ b);
911 3 100         } else if (type == 7) { /* TYPE_HASHREF */
912 1           xs_jit_if(aTHX_ b, "SvOK(val) && !(SvROK(val) && SvTYPE(SvRV(val)) == SVt_PVHV)");
913 1           xs_jit_croak(aTHX_ b, error_msg);
914 1           xs_jit_endif(aTHX_ b);
915 2 100         } else if (type == 8) { /* TYPE_CODEREF */
916 1           xs_jit_if(aTHX_ b, "SvOK(val) && !(SvROK(val) && SvTYPE(SvRV(val)) == SVt_PVCV)");
917 1           xs_jit_croak(aTHX_ b, error_msg);
918 1           xs_jit_endif(aTHX_ b);
919 1 50         } else if (type == 9) { /* TYPE_OBJECT */
920 1           xs_jit_if(aTHX_ b, "SvOK(val) && !sv_isobject(val)");
921 1           xs_jit_croak(aTHX_ b, error_msg);
922 1           xs_jit_endif(aTHX_ b);
923             }
924             /* TYPE_ANY (0) and TYPE_BLESSED (10) - no check for TYPE_ANY,
925             TYPE_BLESSED requires classname which we don't have here */
926            
927 10           xs_jit_line(aTHX_ b, "hv_store(hv, \"%s\", %d, newSVsv(val), 0);",
928             attr_name, (int)attr_len);
929 10           xs_jit_endif(aTHX_ b);
930 10           xs_jit_blank(aTHX_ b);
931            
932 10           xs_jit_comment(aTHX_ b, "Getter");
933 10           xs_jit_line(aTHX_ b, "SV** valp = hv_fetch(hv, \"%s\", %d, 0);",
934             attr_name, (int)attr_len);
935 10           xs_jit_if(aTHX_ b, "valp && *valp");
936 10           xs_jit_line(aTHX_ b, "ST(0) = *valp;");
937 10           xs_jit_else(aTHX_ b);
938 10           xs_jit_line(aTHX_ b, "ST(0) = &PL_sv_undef;");
939 10           xs_jit_endif(aTHX_ b);
940 10           xs_jit_line(aTHX_ b, "XSRETURN(1);");
941            
942 10           xs_jit_xs_end(aTHX_ b);
943 10           }
944              
945             /* ============================================
946             * Clone methods
947             * ============================================ */
948              
949 4           void xs_jit_clone_hash(pTHX_ XS_JIT_Builder* b, const char* func_name) {
950 4           xs_jit_xs_function(aTHX_ b, func_name);
951 4           xs_jit_xs_preamble(aTHX_ b);
952            
953 4           xs_jit_comment(aTHX_ b, "Get self and source hash");
954 4           xs_jit_line(aTHX_ b, "SV* self = ST(0);");
955 4           xs_jit_line(aTHX_ b, "if (!SvROK(self) || SvTYPE(SvRV(self)) != SVt_PVHV) {");
956 4           xs_jit_indent(b);
957 4           xs_jit_croak(aTHX_ b, "clone requires a hash-based object");
958 4           xs_jit_dedent(b);
959 4           xs_jit_line(aTHX_ b, "}");
960 4           xs_jit_line(aTHX_ b, "HV* src = (HV*)SvRV(self);");
961 4           xs_jit_blank(aTHX_ b);
962            
963 4           xs_jit_comment(aTHX_ b, "Create new hash and copy all entries");
964 4           xs_jit_line(aTHX_ b, "HV* dst = newHV();");
965 4           xs_jit_line(aTHX_ b, "hv_iterinit(src);");
966 4           xs_jit_line(aTHX_ b, "HE* entry;");
967 4           xs_jit_line(aTHX_ b, "SV* key_sv;");
968 4           xs_jit_line(aTHX_ b, "SV* val;");
969 4           xs_jit_while(aTHX_ b, "(entry = hv_iternext(src)) != NULL");
970 4           xs_jit_assign(aTHX_ b, "key_sv", "hv_iterkeysv(entry)");
971 4           xs_jit_assign(aTHX_ b, "val", "hv_iterval(src, entry)");
972 4           xs_jit_line(aTHX_ b, "hv_store_ent(dst, key_sv, newSVsv(val), 0);");
973 4           xs_jit_endloop(aTHX_ b);
974 4           xs_jit_blank(aTHX_ b);
975            
976 4           xs_jit_comment(aTHX_ b, "Bless with same class as original");
977 4           xs_jit_line(aTHX_ b, "SV* clone = newRV_noinc((SV*)dst);");
978 4           xs_jit_line(aTHX_ b, "sv_bless(clone, SvSTASH(SvRV(self)));");
979 4           xs_jit_blank(aTHX_ b);
980            
981 4           xs_jit_line(aTHX_ b, "ST(0) = sv_2mortal(clone);");
982 4           xs_jit_line(aTHX_ b, "XSRETURN(1);");
983            
984 4           xs_jit_xs_end(aTHX_ b);
985 4           }
986              
987 4           void xs_jit_clone_array(pTHX_ XS_JIT_Builder* b, const char* func_name) {
988 4           xs_jit_xs_function(aTHX_ b, func_name);
989 4           xs_jit_xs_preamble(aTHX_ b);
990            
991 4           xs_jit_comment(aTHX_ b, "Get self and source array");
992 4           xs_jit_line(aTHX_ b, "SV* self = ST(0);");
993 4           xs_jit_line(aTHX_ b, "if (!SvROK(self) || SvTYPE(SvRV(self)) != SVt_PVAV) {");
994 4           xs_jit_indent(b);
995 4           xs_jit_croak(aTHX_ b, "clone requires an array-based object");
996 4           xs_jit_dedent(b);
997 4           xs_jit_line(aTHX_ b, "}");
998 4           xs_jit_line(aTHX_ b, "AV* src = (AV*)SvRV(self);");
999 4           xs_jit_blank(aTHX_ b);
1000            
1001 4           xs_jit_comment(aTHX_ b, "Create new array and copy all elements");
1002 4           xs_jit_line(aTHX_ b, "SSize_t len = av_len(src) + 1;");
1003 4           xs_jit_line(aTHX_ b, "AV* dst = newAV();");
1004 4           xs_jit_line(aTHX_ b, "av_extend(dst, len - 1);");
1005 4           xs_jit_line(aTHX_ b, "SSize_t i;");
1006 4           xs_jit_for(aTHX_ b, "i = 0", "i < len", "i++");
1007 4           xs_jit_line(aTHX_ b, "SV** elem = av_fetch(src, i, 0);");
1008 4           xs_jit_line(aTHX_ b, "if (elem && *elem) {");
1009 4           xs_jit_indent(b);
1010 4           xs_jit_line(aTHX_ b, "av_store(dst, i, newSVsv(*elem));");
1011 4           xs_jit_dedent(b);
1012 4           xs_jit_line(aTHX_ b, "} else {");
1013 4           xs_jit_indent(b);
1014 4           xs_jit_line(aTHX_ b, "av_store(dst, i, newSV(0));");
1015 4           xs_jit_dedent(b);
1016 4           xs_jit_line(aTHX_ b, "}");
1017 4           xs_jit_endloop(aTHX_ b);
1018 4           xs_jit_blank(aTHX_ b);
1019            
1020 4           xs_jit_comment(aTHX_ b, "Bless with same class as original");
1021 4           xs_jit_line(aTHX_ b, "SV* clone = newRV_noinc((SV*)dst);");
1022 4           xs_jit_line(aTHX_ b, "sv_bless(clone, SvSTASH(SvRV(self)));");
1023 4           xs_jit_blank(aTHX_ b);
1024            
1025 4           xs_jit_line(aTHX_ b, "ST(0) = sv_2mortal(clone);");
1026 4           xs_jit_line(aTHX_ b, "XSRETURN(1);");
1027            
1028 4           xs_jit_xs_end(aTHX_ b);
1029 4           }
1030              
1031             /* ============================================
1032             * Unified constructor & weak refs (Phase 3)
1033             * ============================================ */
1034              
1035 2           void xs_jit_hv_store_weak(pTHX_ XS_JIT_Builder* b, const char* hv_name,
1036             const char* key, int key_len, const char* value_expr) {
1037 2           xs_jit_line(aTHX_ b, "{");
1038 2           xs_jit_indent(b);
1039 2           xs_jit_line(aTHX_ b, "SV* weak_val = %s;", value_expr);
1040 2           xs_jit_if(aTHX_ b, "SvROK(weak_val)");
1041 2           xs_jit_line(aTHX_ b, "sv_rvweaken(weak_val);");
1042 2           xs_jit_endif(aTHX_ b);
1043 2           xs_jit_line(aTHX_ b, "hv_store(%s, \"%s\", %d, weak_val, 0);",
1044             hv_name, key, key_len);
1045 2           xs_jit_dedent(b);
1046 2           xs_jit_line(aTHX_ b, "}");
1047 2           }
1048              
1049 4           void xs_jit_rw_accessor_weak(pTHX_ XS_JIT_Builder* b, const char* func_name,
1050             const char* attr_name, STRLEN attr_len) {
1051 4           xs_jit_xs_function(aTHX_ b, func_name);
1052 4           xs_jit_xs_preamble(aTHX_ b);
1053            
1054 4           xs_jit_comment(aTHX_ b, "Get self hash");
1055 4           xs_jit_get_self_hv(aTHX_ b);
1056 4           xs_jit_blank(aTHX_ b);
1057            
1058 4           xs_jit_comment(aTHX_ b, "Setter with weak reference");
1059 4           xs_jit_if(aTHX_ b, "items > 1");
1060 4           xs_jit_line(aTHX_ b, "SV* val = newSVsv(ST(1));");
1061 4           xs_jit_if(aTHX_ b, "SvROK(val)");
1062 4           xs_jit_line(aTHX_ b, "sv_rvweaken(val);");
1063 4           xs_jit_endif(aTHX_ b);
1064 4           xs_jit_line(aTHX_ b, "hv_store(hv, \"%s\", %d, val, 0);",
1065             attr_name, (int)attr_len);
1066 4           xs_jit_endif(aTHX_ b);
1067 4           xs_jit_blank(aTHX_ b);
1068            
1069 4           xs_jit_comment(aTHX_ b, "Getter");
1070 4           xs_jit_line(aTHX_ b, "SV** valp = hv_fetch(hv, \"%s\", %d, 0);",
1071             attr_name, (int)attr_len);
1072 4           xs_jit_if(aTHX_ b, "valp && SvOK(*valp)");
1073 4           xs_jit_line(aTHX_ b, "ST(0) = *valp;");
1074 4           xs_jit_else(aTHX_ b);
1075 4           xs_jit_line(aTHX_ b, "ST(0) = &PL_sv_undef;");
1076 4           xs_jit_endif(aTHX_ b);
1077 4           xs_jit_line(aTHX_ b, "XSRETURN(1);");
1078            
1079 4           xs_jit_xs_end(aTHX_ b);
1080 4           }
1081              
1082 14           void xs_jit_new_complete(pTHX_ XS_JIT_Builder* b, const char* func_name,
1083             XS_JIT_AttrSpec* attrs, int num_attrs,
1084             int call_build) {
1085             int i;
1086            
1087 14           xs_jit_xs_function(aTHX_ b, func_name);
1088 14           xs_jit_xs_preamble(aTHX_ b);
1089            
1090 14           xs_jit_comment(aTHX_ b, "Get class and create object hash");
1091 14           xs_jit_line(aTHX_ b, "SV* class_sv = ST(0);");
1092 14           xs_jit_line(aTHX_ b, "const char* classname;");
1093 14           xs_jit_line(aTHX_ b, "HV* stash;");
1094 14           xs_jit_blank(aTHX_ b);
1095            
1096 14           xs_jit_if(aTHX_ b, "SvROK(class_sv)");
1097 14           xs_jit_line(aTHX_ b, "stash = SvSTASH(SvRV(class_sv));");
1098 14           xs_jit_line(aTHX_ b, "classname = HvNAME(stash);");
1099 14           xs_jit_else(aTHX_ b);
1100 14           xs_jit_line(aTHX_ b, "classname = SvPV_nolen(class_sv);");
1101 14           xs_jit_line(aTHX_ b, "stash = gv_stashsv(class_sv, GV_ADD);");
1102 14           xs_jit_endif(aTHX_ b);
1103 14           xs_jit_blank(aTHX_ b);
1104            
1105 14           xs_jit_line(aTHX_ b, "HV* hv = newHV();");
1106 14           xs_jit_line(aTHX_ b, "HV* args = NULL;");
1107 14           xs_jit_line(aTHX_ b, "STRLEN klen;");
1108 14           xs_jit_line(aTHX_ b, "const char* key;");
1109 14           xs_jit_line(aTHX_ b, "int i;");
1110 14           xs_jit_blank(aTHX_ b);
1111              
1112 14           xs_jit_comment(aTHX_ b, "Parse args - accept hashref or flat list");
1113 14           xs_jit_if(aTHX_ b, "items > 1");
1114 14           xs_jit_if(aTHX_ b, "SvROK(ST(1)) && SvTYPE(SvRV(ST(1))) == SVt_PVHV");
1115 14           xs_jit_comment(aTHX_ b, "Hashref: Class->new(\\%args)");
1116 14           xs_jit_assign(aTHX_ b, "args", "(HV*)SvRV(ST(1))");
1117 14           xs_jit_else(aTHX_ b);
1118 14           xs_jit_comment(aTHX_ b, "Flat list: Class->new(key => val, ...)");
1119 14           xs_jit_if(aTHX_ b, "(items - 1) % 2 != 0");
1120 14           xs_jit_croak(aTHX_ b, "Odd number of arguments to new()");
1121 14           xs_jit_endif(aTHX_ b);
1122 14           xs_jit_assign(aTHX_ b, "args", "newHV()");
1123 14           xs_jit_for(aTHX_ b, "i = 1", "i < items", "i += 2");
1124 14           xs_jit_assign(aTHX_ b, "key", "SvPV(ST(i), klen)");
1125 14           xs_jit_line(aTHX_ b, "hv_store(args, key, klen, newSVsv(ST(i + 1)), 0);");
1126 14           xs_jit_endloop(aTHX_ b);
1127 14           xs_jit_endif(aTHX_ b);
1128 14           xs_jit_endif(aTHX_ b);
1129 14           xs_jit_blank(aTHX_ b);
1130            
1131             /* Process each attribute */
1132 31 100         for (i = 0; i < num_attrs; i++) {
1133 17           XS_JIT_AttrSpec* attr = &attrs[i];
1134            
1135 17           xs_jit_line(aTHX_ b, "/* Process attribute '%s' */", attr->name);
1136 17           xs_jit_line(aTHX_ b, "{");
1137 17           xs_jit_indent(b);
1138            
1139 17           xs_jit_line(aTHX_ b, "SV** valp = args ? hv_fetch(args, \"%s\", %d, 0) : NULL;",
1140 17           attr->name, (int)attr->len);
1141 17           xs_jit_line(aTHX_ b, "SV* val = (valp && SvOK(*valp)) ? *valp : NULL;");
1142 17           xs_jit_blank(aTHX_ b);
1143            
1144             /* Coercion: call method to transform value */
1145 17 100         if (attr->coerce && attr->coerce_len > 0) {
    50          
1146 1           xs_jit_if(aTHX_ b, "val");
1147 1           xs_jit_line(aTHX_ b, "{");
1148 1           xs_jit_indent(b);
1149 1           xs_jit_line(aTHX_ b, "dSP;");
1150 1           xs_jit_line(aTHX_ b, "ENTER;");
1151 1           xs_jit_line(aTHX_ b, "SAVETMPS;");
1152 1           xs_jit_line(aTHX_ b, "PUSHMARK(SP);");
1153 1           xs_jit_line(aTHX_ b, "XPUSHs(class_sv);");
1154 1           xs_jit_line(aTHX_ b, "XPUSHs(val);");
1155 1           xs_jit_line(aTHX_ b, "PUTBACK;");
1156 1           xs_jit_line(aTHX_ b, "int count = call_method(\"%s\", G_SCALAR);", attr->coerce);
1157 1           xs_jit_line(aTHX_ b, "SPAGAIN;");
1158 1           xs_jit_if(aTHX_ b, "count > 0");
1159 1           xs_jit_line(aTHX_ b, "val = newSVsv(POPs);");
1160 1           xs_jit_endif(aTHX_ b);
1161 1           xs_jit_line(aTHX_ b, "PUTBACK;");
1162 1           xs_jit_line(aTHX_ b, "FREETMPS;");
1163 1           xs_jit_line(aTHX_ b, "LEAVE;");
1164 1           xs_jit_dedent(b);
1165 1           xs_jit_line(aTHX_ b, "}");
1166 1           xs_jit_endif(aTHX_ b);
1167             }
1168            
1169             /* Required check */
1170 17 100         if (attr->required) {
1171 3           xs_jit_if(aTHX_ b, "!val");
1172 3           xs_jit_line(aTHX_ b, "SvREFCNT_dec((SV*)hv);");
1173 3           xs_jit_line(aTHX_ b, "croak(\"Missing required attribute '%s'\");", attr->name);
1174 3           xs_jit_endif(aTHX_ b);
1175             }
1176            
1177             /* Type validation */
1178 17 100         if (attr->type > 0 && attr->type_msg) {
    50          
1179 3           xs_jit_if(aTHX_ b, "val");
1180            
1181 3           switch (attr->type) {
1182 0           case 1: /* TYPE_DEFINED */
1183             /* Already checked via val != NULL */
1184 0           break;
1185 3           case 2: /* TYPE_INT */
1186 3           xs_jit_if(aTHX_ b, "!SvIOK(val) && !(SvNOK(val) && SvNV(val) == (NV)(IV)SvNV(val))");
1187 3           xs_jit_line(aTHX_ b, "SvREFCNT_dec((SV*)hv);");
1188 3           xs_jit_croak(aTHX_ b, attr->type_msg);
1189 3           xs_jit_endif(aTHX_ b);
1190 3           break;
1191 0           case 3: /* TYPE_NUM */
1192 0           xs_jit_if(aTHX_ b, "!SvNOK(val) && !SvIOK(val) && !looks_like_number(val)");
1193 0           xs_jit_line(aTHX_ b, "SvREFCNT_dec((SV*)hv);");
1194 0           xs_jit_croak(aTHX_ b, attr->type_msg);
1195 0           xs_jit_endif(aTHX_ b);
1196 0           break;
1197 0           case 4: /* TYPE_STR */
1198 0           xs_jit_if(aTHX_ b, "SvROK(val)");
1199 0           xs_jit_line(aTHX_ b, "SvREFCNT_dec((SV*)hv);");
1200 0           xs_jit_croak(aTHX_ b, attr->type_msg);
1201 0           xs_jit_endif(aTHX_ b);
1202 0           break;
1203 0           case 5: /* TYPE_REF */
1204 0           xs_jit_if(aTHX_ b, "!SvROK(val)");
1205 0           xs_jit_line(aTHX_ b, "SvREFCNT_dec((SV*)hv);");
1206 0           xs_jit_croak(aTHX_ b, attr->type_msg);
1207 0           xs_jit_endif(aTHX_ b);
1208 0           break;
1209 0           case 6: /* TYPE_ARRAYREF */
1210 0           xs_jit_if(aTHX_ b, "!(SvROK(val) && SvTYPE(SvRV(val)) == SVt_PVAV)");
1211 0           xs_jit_line(aTHX_ b, "SvREFCNT_dec((SV*)hv);");
1212 0           xs_jit_croak(aTHX_ b, attr->type_msg);
1213 0           xs_jit_endif(aTHX_ b);
1214 0           break;
1215 0           case 7: /* TYPE_HASHREF */
1216 0           xs_jit_if(aTHX_ b, "!(SvROK(val) && SvTYPE(SvRV(val)) == SVt_PVHV)");
1217 0           xs_jit_line(aTHX_ b, "SvREFCNT_dec((SV*)hv);");
1218 0           xs_jit_croak(aTHX_ b, attr->type_msg);
1219 0           xs_jit_endif(aTHX_ b);
1220 0           break;
1221 0           case 8: /* TYPE_CODEREF */
1222 0           xs_jit_if(aTHX_ b, "!(SvROK(val) && SvTYPE(SvRV(val)) == SVt_PVCV)");
1223 0           xs_jit_line(aTHX_ b, "SvREFCNT_dec((SV*)hv);");
1224 0           xs_jit_croak(aTHX_ b, attr->type_msg);
1225 0           xs_jit_endif(aTHX_ b);
1226 0           break;
1227 0           case 9: /* TYPE_OBJECT */
1228 0           xs_jit_if(aTHX_ b, "!sv_isobject(val)");
1229 0           xs_jit_line(aTHX_ b, "SvREFCNT_dec((SV*)hv);");
1230 0           xs_jit_croak(aTHX_ b, attr->type_msg);
1231 0           xs_jit_endif(aTHX_ b);
1232 0           break;
1233             }
1234            
1235 3           xs_jit_endif(aTHX_ b);
1236             }
1237            
1238             /* Store value or apply default */
1239 17           xs_jit_if(aTHX_ b, "val");
1240            
1241 17 100         if (attr->weak) {
1242 1           xs_jit_line(aTHX_ b, "SV* store_val = newSVsv(val);");
1243 1           xs_jit_if(aTHX_ b, "SvROK(store_val)");
1244 1           xs_jit_line(aTHX_ b, "sv_rvweaken(store_val);");
1245 1           xs_jit_endif(aTHX_ b);
1246 1           xs_jit_line(aTHX_ b, "hv_store(hv, \"%s\", %d, store_val, 0);",
1247 1           attr->name, (int)attr->len);
1248             } else {
1249 16           xs_jit_line(aTHX_ b, "hv_store(hv, \"%s\", %d, newSVsv(val), 0);",
1250 16           attr->name, (int)attr->len);
1251             }
1252            
1253 17           xs_jit_else(aTHX_ b);
1254            
1255             /* Apply default if no value */
1256 17           switch (attr->has_default) {
1257 3           case 1: /* IV */
1258 3           xs_jit_line(aTHX_ b, "hv_store(hv, \"%s\", %d, newSViv(%" IVdf "), 0);",
1259 3           attr->name, (int)attr->len, attr->default_iv);
1260 3           break;
1261 0           case 2: /* NV */
1262 0           xs_jit_line(aTHX_ b, "hv_store(hv, \"%s\", %d, newSVnv(%g), 0);",
1263 0           attr->name, (int)attr->len, attr->default_nv);
1264 0           break;
1265 2           case 3: /* PV */
1266 2           xs_jit_line(aTHX_ b, "hv_store(hv, \"%s\", %d, newSVpvn(\"%s\", %d), 0);",
1267 2           attr->name, (int)attr->len,
1268 2           attr->default_pv, (int)attr->default_pv_len);
1269 2           break;
1270 2           case 4: /* AV (empty arrayref) */
1271 2           xs_jit_line(aTHX_ b, "hv_store(hv, \"%s\", %d, newRV_noinc((SV*)newAV()), 0);",
1272 2           attr->name, (int)attr->len);
1273 2           break;
1274 1           case 5: /* HV (empty hashref) */
1275 1           xs_jit_line(aTHX_ b, "hv_store(hv, \"%s\", %d, newRV_noinc((SV*)newHV()), 0);",
1276 1           attr->name, (int)attr->len);
1277 1           break;
1278 9           default:
1279             /* No default, leave undefined */
1280 9           break;
1281             }
1282            
1283 17           xs_jit_endif(aTHX_ b);
1284            
1285 17           xs_jit_dedent(b);
1286 17           xs_jit_line(aTHX_ b, "}");
1287 17           xs_jit_blank(aTHX_ b);
1288             }
1289            
1290 14           xs_jit_comment(aTHX_ b, "Bless and return");
1291 14           xs_jit_line(aTHX_ b, "SV* self = newRV_noinc((SV*)hv);");
1292 14           xs_jit_line(aTHX_ b, "sv_bless(self, stash);");
1293 14           xs_jit_blank(aTHX_ b);
1294            
1295             /* Call BUILD if requested */
1296 14 100         if (call_build) {
1297 1           xs_jit_comment(aTHX_ b, "Call BUILD if it exists");
1298 1           xs_jit_line(aTHX_ b, "GV* build_gv = gv_fetchmethod_autoload(stash, \"BUILD\", 0);");
1299 1           xs_jit_if(aTHX_ b, "build_gv");
1300 1           xs_jit_line(aTHX_ b, "dSP;");
1301 1           xs_jit_line(aTHX_ b, "ENTER;");
1302 1           xs_jit_line(aTHX_ b, "SAVETMPS;");
1303 1           xs_jit_line(aTHX_ b, "PUSHMARK(SP);");
1304 1           xs_jit_line(aTHX_ b, "XPUSHs(self);");
1305 1           xs_jit_if(aTHX_ b, "args");
1306 1           xs_jit_line(aTHX_ b, "XPUSHs(sv_2mortal(newRV_inc((SV*)args)));");
1307 1           xs_jit_endif(aTHX_ b);
1308 1           xs_jit_line(aTHX_ b, "PUTBACK;");
1309 1           xs_jit_line(aTHX_ b, "call_method(\"BUILD\", G_DISCARD);");
1310 1           xs_jit_line(aTHX_ b, "FREETMPS;");
1311 1           xs_jit_line(aTHX_ b, "LEAVE;");
1312 1           xs_jit_endif(aTHX_ b);
1313 1           xs_jit_blank(aTHX_ b);
1314             }
1315            
1316 14           xs_jit_line(aTHX_ b, "ST(0) = sv_2mortal(self);");
1317 14           xs_jit_line(aTHX_ b, "XSRETURN(1);");
1318            
1319 14           xs_jit_xs_end(aTHX_ b);
1320 14           }
1321              
1322             /* ============================================
1323             * Callbacks & Triggers (Phase 4)
1324             * ============================================ */
1325              
1326 1           void xs_jit_call_sv(pTHX_ XS_JIT_Builder* b, const char* cv_expr,
1327             const char** args, int num_args) {
1328             int i;
1329            
1330 1           xs_jit_line(aTHX_ b, "{");
1331 1           xs_jit_indent(b);
1332 1           xs_jit_line(aTHX_ b, "dSP;");
1333 1           xs_jit_line(aTHX_ b, "ENTER;");
1334 1           xs_jit_line(aTHX_ b, "SAVETMPS;");
1335 1           xs_jit_line(aTHX_ b, "PUSHMARK(SP);");
1336            
1337 3 100         for (i = 0; i < num_args; i++) {
1338 2           xs_jit_line(aTHX_ b, "XPUSHs(%s);", args[i]);
1339             }
1340            
1341 1           xs_jit_line(aTHX_ b, "PUTBACK;");
1342 1           xs_jit_line(aTHX_ b, "call_sv(%s, G_DISCARD);", cv_expr);
1343 1           xs_jit_line(aTHX_ b, "FREETMPS;");
1344 1           xs_jit_line(aTHX_ b, "LEAVE;");
1345 1           xs_jit_dedent(b);
1346 1           xs_jit_line(aTHX_ b, "}");
1347 1           }
1348              
1349 1           void xs_jit_call_method(pTHX_ XS_JIT_Builder* b, const char* method_name,
1350             const char* invocant, const char** args, int num_args) {
1351             int i;
1352            
1353 1           xs_jit_line(aTHX_ b, "{");
1354 1           xs_jit_indent(b);
1355 1           xs_jit_line(aTHX_ b, "dSP;");
1356 1           xs_jit_line(aTHX_ b, "ENTER;");
1357 1           xs_jit_line(aTHX_ b, "SAVETMPS;");
1358 1           xs_jit_line(aTHX_ b, "PUSHMARK(SP);");
1359 1           xs_jit_line(aTHX_ b, "XPUSHs(%s);", invocant);
1360            
1361 3 100         for (i = 0; i < num_args; i++) {
1362 2           xs_jit_line(aTHX_ b, "XPUSHs(%s);", args[i]);
1363             }
1364            
1365 1           xs_jit_line(aTHX_ b, "PUTBACK;");
1366 1           xs_jit_line(aTHX_ b, "call_method(\"%s\", G_DISCARD);", method_name);
1367 1           xs_jit_line(aTHX_ b, "FREETMPS;");
1368 1           xs_jit_line(aTHX_ b, "LEAVE;");
1369 1           xs_jit_dedent(b);
1370 1           xs_jit_line(aTHX_ b, "}");
1371 1           }
1372              
1373 2           void xs_jit_rw_accessor_trigger(pTHX_ XS_JIT_Builder* b, const char* func_name,
1374             const char* attr_name, STRLEN attr_len,
1375             const char* trigger_method) {
1376 2           xs_jit_xs_function(aTHX_ b, func_name);
1377 2           xs_jit_xs_preamble(aTHX_ b);
1378            
1379 2           xs_jit_comment(aTHX_ b, "Get self hash");
1380 2           xs_jit_get_self_hv(aTHX_ b);
1381 2           xs_jit_blank(aTHX_ b);
1382            
1383 2           xs_jit_comment(aTHX_ b, "Setter with trigger");
1384 2           xs_jit_if(aTHX_ b, "items > 1");
1385 2           xs_jit_line(aTHX_ b, "SV* new_val = newSVsv(ST(1));");
1386 2           xs_jit_line(aTHX_ b, "hv_store(hv, \"%s\", %d, new_val, 0);",
1387             attr_name, (int)attr_len);
1388 2           xs_jit_blank(aTHX_ b);
1389            
1390 2           xs_jit_comment(aTHX_ b, "Call trigger method");
1391 2           xs_jit_line(aTHX_ b, "{");
1392 2           xs_jit_indent(b);
1393 2           xs_jit_line(aTHX_ b, "dSP;");
1394 2           xs_jit_line(aTHX_ b, "ENTER;");
1395 2           xs_jit_line(aTHX_ b, "SAVETMPS;");
1396 2           xs_jit_line(aTHX_ b, "PUSHMARK(SP);");
1397 2           xs_jit_line(aTHX_ b, "XPUSHs(self);");
1398 2           xs_jit_line(aTHX_ b, "XPUSHs(new_val);");
1399 2           xs_jit_line(aTHX_ b, "PUTBACK;");
1400 2           xs_jit_line(aTHX_ b, "call_method(\"%s\", G_DISCARD);", trigger_method);
1401 2           xs_jit_line(aTHX_ b, "FREETMPS;");
1402 2           xs_jit_line(aTHX_ b, "LEAVE;");
1403 2           xs_jit_dedent(b);
1404 2           xs_jit_line(aTHX_ b, "}");
1405            
1406 2           xs_jit_endif(aTHX_ b);
1407 2           xs_jit_blank(aTHX_ b);
1408            
1409 2           xs_jit_comment(aTHX_ b, "Getter");
1410 2           xs_jit_line(aTHX_ b, "SV** valp = hv_fetch(hv, \"%s\", %d, 0);",
1411             attr_name, (int)attr_len);
1412 2           xs_jit_if(aTHX_ b, "valp && SvOK(*valp)");
1413 2           xs_jit_line(aTHX_ b, "ST(0) = *valp;");
1414 2           xs_jit_else(aTHX_ b);
1415 2           xs_jit_line(aTHX_ b, "ST(0) = &PL_sv_undef;");
1416 2           xs_jit_endif(aTHX_ b);
1417 2           xs_jit_line(aTHX_ b, "XSRETURN(1);");
1418            
1419 2           xs_jit_xs_end(aTHX_ b);
1420 2           }
1421              
1422 1           void xs_jit_accessor_lazy_builder(pTHX_ XS_JIT_Builder* b, const char* func_name,
1423             const char* attr_name, STRLEN attr_len,
1424             const char* builder_method) {
1425 1           xs_jit_xs_function(aTHX_ b, func_name);
1426 1           xs_jit_xs_preamble(aTHX_ b);
1427            
1428 1           xs_jit_comment(aTHX_ b, "Get self hash");
1429 1           xs_jit_get_self_hv(aTHX_ b);
1430 1           xs_jit_blank(aTHX_ b);
1431            
1432 1           xs_jit_comment(aTHX_ b, "Setter - just store value");
1433 1           xs_jit_if(aTHX_ b, "items > 1");
1434 1           xs_jit_line(aTHX_ b, "hv_store(hv, \"%s\", %d, newSVsv(ST(1)), 0);",
1435             attr_name, (int)attr_len);
1436 1           xs_jit_endif(aTHX_ b);
1437 1           xs_jit_blank(aTHX_ b);
1438            
1439 1           xs_jit_comment(aTHX_ b, "Getter with lazy builder");
1440 1           xs_jit_line(aTHX_ b, "SV** valp = hv_fetch(hv, \"%s\", %d, 0);",
1441             attr_name, (int)attr_len);
1442            
1443 1           xs_jit_if(aTHX_ b, "!valp || !SvOK(*valp)");
1444 1           xs_jit_comment(aTHX_ b, "Call builder method and cache result");
1445 1           xs_jit_line(aTHX_ b, "{");
1446 1           xs_jit_indent(b);
1447 1           xs_jit_line(aTHX_ b, "dSP;");
1448 1           xs_jit_line(aTHX_ b, "int count;");
1449 1           xs_jit_line(aTHX_ b, "ENTER;");
1450 1           xs_jit_line(aTHX_ b, "SAVETMPS;");
1451 1           xs_jit_line(aTHX_ b, "PUSHMARK(SP);");
1452 1           xs_jit_line(aTHX_ b, "XPUSHs(self);");
1453 1           xs_jit_line(aTHX_ b, "PUTBACK;");
1454 1           xs_jit_line(aTHX_ b, "count = call_method(\"%s\", G_SCALAR);", builder_method);
1455 1           xs_jit_line(aTHX_ b, "SPAGAIN;");
1456 1           xs_jit_if(aTHX_ b, "count > 0");
1457 1           xs_jit_line(aTHX_ b, "SV* built = POPs;");
1458 1           xs_jit_line(aTHX_ b, "SV* stored = newSVsv(built);");
1459 1           xs_jit_line(aTHX_ b, "hv_store(hv, \"%s\", %d, stored, 0);",
1460             attr_name, (int)attr_len);
1461 1           xs_jit_line(aTHX_ b, "PUTBACK;");
1462 1           xs_jit_line(aTHX_ b, "FREETMPS;");
1463 1           xs_jit_line(aTHX_ b, "LEAVE;");
1464 1           xs_jit_line(aTHX_ b, "ST(0) = stored;");
1465 1           xs_jit_line(aTHX_ b, "XSRETURN(1);");
1466 1           xs_jit_else(aTHX_ b);
1467 1           xs_jit_line(aTHX_ b, "PUTBACK;");
1468 1           xs_jit_line(aTHX_ b, "FREETMPS;");
1469 1           xs_jit_line(aTHX_ b, "LEAVE;");
1470 1           xs_jit_line(aTHX_ b, "ST(0) = &PL_sv_undef;");
1471 1           xs_jit_line(aTHX_ b, "XSRETURN(1);");
1472 1           xs_jit_endif(aTHX_ b);
1473 1           xs_jit_dedent(b);
1474 1           xs_jit_line(aTHX_ b, "}");
1475 1           xs_jit_endif(aTHX_ b);
1476 1           xs_jit_blank(aTHX_ b);
1477            
1478 1           xs_jit_comment(aTHX_ b, "Return cached value");
1479 1           xs_jit_line(aTHX_ b, "ST(0) = *valp;");
1480 1           xs_jit_line(aTHX_ b, "XSRETURN(1);");
1481            
1482 1           xs_jit_xs_end(aTHX_ b);
1483 1           }
1484              
1485 1           void xs_jit_destroy_with_demolish(pTHX_ XS_JIT_Builder* b, const char* func_name) {
1486 1           xs_jit_xs_function(aTHX_ b, func_name);
1487 1           xs_jit_xs_preamble(aTHX_ b);
1488            
1489 1           xs_jit_comment(aTHX_ b, "Get self");
1490 1           xs_jit_line(aTHX_ b, "SV* self = ST(0);");
1491 1           xs_jit_if(aTHX_ b, "!SvROK(self)");
1492 1           xs_jit_line(aTHX_ b, "XSRETURN_EMPTY;");
1493 1           xs_jit_endif(aTHX_ b);
1494 1           xs_jit_blank(aTHX_ b);
1495            
1496 1           xs_jit_comment(aTHX_ b, "Check if DEMOLISH exists");
1497 1           xs_jit_line(aTHX_ b, "HV* stash = SvSTASH(SvRV(self));");
1498 1           xs_jit_line(aTHX_ b, "GV* demolish_gv = gv_fetchmethod_autoload(stash, \"DEMOLISH\", 0);");
1499 1           xs_jit_blank(aTHX_ b);
1500            
1501 1           xs_jit_if(aTHX_ b, "demolish_gv");
1502 1           xs_jit_comment(aTHX_ b, "Call DEMOLISH");
1503 1           xs_jit_line(aTHX_ b, "{");
1504 1           xs_jit_indent(b);
1505 1           xs_jit_line(aTHX_ b, "dSP;");
1506 1           xs_jit_line(aTHX_ b, "ENTER;");
1507 1           xs_jit_line(aTHX_ b, "SAVETMPS;");
1508 1           xs_jit_line(aTHX_ b, "PUSHMARK(SP);");
1509 1           xs_jit_line(aTHX_ b, "XPUSHs(self);");
1510 1           xs_jit_line(aTHX_ b, "XPUSHs(boolSV(PL_dirty));"); /* in_global_destruction */
1511 1           xs_jit_line(aTHX_ b, "PUTBACK;");
1512 1           xs_jit_line(aTHX_ b, "call_method(\"DEMOLISH\", G_DISCARD);");
1513 1           xs_jit_line(aTHX_ b, "FREETMPS;");
1514 1           xs_jit_line(aTHX_ b, "LEAVE;");
1515 1           xs_jit_dedent(b);
1516 1           xs_jit_line(aTHX_ b, "}");
1517 1           xs_jit_endif(aTHX_ b);
1518 1           xs_jit_blank(aTHX_ b);
1519            
1520 1           xs_jit_line(aTHX_ b, "XSRETURN_EMPTY;");
1521            
1522 1           xs_jit_xs_end(aTHX_ b);
1523 1           }
1524              
1525             /* ============================================
1526             * Control Flow & Extended Patterns (Phase 5)
1527             * ============================================ */
1528              
1529 1           void xs_jit_do(pTHX_ XS_JIT_Builder* b) {
1530 1           xs_jit_line(aTHX_ b, "do {");
1531 1           xs_jit_indent(b);
1532 1           }
1533              
1534 1           void xs_jit_end_do_while(pTHX_ XS_JIT_Builder* b, const char* condition) {
1535 1           xs_jit_dedent(b);
1536 1           xs_jit_line(aTHX_ b, "} while (%s);", condition);
1537 1           }
1538              
1539 1           void xs_jit_if_list_context(pTHX_ XS_JIT_Builder* b) {
1540 1           xs_jit_if(aTHX_ b, "GIMME_V == G_LIST");
1541 1           }
1542              
1543 1           void xs_jit_if_scalar_context(pTHX_ XS_JIT_Builder* b) {
1544 1           xs_jit_if(aTHX_ b, "GIMME_V == G_SCALAR");
1545 1           }
1546              
1547 1           void xs_jit_extend_stack(pTHX_ XS_JIT_Builder* b, const char* count_expr) {
1548 1           xs_jit_line(aTHX_ b, "EXTEND(SP, %s);", count_expr);
1549 1           }
1550              
1551 1           void xs_jit_return_list(pTHX_ XS_JIT_Builder* b, const char** values, int num_values) {
1552             int i;
1553            
1554 1 50         if (num_values > 0) {
1555 1           xs_jit_line(aTHX_ b, "EXTEND(SP, %d);", num_values);
1556 4 100         for (i = 0; i < num_values; i++) {
1557 3           xs_jit_line(aTHX_ b, "ST(%d) = sv_2mortal(%s);", i, values[i]);
1558             }
1559             }
1560 1           xs_jit_line(aTHX_ b, "XSRETURN(%d);", num_values);
1561 1           }
1562              
1563 1           void xs_jit_declare_ternary(pTHX_ XS_JIT_Builder* b, const char* type,
1564             const char* name, const char* cond,
1565             const char* true_expr, const char* false_expr) {
1566 1           xs_jit_line(aTHX_ b, "%s %s = (%s) ? %s : %s;",
1567             type, name, cond, true_expr, false_expr);
1568 1           }
1569              
1570 1           void xs_jit_assign_ternary(pTHX_ XS_JIT_Builder* b, const char* var,
1571             const char* cond, const char* true_expr,
1572             const char* false_expr) {
1573 1           xs_jit_line(aTHX_ b, "%s = (%s) ? %s : %s;",
1574             var, cond, true_expr, false_expr);
1575 1           }
1576              
1577 3           void xs_jit_delegate_method(pTHX_ XS_JIT_Builder* b, const char* func_name,
1578             const char* attr_name, STRLEN attr_len,
1579             const char* target_method) {
1580 3           xs_jit_xs_function(aTHX_ b, func_name);
1581 3           xs_jit_xs_preamble(aTHX_ b);
1582            
1583 3           xs_jit_comment(aTHX_ b, "Get self hash and fetch delegate");
1584 3           xs_jit_get_self_hv(aTHX_ b);
1585 3           xs_jit_line(aTHX_ b, "SV** delegate_p = hv_fetch(hv, \"%s\", %d, 0);",
1586             attr_name, (int)attr_len);
1587 3           xs_jit_blank(aTHX_ b);
1588            
1589 3           xs_jit_if(aTHX_ b, "!delegate_p || !SvOK(*delegate_p) || !SvROK(*delegate_p)");
1590 3           xs_jit_line(aTHX_ b, "croak(\"Cannot delegate: '%s' is not set or not a reference\");",
1591             attr_name);
1592 3           xs_jit_endif(aTHX_ b);
1593 3           xs_jit_blank(aTHX_ b);
1594            
1595 3           xs_jit_comment(aTHX_ b, "Call method on delegate, passing remaining args");
1596 3           xs_jit_line(aTHX_ b, "{");
1597 3           xs_jit_indent(b);
1598 3           xs_jit_line(aTHX_ b, "dSP;");
1599 3           xs_jit_line(aTHX_ b, "int i, count;");
1600 3           xs_jit_line(aTHX_ b, "SV* result = NULL;");
1601 3           xs_jit_line(aTHX_ b, "ENTER;");
1602 3           xs_jit_line(aTHX_ b, "SAVETMPS;");
1603 3           xs_jit_line(aTHX_ b, "PUSHMARK(SP);");
1604 3           xs_jit_line(aTHX_ b, "XPUSHs(*delegate_p);");
1605            
1606 3           xs_jit_comment(aTHX_ b, "Pass through any additional arguments");
1607 3           xs_jit_for(aTHX_ b, "i = 1", "i < items", "i++");
1608 3           xs_jit_line(aTHX_ b, "XPUSHs(ST(i));");
1609 3           xs_jit_endloop(aTHX_ b);
1610            
1611 3           xs_jit_line(aTHX_ b, "PUTBACK;");
1612 3           xs_jit_line(aTHX_ b, "count = call_method(\"%s\", G_SCALAR);", target_method);
1613 3           xs_jit_line(aTHX_ b, "SPAGAIN;");
1614 3           xs_jit_blank(aTHX_ b);
1615            
1616 3           xs_jit_comment(aTHX_ b, "Capture result before cleanup");
1617 3           xs_jit_if(aTHX_ b, "count > 0");
1618 3           xs_jit_line(aTHX_ b, "result = newSVsv(POPs);");
1619 3           xs_jit_endif(aTHX_ b);
1620            
1621 3           xs_jit_line(aTHX_ b, "PUTBACK;");
1622 3           xs_jit_line(aTHX_ b, "FREETMPS;");
1623 3           xs_jit_line(aTHX_ b, "LEAVE;");
1624 3           xs_jit_blank(aTHX_ b);
1625            
1626 3           xs_jit_if(aTHX_ b, "result");
1627 3           xs_jit_line(aTHX_ b, "ST(0) = sv_2mortal(result);");
1628 3           xs_jit_line(aTHX_ b, "XSRETURN(1);");
1629 3           xs_jit_else(aTHX_ b);
1630 3           xs_jit_line(aTHX_ b, "XSRETURN_EMPTY;");
1631 3           xs_jit_endif(aTHX_ b);
1632 3           xs_jit_dedent(b);
1633 3           xs_jit_line(aTHX_ b, "}");
1634            
1635 3           xs_jit_xs_end(aTHX_ b);
1636 3           }
1637              
1638             /* ============================================
1639             * Singleton Pattern (Phase 6)
1640             * ============================================ */
1641              
1642 4           void xs_jit_singleton_accessor(pTHX_ XS_JIT_Builder* b, const char* func_name,
1643             const char* class_name) {
1644 4           xs_jit_xs_function(aTHX_ b, func_name);
1645 4           xs_jit_xs_preamble(aTHX_ b);
1646            
1647 4           xs_jit_comment(aTHX_ b, "Get or create the singleton instance");
1648 4           xs_jit_line(aTHX_ b, "HV* stash = gv_stashpv(\"%s\", GV_ADD);", class_name);
1649 4           xs_jit_line(aTHX_ b, "GV* gv = gv_fetchpv(\"%s::_instance\", GV_ADD, SVt_PV);", class_name);
1650 4           xs_jit_line(aTHX_ b, "SV* instance = GvSV(gv);");
1651 4           xs_jit_blank(aTHX_ b);
1652            
1653 4           xs_jit_if(aTHX_ b, "!instance || !SvOK(instance) || !SvROK(instance)");
1654 4           xs_jit_comment(aTHX_ b, "Create new instance");
1655 4           xs_jit_line(aTHX_ b, "HV* hv = newHV();");
1656 4           xs_jit_line(aTHX_ b, "SV* self = newRV_noinc((SV*)hv);");
1657 4           xs_jit_line(aTHX_ b, "sv_bless(self, stash);");
1658 4           xs_jit_line(aTHX_ b, "SvSetSV(GvSVn(gv), self);");
1659 4           xs_jit_line(aTHX_ b, "SvREFCNT_dec(self);"); /* gv now owns it */
1660 4           xs_jit_line(aTHX_ b, "instance = GvSV(gv);");
1661 4           xs_jit_endif(aTHX_ b);
1662 4           xs_jit_blank(aTHX_ b);
1663            
1664 4           xs_jit_line(aTHX_ b, "ST(0) = instance;");
1665 4           xs_jit_line(aTHX_ b, "XSRETURN(1);");
1666            
1667 4           xs_jit_xs_end(aTHX_ b);
1668 4           }
1669              
1670 2           void xs_jit_singleton_reset(pTHX_ XS_JIT_Builder* b, const char* func_name,
1671             const char* class_name) {
1672 2           xs_jit_xs_function(aTHX_ b, func_name);
1673 2           xs_jit_xs_preamble(aTHX_ b);
1674            
1675 2           xs_jit_comment(aTHX_ b, "Clear the singleton instance");
1676 2           xs_jit_line(aTHX_ b, "GV* gv = gv_fetchpv(\"%s::_instance\", GV_ADD, SVt_PV);", class_name);
1677 2           xs_jit_line(aTHX_ b, "sv_setsv(GvSVn(gv), &PL_sv_undef);");
1678 2           xs_jit_line(aTHX_ b, "XSRETURN_EMPTY;");
1679            
1680 2           xs_jit_xs_end(aTHX_ b);
1681 2           }
1682              
1683             /* ============================================
1684             * Registry Pattern (Phase 7)
1685             * ============================================ */
1686              
1687 13           void xs_jit_registry_add(pTHX_ XS_JIT_Builder* b, const char* func_name,
1688             const char* registry_attr, STRLEN registry_len) {
1689             PERL_UNUSED_VAR(registry_len);
1690 13           xs_jit_xs_function(aTHX_ b, func_name);
1691 13           xs_jit_xs_preamble(aTHX_ b);
1692            
1693 13           xs_jit_comment(aTHX_ b, "Add an item to the registry hash");
1694 13           xs_jit_line(aTHX_ b, "if (items < 3) croak(\"Usage: $self->%s($key, $value)\");", func_name);
1695 13           xs_jit_line(aTHX_ b, "SV* self = ST(0);");
1696 13           xs_jit_line(aTHX_ b, "SV* key = ST(1);");
1697 13           xs_jit_line(aTHX_ b, "SV* value = ST(2);");
1698 13           xs_jit_line(aTHX_ b, "HV* obj = (HV*)SvRV(self);");
1699            
1700 13           xs_jit_comment(aTHX_ b, "Get or create the registry hash");
1701 13           xs_jit_line(aTHX_ b, "SV** registry_ptr = hv_fetch(obj, \"%s\", %d, 0);", registry_attr, (int)strlen(registry_attr));
1702 13           xs_jit_line(aTHX_ b, "HV* registry;");
1703 13           xs_jit_if(aTHX_ b, "registry_ptr && SvROK(*registry_ptr) && SvTYPE(SvRV(*registry_ptr)) == SVt_PVHV");
1704 13           xs_jit_line(aTHX_ b, "registry = (HV*)SvRV(*registry_ptr);");
1705 13           xs_jit_else(aTHX_ b);
1706 13           xs_jit_comment(aTHX_ b, "Create new registry hash");
1707 13           xs_jit_line(aTHX_ b, "registry = newHV();");
1708 13           xs_jit_line(aTHX_ b, "hv_store(obj, \"%s\", %d, newRV_noinc((SV*)registry), 0);", registry_attr, (int)strlen(registry_attr));
1709 13           xs_jit_endif(aTHX_ b);
1710            
1711 13           xs_jit_comment(aTHX_ b, "Store the value in registry");
1712 13           xs_jit_line(aTHX_ b, "STRLEN klen;");
1713 13           xs_jit_line(aTHX_ b, "const char* kstr = SvPV(key, klen);");
1714 13           xs_jit_line(aTHX_ b, "hv_store(registry, kstr, klen, newSVsv(value), 0);");
1715            
1716 13           xs_jit_line(aTHX_ b, "ST(0) = self;");
1717 13           xs_jit_line(aTHX_ b, "XSRETURN(1);");
1718            
1719 13           xs_jit_xs_end(aTHX_ b);
1720 13           }
1721              
1722 11           void xs_jit_registry_get(pTHX_ XS_JIT_Builder* b, const char* func_name,
1723             const char* registry_attr, STRLEN registry_len) {
1724             PERL_UNUSED_VAR(registry_len);
1725 11           xs_jit_xs_function(aTHX_ b, func_name);
1726 11           xs_jit_xs_preamble(aTHX_ b);
1727            
1728 11           xs_jit_comment(aTHX_ b, "Get an item from the registry hash");
1729 11           xs_jit_line(aTHX_ b, "if (items < 2) croak(\"Usage: $self->%s($key)\");", func_name);
1730 11           xs_jit_line(aTHX_ b, "SV* self = ST(0);");
1731 11           xs_jit_line(aTHX_ b, "SV* key = ST(1);");
1732 11           xs_jit_line(aTHX_ b, "HV* obj = (HV*)SvRV(self);");
1733            
1734 11           xs_jit_comment(aTHX_ b, "Get the registry hash");
1735 11           xs_jit_line(aTHX_ b, "SV** registry_ptr = hv_fetch(obj, \"%s\", %d, 0);", registry_attr, (int)strlen(registry_attr));
1736 11           xs_jit_if(aTHX_ b, "!registry_ptr || !SvROK(*registry_ptr)");
1737 11           xs_jit_line(aTHX_ b, "XSRETURN_UNDEF;");
1738 11           xs_jit_endif(aTHX_ b);
1739            
1740 11           xs_jit_line(aTHX_ b, "HV* registry = (HV*)SvRV(*registry_ptr);");
1741 11           xs_jit_line(aTHX_ b, "STRLEN klen;");
1742 11           xs_jit_line(aTHX_ b, "const char* kstr = SvPV(key, klen);");
1743 11           xs_jit_line(aTHX_ b, "SV** val_ptr = hv_fetch(registry, kstr, klen, 0);");
1744            
1745 11           xs_jit_if(aTHX_ b, "val_ptr && *val_ptr");
1746 11           xs_jit_line(aTHX_ b, "ST(0) = *val_ptr;");
1747 11           xs_jit_line(aTHX_ b, "XSRETURN(1);");
1748 11           xs_jit_endif(aTHX_ b);
1749            
1750 11           xs_jit_line(aTHX_ b, "XSRETURN_UNDEF;");
1751            
1752 11           xs_jit_xs_end(aTHX_ b);
1753 11           }
1754              
1755 3           void xs_jit_registry_remove(pTHX_ XS_JIT_Builder* b, const char* func_name,
1756             const char* registry_attr, STRLEN registry_len) {
1757             PERL_UNUSED_VAR(registry_len);
1758 3           xs_jit_xs_function(aTHX_ b, func_name);
1759 3           xs_jit_xs_preamble(aTHX_ b);
1760            
1761 3           xs_jit_comment(aTHX_ b, "Remove an item from the registry hash");
1762 3           xs_jit_line(aTHX_ b, "if (items < 2) croak(\"Usage: $self->%s($key)\");", func_name);
1763 3           xs_jit_line(aTHX_ b, "SV* self = ST(0);");
1764 3           xs_jit_line(aTHX_ b, "SV* key = ST(1);");
1765 3           xs_jit_line(aTHX_ b, "HV* obj = (HV*)SvRV(self);");
1766            
1767 3           xs_jit_comment(aTHX_ b, "Get the registry hash");
1768 3           xs_jit_line(aTHX_ b, "SV** registry_ptr = hv_fetch(obj, \"%s\", %d, 0);", registry_attr, (int)strlen(registry_attr));
1769 3           xs_jit_if(aTHX_ b, "!registry_ptr || !SvROK(*registry_ptr)");
1770 3           xs_jit_line(aTHX_ b, "XSRETURN_UNDEF;");
1771 3           xs_jit_endif(aTHX_ b);
1772            
1773 3           xs_jit_line(aTHX_ b, "HV* registry = (HV*)SvRV(*registry_ptr);");
1774 3           xs_jit_line(aTHX_ b, "STRLEN klen;");
1775 3           xs_jit_line(aTHX_ b, "const char* kstr = SvPV(key, klen);");
1776            
1777 3           xs_jit_comment(aTHX_ b, "Delete and return the removed value");
1778 3           xs_jit_line(aTHX_ b, "SV* deleted = hv_delete(registry, kstr, klen, 0);");
1779 3           xs_jit_if(aTHX_ b, "deleted");
1780 3           xs_jit_line(aTHX_ b, "ST(0) = deleted;");
1781 3           xs_jit_line(aTHX_ b, "XSRETURN(1);");
1782 3           xs_jit_endif(aTHX_ b);
1783            
1784 3           xs_jit_line(aTHX_ b, "XSRETURN_UNDEF;");
1785            
1786 3           xs_jit_xs_end(aTHX_ b);
1787 3           }
1788              
1789 5           void xs_jit_registry_all(pTHX_ XS_JIT_Builder* b, const char* func_name,
1790             const char* registry_attr, STRLEN registry_len) {
1791             PERL_UNUSED_VAR(registry_len);
1792 5           xs_jit_xs_function(aTHX_ b, func_name);
1793 5           xs_jit_xs_preamble(aTHX_ b);
1794            
1795 5           xs_jit_comment(aTHX_ b, "Return all items from the registry");
1796 5           xs_jit_line(aTHX_ b, "SV* self = ST(0);");
1797 5           xs_jit_line(aTHX_ b, "HV* obj = (HV*)SvRV(self);");
1798            
1799 5           xs_jit_comment(aTHX_ b, "Get the registry hash");
1800 5           xs_jit_line(aTHX_ b, "SV** registry_ptr = hv_fetch(obj, \"%s\", %d, 0);", registry_attr, (int)strlen(registry_attr));
1801 5           xs_jit_if(aTHX_ b, "!registry_ptr || !SvROK(*registry_ptr)");
1802 5           xs_jit_comment(aTHX_ b, "Return empty list or empty hashref based on context");
1803 5           xs_jit_line(aTHX_ b, "if (GIMME_V == G_ARRAY) { XSRETURN_EMPTY; }");
1804 5           xs_jit_line(aTHX_ b, "else { ST(0) = sv_2mortal(newRV_noinc((SV*)newHV())); XSRETURN(1); }");
1805 5           xs_jit_endif(aTHX_ b);
1806            
1807 5           xs_jit_line(aTHX_ b, "HV* registry = (HV*)SvRV(*registry_ptr);");
1808            
1809 5           xs_jit_comment(aTHX_ b, "Context-aware return");
1810 5           xs_jit_if(aTHX_ b, "GIMME_V == G_ARRAY");
1811 5           xs_jit_comment(aTHX_ b, "List context: return key-value pairs");
1812 5           xs_jit_line(aTHX_ b, "I32 count = hv_iterinit(registry);");
1813 5           xs_jit_line(aTHX_ b, "EXTEND(SP, count * 2);");
1814 5           xs_jit_line(aTHX_ b, "HE* entry;");
1815 5           xs_jit_line(aTHX_ b, "I32 i = 0;");
1816 5           xs_jit_line(aTHX_ b, "while ((entry = hv_iternext(registry))) {");
1817 5           xs_jit_line(aTHX_ b, " ST(i++) = hv_iterkeysv(entry);");
1818 5           xs_jit_line(aTHX_ b, " ST(i++) = hv_iterval(registry, entry);");
1819 5           xs_jit_line(aTHX_ b, "}");
1820 5           xs_jit_line(aTHX_ b, "XSRETURN(i);");
1821 5           xs_jit_else(aTHX_ b);
1822 5           xs_jit_comment(aTHX_ b, "Scalar context: return shallow copy as hashref");
1823 5           xs_jit_line(aTHX_ b, "HV* copy = newHV();");
1824 5           xs_jit_line(aTHX_ b, "hv_iterinit(registry);");
1825 5           xs_jit_line(aTHX_ b, "HE* entry;");
1826 5           xs_jit_line(aTHX_ b, "while ((entry = hv_iternext(registry))) {");
1827 5           xs_jit_line(aTHX_ b, " SV* key = hv_iterkeysv(entry);");
1828 5           xs_jit_line(aTHX_ b, " SV* val = hv_iterval(registry, entry);");
1829 5           xs_jit_line(aTHX_ b, " STRLEN klen;");
1830 5           xs_jit_line(aTHX_ b, " const char* kstr = SvPV(key, klen);");
1831 5           xs_jit_line(aTHX_ b, " hv_store(copy, kstr, klen, newSVsv(val), 0);");
1832 5           xs_jit_line(aTHX_ b, "}");
1833 5           xs_jit_line(aTHX_ b, "ST(0) = sv_2mortal(newRV_noinc((SV*)copy));");
1834 5           xs_jit_line(aTHX_ b, "XSRETURN(1);");
1835 5           xs_jit_endif(aTHX_ b);
1836            
1837 5           xs_jit_xs_end(aTHX_ b);
1838 5           }
1839              
1840             /* ============================================
1841             * Method Modifiers (Phase 8)
1842             * ============================================ */
1843              
1844 6           void xs_jit_wrap_before(pTHX_ XS_JIT_Builder* b, const char* func_name,
1845             const char* orig_name, const char* before_cv_name) {
1846 6           xs_jit_xs_function(aTHX_ b, func_name);
1847 6           xs_jit_xs_preamble(aTHX_ b);
1848            
1849 6           xs_jit_comment(aTHX_ b, "Method modifier: before");
1850 6           xs_jit_line(aTHX_ b, "I32 gimme = GIMME_V;");
1851 6           xs_jit_line(aTHX_ b, "I32 i;");
1852 6           xs_jit_line(aTHX_ b, "I32 count;");
1853 6           xs_jit_line(aTHX_ b, "AV* saved_results;");
1854            
1855 6           xs_jit_comment(aTHX_ b, "Get the before CV and original CV");
1856 6           xs_jit_line(aTHX_ b, "SV* before_cv = get_sv(\"%s\", 0);", before_cv_name);
1857 6           xs_jit_line(aTHX_ b, "SV* orig_cv = get_sv(\"%s\", 0);", orig_name);
1858            
1859 6           xs_jit_comment(aTHX_ b, "Save args for re-use");
1860 6           xs_jit_line(aTHX_ b, "AV* saved_args = newAV();");
1861 6           xs_jit_line(aTHX_ b, "sv_2mortal((SV*)saved_args);");
1862 6           xs_jit_line(aTHX_ b, "for (i = 0; i < items; i++) av_push(saved_args, newSVsv(ST(i)));");
1863            
1864 6           xs_jit_comment(aTHX_ b, "Call the before hook (discard return value)");
1865 6           xs_jit_line(aTHX_ b, "{");
1866 6           xs_jit_line(aTHX_ b, " dSP;");
1867 6           xs_jit_line(aTHX_ b, " I32 argc = av_len(saved_args) + 1;");
1868 6           xs_jit_line(aTHX_ b, " ENTER; SAVETMPS;");
1869 6           xs_jit_line(aTHX_ b, " PUSHMARK(SP);");
1870 6           xs_jit_line(aTHX_ b, " EXTEND(SP, argc);");
1871 6           xs_jit_line(aTHX_ b, " for (i = 0; i < argc; i++) PUSHs(*av_fetch(saved_args, i, 0));");
1872 6           xs_jit_line(aTHX_ b, " PUTBACK;");
1873 6           xs_jit_line(aTHX_ b, " call_sv(before_cv, G_DISCARD);");
1874 6           xs_jit_line(aTHX_ b, " FREETMPS; LEAVE;");
1875 6           xs_jit_line(aTHX_ b, "}");
1876            
1877 6           xs_jit_comment(aTHX_ b, "Call the original and save return values");
1878 6           xs_jit_line(aTHX_ b, "saved_results = newAV();");
1879 6           xs_jit_line(aTHX_ b, "sv_2mortal((SV*)saved_results);");
1880 6           xs_jit_line(aTHX_ b, "{");
1881 6           xs_jit_line(aTHX_ b, " dSP;");
1882 6           xs_jit_line(aTHX_ b, " I32 argc = av_len(saved_args) + 1;");
1883 6           xs_jit_line(aTHX_ b, " ENTER; SAVETMPS;");
1884 6           xs_jit_line(aTHX_ b, " PUSHMARK(SP);");
1885 6           xs_jit_line(aTHX_ b, " EXTEND(SP, argc);");
1886 6           xs_jit_line(aTHX_ b, " for (i = 0; i < argc; i++) PUSHs(*av_fetch(saved_args, i, 0));");
1887 6           xs_jit_line(aTHX_ b, " PUTBACK;");
1888 6           xs_jit_line(aTHX_ b, " count = call_sv(orig_cv, gimme | G_EVAL);");
1889 6           xs_jit_line(aTHX_ b, " SPAGAIN;");
1890 6           xs_jit_line(aTHX_ b, " if (SvTRUE(ERRSV)) { FREETMPS; LEAVE; croak(\"%%s\", SvPV_nolen(ERRSV)); }");
1891 6           xs_jit_line(aTHX_ b, " for (i = count - 1; i >= 0; i--) av_store(saved_results, i, newSVsv(POPs));");
1892 6           xs_jit_line(aTHX_ b, " FREETMPS; LEAVE;");
1893 6           xs_jit_line(aTHX_ b, "}");
1894              
1895 6           xs_jit_comment(aTHX_ b, "Return the saved results");
1896 6           xs_jit_line(aTHX_ b, "count = av_len(saved_results) + 1;");
1897 6           xs_jit_line(aTHX_ b, "if (gimme == G_ARRAY) {");
1898 6           xs_jit_line(aTHX_ b, " for (i = 0; i < count; i++) ST(i) = sv_2mortal(SvREFCNT_inc(*av_fetch(saved_results, i, 0)));");
1899 6           xs_jit_line(aTHX_ b, " XSRETURN(count);");
1900 6           xs_jit_line(aTHX_ b, "} else if (gimme == G_SCALAR && count > 0) {");
1901 6           xs_jit_line(aTHX_ b, " ST(0) = sv_2mortal(SvREFCNT_inc(*av_fetch(saved_results, count - 1, 0)));");
1902 6           xs_jit_line(aTHX_ b, " XSRETURN(1);");
1903 6           xs_jit_line(aTHX_ b, "}");
1904 6           xs_jit_line(aTHX_ b, "XSRETURN(0);");
1905            
1906 6           xs_jit_xs_end(aTHX_ b);
1907 6           }
1908              
1909 5           void xs_jit_wrap_after(pTHX_ XS_JIT_Builder* b, const char* func_name,
1910             const char* orig_name, const char* after_cv_name) {
1911 5           xs_jit_xs_function(aTHX_ b, func_name);
1912 5           xs_jit_xs_preamble(aTHX_ b);
1913            
1914 5           xs_jit_comment(aTHX_ b, "Method modifier: after");
1915 5           xs_jit_line(aTHX_ b, "I32 gimme = GIMME_V;");
1916 5           xs_jit_line(aTHX_ b, "I32 i;");
1917 5           xs_jit_line(aTHX_ b, "I32 orig_count = 0;");
1918 5           xs_jit_line(aTHX_ b, "AV* saved_results = NULL;");
1919            
1920 5           xs_jit_comment(aTHX_ b, "Get the original CV and after CV");
1921 5           xs_jit_line(aTHX_ b, "SV* orig_cv = get_sv(\"%s\", 0);", orig_name);
1922 5           xs_jit_line(aTHX_ b, "SV* after_cv = get_sv(\"%s\", 0);", after_cv_name);
1923            
1924 5           xs_jit_comment(aTHX_ b, "Save original args for after hook");
1925 5           xs_jit_line(aTHX_ b, "AV* saved_args = newAV();");
1926 5           xs_jit_line(aTHX_ b, "sv_2mortal((SV*)saved_args);");
1927 5           xs_jit_line(aTHX_ b, "for (i = 0; i < items; i++) av_push(saved_args, newSVsv(ST(i)));");
1928            
1929 5           xs_jit_comment(aTHX_ b, "Call the original and save return values");
1930 5           xs_jit_line(aTHX_ b, "saved_results = newAV();");
1931 5           xs_jit_line(aTHX_ b, "sv_2mortal((SV*)saved_results);");
1932 5           xs_jit_line(aTHX_ b, "{");
1933 5           xs_jit_line(aTHX_ b, " dSP;");
1934 5           xs_jit_line(aTHX_ b, " I32 argc = av_len(saved_args) + 1;");
1935 5           xs_jit_line(aTHX_ b, " ENTER; SAVETMPS;");
1936 5           xs_jit_line(aTHX_ b, " PUSHMARK(SP);");
1937 5           xs_jit_line(aTHX_ b, " EXTEND(SP, argc);");
1938 5           xs_jit_line(aTHX_ b, " for (i = 0; i < argc; i++) PUSHs(*av_fetch(saved_args, i, 0));");
1939 5           xs_jit_line(aTHX_ b, " PUTBACK;");
1940 5           xs_jit_line(aTHX_ b, " orig_count = call_sv(orig_cv, gimme | G_EVAL);");
1941 5           xs_jit_line(aTHX_ b, " SPAGAIN;");
1942 5           xs_jit_line(aTHX_ b, " if (SvTRUE(ERRSV)) { FREETMPS; LEAVE; croak(\"%%s\", SvPV_nolen(ERRSV)); }");
1943 5           xs_jit_line(aTHX_ b, " for (i = orig_count - 1; i >= 0; i--) av_store(saved_results, i, newSVsv(POPs));");
1944 5           xs_jit_line(aTHX_ b, " FREETMPS; LEAVE;");
1945 5           xs_jit_line(aTHX_ b, "}");
1946            
1947 5           xs_jit_comment(aTHX_ b, "Call the after hook (discard return value)");
1948 5           xs_jit_line(aTHX_ b, "{");
1949 5           xs_jit_line(aTHX_ b, " dSP;");
1950 5           xs_jit_line(aTHX_ b, " I32 argc = av_len(saved_args) + 1;");
1951 5           xs_jit_line(aTHX_ b, " ENTER; SAVETMPS;");
1952 5           xs_jit_line(aTHX_ b, " PUSHMARK(SP);");
1953 5           xs_jit_line(aTHX_ b, " EXTEND(SP, argc);");
1954 5           xs_jit_line(aTHX_ b, " for (i = 0; i < argc; i++) PUSHs(*av_fetch(saved_args, i, 0));");
1955 5           xs_jit_line(aTHX_ b, " PUTBACK;");
1956 5           xs_jit_line(aTHX_ b, " call_sv(after_cv, G_DISCARD);");
1957 5           xs_jit_line(aTHX_ b, " FREETMPS; LEAVE;");
1958 5           xs_jit_line(aTHX_ b, "}");
1959            
1960 5           xs_jit_comment(aTHX_ b, "Return the saved results from original");
1961 5           xs_jit_line(aTHX_ b, "orig_count = av_len(saved_results) + 1;");
1962 5           xs_jit_line(aTHX_ b, "if (gimme == G_ARRAY) {");
1963 5           xs_jit_line(aTHX_ b, " for (i = 0; i < orig_count; i++) ST(i) = sv_2mortal(SvREFCNT_inc(*av_fetch(saved_results, i, 0)));");
1964 5           xs_jit_line(aTHX_ b, " XSRETURN(orig_count);");
1965 5           xs_jit_line(aTHX_ b, "} else if (gimme == G_SCALAR && orig_count > 0) {");
1966 5           xs_jit_line(aTHX_ b, " ST(0) = sv_2mortal(SvREFCNT_inc(*av_fetch(saved_results, orig_count - 1, 0)));");
1967 5           xs_jit_line(aTHX_ b, " XSRETURN(1);");
1968 5           xs_jit_line(aTHX_ b, "}");
1969 5           xs_jit_line(aTHX_ b, "XSRETURN(0);");
1970            
1971 5           xs_jit_xs_end(aTHX_ b);
1972 5           }
1973              
1974 6           void xs_jit_wrap_around(pTHX_ XS_JIT_Builder* b, const char* func_name,
1975             const char* orig_name, const char* around_cv_name) {
1976 6           xs_jit_xs_function(aTHX_ b, func_name);
1977 6           xs_jit_xs_preamble(aTHX_ b);
1978            
1979 6           xs_jit_comment(aTHX_ b, "Method modifier: around");
1980 6           xs_jit_line(aTHX_ b, "I32 gimme = GIMME_V;");
1981 6           xs_jit_line(aTHX_ b, "I32 i;");
1982            
1983 6           xs_jit_comment(aTHX_ b, "Get the around CV and original CV");
1984 6           xs_jit_line(aTHX_ b, "SV* around_cv = get_sv(\"%s\", 0);", around_cv_name);
1985 6           xs_jit_line(aTHX_ b, "SV* orig_cv = get_sv(\"%s\", 0);", orig_name);
1986            
1987 6           xs_jit_comment(aTHX_ b, "Save original args");
1988 6           xs_jit_line(aTHX_ b, "AV* saved_args = newAV();");
1989 6           xs_jit_line(aTHX_ b, "sv_2mortal((SV*)saved_args);");
1990 6           xs_jit_line(aTHX_ b, "for (i = 0; i < items; i++) av_push(saved_args, newSVsv(ST(i)));");
1991            
1992 6           xs_jit_comment(aTHX_ b, "Call around with $orig as first arg, then original args");
1993 6           xs_jit_line(aTHX_ b, "{");
1994 6           xs_jit_line(aTHX_ b, " dSP;");
1995 6           xs_jit_line(aTHX_ b, " I32 count;");
1996 6           xs_jit_line(aTHX_ b, " I32 argc = av_len(saved_args) + 1;");
1997 6           xs_jit_line(aTHX_ b, " AV* saved_results = newAV();");
1998 6           xs_jit_line(aTHX_ b, " sv_2mortal((SV*)saved_results);");
1999 6           xs_jit_line(aTHX_ b, " ENTER; SAVETMPS;");
2000 6           xs_jit_line(aTHX_ b, " PUSHMARK(SP);");
2001 6           xs_jit_line(aTHX_ b, " EXTEND(SP, argc + 1);");
2002 6           xs_jit_line(aTHX_ b, " PUSHs(orig_cv);");
2003 6           xs_jit_line(aTHX_ b, " for (i = 0; i < argc; i++) PUSHs(*av_fetch(saved_args, i, 0));");
2004 6           xs_jit_line(aTHX_ b, " PUTBACK;");
2005 6           xs_jit_line(aTHX_ b, " count = call_sv(around_cv, gimme | G_EVAL);");
2006 6           xs_jit_line(aTHX_ b, " SPAGAIN;");
2007 6           xs_jit_line(aTHX_ b, " if (SvTRUE(ERRSV)) { FREETMPS; LEAVE; croak(\"%%s\", SvPV_nolen(ERRSV)); }");
2008 6           xs_jit_line(aTHX_ b, " for (i = count - 1; i >= 0; i--) av_store(saved_results, i, newSVsv(POPs));");
2009 6           xs_jit_line(aTHX_ b, " FREETMPS; LEAVE;");
2010 6           xs_jit_line(aTHX_ b, " count = av_len(saved_results) + 1;");
2011 6           xs_jit_line(aTHX_ b, " if (gimme == G_ARRAY) {");
2012 6           xs_jit_line(aTHX_ b, " for (i = 0; i < count; i++) ST(i) = sv_2mortal(SvREFCNT_inc(*av_fetch(saved_results, i, 0)));");
2013 6           xs_jit_line(aTHX_ b, " XSRETURN(count);");
2014 6           xs_jit_line(aTHX_ b, " } else if (gimme == G_SCALAR && count > 0) {");
2015 6           xs_jit_line(aTHX_ b, " ST(0) = sv_2mortal(SvREFCNT_inc(*av_fetch(saved_results, count - 1, 0)));");
2016 6           xs_jit_line(aTHX_ b, " XSRETURN(1);");
2017 6           xs_jit_line(aTHX_ b, " }");
2018 6           xs_jit_line(aTHX_ b, " XSRETURN(0);");
2019 6           xs_jit_line(aTHX_ b, "}");
2020            
2021 6           xs_jit_xs_end(aTHX_ b);
2022 6           }
2023              
2024             /* ============================================
2025             * Op-based accessors (array-based objects with inline ops)
2026             * ============================================ */
2027              
2028 3           void xs_jit_op_ro_accessor(pTHX_ XS_JIT_Builder* b, const char* func_name, IV slot) {
2029 3           xs_jit_xs_function(aTHX_ b, func_name);
2030 3           xs_jit_xs_preamble(aTHX_ b);
2031            
2032 3           xs_jit_if(aTHX_ b, "items > 1");
2033 3           xs_jit_croak(aTHX_ b, "Read only attributes cannot be set");
2034 3           xs_jit_endif(aTHX_ b);
2035            
2036 3           xs_jit_line(aTHX_ b, "SV** ary = AvARRAY((AV*)SvRV(ST(0)));");
2037 3           xs_jit_line(aTHX_ b, "ST(0) = ary[%ld] ? ary[%ld] : &PL_sv_undef;", (long)slot, (long)slot);
2038 3           xs_jit_line(aTHX_ b, "XSRETURN(1);");
2039            
2040 3           xs_jit_xs_end(aTHX_ b);
2041 3           }
2042              
2043 4           void xs_jit_op_rw_accessor(pTHX_ XS_JIT_Builder* b, const char* func_name, IV slot) {
2044 4           xs_jit_xs_function(aTHX_ b, func_name);
2045 4           xs_jit_xs_preamble(aTHX_ b);
2046            
2047 4           xs_jit_line(aTHX_ b, "AV* av = (AV*)SvRV(ST(0));");
2048            
2049 4           xs_jit_if(aTHX_ b, "items > 1");
2050 4           xs_jit_line(aTHX_ b, "SV* new_val = newSVsv(ST(1));");
2051 4           xs_jit_line(aTHX_ b, "av_store(av, %ld, new_val);", (long)slot);
2052 4           xs_jit_line(aTHX_ b, "ST(0) = new_val;");
2053 4           xs_jit_line(aTHX_ b, "XSRETURN(1);");
2054 4           xs_jit_endif(aTHX_ b);
2055            
2056 4           xs_jit_line(aTHX_ b, "SV** ary = AvARRAY(av);");
2057 4           xs_jit_line(aTHX_ b, "ST(0) = ary[%ld] ? ary[%ld] : &PL_sv_undef;", (long)slot, (long)slot);
2058 4           xs_jit_line(aTHX_ b, "XSRETURN(1);");
2059            
2060 4           xs_jit_xs_end(aTHX_ b);
2061 4           }
2062              
2063             /* ============================================
2064             * Custom op builder (pp functions)
2065             * ============================================ */
2066              
2067 20           void xs_jit_pp_start(pTHX_ XS_JIT_Builder* b, const char* name) {
2068 20           xs_jit_line(aTHX_ b, "static OP* S_pp_%s(pTHX) {", name);
2069 20           b->indent++;
2070 20           }
2071              
2072 6           void xs_jit_pp_end(pTHX_ XS_JIT_Builder* b) {
2073 6           b->indent--;
2074 6           xs_jit_line(aTHX_ b, "}");
2075 6           xs_jit_blank(aTHX_ b);
2076 6           }
2077              
2078 18           void xs_jit_pp_dsp(pTHX_ XS_JIT_Builder* b) {
2079 18           xs_jit_line(aTHX_ b, "dSP;");
2080 18           }
2081              
2082 7           void xs_jit_pp_get_self(pTHX_ XS_JIT_Builder* b) {
2083 7           xs_jit_line(aTHX_ b, "SV* self = TOPs;");
2084 7           }
2085              
2086 2           void xs_jit_pp_pop_self(pTHX_ XS_JIT_Builder* b) {
2087 2           xs_jit_line(aTHX_ b, "SV* self = POPs;");
2088 2           }
2089              
2090 2           void xs_jit_pp_pop_sv(pTHX_ XS_JIT_Builder* b, const char* name) {
2091 2           xs_jit_line(aTHX_ b, "SV* %s = POPs;", name);
2092 2           }
2093              
2094 1           void xs_jit_pp_pop_nv(pTHX_ XS_JIT_Builder* b, const char* name) {
2095 1           xs_jit_line(aTHX_ b, "NV %s = POPn;", name);
2096 1           }
2097              
2098 1           void xs_jit_pp_pop_iv(pTHX_ XS_JIT_Builder* b, const char* name) {
2099 1           xs_jit_line(aTHX_ b, "IV %s = POPi;", name);
2100 1           }
2101              
2102 7           void xs_jit_pp_get_slots(pTHX_ XS_JIT_Builder* b) {
2103 7           xs_jit_line(aTHX_ b, "SV** ary = AvARRAY((AV*)SvRV(self));");
2104 7           }
2105              
2106 2           void xs_jit_pp_slot(pTHX_ XS_JIT_Builder* b, const char* name, IV slot) {
2107 2           xs_jit_line(aTHX_ b, "SV* %s = ary[%ld] ? ary[%ld] : &PL_sv_undef;", name, (long)slot, (long)slot);
2108 2           }
2109              
2110 4           void xs_jit_pp_return_sv(pTHX_ XS_JIT_Builder* b, const char* sv_expr) {
2111 4           xs_jit_line(aTHX_ b, "SETs(%s);", sv_expr);
2112 4           xs_jit_line(aTHX_ b, "return NORMAL;");
2113 4           }
2114              
2115 1           void xs_jit_pp_return_nv(pTHX_ XS_JIT_Builder* b, const char* nv_expr) {
2116 1           xs_jit_line(aTHX_ b, "SETs(sv_2mortal(newSVnv(%s)));", nv_expr);
2117 1           xs_jit_line(aTHX_ b, "return NORMAL;");
2118 1           }
2119              
2120 2           void xs_jit_pp_return_iv(pTHX_ XS_JIT_Builder* b, const char* iv_expr) {
2121 2           xs_jit_line(aTHX_ b, "SETs(sv_2mortal(newSViv(%s)));", iv_expr);
2122 2           xs_jit_line(aTHX_ b, "return NORMAL;");
2123 2           }
2124              
2125 1           void xs_jit_pp_return_pv(pTHX_ XS_JIT_Builder* b, const char* pv_expr) {
2126 1           xs_jit_line(aTHX_ b, "SETs(sv_2mortal(newSVpv(%s, 0)));", pv_expr);
2127 1           xs_jit_line(aTHX_ b, "return NORMAL;");
2128 1           }
2129              
2130 3           void xs_jit_pp_return(pTHX_ XS_JIT_Builder* b) {
2131 3           xs_jit_line(aTHX_ b, "return NORMAL;");
2132 3           }
2133              
2134             /* ============================================
2135             * Call checker builder
2136             * ============================================ */
2137              
2138 9           void xs_jit_ck_start(pTHX_ XS_JIT_Builder* b, const char* name) {
2139 9           xs_jit_line(aTHX_ b, "static OP* S_ck_%s(pTHX_ OP* entersubop, GV* namegv, SV* ckobj) {", name);
2140 9           b->indent++;
2141 9           xs_jit_line(aTHX_ b, "PERL_UNUSED_ARG(namegv);");
2142 9           }
2143              
2144 4           void xs_jit_ck_end(pTHX_ XS_JIT_Builder* b) {
2145 4           b->indent--;
2146 4           xs_jit_line(aTHX_ b, "}");
2147 4           xs_jit_blank(aTHX_ b);
2148 4           }
2149              
2150 7           void xs_jit_ck_preamble(pTHX_ XS_JIT_Builder* b) {
2151 7           xs_jit_line(aTHX_ b, "OP* parent = entersubop;");
2152 7           xs_jit_line(aTHX_ b, "OP* pushmark = cUNOPx(entersubop)->op_first;");
2153 7           xs_jit_blank(aTHX_ b);
2154 7           xs_jit_line(aTHX_ b, "if (!OpHAS_SIBLING(pushmark)) {");
2155 7           b->indent++;
2156 7           xs_jit_line(aTHX_ b, "parent = pushmark;");
2157 7           xs_jit_line(aTHX_ b, "pushmark = cUNOPx(pushmark)->op_first;");
2158 7           b->indent--;
2159 7           xs_jit_line(aTHX_ b, "}");
2160 7           xs_jit_blank(aTHX_ b);
2161 7           xs_jit_line(aTHX_ b, "OP* selfop = OpSIBLING(pushmark);");
2162 7           xs_jit_line(aTHX_ b, "if (!selfop || selfop->op_type == OP_RV2CV || selfop->op_type == OP_NULL) {");
2163 7           b->indent++;
2164 7           xs_jit_line(aTHX_ b, "return entersubop;");
2165 7           b->indent--;
2166 7           xs_jit_line(aTHX_ b, "}");
2167 7           xs_jit_blank(aTHX_ b);
2168 7           }
2169              
2170 3           void xs_jit_ck_build_unop(pTHX_ XS_JIT_Builder* b, const char* pp_func, const char* targ_expr) {
2171 3           xs_jit_line(aTHX_ b, "op_sibling_splice(parent, pushmark, 1, NULL);");
2172 3           xs_jit_line(aTHX_ b, "op_free(entersubop);");
2173 3           xs_jit_blank(aTHX_ b);
2174 3           xs_jit_line(aTHX_ b, "UNOP* newop;");
2175 3           xs_jit_line(aTHX_ b, "NewOp(1234, newop, 1, UNOP);");
2176 3           xs_jit_line(aTHX_ b, "newop->op_type = OP_CUSTOM;");
2177 3           xs_jit_line(aTHX_ b, "newop->op_ppaddr = %s;", pp_func);
2178 3           xs_jit_line(aTHX_ b, "newop->op_flags = OPf_KIDS | OPf_WANT_SCALAR;");
2179 3           xs_jit_line(aTHX_ b, "newop->op_private = 0;");
2180 3           xs_jit_line(aTHX_ b, "newop->op_targ = (PADOFFSET)(%s);", targ_expr);
2181 3           xs_jit_blank(aTHX_ b);
2182 3           xs_jit_line(aTHX_ b, "op_sibling_splice((OP*)newop, NULL, 0, selfop);");
2183 3           xs_jit_blank(aTHX_ b);
2184 3           xs_jit_line(aTHX_ b, "return (OP*)newop;");
2185 3           }
2186              
2187 1           void xs_jit_ck_build_binop(pTHX_ XS_JIT_Builder* b, const char* pp_func, const char* targ_expr) {
2188 1           xs_jit_line(aTHX_ b, "OP* valop = OpSIBLING(selfop);");
2189 1           xs_jit_line(aTHX_ b, "if (!valop || valop->op_type == OP_RV2CV || valop->op_type == OP_NULL) {");
2190 1           b->indent++;
2191 1           xs_jit_line(aTHX_ b, "return entersubop;");
2192 1           b->indent--;
2193 1           xs_jit_line(aTHX_ b, "}");
2194 1           xs_jit_blank(aTHX_ b);
2195 1           xs_jit_line(aTHX_ b, "op_sibling_splice(parent, pushmark, 2, NULL);");
2196 1           xs_jit_line(aTHX_ b, "op_free(entersubop);");
2197 1           xs_jit_blank(aTHX_ b);
2198 1           xs_jit_line(aTHX_ b, "BINOP* newop;");
2199 1           xs_jit_line(aTHX_ b, "NewOp(1234, newop, 1, BINOP);");
2200 1           xs_jit_line(aTHX_ b, "newop->op_type = OP_CUSTOM;");
2201 1           xs_jit_line(aTHX_ b, "newop->op_ppaddr = %s;", pp_func);
2202 1           xs_jit_line(aTHX_ b, "newop->op_flags = OPf_KIDS | OPf_STACKED | OPf_WANT_SCALAR;");
2203 1           xs_jit_line(aTHX_ b, "newop->op_private = 1;");
2204 1           xs_jit_line(aTHX_ b, "newop->op_targ = (PADOFFSET)(%s);", targ_expr);
2205 1           xs_jit_blank(aTHX_ b);
2206 1           xs_jit_line(aTHX_ b, "OpMORESIB_set(selfop, valop);");
2207 1           xs_jit_line(aTHX_ b, "OpLASTSIB_set(valop, (OP*)newop);");
2208 1           xs_jit_line(aTHX_ b, "newop->op_first = selfop;");
2209 1           xs_jit_line(aTHX_ b, "newop->op_last = valop;");
2210 1           xs_jit_blank(aTHX_ b);
2211 1           xs_jit_line(aTHX_ b, "return (OP*)newop;");
2212 1           }
2213              
2214 2           void xs_jit_ck_fallback(pTHX_ XS_JIT_Builder* b) {
2215 2           xs_jit_line(aTHX_ b, "return entersubop;");
2216 2           }
2217              
2218             /* ============================================
2219             * XOP registration helpers
2220             * ============================================ */
2221              
2222 5           void xs_jit_xop_declare(pTHX_ XS_JIT_Builder* b, const char* name, const char* pp_func, const char* desc) {
2223 5           xs_jit_line(aTHX_ b, "static XOP xop_%s;", name);
2224 5           xs_jit_blank(aTHX_ b);
2225 5           xs_jit_line(aTHX_ b, "static void register_xop_%s(pTHX) {", name);
2226 5           b->indent++;
2227 5           xs_jit_line(aTHX_ b, "static int registered = 0;");
2228 5           xs_jit_line(aTHX_ b, "if (registered) return;");
2229 5           xs_jit_blank(aTHX_ b);
2230 5           xs_jit_line(aTHX_ b, "XopENTRY_set(&xop_%s, xop_name, \"%s\");", name, name);
2231 5           xs_jit_line(aTHX_ b, "XopENTRY_set(&xop_%s, xop_desc, \"%s\");", name, desc);
2232 5           xs_jit_line(aTHX_ b, "XopENTRY_set(&xop_%s, xop_class, OA_UNOP);", name);
2233 5           xs_jit_line(aTHX_ b, "Perl_custom_op_register(aTHX_ %s, &xop_%s);", pp_func, name);
2234 5           xs_jit_blank(aTHX_ b);
2235 5           xs_jit_line(aTHX_ b, "registered = 1;");
2236 5           b->indent--;
2237 5           xs_jit_line(aTHX_ b, "}");
2238 5           xs_jit_blank(aTHX_ b);
2239 5           }
2240              
2241 2           void xs_jit_register_checker(pTHX_ XS_JIT_Builder* b, const char* cv_expr, const char* ck_func, const char* ckobj_expr) {
2242 2           xs_jit_line(aTHX_ b, "cv_set_call_checker_flags(%s, %s, %s, 0);", cv_expr, ck_func, ckobj_expr);
2243 2           }
2244              
2245             /* ============================================
2246             * Inline op support
2247             * Custom ops work on all Perl versions (with compat shim for pre-5.14)
2248             * cv_set_call_checker requires Perl 5.14+ - returns 0 on older Perls
2249             * ============================================ */
2250              
2251             /* For cv_set_call_checker - need Perl 5.14+ */
2252             #ifndef cv_set_call_checker_flags
2253             #define cv_set_call_checker_flags(cv, ckfun, ckobj, ckflags) \
2254             cv_set_call_checker(cv, ckfun, ckobj)
2255             #endif
2256              
2257             /* XOP descriptors for custom ops */
2258             static XOP xs_jit_xop_getter;
2259             static XOP xs_jit_xop_setter;
2260             static int xs_jit_xops_registered = 0;
2261              
2262             /* Forward declarations */
2263             static OP* S_pp_xs_jit_get(pTHX);
2264             static OP* S_pp_xs_jit_set(pTHX);
2265             #if PERL_VERSION_GE(5,14,0)
2266             static OP* S_ck_xs_jit_get(pTHX_ OP* entersubop, GV* namegv, SV* ckobj);
2267             static OP* S_ck_xs_jit_set(pTHX_ OP* entersubop, GV* namegv, SV* ckobj);
2268             #endif
2269              
2270             /* Initialize inline op subsystem */
2271 3           void xs_jit_inline_init(pTHX) {
2272 3 100         if (xs_jit_xops_registered) return;
2273            
2274             /* Initialize getter XOP */
2275 1           XopENTRY_set(&xs_jit_xop_getter, xop_name, "xs_jit_get");
2276 1           XopENTRY_set(&xs_jit_xop_getter, xop_desc, "XS::JIT inline getter");
2277 1           XopENTRY_set(&xs_jit_xop_getter, xop_class, OA_UNOP);
2278 1           Perl_custom_op_register(aTHX_ S_pp_xs_jit_get, &xs_jit_xop_getter);
2279            
2280             /* Initialize setter XOP */
2281 1           XopENTRY_set(&xs_jit_xop_setter, xop_name, "xs_jit_set");
2282 1           XopENTRY_set(&xs_jit_xop_setter, xop_desc, "XS::JIT inline setter");
2283 1           XopENTRY_set(&xs_jit_xop_setter, xop_class, OA_BINOP);
2284 1           Perl_custom_op_register(aTHX_ S_pp_xs_jit_set, &xs_jit_xop_setter);
2285            
2286 1           xs_jit_xops_registered = 1;
2287             }
2288              
2289             /*
2290             * pp_xs_jit_get - Ultra-fast getter custom op
2291             *
2292             * Stack: self -> [result]
2293             * Slot index stored in op_targ
2294             */
2295 0           static OP* S_pp_xs_jit_get(pTHX) {
2296 0           dSP;
2297 0           SV* self = TOPs;
2298 0           PADOFFSET slot_index = PL_op->op_targ;
2299            
2300 0           SV** ary = AvARRAY((AV*)SvRV(self));
2301 0 0         SETs(ary[slot_index] ? ary[slot_index] : &PL_sv_undef);
2302            
2303 0           return NORMAL;
2304             }
2305              
2306             /*
2307             * pp_xs_jit_set - Ultra-fast setter custom op
2308             *
2309             * Stack: self, [value] -> [result]
2310             * Slot index stored in op_targ
2311             */
2312 0           static OP* S_pp_xs_jit_set(pTHX) {
2313 0           dSP;
2314 0           PADOFFSET slot_index = PL_op->op_targ;
2315            
2316             /* Check if we have a value argument (setter mode) */
2317 0 0         if (PL_op->op_private & 1) {
2318             /* Setter: self, value on stack */
2319 0           SV* value = POPs;
2320 0           SV* self = TOPs;
2321 0           AV* av = (AV*)SvRV(self);
2322            
2323 0           SvREFCNT_inc(value);
2324 0           av_store(av, slot_index, value);
2325 0           SETs(value);
2326             } else {
2327             /* Getter: just self on stack */
2328 0           SV* self = TOPs;
2329 0           SV** ary = AvARRAY((AV*)SvRV(self));
2330 0 0         SETs(ary[slot_index] ? ary[slot_index] : &PL_sv_undef);
2331             }
2332            
2333 0           return NORMAL;
2334             }
2335              
2336             #if PERL_VERSION_GE(5,14,0)
2337             /*
2338             * S_ck_xs_jit_get - Call checker for read-only accessors
2339             */
2340 0           static OP* S_ck_xs_jit_get(pTHX_ OP* entersubop, GV* namegv, SV* ckobj) {
2341             OP* parent;
2342             OP* pushmark;
2343             OP* selfop;
2344             UNOP* newop;
2345            
2346             PERL_UNUSED_ARG(namegv);
2347            
2348 0           IV slot_index = SvIV(ckobj);
2349            
2350 0           parent = entersubop;
2351 0           pushmark = cUNOPx(entersubop)->op_first;
2352            
2353 0 0         if (!OpHAS_SIBLING(pushmark)) {
2354 0           parent = pushmark;
2355 0           pushmark = cUNOPx(pushmark)->op_first;
2356             }
2357            
2358 0 0         selfop = OpSIBLING(pushmark);
2359            
2360 0 0         if (!selfop || selfop->op_type == OP_RV2CV || selfop->op_type == OP_NULL) {
    0          
    0          
2361 0           return entersubop;
2362             }
2363            
2364             /* Check for extra arguments (setter call on ro) */
2365 0 0         OP* nextop = OpSIBLING(selfop);
2366 0 0         if (nextop && nextop->op_type != OP_RV2CV && nextop->op_type != OP_NULL) {
    0          
    0          
2367 0           return entersubop;
2368             }
2369            
2370             /* Detach selfop */
2371 0           op_sibling_splice(parent, pushmark, 1, NULL);
2372 0           op_free(entersubop);
2373            
2374             /* Create custom UNOP */
2375 0           NewOp(1234, newop, 1, UNOP);
2376 0           newop->op_type = OP_CUSTOM;
2377 0           newop->op_ppaddr = S_pp_xs_jit_get;
2378 0           newop->op_flags = OPf_KIDS | OPf_WANT_SCALAR;
2379 0           newop->op_private = 0;
2380 0           newop->op_targ = (PADOFFSET)slot_index;
2381            
2382 0           op_sibling_splice((OP*)newop, NULL, 0, selfop);
2383            
2384 0           return (OP*)newop;
2385             }
2386              
2387             /*
2388             * S_ck_xs_jit_set - Call checker for read-write accessors
2389             */
2390 0           static OP* S_ck_xs_jit_set(pTHX_ OP* entersubop, GV* namegv, SV* ckobj) {
2391             OP* parent;
2392             OP* pushmark;
2393             OP* selfop;
2394             OP* valop;
2395            
2396             PERL_UNUSED_ARG(namegv);
2397            
2398 0           IV slot_index = SvIV(ckobj);
2399            
2400 0           parent = entersubop;
2401 0           pushmark = cUNOPx(entersubop)->op_first;
2402            
2403 0 0         if (!OpHAS_SIBLING(pushmark)) {
2404 0           parent = pushmark;
2405 0           pushmark = cUNOPx(pushmark)->op_first;
2406             }
2407            
2408 0 0         selfop = OpSIBLING(pushmark);
2409 0 0         if (!selfop || selfop->op_type == OP_RV2CV || selfop->op_type == OP_NULL) {
    0          
    0          
2410 0           return entersubop;
2411             }
2412            
2413 0 0         valop = OpSIBLING(selfop);
2414            
2415             /* Determine getter vs setter */
2416 0           int is_setter = 0;
2417 0 0         if (valop && valop->op_type != OP_RV2CV && valop->op_type != OP_NULL) {
    0          
    0          
2418 0 0         OP* afterval = OpSIBLING(valop);
2419 0 0         if (!afterval || afterval->op_type == OP_RV2CV || afterval->op_type == OP_NULL) {
    0          
    0          
2420 0           is_setter = 1;
2421             } else {
2422 0           return entersubop;
2423             }
2424             }
2425            
2426 0 0         if (is_setter) {
2427             BINOP* newop;
2428            
2429 0           op_sibling_splice(parent, pushmark, 2, NULL);
2430 0           op_free(entersubop);
2431            
2432 0           NewOp(1234, newop, 1, BINOP);
2433 0           newop->op_type = OP_CUSTOM;
2434 0           newop->op_ppaddr = S_pp_xs_jit_set;
2435 0           newop->op_flags = OPf_KIDS | OPf_STACKED | OPf_WANT_SCALAR;
2436 0           newop->op_private = 1; /* Flag: is setter */
2437 0           newop->op_targ = (PADOFFSET)slot_index;
2438            
2439 0           OpMORESIB_set(selfop, valop);
2440 0           OpLASTSIB_set(valop, (OP*)newop);
2441 0           newop->op_first = selfop;
2442 0           newop->op_last = valop;
2443            
2444 0           return (OP*)newop;
2445             } else {
2446             UNOP* newop;
2447            
2448 0           op_sibling_splice(parent, pushmark, 1, NULL);
2449 0           op_free(entersubop);
2450            
2451 0           NewOp(1234, newop, 1, UNOP);
2452 0           newop->op_type = OP_CUSTOM;
2453 0           newop->op_ppaddr = S_pp_xs_jit_set;
2454 0           newop->op_flags = OPf_KIDS | OPf_WANT_SCALAR;
2455 0           newop->op_private = 0; /* Flag: is getter */
2456 0           newop->op_targ = (PADOFFSET)slot_index;
2457            
2458 0           op_sibling_splice((OP*)newop, NULL, 0, selfop);
2459            
2460 0           return (OP*)newop;
2461             }
2462             }
2463             #endif /* PERL_VERSION_GE(5,14,0) */
2464              
2465             /* Register inline op for a CV */
2466 2           int xs_jit_inline_register(pTHX_ CV* cv, XS_JIT_InlineType type,
2467             IV slot, const char* key, STRLEN key_len) {
2468             PERL_UNUSED_ARG(key);
2469             PERL_UNUSED_ARG(key_len);
2470            
2471 2 50         if (!cv) return 0;
2472            
2473             /* cv_set_call_checker requires Perl 5.14+ - on older Perls it's a no-op */
2474             #if !PERL_VERSION_GE(5,14,0)
2475             PERL_UNUSED_ARG(slot);
2476             PERL_UNUSED_ARG(type);
2477             return 0; /* Not supported on pre-5.14 */
2478             #else
2479 2           xs_jit_inline_init(aTHX);
2480            
2481 2           SV* ckobj = newSViv(slot);
2482            
2483 2           switch (type) {
2484 1           case XS_JIT_INLINE_GETTER:
2485 1           cv_set_call_checker_flags(cv, S_ck_xs_jit_get, ckobj, 0);
2486 1           break;
2487 1           case XS_JIT_INLINE_SETTER:
2488 1           cv_set_call_checker_flags(cv, S_ck_xs_jit_set, ckobj, 0);
2489 1           break;
2490 0           case XS_JIT_INLINE_HV_GETTER:
2491             case XS_JIT_INLINE_HV_SETTER:
2492             /* TODO: Implement hash-based inline ops */
2493 0           SvREFCNT_dec(ckobj);
2494 0           return 0;
2495 0           default:
2496 0           SvREFCNT_dec(ckobj);
2497 0           return 0;
2498             }
2499            
2500 2           return 1;
2501             #endif
2502             }
2503              
2504             /* Check if CV has inline op */
2505 2           XS_JIT_InlineType xs_jit_inline_get_type(pTHX_ CV* cv) {
2506             #if !PERL_VERSION_GE(5,14,0)
2507             PERL_UNUSED_ARG(cv);
2508             return XS_JIT_INLINE_NONE;
2509             #else
2510             MAGIC* mg;
2511            
2512 2 50         if (!cv) return XS_JIT_INLINE_NONE;
2513            
2514 2           mg = mg_find((SV*)cv, PERL_MAGIC_checkcall);
2515 2 50         if (!mg) return XS_JIT_INLINE_NONE;
2516            
2517             /* Check which checker function is registered */
2518 2 100         if (mg->mg_ptr == (char*)S_ck_xs_jit_get) {
2519 1           return XS_JIT_INLINE_GETTER;
2520 1 50         } else if (mg->mg_ptr == (char*)S_ck_xs_jit_set) {
2521 1           return XS_JIT_INLINE_SETTER;
2522             }
2523            
2524 0           return XS_JIT_INLINE_NONE;
2525             #endif
2526             }
2527              
2528             /* ============================================
2529             * Direct AvARRAY access (Meow-style fast slots)
2530             * ============================================ */
2531              
2532 1           void xs_jit_av_direct(pTHX_ XS_JIT_Builder* b, const char* result_var, const char* av_expr) {
2533 1           xs_jit_line(aTHX_ b, "SV** %s = AvARRAY(%s);", result_var, av_expr);
2534 1           }
2535              
2536 1           void xs_jit_av_slot_read(pTHX_ XS_JIT_Builder* b, const char* result_var,
2537             const char* slots_var, IV slot) {
2538 1           xs_jit_line(aTHX_ b, "SV* %s = %s[%ld] ? %s[%ld] : &PL_sv_undef;",
2539             result_var, slots_var, (long)slot, slots_var, (long)slot);
2540 1           }
2541              
2542 1           void xs_jit_av_slot_write(pTHX_ XS_JIT_Builder* b, const char* slots_var,
2543             IV slot, const char* value) {
2544 1           xs_jit_line(aTHX_ b, "SvREFCNT_dec(%s[%ld]);", slots_var, (long)slot);
2545 1           xs_jit_line(aTHX_ b, "%s[%ld] = SvREFCNT_inc(%s);", slots_var, (long)slot, value);
2546 1           }
2547              
2548             /* ============================================
2549             * Type checking helpers
2550             * ============================================ */
2551              
2552             /* Static buffer for type check expressions (non-reentrant but sufficient for code gen) */
2553             static char xs_jit_type_check_buf[256];
2554              
2555 1           const char* xs_jit_type_check_expr(pTHX_ XS_JIT_TypeCheck type,
2556             const char* sv, const char* classname) {
2557 1           switch (type) {
2558 0           case XS_JIT_TYPE_ANY:
2559 0           return "1";
2560 0           case XS_JIT_TYPE_DEFINED:
2561 0           snprintf(xs_jit_type_check_buf, sizeof(xs_jit_type_check_buf),
2562             "SvOK(%s)", sv);
2563 0           break;
2564 0           case XS_JIT_TYPE_INT:
2565 0           snprintf(xs_jit_type_check_buf, sizeof(xs_jit_type_check_buf),
2566             "SvIOK(%s)", sv);
2567 0           break;
2568 0           case XS_JIT_TYPE_NUM:
2569 0           snprintf(xs_jit_type_check_buf, sizeof(xs_jit_type_check_buf),
2570             "(SvNOK(%s) || SvIOK(%s))", sv, sv);
2571 0           break;
2572 0           case XS_JIT_TYPE_STR:
2573 0           snprintf(xs_jit_type_check_buf, sizeof(xs_jit_type_check_buf),
2574             "SvPOK(%s)", sv);
2575 0           break;
2576 0           case XS_JIT_TYPE_REF:
2577 0           snprintf(xs_jit_type_check_buf, sizeof(xs_jit_type_check_buf),
2578             "SvROK(%s)", sv);
2579 0           break;
2580 1           case XS_JIT_TYPE_ARRAYREF:
2581 1           snprintf(xs_jit_type_check_buf, sizeof(xs_jit_type_check_buf),
2582             "(SvROK(%s) && SvTYPE(SvRV(%s)) == SVt_PVAV)", sv, sv);
2583 1           break;
2584 0           case XS_JIT_TYPE_HASHREF:
2585 0           snprintf(xs_jit_type_check_buf, sizeof(xs_jit_type_check_buf),
2586             "(SvROK(%s) && SvTYPE(SvRV(%s)) == SVt_PVHV)", sv, sv);
2587 0           break;
2588 0           case XS_JIT_TYPE_CODEREF:
2589 0           snprintf(xs_jit_type_check_buf, sizeof(xs_jit_type_check_buf),
2590             "(SvROK(%s) && SvTYPE(SvRV(%s)) == SVt_PVCV)", sv, sv);
2591 0           break;
2592 0           case XS_JIT_TYPE_OBJECT:
2593 0           snprintf(xs_jit_type_check_buf, sizeof(xs_jit_type_check_buf),
2594             "sv_isobject(%s)", sv);
2595 0           break;
2596 0           case XS_JIT_TYPE_BLESSED:
2597 0 0         if (classname && *classname) {
    0          
2598 0           snprintf(xs_jit_type_check_buf, sizeof(xs_jit_type_check_buf),
2599             "sv_derived_from(%s, \"%s\")", sv, classname);
2600             } else {
2601 0           snprintf(xs_jit_type_check_buf, sizeof(xs_jit_type_check_buf),
2602             "sv_isobject(%s)", sv);
2603             }
2604 0           break;
2605 0           default:
2606 0           return "1";
2607             }
2608 1           return xs_jit_type_check_buf;
2609             }
2610              
2611 1           void xs_jit_check_value_type(pTHX_ XS_JIT_Builder* b, const char* sv,
2612             XS_JIT_TypeCheck type, const char* classname,
2613             const char* error_msg) {
2614 1           const char* check = xs_jit_type_check_expr(aTHX_ type, sv, classname);
2615             char cond[280];
2616 1           snprintf(cond, sizeof(cond), "!(%s)", check);
2617 1           xs_jit_if(aTHX_ b, cond);
2618 1           xs_jit_croak(aTHX_ b, error_msg);
2619 1           xs_jit_endif(aTHX_ b);
2620 1           }
2621              
2622             /* ============================================
2623             * Lazy initialization accessors
2624             * ============================================ */
2625              
2626 2           void xs_jit_lazy_init_dor(pTHX_ XS_JIT_Builder* b, const char* func_name,
2627             const char* attr_name, STRLEN attr_len,
2628             const char* default_expr, int is_mortal) {
2629 2           xs_jit_xs_function(aTHX_ b, func_name);
2630 2           xs_jit_line(aTHX_ b, "dXSARGS;");
2631 2           xs_jit_line(aTHX_ b, "PERL_UNUSED_VAR(cv); PERL_UNUSED_VAR(items);");
2632            
2633 2           xs_jit_line(aTHX_ b, "HV* hv = (HV*)SvRV(ST(0));");
2634 2           xs_jit_line(aTHX_ b, "SV** valp = hv_fetch(hv, \"%s\", %lu, 0);",
2635             attr_name, (unsigned long)attr_len);
2636 2           xs_jit_line(aTHX_ b, "SV* val = (valp && *valp) ? *valp : NULL;");
2637            
2638 2           xs_jit_if(aTHX_ b, "!val || !SvOK(val)");
2639 2 50         if (is_mortal) {
2640 0           xs_jit_line(aTHX_ b, "val = sv_2mortal(%s);", default_expr);
2641             } else {
2642 2           xs_jit_line(aTHX_ b, "val = %s;", default_expr);
2643             }
2644 2           xs_jit_line(aTHX_ b, "hv_store(hv, \"%s\", %lu, SvREFCNT_inc(val), 0);",
2645             attr_name, (unsigned long)attr_len);
2646 2           xs_jit_endif(aTHX_ b);
2647            
2648 2           xs_jit_line(aTHX_ b, "ST(0) = val;");
2649 2           xs_jit_line(aTHX_ b, "XSRETURN(1);");
2650            
2651 2           xs_jit_xs_end(aTHX_ b);
2652 2           }
2653              
2654 1           void xs_jit_lazy_init_or(pTHX_ XS_JIT_Builder* b, const char* func_name,
2655             const char* attr_name, STRLEN attr_len,
2656             const char* default_expr, int is_mortal) {
2657 1           xs_jit_xs_function(aTHX_ b, func_name);
2658 1           xs_jit_line(aTHX_ b, "dXSARGS;");
2659 1           xs_jit_line(aTHX_ b, "PERL_UNUSED_VAR(cv); PERL_UNUSED_VAR(items);");
2660            
2661 1           xs_jit_line(aTHX_ b, "HV* hv = (HV*)SvRV(ST(0));");
2662 1           xs_jit_line(aTHX_ b, "SV** valp = hv_fetch(hv, \"%s\", %lu, 0);",
2663             attr_name, (unsigned long)attr_len);
2664 1           xs_jit_line(aTHX_ b, "SV* val = (valp && *valp) ? *valp : NULL;");
2665            
2666 1           xs_jit_if(aTHX_ b, "!val || !SvTRUE(val)");
2667 1 50         if (is_mortal) {
2668 0           xs_jit_line(aTHX_ b, "val = sv_2mortal(%s);", default_expr);
2669             } else {
2670 1           xs_jit_line(aTHX_ b, "val = %s;", default_expr);
2671             }
2672 1           xs_jit_line(aTHX_ b, "hv_store(hv, \"%s\", %lu, SvREFCNT_inc(val), 0);",
2673             attr_name, (unsigned long)attr_len);
2674 1           xs_jit_endif(aTHX_ b);
2675            
2676 1           xs_jit_line(aTHX_ b, "ST(0) = val;");
2677 1           xs_jit_line(aTHX_ b, "XSRETURN(1);");
2678            
2679 1           xs_jit_xs_end(aTHX_ b);
2680 1           }
2681              
2682 1           void xs_jit_slot_lazy_init_dor(pTHX_ XS_JIT_Builder* b, const char* func_name,
2683             IV slot, const char* default_expr, int is_mortal) {
2684 1           xs_jit_xs_function(aTHX_ b, func_name);
2685 1           xs_jit_line(aTHX_ b, "dXSARGS;");
2686 1           xs_jit_line(aTHX_ b, "PERL_UNUSED_VAR(cv); PERL_UNUSED_VAR(items);");
2687            
2688 1           xs_jit_line(aTHX_ b, "AV* av = (AV*)SvRV(ST(0));");
2689 1           xs_jit_line(aTHX_ b, "SV** ary = AvARRAY(av);");
2690 1           xs_jit_line(aTHX_ b, "SV* val = ary[%ld];", (long)slot);
2691            
2692 1           xs_jit_if(aTHX_ b, "!val || !SvOK(val)");
2693 1 50         if (is_mortal) {
2694 0           xs_jit_line(aTHX_ b, "val = sv_2mortal(%s);", default_expr);
2695             } else {
2696 1           xs_jit_line(aTHX_ b, "val = %s;", default_expr);
2697             }
2698 1           xs_jit_line(aTHX_ b, "ary[%ld] = SvREFCNT_inc(val);", (long)slot);
2699 1           xs_jit_endif(aTHX_ b);
2700            
2701 1           xs_jit_line(aTHX_ b, "ST(0) = val;");
2702 1           xs_jit_line(aTHX_ b, "XSRETURN(1);");
2703            
2704 1           xs_jit_xs_end(aTHX_ b);
2705 1           }
2706              
2707 0           void xs_jit_slot_lazy_init_or(pTHX_ XS_JIT_Builder* b, const char* func_name,
2708             IV slot, const char* default_expr, int is_mortal) {
2709 0           xs_jit_xs_function(aTHX_ b, func_name);
2710 0           xs_jit_line(aTHX_ b, "dXSARGS;");
2711 0           xs_jit_line(aTHX_ b, "PERL_UNUSED_VAR(cv); PERL_UNUSED_VAR(items);");
2712            
2713 0           xs_jit_line(aTHX_ b, "AV* av = (AV*)SvRV(ST(0));");
2714 0           xs_jit_line(aTHX_ b, "SV** ary = AvARRAY(av);");
2715 0           xs_jit_line(aTHX_ b, "SV* val = ary[%ld];", (long)slot);
2716            
2717 0           xs_jit_if(aTHX_ b, "!val || !SvTRUE(val)");
2718 0 0         if (is_mortal) {
2719 0           xs_jit_line(aTHX_ b, "val = sv_2mortal(%s);", default_expr);
2720             } else {
2721 0           xs_jit_line(aTHX_ b, "val = %s;", default_expr);
2722             }
2723 0           xs_jit_line(aTHX_ b, "ary[%ld] = SvREFCNT_inc(val);", (long)slot);
2724 0           xs_jit_endif(aTHX_ b);
2725            
2726 0           xs_jit_line(aTHX_ b, "ST(0) = val;");
2727 0           xs_jit_line(aTHX_ b, "XSRETURN(1);");
2728            
2729 0           xs_jit_xs_end(aTHX_ b);
2730 0           }
2731              
2732             /* ============================================
2733             * Setter chain patterns
2734             * ============================================ */
2735              
2736 3           void xs_jit_setter_chain(pTHX_ XS_JIT_Builder* b, const char* func_name,
2737             const char* attr_name, STRLEN attr_len) {
2738 3           xs_jit_xs_function(aTHX_ b, func_name);
2739 3           xs_jit_line(aTHX_ b, "dXSARGS;");
2740 3           xs_jit_line(aTHX_ b, "PERL_UNUSED_VAR(cv);");
2741            
2742 3           xs_jit_if(aTHX_ b, "items < 2");
2743 3           xs_jit_croak(aTHX_ b, "Usage: $self->%s($value)");
2744 3           xs_jit_endif(aTHX_ b);
2745            
2746 3           xs_jit_line(aTHX_ b, "SV* self = ST(0);");
2747 3           xs_jit_line(aTHX_ b, "HV* hv = (HV*)SvRV(self);");
2748 3           xs_jit_line(aTHX_ b, "SV* val = newSVsv(ST(1));");
2749 3           xs_jit_line(aTHX_ b, "hv_store(hv, \"%s\", %lu, val, 0);",
2750             attr_name, (unsigned long)attr_len);
2751 3           xs_jit_line(aTHX_ b, "ST(0) = self;");
2752 3           xs_jit_line(aTHX_ b, "XSRETURN(1);");
2753            
2754 3           xs_jit_xs_end(aTHX_ b);
2755 3           }
2756              
2757 0           void xs_jit_slot_setter_chain(pTHX_ XS_JIT_Builder* b, const char* func_name, IV slot) {
2758 0           xs_jit_xs_function(aTHX_ b, func_name);
2759 0           xs_jit_line(aTHX_ b, "dXSARGS;");
2760 0           xs_jit_line(aTHX_ b, "PERL_UNUSED_VAR(cv);");
2761            
2762 0           xs_jit_if(aTHX_ b, "items < 2");
2763 0           xs_jit_croak(aTHX_ b, "Usage: $self->setter($value)");
2764 0           xs_jit_endif(aTHX_ b);
2765            
2766 0           xs_jit_line(aTHX_ b, "SV* self = ST(0);");
2767 0           xs_jit_line(aTHX_ b, "AV* av = (AV*)SvRV(self);");
2768 0           xs_jit_line(aTHX_ b, "SV* val = newSVsv(ST(1));");
2769 0           xs_jit_line(aTHX_ b, "av_store(av, %ld, val);", (long)slot);
2770 0           xs_jit_line(aTHX_ b, "ST(0) = self;");
2771 0           xs_jit_line(aTHX_ b, "XSRETURN(1);");
2772            
2773 0           xs_jit_xs_end(aTHX_ b);
2774 0           }
2775              
2776 2           void xs_jit_setter_return_value(pTHX_ XS_JIT_Builder* b, const char* func_name,
2777             const char* attr_name, STRLEN attr_len) {
2778 2           xs_jit_xs_function(aTHX_ b, func_name);
2779 2           xs_jit_line(aTHX_ b, "dXSARGS;");
2780 2           xs_jit_line(aTHX_ b, "PERL_UNUSED_VAR(cv);");
2781            
2782 2           xs_jit_if(aTHX_ b, "items < 2");
2783 2           xs_jit_croak(aTHX_ b, "Usage: $self->%s($value)");
2784 2           xs_jit_endif(aTHX_ b);
2785            
2786 2           xs_jit_line(aTHX_ b, "HV* hv = (HV*)SvRV(ST(0));");
2787 2           xs_jit_line(aTHX_ b, "SV* val = newSVsv(ST(1));");
2788 2           xs_jit_line(aTHX_ b, "hv_store(hv, \"%s\", %lu, val, 0);",
2789             attr_name, (unsigned long)attr_len);
2790 2           xs_jit_line(aTHX_ b, "ST(0) = val;");
2791 2           xs_jit_line(aTHX_ b, "XSRETURN(1);");
2792            
2793 2           xs_jit_xs_end(aTHX_ b);
2794 2           }
2795              
2796             /* ============================================
2797             * Array attribute operations
2798             * ============================================ */
2799              
2800 2           void xs_jit_attr_push(pTHX_ XS_JIT_Builder* b, const char* func_name,
2801             const char* attr_name, STRLEN attr_len) {
2802 2           xs_jit_xs_function(aTHX_ b, func_name);
2803 2           xs_jit_xs_preamble(aTHX_ b);
2804 2           xs_jit_get_self_hv(aTHX_ b);
2805            
2806 2           xs_jit_hv_fetch(aTHX_ b, "hv", attr_name, attr_len, "aref");
2807 2           xs_jit_if(aTHX_ b, "!aref || !SvROK(*aref) || SvTYPE(SvRV(*aref)) != SVt_PVAV");
2808 2           xs_jit_croak(aTHX_ b, "Attribute is not an arrayref");
2809 2           xs_jit_endif(aTHX_ b);
2810            
2811 2           xs_jit_line(aTHX_ b, "AV* av = (AV*)SvRV(*aref);");
2812 2           xs_jit_line(aTHX_ b, "I32 i;");
2813 2           xs_jit_line(aTHX_ b, "for (i = 1; i < items; i++) {");
2814 2           b->indent++;
2815 2           xs_jit_line(aTHX_ b, "av_push(av, newSVsv(ST(i)));");
2816 2           b->indent--;
2817 2           xs_jit_line(aTHX_ b, "}");
2818            
2819 2           xs_jit_return_iv(aTHX_ b, "av_len(av) + 1");
2820 2           xs_jit_xs_end(aTHX_ b);
2821 2           }
2822              
2823 2           void xs_jit_attr_pop(pTHX_ XS_JIT_Builder* b, const char* func_name,
2824             const char* attr_name, STRLEN attr_len) {
2825 2           xs_jit_xs_function(aTHX_ b, func_name);
2826 2           xs_jit_xs_preamble(aTHX_ b);
2827 2           xs_jit_get_self_hv(aTHX_ b);
2828            
2829 2           xs_jit_hv_fetch(aTHX_ b, "hv", attr_name, attr_len, "aref");
2830 2           xs_jit_if(aTHX_ b, "!aref || !SvROK(*aref) || SvTYPE(SvRV(*aref)) != SVt_PVAV");
2831 2           xs_jit_croak(aTHX_ b, "Attribute is not an arrayref");
2832 2           xs_jit_endif(aTHX_ b);
2833            
2834 2           xs_jit_line(aTHX_ b, "AV* av = (AV*)SvRV(*aref);");
2835 2           xs_jit_line(aTHX_ b, "SV* val = av_pop(av);");
2836 2           xs_jit_line(aTHX_ b, "ST(0) = val ? sv_2mortal(val) : &PL_sv_undef;");
2837 2           xs_jit_xs_return(aTHX_ b, 1);
2838            
2839 2           xs_jit_xs_end(aTHX_ b);
2840 2           }
2841              
2842 1           void xs_jit_attr_shift(pTHX_ XS_JIT_Builder* b, const char* func_name,
2843             const char* attr_name, STRLEN attr_len) {
2844 1           xs_jit_xs_function(aTHX_ b, func_name);
2845 1           xs_jit_xs_preamble(aTHX_ b);
2846 1           xs_jit_get_self_hv(aTHX_ b);
2847            
2848 1           xs_jit_hv_fetch(aTHX_ b, "hv", attr_name, attr_len, "aref");
2849 1           xs_jit_if(aTHX_ b, "!aref || !SvROK(*aref) || SvTYPE(SvRV(*aref)) != SVt_PVAV");
2850 1           xs_jit_croak(aTHX_ b, "Attribute is not an arrayref");
2851 1           xs_jit_endif(aTHX_ b);
2852            
2853 1           xs_jit_line(aTHX_ b, "AV* av = (AV*)SvRV(*aref);");
2854 1           xs_jit_line(aTHX_ b, "SV* val = av_shift(av);");
2855 1           xs_jit_line(aTHX_ b, "ST(0) = val ? sv_2mortal(val) : &PL_sv_undef;");
2856 1           xs_jit_xs_return(aTHX_ b, 1);
2857            
2858 1           xs_jit_xs_end(aTHX_ b);
2859 1           }
2860              
2861 1           void xs_jit_attr_unshift(pTHX_ XS_JIT_Builder* b, const char* func_name,
2862             const char* attr_name, STRLEN attr_len) {
2863 1           xs_jit_xs_function(aTHX_ b, func_name);
2864 1           xs_jit_xs_preamble(aTHX_ b);
2865 1           xs_jit_get_self_hv(aTHX_ b);
2866            
2867 1           xs_jit_hv_fetch(aTHX_ b, "hv", attr_name, attr_len, "aref");
2868 1           xs_jit_if(aTHX_ b, "!aref || !SvROK(*aref) || SvTYPE(SvRV(*aref)) != SVt_PVAV");
2869 1           xs_jit_croak(aTHX_ b, "Attribute is not an arrayref");
2870 1           xs_jit_endif(aTHX_ b);
2871            
2872 1           xs_jit_line(aTHX_ b, "AV* av = (AV*)SvRV(*aref);");
2873 1           xs_jit_line(aTHX_ b, "I32 i;");
2874 1           xs_jit_line(aTHX_ b, "av_unshift(av, items - 1);");
2875 1           xs_jit_line(aTHX_ b, "for (i = 1; i < items; i++) {");
2876 1           b->indent++;
2877 1           xs_jit_line(aTHX_ b, "av_store(av, i - 1, newSVsv(ST(i)));");
2878 1           b->indent--;
2879 1           xs_jit_line(aTHX_ b, "}");
2880            
2881 1           xs_jit_return_iv(aTHX_ b, "av_len(av) + 1");
2882 1           xs_jit_xs_end(aTHX_ b);
2883 1           }
2884              
2885 2           void xs_jit_attr_count(pTHX_ XS_JIT_Builder* b, const char* func_name,
2886             const char* attr_name, STRLEN attr_len) {
2887 2           xs_jit_xs_function(aTHX_ b, func_name);
2888 2           xs_jit_xs_preamble(aTHX_ b);
2889 2           xs_jit_get_self_hv(aTHX_ b);
2890            
2891 2           xs_jit_hv_fetch(aTHX_ b, "hv", attr_name, attr_len, "aref");
2892 2           xs_jit_if(aTHX_ b, "!aref || !SvROK(*aref) || SvTYPE(SvRV(*aref)) != SVt_PVAV");
2893 2           xs_jit_return_iv(aTHX_ b, "0");
2894 2           xs_jit_endif(aTHX_ b);
2895            
2896 2           xs_jit_line(aTHX_ b, "AV* av = (AV*)SvRV(*aref);");
2897 2           xs_jit_return_iv(aTHX_ b, "av_len(av) + 1");
2898            
2899 2           xs_jit_xs_end(aTHX_ b);
2900 2           }
2901              
2902 1           void xs_jit_attr_clear(pTHX_ XS_JIT_Builder* b, const char* func_name,
2903             const char* attr_name, STRLEN attr_len) {
2904 1           xs_jit_xs_function(aTHX_ b, func_name);
2905 1           xs_jit_xs_preamble(aTHX_ b);
2906 1           xs_jit_get_self_hv(aTHX_ b);
2907            
2908 1           xs_jit_hv_fetch(aTHX_ b, "hv", attr_name, attr_len, "aref");
2909 1           xs_jit_if(aTHX_ b, "aref && SvROK(*aref) && SvTYPE(SvRV(*aref)) == SVt_PVAV");
2910 1           xs_jit_line(aTHX_ b, "av_clear((AV*)SvRV(*aref));");
2911 1           xs_jit_endif(aTHX_ b);
2912            
2913 1           xs_jit_return_self(aTHX_ b);
2914 1           xs_jit_xs_end(aTHX_ b);
2915 1           }
2916              
2917             /* ============================================
2918             * Hash attribute operations
2919             * ============================================ */
2920              
2921 2           void xs_jit_attr_keys(pTHX_ XS_JIT_Builder* b, const char* func_name,
2922             const char* attr_name, STRLEN attr_len) {
2923 2           xs_jit_xs_function(aTHX_ b, func_name);
2924 2           xs_jit_xs_preamble(aTHX_ b);
2925 2           xs_jit_get_self_hv(aTHX_ b);
2926            
2927 2           xs_jit_hv_fetch(aTHX_ b, "hv", attr_name, attr_len, "href");
2928 2           xs_jit_if(aTHX_ b, "!href || !SvROK(*href) || SvTYPE(SvRV(*href)) != SVt_PVHV");
2929 2           xs_jit_xs_return(aTHX_ b, 0);
2930 2           xs_jit_endif(aTHX_ b);
2931            
2932 2           xs_jit_line(aTHX_ b, "HV* ahv = (HV*)SvRV(*href);");
2933 2           xs_jit_line(aTHX_ b, "I32 key_count = HvUSEDKEYS(ahv);");
2934 2           xs_jit_line(aTHX_ b, "I32 count = 0;");
2935 2           xs_jit_line(aTHX_ b, "EXTEND(SP, key_count);"); /* Fix: extend stack before writing */
2936 2           xs_jit_line(aTHX_ b, "hv_iterinit(ahv);");
2937 2           xs_jit_line(aTHX_ b, "HE* entry;");
2938 2           xs_jit_line(aTHX_ b, "while ((entry = hv_iternext(ahv))) {");
2939 2           b->indent++;
2940 2           xs_jit_line(aTHX_ b, "XST_mPV(count, HePV(entry, PL_na));");
2941 2           xs_jit_line(aTHX_ b, "count++;");
2942 2           b->indent--;
2943 2           xs_jit_line(aTHX_ b, "}");
2944 2           xs_jit_line(aTHX_ b, "XSRETURN(count);");
2945              
2946 2           xs_jit_xs_end(aTHX_ b);
2947 2           }
2948              
2949 1           void xs_jit_attr_values(pTHX_ XS_JIT_Builder* b, const char* func_name,
2950             const char* attr_name, STRLEN attr_len) {
2951 1           xs_jit_xs_function(aTHX_ b, func_name);
2952 1           xs_jit_xs_preamble(aTHX_ b);
2953 1           xs_jit_get_self_hv(aTHX_ b);
2954              
2955 1           xs_jit_hv_fetch(aTHX_ b, "hv", attr_name, attr_len, "href");
2956 1           xs_jit_if(aTHX_ b, "!href || !SvROK(*href) || SvTYPE(SvRV(*href)) != SVt_PVHV");
2957 1           xs_jit_xs_return(aTHX_ b, 0);
2958 1           xs_jit_endif(aTHX_ b);
2959              
2960 1           xs_jit_line(aTHX_ b, "HV* ahv = (HV*)SvRV(*href);");
2961 1           xs_jit_line(aTHX_ b, "I32 key_count = HvUSEDKEYS(ahv);");
2962 1           xs_jit_line(aTHX_ b, "I32 count = 0;");
2963 1           xs_jit_line(aTHX_ b, "EXTEND(SP, key_count);"); /* Fix: extend stack before writing */
2964 1           xs_jit_line(aTHX_ b, "hv_iterinit(ahv);");
2965 1           xs_jit_line(aTHX_ b, "HE* entry;");
2966 1           xs_jit_line(aTHX_ b, "while ((entry = hv_iternext(ahv))) {");
2967 1           b->indent++;
2968 1           xs_jit_line(aTHX_ b, "ST(count) = HeVAL(entry);");
2969 1           xs_jit_line(aTHX_ b, "count++;");
2970 1           b->indent--;
2971 1           xs_jit_line(aTHX_ b, "}");
2972 1           xs_jit_line(aTHX_ b, "XSRETURN(count);");
2973              
2974 1           xs_jit_xs_end(aTHX_ b);
2975 1           }
2976              
2977 2           void xs_jit_attr_delete(pTHX_ XS_JIT_Builder* b, const char* func_name,
2978             const char* attr_name, STRLEN attr_len) {
2979 2           xs_jit_xs_function(aTHX_ b, func_name);
2980 2           xs_jit_xs_preamble(aTHX_ b);
2981            
2982 2           xs_jit_check_items(aTHX_ b, 2, 2, "$self->delete($key)");
2983 2           xs_jit_get_self_hv(aTHX_ b);
2984            
2985 2           xs_jit_hv_fetch(aTHX_ b, "hv", attr_name, attr_len, "href");
2986 2           xs_jit_if(aTHX_ b, "!href || !SvROK(*href) || SvTYPE(SvRV(*href)) != SVt_PVHV");
2987 2           xs_jit_xs_return_undef(aTHX_ b);
2988 2           xs_jit_endif(aTHX_ b);
2989            
2990 2           xs_jit_line(aTHX_ b, "HV* ahv = (HV*)SvRV(*href);");
2991 2           xs_jit_line(aTHX_ b, "STRLEN klen;");
2992 2           xs_jit_line(aTHX_ b, "const char* key = SvPV(ST(1), klen);");
2993 2           xs_jit_line(aTHX_ b, "SV* deleted = hv_delete(ahv, key, klen, 0);");
2994 2           xs_jit_line(aTHX_ b, "ST(0) = deleted ? deleted : &PL_sv_undef;");
2995 2           xs_jit_xs_return(aTHX_ b, 1);
2996            
2997 2           xs_jit_xs_end(aTHX_ b);
2998 2           }
2999              
3000 2           void xs_jit_attr_hash_clear(pTHX_ XS_JIT_Builder* b, const char* func_name,
3001             const char* attr_name, STRLEN attr_len) {
3002 2           xs_jit_xs_function(aTHX_ b, func_name);
3003 2           xs_jit_xs_preamble(aTHX_ b);
3004 2           xs_jit_get_self_hv(aTHX_ b);
3005              
3006 2           xs_jit_hv_fetch(aTHX_ b, "hv", attr_name, attr_len, "href");
3007 2           xs_jit_if(aTHX_ b, "href && SvROK(*href) && SvTYPE(SvRV(*href)) == SVt_PVHV");
3008 2           xs_jit_line(aTHX_ b, "hv_clear((HV*)SvRV(*href));");
3009 2           xs_jit_endif(aTHX_ b);
3010              
3011 2           xs_jit_return_self(aTHX_ b);
3012 2           xs_jit_xs_end(aTHX_ b);
3013 2           }
3014              
3015             /* ============================================
3016             * Conditional DSL (Struct::Conditional format)
3017             * ============================================ */
3018              
3019             /* Build C condition string from a clause */
3020 65           static SV* xs_jit_build_condition(pTHX_ XS_JIT_Clause* clause) {
3021 65           SV* cond = newSVpvs("");
3022 65           const char* key = clause->key;
3023 65           const char* val = clause->expr_value;
3024              
3025 65           switch (clause->expr_type) {
3026 0           case XS_JIT_EXPR_NONE:
3027 0           sv_catpvs(cond, "1"); /* always true */
3028 0           break;
3029 13           case XS_JIT_EXPR_GT:
3030 13           sv_catpvf(cond, "SvIV(%s) > %s", key, val);
3031 13           break;
3032 12           case XS_JIT_EXPR_LT:
3033 12           sv_catpvf(cond, "SvIV(%s) < %s", key, val);
3034 12           break;
3035 4           case XS_JIT_EXPR_GTE:
3036 4           sv_catpvf(cond, "SvIV(%s) >= %s", key, val);
3037 4           break;
3038 0           case XS_JIT_EXPR_LTE:
3039 0           sv_catpvf(cond, "SvIV(%s) <= %s", key, val);
3040 0           break;
3041 30           case XS_JIT_EXPR_EQ:
3042 30           sv_catpvf(cond, "strEQ(SvPV_nolen(%s), \"%s\")", key, val);
3043 30           break;
3044 1           case XS_JIT_EXPR_NE:
3045 1           sv_catpvf(cond, "!strEQ(SvPV_nolen(%s), \"%s\")", key, val);
3046 1           break;
3047 2           case XS_JIT_EXPR_M:
3048             /* For simple substring match, use strstr */
3049 2           sv_catpvf(cond, "strstr(SvPV_nolen(%s), \"%s\") != NULL", key, val);
3050 2           break;
3051 0           case XS_JIT_EXPR_IM:
3052             /* Case-insensitive: use strcasestr if available, or manual loop */
3053 0           sv_catpvf(cond, "strcasestr(SvPV_nolen(%s), \"%s\") != NULL", key, val);
3054 0           break;
3055 0           case XS_JIT_EXPR_NM:
3056 0           sv_catpvf(cond, "strstr(SvPV_nolen(%s), \"%s\") == NULL", key, val);
3057 0           break;
3058 0           case XS_JIT_EXPR_INM:
3059 0           sv_catpvf(cond, "strcasestr(SvPV_nolen(%s), \"%s\") == NULL", key, val);
3060 0           break;
3061 2           case XS_JIT_EXPR_EXISTS:
3062 2           sv_catpvf(cond, "SvOK(%s)", key);
3063 2           break;
3064 1           case XS_JIT_EXPR_TRUE:
3065 1           sv_catpvf(cond, "SvTRUE(%s)", key);
3066 1           break;
3067             }
3068              
3069             /* Handle AND chaining */
3070 65 100         if (clause->and_clause) {
3071 15           SV* and_cond = xs_jit_build_condition(aTHX_ clause->and_clause);
3072 15           sv_catpvf(cond, " && (%s)", SvPV_nolen(and_cond));
3073 15           SvREFCNT_dec(and_cond);
3074             }
3075              
3076             /* Handle OR chaining */
3077 65 100         if (clause->or_clause) {
3078 6           SV* or_cond = xs_jit_build_condition(aTHX_ clause->or_clause);
3079 6           sv_catpvf(cond, " || (%s)", SvPV_nolen(or_cond));
3080 6           SvREFCNT_dec(or_cond);
3081             }
3082              
3083 65           return cond;
3084             }
3085              
3086             /* Emit actions for a then block */
3087 146           static void xs_jit_emit_actions(pTHX_ XS_JIT_Builder* b,
3088             XS_JIT_Action* actions, int num) {
3089             int i;
3090 294 100         for (i = 0; i < num; i++) {
3091 148           switch (actions[i].type) {
3092 28           case XS_JIT_ACTION_LINE:
3093 28           xs_jit_line(aTHX_ b, "%s", actions[i].value);
3094 28           break;
3095 60           case XS_JIT_ACTION_RETURN_IV:
3096 60           xs_jit_line(aTHX_ b, "XSRETURN_IV(%s);", actions[i].value);
3097 60           break;
3098 4           case XS_JIT_ACTION_RETURN_NV:
3099 4           xs_jit_line(aTHX_ b, "ST(0) = sv_2mortal(newSVnv(%s)); XSRETURN(1);", actions[i].value);
3100 4           break;
3101 55           case XS_JIT_ACTION_RETURN_PV:
3102 55           xs_jit_line(aTHX_ b, "XSRETURN_PV(%s);", actions[i].value);
3103 55           break;
3104 0           case XS_JIT_ACTION_RETURN_SV:
3105 0           xs_jit_return_sv(aTHX_ b, actions[i].value);
3106 0           break;
3107 1           case XS_JIT_ACTION_CROAK:
3108 1           xs_jit_croak(aTHX_ b, actions[i].value);
3109 1           break;
3110             }
3111             }
3112 146           }
3113              
3114             /* Main conditional generator */
3115 26           void xs_jit_conditional(pTHX_ XS_JIT_Builder* b, XS_JIT_Conditional* cond) {
3116             int i;
3117              
3118 26 50         if (!cond || !cond->if_clause) {
    50          
3119 0           return;
3120             }
3121              
3122             /* Generate if clause */
3123 26           SV* if_cond = xs_jit_build_condition(aTHX_ cond->if_clause);
3124 26           xs_jit_if(aTHX_ b, SvPV_nolen(if_cond));
3125 26           SvREFCNT_dec(if_cond);
3126              
3127 26           xs_jit_emit_actions(aTHX_ b, cond->if_clause->actions,
3128 26           cond->if_clause->num_actions);
3129              
3130             /* Generate elsif clauses */
3131 34 100         for (i = 0; i < cond->num_elsif; i++) {
3132 8           SV* elsif_cond = xs_jit_build_condition(aTHX_ cond->elsif_clauses[i]);
3133 8           xs_jit_elsif(aTHX_ b, SvPV_nolen(elsif_cond));
3134 8           SvREFCNT_dec(elsif_cond);
3135              
3136 8           xs_jit_emit_actions(aTHX_ b, cond->elsif_clauses[i]->actions,
3137 8           cond->elsif_clauses[i]->num_actions);
3138             }
3139              
3140             /* Generate else clause */
3141 26 100         if (cond->num_else_actions > 0) {
3142 9           xs_jit_else(aTHX_ b);
3143 9           xs_jit_emit_actions(aTHX_ b, cond->else_actions,
3144             cond->num_else_actions);
3145             }
3146              
3147 26           xs_jit_endif(aTHX_ b);
3148             }
3149              
3150             /* Given/when generator (generates if-elsif chain) */
3151 3           void xs_jit_given(pTHX_ XS_JIT_Builder* b, XS_JIT_Given* given) {
3152             int i;
3153              
3154 3 50         if (!given || given->num_when == 0) {
    50          
3155             /* No when clauses, just emit default if present */
3156 0 0         if (given && given->num_default_actions > 0) {
    0          
3157 0           xs_jit_emit_actions(aTHX_ b, given->default_actions,
3158             given->num_default_actions);
3159             }
3160 0           return;
3161             }
3162              
3163 11 100         for (i = 0; i < given->num_when; i++) {
3164 8           XS_JIT_Clause* when = given->when_clauses[i];
3165              
3166             /* Inherit key from given if not set on when clause */
3167 8 100         if (!when->key && given->key) {
    50          
3168 2           when->key = given->key;
3169             }
3170              
3171 8           SV* cond = xs_jit_build_condition(aTHX_ when);
3172              
3173 8 100         if (i == 0) {
3174 3           xs_jit_if(aTHX_ b, SvPV_nolen(cond));
3175             } else {
3176 5           xs_jit_elsif(aTHX_ b, SvPV_nolen(cond));
3177             }
3178 8           SvREFCNT_dec(cond);
3179              
3180 8           xs_jit_emit_actions(aTHX_ b, when->actions, when->num_actions);
3181             }
3182              
3183             /* Default clause becomes else */
3184 3 50         if (given->num_default_actions > 0) {
3185 3           xs_jit_else(aTHX_ b);
3186 3           xs_jit_emit_actions(aTHX_ b, given->default_actions,
3187             given->num_default_actions);
3188             }
3189              
3190 3           xs_jit_endif(aTHX_ b);
3191             }
3192              
3193             /* ============================================
3194             * Conditional DSL parsing helpers
3195             * ============================================ */
3196              
3197             /* Parse actions from 'then' value - can be hashref or arrayref */
3198 150           XS_JIT_Action* xs_jit_parse_actions(pTHX_ SV* then_sv, int* num_actions) {
3199 150           XS_JIT_Action* actions = NULL;
3200 150           int count = 0;
3201              
3202 150 50         if (!then_sv || !SvOK(then_sv)) {
    50          
3203 0           *num_actions = 0;
3204 0           return NULL;
3205             }
3206              
3207 298 50         if (SvROK(then_sv) && SvTYPE(SvRV(then_sv)) == SVt_PVHV) {
    100          
3208             /* Single action hashref: { line => '...' } or { return_iv => 42 } */
3209 148           HV* then_hv = (HV*)SvRV(then_sv);
3210             SV** val;
3211              
3212             /* Allocate for single action */
3213 148           Newxz(actions, 1, XS_JIT_Action);
3214 148           count = 1;
3215              
3216 148 100         if ((val = hv_fetchs(then_hv, "line", 0)) && SvOK(*val)) {
    50          
3217 28           actions[0].type = XS_JIT_ACTION_LINE;
3218 28           actions[0].value = SvPV(*val, actions[0].value_len);
3219             }
3220 120 100         else if ((val = hv_fetchs(then_hv, "return_iv", 0)) && SvOK(*val)) {
    50          
3221 60           actions[0].type = XS_JIT_ACTION_RETURN_IV;
3222 60           actions[0].value = SvPV(*val, actions[0].value_len);
3223             }
3224 60 100         else if ((val = hv_fetchs(then_hv, "return_nv", 0)) && SvOK(*val)) {
    50          
3225 4           actions[0].type = XS_JIT_ACTION_RETURN_NV;
3226 4           actions[0].value = SvPV(*val, actions[0].value_len);
3227             }
3228 56 100         else if ((val = hv_fetchs(then_hv, "return_pv", 0)) && SvOK(*val)) {
    50          
3229 55           actions[0].type = XS_JIT_ACTION_RETURN_PV;
3230 55           actions[0].value = SvPV(*val, actions[0].value_len);
3231             }
3232 1 50         else if ((val = hv_fetchs(then_hv, "return_sv", 0)) && SvOK(*val)) {
    0          
3233 0           actions[0].type = XS_JIT_ACTION_RETURN_SV;
3234 0           actions[0].value = SvPV(*val, actions[0].value_len);
3235             }
3236 1 50         else if ((val = hv_fetchs(then_hv, "croak", 0)) && SvOK(*val)) {
    50          
3237 1           actions[0].type = XS_JIT_ACTION_CROAK;
3238 1           actions[0].value = SvPV(*val, actions[0].value_len);
3239             }
3240             else {
3241             /* No recognized action, free and return NULL */
3242 0           Safefree(actions);
3243 0           actions = NULL;
3244 0           count = 0;
3245             }
3246             }
3247 2 50         else if (SvROK(then_sv) && SvTYPE(SvRV(then_sv)) == SVt_PVAV) {
    50          
3248             /* Array of actions: [ { line => '...' }, { line => '...' } ] */
3249 2           AV* then_av = (AV*)SvRV(then_sv);
3250 2           I32 len = av_len(then_av) + 1;
3251             int i;
3252              
3253 2 50         if (len > 0) {
3254 2           Newxz(actions, len, XS_JIT_Action);
3255              
3256 6 100         for (i = 0; i < len; i++) {
3257 4           SV** elem = av_fetch(then_av, i, 0);
3258 4 50         if (elem && SvOK(*elem)) {
    50          
3259             int sub_count;
3260 4           XS_JIT_Action* sub_actions = xs_jit_parse_actions(aTHX_ *elem, &sub_count);
3261 4 50         if (sub_actions && sub_count > 0) {
    50          
3262 4           actions[count] = sub_actions[0];
3263 4           count++;
3264 4           Safefree(sub_actions);
3265             }
3266             }
3267             }
3268             }
3269             }
3270              
3271 150           *num_actions = count;
3272 150           return actions;
3273             }
3274              
3275             /* Parse a clause hashref into XS_JIT_Clause */
3276 131           XS_JIT_Clause* xs_jit_parse_clause(pTHX_ HV* clause_hv) {
3277             XS_JIT_Clause* clause;
3278             SV** val;
3279              
3280 131 50         if (!clause_hv) {
3281 0           return NULL;
3282             }
3283              
3284 131           Newxz(clause, 1, XS_JIT_Clause);
3285              
3286             /* Get key (C variable name) */
3287 131 100         if ((val = hv_fetchs(clause_hv, "key", 0)) && SvOK(*val)) {
    50          
3288 55           clause->key = SvPV_nolen(*val);
3289             }
3290              
3291             /* Determine expression type and value */
3292 131           clause->expr_type = XS_JIT_EXPR_NONE;
3293              
3294 131 100         if ((val = hv_fetchs(clause_hv, "gt", 0)) && SvOK(*val)) {
    50          
3295 16           clause->expr_type = XS_JIT_EXPR_GT;
3296 16           clause->expr_value = SvPV(*val, clause->expr_value_len);
3297             }
3298 115 100         else if ((val = hv_fetchs(clause_hv, "lt", 0)) && SvOK(*val)) {
    50          
3299 16           clause->expr_type = XS_JIT_EXPR_LT;
3300 16           clause->expr_value = SvPV(*val, clause->expr_value_len);
3301             }
3302 99 100         else if ((val = hv_fetchs(clause_hv, "gte", 0)) && SvOK(*val)) {
    50          
3303 8           clause->expr_type = XS_JIT_EXPR_GTE;
3304 8           clause->expr_value = SvPV(*val, clause->expr_value_len);
3305             }
3306 91 50         else if ((val = hv_fetchs(clause_hv, "lte", 0)) && SvOK(*val)) {
    0          
3307 0           clause->expr_type = XS_JIT_EXPR_LTE;
3308 0           clause->expr_value = SvPV(*val, clause->expr_value_len);
3309             }
3310 91 100         else if ((val = hv_fetchs(clause_hv, "eq", 0)) && SvOK(*val)) {
    50          
3311 84           clause->expr_type = XS_JIT_EXPR_EQ;
3312 84           clause->expr_value = SvPV(*val, clause->expr_value_len);
3313             }
3314 7 100         else if ((val = hv_fetchs(clause_hv, "ne", 0)) && SvOK(*val)) {
    50          
3315 2           clause->expr_type = XS_JIT_EXPR_NE;
3316 2           clause->expr_value = SvPV(*val, clause->expr_value_len);
3317             }
3318 5 100         else if ((val = hv_fetchs(clause_hv, "m", 0)) && SvOK(*val)) {
    50          
3319 2           clause->expr_type = XS_JIT_EXPR_M;
3320 2           clause->expr_value = SvPV(*val, clause->expr_value_len);
3321             }
3322 3 50         else if ((val = hv_fetchs(clause_hv, "im", 0)) && SvOK(*val)) {
    0          
3323 0           clause->expr_type = XS_JIT_EXPR_IM;
3324 0           clause->expr_value = SvPV(*val, clause->expr_value_len);
3325             }
3326 3 50         else if ((val = hv_fetchs(clause_hv, "nm", 0)) && SvOK(*val)) {
    0          
3327 0           clause->expr_type = XS_JIT_EXPR_NM;
3328 0           clause->expr_value = SvPV(*val, clause->expr_value_len);
3329             }
3330 3 50         else if ((val = hv_fetchs(clause_hv, "inm", 0)) && SvOK(*val)) {
    0          
3331 0           clause->expr_type = XS_JIT_EXPR_INM;
3332 0           clause->expr_value = SvPV(*val, clause->expr_value_len);
3333             }
3334 3 100         else if ((val = hv_fetchs(clause_hv, "exists", 0)) && SvOK(*val)) {
    50          
3335 2           clause->expr_type = XS_JIT_EXPR_EXISTS;
3336             }
3337 1 50         else if ((val = hv_fetchs(clause_hv, "true", 0)) && SvOK(*val)) {
    50          
3338 1           clause->expr_type = XS_JIT_EXPR_TRUE;
3339             }
3340              
3341             /* Parse 'then' actions */
3342 131 100         if ((val = hv_fetchs(clause_hv, "then", 0)) && SvOK(*val)) {
    50          
3343 110           clause->actions = xs_jit_parse_actions(aTHX_ *val, &clause->num_actions);
3344             }
3345              
3346             /* Parse chained 'and' clause */
3347 131 100         if ((val = hv_fetchs(clause_hv, "and", 0)) && SvOK(*val) && SvROK(*val)) {
    50          
    50          
3348 15           clause->and_clause = xs_jit_parse_clause(aTHX_ (HV*)SvRV(*val));
3349             }
3350              
3351             /* Parse chained 'or' clause */
3352 131 100         if ((val = hv_fetchs(clause_hv, "or", 0)) && SvOK(*val) && SvROK(*val)) {
    50          
    50          
3353 6           clause->or_clause = xs_jit_parse_clause(aTHX_ (HV*)SvRV(*val));
3354             }
3355              
3356 131           return clause;
3357             }
3358              
3359             /* Free functions */
3360 185           void xs_jit_free_actions(pTHX_ XS_JIT_Action* actions, int num_actions) {
3361             PERL_UNUSED_ARG(num_actions);
3362 185 100         if (actions) {
3363 146           Safefree(actions);
3364             }
3365 185           }
3366              
3367 137           void xs_jit_free_clause(pTHX_ XS_JIT_Clause* clause) {
3368 137 50         if (!clause) return;
3369              
3370 137           xs_jit_free_actions(aTHX_ clause->actions, clause->num_actions);
3371              
3372 137 100         if (clause->and_clause) {
3373 15           xs_jit_free_clause(aTHX_ clause->and_clause);
3374             }
3375 137 100         if (clause->or_clause) {
3376 6           xs_jit_free_clause(aTHX_ clause->or_clause);
3377             }
3378              
3379 137           Safefree(clause);
3380             }
3381              
3382 26           void xs_jit_free_conditional(pTHX_ XS_JIT_Conditional* cond) {
3383             int i;
3384              
3385 26 50         if (!cond) return;
3386              
3387 26 50         if (cond->if_clause) {
3388 26           xs_jit_free_clause(aTHX_ cond->if_clause);
3389             }
3390              
3391 34 100         for (i = 0; i < cond->num_elsif; i++) {
3392 8           xs_jit_free_clause(aTHX_ cond->elsif_clauses[i]);
3393             }
3394 26 100         if (cond->elsif_clauses) {
3395 4           Safefree(cond->elsif_clauses);
3396             }
3397              
3398 26           xs_jit_free_actions(aTHX_ cond->else_actions, cond->num_else_actions);
3399             }
3400              
3401 3           void xs_jit_free_given(pTHX_ XS_JIT_Given* given) {
3402             int i;
3403              
3404 3 50         if (!given) return;
3405              
3406 11 100         for (i = 0; i < given->num_when; i++) {
3407 8           xs_jit_free_clause(aTHX_ given->when_clauses[i]);
3408             }
3409 3 50         if (given->when_clauses) {
3410 3           Safefree(given->when_clauses);
3411             }
3412              
3413 3           xs_jit_free_actions(aTHX_ given->default_actions, given->num_default_actions);
3414             }
3415              
3416             /* ============================================
3417             * Switch Statement (Optimized multi-branch)
3418             * ============================================ */
3419              
3420             /* Detect if all cases use same operator type for optimization.
3421             * Returns: 1 = all string ops, 2 = all numeric ops, 0 = mixed */
3422 18           static int xs_jit_switch_detect_type(XS_JIT_Switch* sw) {
3423 18           int string_ops = 0, numeric_ops = 0, other_ops = 0;
3424             int i;
3425              
3426 92 100         for (i = 0; i < sw->num_cases; i++) {
3427 74           XS_JIT_Clause* c = sw->cases[i];
3428             /* Skip clauses with AND/OR chaining - can't optimize those */
3429 74 50         if (c->and_clause || c->or_clause) {
    50          
3430 0           other_ops++;
3431 0           continue;
3432             }
3433 74           switch (c->expr_type) {
3434 61           case XS_JIT_EXPR_EQ:
3435             case XS_JIT_EXPR_NE:
3436 61           string_ops++;
3437 61           break;
3438 0           case XS_JIT_EXPR_M:
3439             case XS_JIT_EXPR_IM:
3440             case XS_JIT_EXPR_NM:
3441             case XS_JIT_EXPR_INM:
3442             /* Pattern matching - string but different optimization */
3443 0           other_ops++;
3444 0           break;
3445 11           case XS_JIT_EXPR_GT:
3446             case XS_JIT_EXPR_LT:
3447             case XS_JIT_EXPR_GTE:
3448             case XS_JIT_EXPR_LTE:
3449 11           numeric_ops++;
3450 11           break;
3451 2           default:
3452 2           other_ops++;
3453             }
3454             }
3455              
3456 18 100         if (string_ops > 0 && numeric_ops == 0 && other_ops == 0)
    50          
    50          
3457 13           return 1; /* all string eq/ne */
3458 5 100         if (numeric_ops > 0 && string_ops == 0 && other_ops == 0)
    50          
    50          
3459 3           return 2; /* all numeric comparisons */
3460 2           return 0; /* mixed - no optimization */
3461             }
3462              
3463             /* Build optimized condition for string equality using cached pv/len */
3464 61           static SV* xs_jit_build_string_eq_opt(pTHX_ const char* pv_var,
3465             const char* len_var,
3466             const char* value, STRLEN vlen,
3467             int negated) {
3468 61           SV* cond = newSVpvs("");
3469 61 100         if (negated) {
3470 1           sv_catpvf(cond, "!(%s == %lu && memEQ(%s, \"%s\", %lu))",
3471             len_var, (unsigned long)vlen, pv_var, value, (unsigned long)vlen);
3472             } else {
3473 60           sv_catpvf(cond, "%s == %lu && memEQ(%s, \"%s\", %lu)",
3474             len_var, (unsigned long)vlen, pv_var, value, (unsigned long)vlen);
3475             }
3476 61           return cond;
3477             }
3478              
3479             /* Build optimized condition for numeric comparison using cached iv */
3480 11           static SV* xs_jit_build_numeric_opt(pTHX_ const char* iv_var,
3481             XS_JIT_ExprType expr_type,
3482             const char* value) {
3483 11           SV* cond = newSVpvs("");
3484 11           switch (expr_type) {
3485 3           case XS_JIT_EXPR_GT:
3486 3           sv_catpvf(cond, "%s > %s", iv_var, value);
3487 3           break;
3488 4           case XS_JIT_EXPR_LT:
3489 4           sv_catpvf(cond, "%s < %s", iv_var, value);
3490 4           break;
3491 4           case XS_JIT_EXPR_GTE:
3492 4           sv_catpvf(cond, "%s >= %s", iv_var, value);
3493 4           break;
3494 0           case XS_JIT_EXPR_LTE:
3495 0           sv_catpvf(cond, "%s <= %s", iv_var, value);
3496 0           break;
3497 0           default:
3498 0           sv_catpvf(cond, "%s == %s", iv_var, value);
3499             }
3500 11           return cond;
3501             }
3502              
3503 19           void xs_jit_switch(pTHX_ XS_JIT_Builder* b, XS_JIT_Switch* sw) {
3504             int i;
3505             int opt_type;
3506             const char* key;
3507              
3508 19 50         if (!sw) return;
3509              
3510             /* Handle empty cases - just emit default */
3511 19 100         if (sw->num_cases == 0) {
3512 1 50         if (sw->num_default_actions > 0) {
3513 1           xs_jit_emit_actions(aTHX_ b, sw->default_actions,
3514             sw->num_default_actions);
3515             }
3516 1           return;
3517             }
3518              
3519 18           key = sw->key;
3520 18           opt_type = xs_jit_switch_detect_type(sw);
3521              
3522             /* Open block for cache variables */
3523 18           xs_jit_line(aTHX_ b, "{");
3524 18           xs_jit_indent(b);
3525              
3526 18 100         if (opt_type == 1) {
3527             /* String optimization: cache SvPV once */
3528 13           xs_jit_line(aTHX_ b, "STRLEN _sw_len;");
3529 13           xs_jit_line(aTHX_ b, "const char* _sw_pv = SvPV(%s, _sw_len);", key);
3530 5 100         } else if (opt_type == 2) {
3531             /* Numeric optimization: cache SvIV once */
3532 3           xs_jit_line(aTHX_ b, "IV _sw_iv = SvIV(%s);", key);
3533             }
3534              
3535 92 100         for (i = 0; i < sw->num_cases; i++) {
3536 74           XS_JIT_Clause* c = sw->cases[i];
3537             SV* cond;
3538              
3539 74 100         if (opt_type == 1 && (c->expr_type == XS_JIT_EXPR_EQ ||
    100          
3540 62 50         c->expr_type == XS_JIT_EXPR_NE)) {
3541             /* Optimized string equality/inequality */
3542 61           int negated = (c->expr_type == XS_JIT_EXPR_NE);
3543 61           cond = xs_jit_build_string_eq_opt(aTHX_ "_sw_pv", "_sw_len",
3544             c->expr_value, c->expr_value_len,
3545             negated);
3546 13 100         } else if (opt_type == 2) {
3547             /* Optimized numeric - use cached _sw_iv */
3548 11           cond = xs_jit_build_numeric_opt(aTHX_ "_sw_iv",
3549             c->expr_type, c->expr_value);
3550             } else {
3551             /* No optimization - use standard condition builder */
3552 2 50         if (!c->key) c->key = key;
3553 2           cond = xs_jit_build_condition(aTHX_ c);
3554             }
3555              
3556 74 100         if (i == 0) {
3557 18           xs_jit_if(aTHX_ b, SvPV_nolen(cond));
3558             } else {
3559 56           xs_jit_elsif(aTHX_ b, SvPV_nolen(cond));
3560             }
3561 74           SvREFCNT_dec(cond);
3562              
3563 74           xs_jit_emit_actions(aTHX_ b, c->actions, c->num_actions);
3564             }
3565              
3566             /* Default becomes else */
3567 18 100         if (sw->num_default_actions > 0) {
3568 17           xs_jit_else(aTHX_ b);
3569 17           xs_jit_emit_actions(aTHX_ b, sw->default_actions,
3570             sw->num_default_actions);
3571             }
3572              
3573 18           xs_jit_endif(aTHX_ b);
3574              
3575             /* Close block */
3576 18           xs_jit_dedent(b);
3577 18           xs_jit_line(aTHX_ b, "}");
3578             }
3579              
3580 19           void xs_jit_free_switch(pTHX_ XS_JIT_Switch* sw) {
3581             int i;
3582              
3583 19 50         if (!sw) return;
3584              
3585 93 100         for (i = 0; i < sw->num_cases; i++) {
3586 74           xs_jit_free_clause(aTHX_ sw->cases[i]);
3587             }
3588 19 100         if (sw->cases) {
3589 18           Safefree(sw->cases);
3590             }
3591              
3592 19           xs_jit_free_actions(aTHX_ sw->default_actions, sw->num_default_actions);
3593             }
3594              
3595             /* ============================================
3596             * Enum Generation
3597             * ============================================ */
3598              
3599 13           void xs_jit_enum(pTHX_ XS_JIT_Builder* b, const char* name,
3600             XS_JIT_EnumValue* values, int num_values,
3601             XS_JIT_EnumOpts* opts) {
3602             int i;
3603 13           IV start = 0;
3604 13           const char* prefix = NULL;
3605 13           SV* prefix_sv = NULL;
3606 13           SV* lc_name_sv = NULL;
3607             const char* lc_name;
3608             IV max_val;
3609             char func_buf[256];
3610             char const_buf[256];
3611              
3612 13 50         if (!b || !name || !values || num_values <= 0) return;
    50          
    50          
    50          
3613              
3614             /* Process options */
3615 13 100         if (opts) {
3616 5           start = opts->start;
3617 5 100         if (opts->prefix) {
3618 2           prefix = opts->prefix;
3619             }
3620             }
3621              
3622             /* Generate lowercase name */
3623 13           lc_name_sv = newSVpv(name, 0);
3624 13           sv_catpvn(lc_name_sv, "", 0); /* Ensure null terminator */
3625             {
3626 13           char* p = SvPVX(lc_name_sv);
3627 13           STRLEN len = SvCUR(lc_name_sv);
3628             STRLEN j;
3629 109 100         for (j = 0; j < len; j++) {
3630 96 100         p[j] = toLOWER(p[j]);
3631             }
3632             }
3633 13           lc_name = SvPV_nolen(lc_name_sv);
3634              
3635             /* Generate default prefix if not provided: UC(name) + "_" */
3636 13 100         if (!prefix) {
3637 11           prefix_sv = newSVpv(name, 0);
3638             {
3639 11           char* p = SvPVX(prefix_sv);
3640 11           STRLEN len = SvCUR(prefix_sv);
3641             STRLEN j;
3642 92 100         for (j = 0; j < len; j++) {
3643 81 100         p[j] = toUPPER(p[j]);
3644             }
3645             }
3646 11           sv_catpvn(prefix_sv, "_", 1);
3647 11           prefix = SvPV_nolen(prefix_sv);
3648             }
3649              
3650 13           max_val = start + num_values - 1;
3651              
3652             /* Generate constant functions for each value */
3653 72 100         for (i = 0; i < num_values; i++) {
3654 59           IV val = start + i;
3655 59           SV* uc_val_sv = newSVpv(values[i].name, values[i].name_len);
3656             const char* uc_val;
3657             char val_str[32];
3658             {
3659 59           char* p = SvPVX(uc_val_sv);
3660 59           STRLEN len = SvCUR(uc_val_sv);
3661             STRLEN j;
3662 367 100         for (j = 0; j < len; j++) {
3663 308 100         p[j] = toUPPER(p[j]);
3664             }
3665             }
3666 59           uc_val = SvPV_nolen(uc_val_sv);
3667              
3668             /* Function name: _const_ */
3669 59           snprintf(func_buf, sizeof(func_buf), "%s_const_%s", lc_name, values[i].name);
3670             /* Constant name for comment: */
3671 59           snprintf(const_buf, sizeof(const_buf), "%s%s", prefix, uc_val);
3672             /* Value as string */
3673 59           snprintf(val_str, sizeof(val_str), "%ld", (long)val);
3674              
3675 59           xs_jit_xs_function(aTHX_ b, func_buf);
3676 59           xs_jit_xs_preamble(aTHX_ b);
3677 59           xs_jit_comment(aTHX_ b, const_buf);
3678 59           xs_jit_line(aTHX_ b, "PERL_UNUSED_VAR(items);");
3679 59           xs_jit_return_iv(aTHX_ b, val_str);
3680 59           xs_jit_xs_end(aTHX_ b);
3681 59           xs_jit_blank(aTHX_ b);
3682              
3683 59           SvREFCNT_dec(uc_val_sv);
3684             }
3685              
3686             /* Generate is_valid_ function */
3687 13           snprintf(func_buf, sizeof(func_buf), "is_valid_%s", lc_name);
3688 13           xs_jit_xs_function(aTHX_ b, func_buf);
3689 13           xs_jit_xs_preamble(aTHX_ b);
3690 13           xs_jit_check_items(aTHX_ b, 1, 1, "val");
3691 13           xs_jit_declare_iv(aTHX_ b, "val", "SvIV(ST(0))");
3692             {
3693             char cond_buf[128];
3694 13           snprintf(cond_buf, sizeof(cond_buf), "val >= %ld && val <= %ld",
3695             (long)start, (long)max_val);
3696 13           xs_jit_if(aTHX_ b, cond_buf);
3697             }
3698 13           xs_jit_return_yes(aTHX_ b);
3699 13           xs_jit_else(aTHX_ b);
3700 13           xs_jit_return_no(aTHX_ b);
3701 13           xs_jit_endif(aTHX_ b);
3702 13           xs_jit_xs_end(aTHX_ b);
3703 13           xs_jit_blank(aTHX_ b);
3704              
3705             /* Generate _name function using switch */
3706 13           snprintf(func_buf, sizeof(func_buf), "%s_name", lc_name);
3707 13           xs_jit_xs_function(aTHX_ b, func_buf);
3708 13           xs_jit_xs_preamble(aTHX_ b);
3709 13           xs_jit_check_items(aTHX_ b, 1, 1, "val");
3710 13           xs_jit_declare_iv(aTHX_ b, "val", "SvIV(ST(0))");
3711 13           xs_jit_line(aTHX_ b, "{");
3712 13           xs_jit_indent(b);
3713 72 100         for (i = 0; i < num_values; i++) {
3714 59           IV val = start + i;
3715             char case_cond[64];
3716 59           snprintf(case_cond, sizeof(case_cond), "val == %ld", (long)val);
3717 59 100         if (i == 0) {
3718 13           xs_jit_if(aTHX_ b, case_cond);
3719             } else {
3720 46           xs_jit_elsif(aTHX_ b, case_cond);
3721             }
3722 59           xs_jit_line(aTHX_ b, "ST(0) = sv_2mortal(newSVpvn(\"%s\", %lu));",
3723 59           values[i].name, (unsigned long)values[i].name_len);
3724 59           xs_jit_line(aTHX_ b, "XSRETURN(1);");
3725             }
3726 13           xs_jit_else(aTHX_ b);
3727 13           xs_jit_line(aTHX_ b, "ST(0) = sv_2mortal(newSVpvn(\"\", 0));");
3728 13           xs_jit_line(aTHX_ b, "XSRETURN(1);");
3729 13           xs_jit_endif(aTHX_ b);
3730 13           xs_jit_dedent(b);
3731 13           xs_jit_line(aTHX_ b, "}");
3732 13           xs_jit_xs_end(aTHX_ b);
3733 13           xs_jit_blank(aTHX_ b);
3734              
3735             /* Store enum metadata for later retrieval */
3736             {
3737 13           HV* info = newHV();
3738 13           AV* vals = newAV();
3739            
3740 13           hv_stores(info, "name", newSVpv(name, 0));
3741 13           hv_stores(info, "prefix", newSVpv(prefix, 0));
3742 13           hv_stores(info, "lc_name", newSVpv(lc_name, 0));
3743 13           hv_stores(info, "start", newSViv(start));
3744            
3745 72 100         for (i = 0; i < num_values; i++) {
3746 59           HV* val_info = newHV();
3747 59           hv_stores(val_info, "name", newSVpvn(values[i].name, values[i].name_len));
3748 59           hv_stores(val_info, "index", newSViv(start + i));
3749 59           av_push(vals, newRV_noinc((SV*)val_info));
3750             }
3751 13           hv_stores(info, "values", newRV_noinc((SV*)vals));
3752            
3753 13           (void)hv_store(b->enums, name, strlen(name), newRV_noinc((SV*)info), 0);
3754             }
3755              
3756             /* Cleanup */
3757 13 50         if (lc_name_sv) SvREFCNT_dec(lc_name_sv);
3758 13 100         if (prefix_sv) SvREFCNT_dec(prefix_sv);
3759             }
3760              
3761 13           HV* xs_jit_enum_functions(pTHX_ XS_JIT_Builder* b, const char* name,
3762             const char* package) {
3763             SV** info_svp;
3764             HV* info;
3765             HV* result;
3766             const char* lc_name;
3767             const char* prefix;
3768             AV* vals;
3769             I32 i, num_vals;
3770             char buf[512];
3771              
3772 13 50         if (!b || !name || !package) return NULL;
    50          
    50          
3773              
3774 13           info_svp = hv_fetch(b->enums, name, strlen(name), 0);
3775 13 100         if (!info_svp || !SvROK(*info_svp)) {
    50          
3776 1           croak("No enum named '%s' found", name);
3777             }
3778 12           info = (HV*)SvRV(*info_svp);
3779              
3780 12           lc_name = SvPV_nolen(*hv_fetchs(info, "lc_name", 0));
3781 12           prefix = SvPV_nolen(*hv_fetchs(info, "prefix", 0));
3782 12           vals = (AV*)SvRV(*hv_fetchs(info, "values", 0));
3783 12           num_vals = av_len(vals) + 1;
3784              
3785 12           result = newHV();
3786              
3787             /* Constant functions */
3788 70 100         for (i = 0; i < num_vals; i++) {
3789 58           HV* val_info = (HV*)SvRV(*av_fetch(vals, i, 0));
3790 58           const char* val_name = SvPV_nolen(*hv_fetchs(val_info, "name", 0));
3791             char uc_name[256];
3792 58           STRLEN j, len = strlen(val_name);
3793 58           HV* entry = newHV();
3794            
3795             /* Uppercase the name */
3796 365 100         for (j = 0; j < len && j < sizeof(uc_name) - 1; j++) {
    50          
3797 307 100         uc_name[j] = toUPPER(val_name[j]);
3798             }
3799 58           uc_name[j] = '\0';
3800            
3801 58           snprintf(buf, sizeof(buf), "%s::%s%s", package, prefix, uc_name);
3802 58           hv_stores(entry, "source", newSVpvf("%s_const_%s", lc_name, val_name));
3803 58           hv_stores(entry, "is_xs_native", newSViv(1));
3804 58           (void)hv_store(result, buf, strlen(buf), newRV_noinc((SV*)entry), 0);
3805             }
3806              
3807             /* is_valid function */
3808             {
3809 12           HV* entry = newHV();
3810 12           snprintf(buf, sizeof(buf), "%s::is_valid_%s", package, lc_name);
3811 12           hv_stores(entry, "source", newSVpvf("is_valid_%s", lc_name));
3812 12           hv_stores(entry, "is_xs_native", newSViv(1));
3813 12           (void)hv_store(result, buf, strlen(buf), newRV_noinc((SV*)entry), 0);
3814             }
3815              
3816             /* name function */
3817             {
3818 12           HV* entry = newHV();
3819 12           snprintf(buf, sizeof(buf), "%s::%s_name", package, lc_name);
3820 12           hv_stores(entry, "source", newSVpvf("%s_name", lc_name));
3821 12           hv_stores(entry, "is_xs_native", newSViv(1));
3822 12           (void)hv_store(result, buf, strlen(buf), newRV_noinc((SV*)entry), 0);
3823             }
3824              
3825 12           return result;
3826             }
3827              
3828             /* ============================================
3829             * Memoization
3830             * ============================================ */
3831              
3832 9           void xs_jit_memoize(pTHX_ XS_JIT_Builder* b, const char* func_name,
3833             XS_JIT_MemoizeOpts* opts) {
3834 9           const char* cache_attr = "_memoize_cache";
3835 9           STRLEN cache_attr_len = 15;
3836 9           IV ttl = 0;
3837             char func_buf[256];
3838             char len_buf[32];
3839              
3840 9 50         if (!b || !func_name) return;
    50          
3841              
3842             /* Process options */
3843 9 100         if (opts) {
3844 2 100         if (opts->cache_attr) {
3845 1           cache_attr = opts->cache_attr;
3846 1           cache_attr_len = opts->cache_attr_len;
3847             }
3848 2           ttl = opts->ttl;
3849             }
3850              
3851 9           snprintf(len_buf, sizeof(len_buf), "%lu", (unsigned long)cache_attr_len);
3852              
3853             /* Generate memoized wrapper function */
3854 9           snprintf(func_buf, sizeof(func_buf), "%s_memoized", func_name);
3855 9           xs_jit_xs_function(aTHX_ b, func_buf);
3856 9           xs_jit_xs_preamble(aTHX_ b);
3857 9           xs_jit_line(aTHX_ b, "PERL_UNUSED_VAR(items);");
3858 9           xs_jit_get_self_hv(aTHX_ b);
3859 9           xs_jit_blank(aTHX_ b);
3860              
3861 9           xs_jit_comment(aTHX_ b, "Build cache key from all arguments");
3862 9           xs_jit_declare_sv(aTHX_ b, "cache_key", "newSVpvs(\"\")");
3863 9           xs_jit_line(aTHX_ b, "IV i;");
3864 9           xs_jit_for(aTHX_ b, "i = 1", "i < items", "i++");
3865 9           xs_jit_if(aTHX_ b, "i > 1");
3866 9           xs_jit_line(aTHX_ b, "sv_catpvs(cache_key, \"\\x1C\");");
3867 9           xs_jit_endif(aTHX_ b);
3868 9           xs_jit_line(aTHX_ b, "sv_catsv(cache_key, ST(i));");
3869 9           xs_jit_endloop(aTHX_ b);
3870 9           xs_jit_blank(aTHX_ b);
3871              
3872 9           xs_jit_comment(aTHX_ b, "Get or create the cache hash");
3873 9           xs_jit_hv_fetch(aTHX_ b, "hv", cache_attr, cache_attr_len, "cache_svp");
3874 9           xs_jit_declare_hv(aTHX_ b, "cache", "NULL");
3875 9           xs_jit_if(aTHX_ b, "cache_svp && SvROK(*cache_svp) && SvTYPE(SvRV(*cache_svp)) == SVt_PVHV");
3876 9           xs_jit_assign(aTHX_ b, "cache", "(HV*)SvRV(*cache_svp)");
3877 9           xs_jit_else(aTHX_ b);
3878 9           xs_jit_assign(aTHX_ b, "cache", "newHV()");
3879 9           xs_jit_hv_store(aTHX_ b, "hv", cache_attr, cache_attr_len, "newRV_noinc((SV*)cache)");
3880 9           xs_jit_endif(aTHX_ b);
3881 9           xs_jit_blank(aTHX_ b);
3882              
3883 9           xs_jit_comment(aTHX_ b, "Check cache for existing value");
3884 9           xs_jit_line(aTHX_ b, "STRLEN key_len;");
3885 9           xs_jit_line(aTHX_ b, "const char* key_str = SvPV(cache_key, key_len);");
3886 9           xs_jit_line(aTHX_ b, "SV** cached_svp = hv_fetch(cache, key_str, key_len, 0);");
3887              
3888 9 100         if (ttl > 0) {
3889             /* With TTL support - cache stores [timestamp, value] */
3890 1           xs_jit_if(aTHX_ b, "cached_svp && SvROK(*cached_svp) && SvTYPE(SvRV(*cached_svp)) == SVt_PVAV");
3891 1           xs_jit_declare_av(aTHX_ b, "cached_av", "(AV*)SvRV(*cached_svp)");
3892 1           xs_jit_line(aTHX_ b, "SV** ts_svp = av_fetch(cached_av, 0, 0);");
3893 1           xs_jit_line(aTHX_ b, "SV** val_svp = av_fetch(cached_av, 1, 0);");
3894             {
3895             char ttl_cond[128];
3896 1           snprintf(ttl_cond, sizeof(ttl_cond),
3897             "ts_svp && val_svp && (time(NULL) - SvIV(*ts_svp)) < %ld", (long)ttl);
3898 1           xs_jit_if(aTHX_ b, ttl_cond);
3899             }
3900 1           xs_jit_line(aTHX_ b, "SvREFCNT_dec(cache_key);");
3901 1           xs_jit_return_sv(aTHX_ b, "SvREFCNT_inc(*val_svp)");
3902 1           xs_jit_endif(aTHX_ b);
3903 1           xs_jit_endif(aTHX_ b);
3904             } else {
3905             /* Without TTL - simple cache lookup */
3906 8           xs_jit_if(aTHX_ b, "cached_svp");
3907 8           xs_jit_line(aTHX_ b, "SvREFCNT_dec(cache_key);");
3908 8           xs_jit_return_sv(aTHX_ b, "SvREFCNT_inc(*cached_svp)");
3909 8           xs_jit_endif(aTHX_ b);
3910             }
3911              
3912 9           xs_jit_blank(aTHX_ b);
3913 9           xs_jit_comment(aTHX_ b, "Cache miss - call original function");
3914 9           xs_jit_block_start(aTHX_ b);
3915 9           xs_jit_line(aTHX_ b, "dSP;");
3916 9           xs_jit_line(aTHX_ b, "int count;");
3917 9           xs_jit_line(aTHX_ b, "SV* result;");
3918 9           xs_jit_blank(aTHX_ b);
3919 9           xs_jit_line(aTHX_ b, "ENTER;");
3920 9           xs_jit_line(aTHX_ b, "SAVETMPS;");
3921 9           xs_jit_line(aTHX_ b, "PUSHMARK(SP);");
3922 9           xs_jit_comment(aTHX_ b, "Push all original arguments");
3923 9           xs_jit_for(aTHX_ b, "i = 0", "i < items", "i++");
3924 9           xs_jit_line(aTHX_ b, "XPUSHs(ST(i));");
3925 9           xs_jit_endloop(aTHX_ b);
3926 9           xs_jit_line(aTHX_ b, "PUTBACK;");
3927 9           xs_jit_blank(aTHX_ b);
3928 9           xs_jit_line(aTHX_ b, "count = call_method(\"_orig_%s\", G_SCALAR);", func_name);
3929 9           xs_jit_blank(aTHX_ b);
3930 9           xs_jit_line(aTHX_ b, "SPAGAIN;");
3931 9           xs_jit_if(aTHX_ b, "count > 0");
3932 9           xs_jit_line(aTHX_ b, "result = SvREFCNT_inc(POPs);");
3933 9           xs_jit_else(aTHX_ b);
3934 9           xs_jit_line(aTHX_ b, "result = &PL_sv_undef;");
3935 9           xs_jit_endif(aTHX_ b);
3936 9           xs_jit_line(aTHX_ b, "PUTBACK;");
3937 9           xs_jit_line(aTHX_ b, "FREETMPS;");
3938 9           xs_jit_line(aTHX_ b, "LEAVE;");
3939 9           xs_jit_blank(aTHX_ b);
3940 9           xs_jit_comment(aTHX_ b, "Store in cache");
3941              
3942 9 100         if (ttl > 0) {
3943             /* With TTL - store [timestamp, value] */
3944 1           xs_jit_line(aTHX_ b, "AV* entry = newAV();");
3945 1           xs_jit_line(aTHX_ b, "av_push(entry, newSViv(time(NULL)));");
3946 1           xs_jit_line(aTHX_ b, "av_push(entry, SvREFCNT_inc(result));");
3947 1           xs_jit_line(aTHX_ b, "(void)hv_store(cache, key_str, key_len, newRV_noinc((SV*)entry), 0);");
3948             } else {
3949             /* Without TTL - store value directly */
3950 8           xs_jit_line(aTHX_ b, "(void)hv_store(cache, key_str, key_len, SvREFCNT_inc(result), 0);");
3951             }
3952              
3953 9           xs_jit_line(aTHX_ b, "SvREFCNT_dec(cache_key);");
3954 9           xs_jit_line(aTHX_ b, "ST(0) = sv_2mortal(result);");
3955 9           xs_jit_line(aTHX_ b, "XSRETURN(1);");
3956 9           xs_jit_block_end(aTHX_ b);
3957 9           xs_jit_xs_end(aTHX_ b);
3958 9           xs_jit_blank(aTHX_ b);
3959              
3960             /* Generate clear__cache method */
3961 9           snprintf(func_buf, sizeof(func_buf), "clear_%s_cache", func_name);
3962 9           xs_jit_xs_function(aTHX_ b, func_buf);
3963 9           xs_jit_xs_preamble(aTHX_ b);
3964 9           xs_jit_line(aTHX_ b, "PERL_UNUSED_VAR(items);");
3965 9           xs_jit_get_self_hv(aTHX_ b);
3966 9           xs_jit_hv_fetch(aTHX_ b, "hv", cache_attr, cache_attr_len, "cache_svp");
3967 9           xs_jit_if(aTHX_ b, "cache_svp && SvROK(*cache_svp) && SvTYPE(SvRV(*cache_svp)) == SVt_PVHV");
3968 9           xs_jit_line(aTHX_ b, "hv_clear((HV*)SvRV(*cache_svp));");
3969 9           xs_jit_endif(aTHX_ b);
3970 9           xs_jit_return_self(aTHX_ b);
3971 9           xs_jit_xs_end(aTHX_ b);
3972 9           xs_jit_blank(aTHX_ b);
3973              
3974             /* Store memoize metadata for later retrieval */
3975             {
3976 9           HV* info = newHV();
3977 9           hv_stores(info, "name", newSVpv(func_name, 0));
3978 9           hv_stores(info, "cache_attr", newSVpv(cache_attr, cache_attr_len));
3979 9           hv_stores(info, "ttl", newSViv(ttl));
3980 9           (void)hv_store(b->memoized, func_name, strlen(func_name), newRV_noinc((SV*)info), 0);
3981             }
3982             }
3983              
3984 10           HV* xs_jit_memoize_functions(pTHX_ XS_JIT_Builder* b, const char* func_name,
3985             const char* package) {
3986             SV** info_svp;
3987             HV* result;
3988             char buf[512];
3989              
3990 10 50         if (!b || !func_name || !package) return NULL;
    50          
    50          
3991              
3992 10           info_svp = hv_fetch(b->memoized, func_name, strlen(func_name), 0);
3993 10 100         if (!info_svp || !SvROK(*info_svp)) {
    50          
3994 1           croak("No memoized function named '%s' found", func_name);
3995             }
3996              
3997 9           result = newHV();
3998              
3999             /* Memoized wrapper */
4000             {
4001 9           HV* entry = newHV();
4002 9           snprintf(buf, sizeof(buf), "%s::%s", package, func_name);
4003 9           hv_stores(entry, "source", newSVpvf("%s_memoized", func_name));
4004 9           hv_stores(entry, "is_xs_native", newSViv(1));
4005 9           (void)hv_store(result, buf, strlen(buf), newRV_noinc((SV*)entry), 0);
4006             }
4007              
4008             /* Cache clearer */
4009             {
4010 9           HV* entry = newHV();
4011 9           snprintf(buf, sizeof(buf), "%s::clear_%s_cache", package, func_name);
4012 9           hv_stores(entry, "source", newSVpvf("clear_%s_cache", func_name));
4013 9           hv_stores(entry, "is_xs_native", newSViv(1));
4014 9           (void)hv_store(result, buf, strlen(buf), newRV_noinc((SV*)entry), 0);
4015             }
4016              
4017 9           return result;
4018             }
4019              
4020             /* ============================================
4021             * Role/Mixin Composer
4022             * ============================================ */
4023              
4024             /* Generate Comparable role methods */
4025 7           static void xs_jit_role_comparable(pTHX_ XS_JIT_Builder* b, XS_JIT_RoleOpts* opts) {
4026 7           const char* compare_key = "id";
4027 7           STRLEN compare_key_len = 2;
4028             char len_buf[32];
4029              
4030 7 100         if (opts && opts->compare_key) {
    50          
4031 2           compare_key = opts->compare_key;
4032 2           compare_key_len = opts->compare_key_len;
4033             }
4034              
4035 7           snprintf(len_buf, sizeof(len_buf), "%lu", (unsigned long)compare_key_len);
4036              
4037             /* compare($other) - returns -1, 0, or 1 */
4038 7           xs_jit_xs_function(aTHX_ b, "compare");
4039 7           xs_jit_xs_preamble(aTHX_ b);
4040 7           xs_jit_get_self_hv(aTHX_ b);
4041 7           xs_jit_comment(aTHX_ b, "Declare all variables at top for C89");
4042 7           xs_jit_line(aTHX_ b, "SV* other;");
4043 7           xs_jit_declare_hv(aTHX_ b, "other_hv", NULL);
4044 7           xs_jit_line(aTHX_ b, "SV* self_val;");
4045 7           xs_jit_line(aTHX_ b, "SV* other_val;");
4046 7           xs_jit_line(aTHX_ b, "int cmp;");
4047 7           xs_jit_check_items(aTHX_ b, 2, 2, "$self, $other");
4048 7           xs_jit_blank(aTHX_ b);
4049 7           xs_jit_comment(aTHX_ b, "Get other object's hash");
4050 7           xs_jit_assign(aTHX_ b, "other", "ST(1)");
4051 7           xs_jit_if(aTHX_ b, "!SvROK(other) || SvTYPE(SvRV(other)) != SVt_PVHV");
4052 7           xs_jit_croak(aTHX_ b, "compare() requires another object");
4053 7           xs_jit_endif(aTHX_ b);
4054 7           xs_jit_assign(aTHX_ b, "other_hv", "(HV*)SvRV(other)");
4055 7           xs_jit_blank(aTHX_ b);
4056 7           xs_jit_comment(aTHX_ b, "Fetch compare key from both objects");
4057 7           xs_jit_hv_fetch(aTHX_ b, "hv", compare_key, compare_key_len, "self_svp");
4058 7           xs_jit_hv_fetch(aTHX_ b, "other_hv", compare_key, compare_key_len, "other_svp");
4059 7           xs_jit_blank(aTHX_ b);
4060 7           xs_jit_comment(aTHX_ b, "Compare values");
4061 7           xs_jit_assign(aTHX_ b, "self_val", "(self_svp && *self_svp) ? *self_svp : &PL_sv_undef");
4062 7           xs_jit_assign(aTHX_ b, "other_val", "(other_svp && *other_svp) ? *other_svp : &PL_sv_undef");
4063 7           xs_jit_assign(aTHX_ b, "cmp", "sv_cmp(self_val, other_val)");
4064 7           xs_jit_return_iv(aTHX_ b, "cmp < 0 ? -1 : (cmp > 0 ? 1 : 0)");
4065 7           xs_jit_xs_end(aTHX_ b);
4066 7           xs_jit_blank(aTHX_ b);
4067              
4068             /* equals($other) - returns true if compare == 0 */
4069 7           xs_jit_xs_function(aTHX_ b, "equals");
4070 7           xs_jit_xs_preamble(aTHX_ b);
4071 7           xs_jit_get_self_hv(aTHX_ b);
4072 7           xs_jit_comment(aTHX_ b, "Declare all variables at top for C89");
4073 7           xs_jit_line(aTHX_ b, "SV* other;");
4074 7           xs_jit_declare_hv(aTHX_ b, "other_hv", NULL);
4075 7           xs_jit_line(aTHX_ b, "SV* self_val;");
4076 7           xs_jit_line(aTHX_ b, "SV* other_val;");
4077 7           xs_jit_check_items(aTHX_ b, 2, 2, "$self, $other");
4078 7           xs_jit_blank(aTHX_ b);
4079 7           xs_jit_assign(aTHX_ b, "other", "ST(1)");
4080 7           xs_jit_if(aTHX_ b, "!SvROK(other) || SvTYPE(SvRV(other)) != SVt_PVHV");
4081 7           xs_jit_return_no(aTHX_ b);
4082 7           xs_jit_endif(aTHX_ b);
4083 7           xs_jit_assign(aTHX_ b, "other_hv", "(HV*)SvRV(other)");
4084 7           xs_jit_hv_fetch(aTHX_ b, "hv", compare_key, compare_key_len, "self_svp");
4085 7           xs_jit_hv_fetch(aTHX_ b, "other_hv", compare_key, compare_key_len, "other_svp");
4086 7           xs_jit_assign(aTHX_ b, "self_val", "(self_svp && *self_svp) ? *self_svp : &PL_sv_undef");
4087 7           xs_jit_assign(aTHX_ b, "other_val", "(other_svp && *other_svp) ? *other_svp : &PL_sv_undef");
4088 7           xs_jit_if(aTHX_ b, "sv_eq(self_val, other_val)");
4089 7           xs_jit_return_yes(aTHX_ b);
4090 7           xs_jit_else(aTHX_ b);
4091 7           xs_jit_return_no(aTHX_ b);
4092 7           xs_jit_endif(aTHX_ b);
4093 7           xs_jit_xs_end(aTHX_ b);
4094 7           xs_jit_blank(aTHX_ b);
4095              
4096             /* lt($other) - returns true if self < other */
4097 7           xs_jit_xs_function(aTHX_ b, "lt");
4098 7           xs_jit_xs_preamble(aTHX_ b);
4099 7           xs_jit_get_self_hv(aTHX_ b);
4100 7           xs_jit_comment(aTHX_ b, "Declare all variables at top for C89");
4101 7           xs_jit_line(aTHX_ b, "SV* other;");
4102 7           xs_jit_declare_hv(aTHX_ b, "other_hv", NULL);
4103 7           xs_jit_line(aTHX_ b, "SV* self_val;");
4104 7           xs_jit_line(aTHX_ b, "SV* other_val;");
4105 7           xs_jit_check_items(aTHX_ b, 2, 2, "$self, $other");
4106 7           xs_jit_assign(aTHX_ b, "other", "ST(1)");
4107 7           xs_jit_if(aTHX_ b, "!SvROK(other) || SvTYPE(SvRV(other)) != SVt_PVHV");
4108 7           xs_jit_return_no(aTHX_ b);
4109 7           xs_jit_endif(aTHX_ b);
4110 7           xs_jit_assign(aTHX_ b, "other_hv", "(HV*)SvRV(other)");
4111 7           xs_jit_hv_fetch(aTHX_ b, "hv", compare_key, compare_key_len, "self_svp");
4112 7           xs_jit_hv_fetch(aTHX_ b, "other_hv", compare_key, compare_key_len, "other_svp");
4113 7           xs_jit_assign(aTHX_ b, "self_val", "(self_svp && *self_svp) ? *self_svp : &PL_sv_undef");
4114 7           xs_jit_assign(aTHX_ b, "other_val", "(other_svp && *other_svp) ? *other_svp : &PL_sv_undef");
4115 7           xs_jit_if(aTHX_ b, "sv_cmp(self_val, other_val) < 0");
4116 7           xs_jit_return_yes(aTHX_ b);
4117 7           xs_jit_else(aTHX_ b);
4118 7           xs_jit_return_no(aTHX_ b);
4119 7           xs_jit_endif(aTHX_ b);
4120 7           xs_jit_xs_end(aTHX_ b);
4121 7           xs_jit_blank(aTHX_ b);
4122              
4123             /* gt($other) - returns true if self > other */
4124 7           xs_jit_xs_function(aTHX_ b, "gt");
4125 7           xs_jit_xs_preamble(aTHX_ b);
4126 7           xs_jit_get_self_hv(aTHX_ b);
4127 7           xs_jit_comment(aTHX_ b, "Declare all variables at top for C89");
4128 7           xs_jit_line(aTHX_ b, "SV* other;");
4129 7           xs_jit_declare_hv(aTHX_ b, "other_hv", NULL);
4130 7           xs_jit_line(aTHX_ b, "SV* self_val;");
4131 7           xs_jit_line(aTHX_ b, "SV* other_val;");
4132 7           xs_jit_check_items(aTHX_ b, 2, 2, "$self, $other");
4133 7           xs_jit_assign(aTHX_ b, "other", "ST(1)");
4134 7           xs_jit_if(aTHX_ b, "!SvROK(other) || SvTYPE(SvRV(other)) != SVt_PVHV");
4135 7           xs_jit_return_no(aTHX_ b);
4136 7           xs_jit_endif(aTHX_ b);
4137 7           xs_jit_assign(aTHX_ b, "other_hv", "(HV*)SvRV(other)");
4138 7           xs_jit_hv_fetch(aTHX_ b, "hv", compare_key, compare_key_len, "self_svp");
4139 7           xs_jit_hv_fetch(aTHX_ b, "other_hv", compare_key, compare_key_len, "other_svp");
4140 7           xs_jit_assign(aTHX_ b, "self_val", "(self_svp && *self_svp) ? *self_svp : &PL_sv_undef");
4141 7           xs_jit_assign(aTHX_ b, "other_val", "(other_svp && *other_svp) ? *other_svp : &PL_sv_undef");
4142 7           xs_jit_if(aTHX_ b, "sv_cmp(self_val, other_val) > 0");
4143 7           xs_jit_return_yes(aTHX_ b);
4144 7           xs_jit_else(aTHX_ b);
4145 7           xs_jit_return_no(aTHX_ b);
4146 7           xs_jit_endif(aTHX_ b);
4147 7           xs_jit_xs_end(aTHX_ b);
4148 7           xs_jit_blank(aTHX_ b);
4149              
4150             /* le($other) - returns true if self <= other */
4151 7           xs_jit_xs_function(aTHX_ b, "le");
4152 7           xs_jit_xs_preamble(aTHX_ b);
4153 7           xs_jit_get_self_hv(aTHX_ b);
4154 7           xs_jit_comment(aTHX_ b, "Declare all variables at top for C89");
4155 7           xs_jit_line(aTHX_ b, "SV* other;");
4156 7           xs_jit_declare_hv(aTHX_ b, "other_hv", NULL);
4157 7           xs_jit_line(aTHX_ b, "SV* self_val;");
4158 7           xs_jit_line(aTHX_ b, "SV* other_val;");
4159 7           xs_jit_check_items(aTHX_ b, 2, 2, "$self, $other");
4160 7           xs_jit_assign(aTHX_ b, "other", "ST(1)");
4161 7           xs_jit_if(aTHX_ b, "!SvROK(other) || SvTYPE(SvRV(other)) != SVt_PVHV");
4162 7           xs_jit_return_no(aTHX_ b);
4163 7           xs_jit_endif(aTHX_ b);
4164 7           xs_jit_assign(aTHX_ b, "other_hv", "(HV*)SvRV(other)");
4165 7           xs_jit_hv_fetch(aTHX_ b, "hv", compare_key, compare_key_len, "self_svp");
4166 7           xs_jit_hv_fetch(aTHX_ b, "other_hv", compare_key, compare_key_len, "other_svp");
4167 7           xs_jit_assign(aTHX_ b, "self_val", "(self_svp && *self_svp) ? *self_svp : &PL_sv_undef");
4168 7           xs_jit_assign(aTHX_ b, "other_val", "(other_svp && *other_svp) ? *other_svp : &PL_sv_undef");
4169 7           xs_jit_if(aTHX_ b, "sv_cmp(self_val, other_val) <= 0");
4170 7           xs_jit_return_yes(aTHX_ b);
4171 7           xs_jit_else(aTHX_ b);
4172 7           xs_jit_return_no(aTHX_ b);
4173 7           xs_jit_endif(aTHX_ b);
4174 7           xs_jit_xs_end(aTHX_ b);
4175 7           xs_jit_blank(aTHX_ b);
4176              
4177             /* ge($other) - returns true if self >= other */
4178 7           xs_jit_xs_function(aTHX_ b, "ge");
4179 7           xs_jit_xs_preamble(aTHX_ b);
4180 7           xs_jit_get_self_hv(aTHX_ b);
4181 7           xs_jit_comment(aTHX_ b, "Declare all variables at top for C89");
4182 7           xs_jit_line(aTHX_ b, "SV* other;");
4183 7           xs_jit_declare_hv(aTHX_ b, "other_hv", NULL);
4184 7           xs_jit_line(aTHX_ b, "SV* self_val;");
4185 7           xs_jit_line(aTHX_ b, "SV* other_val;");
4186 7           xs_jit_check_items(aTHX_ b, 2, 2, "$self, $other");
4187 7           xs_jit_assign(aTHX_ b, "other", "ST(1)");
4188 7           xs_jit_if(aTHX_ b, "!SvROK(other) || SvTYPE(SvRV(other)) != SVt_PVHV");
4189 7           xs_jit_return_no(aTHX_ b);
4190 7           xs_jit_endif(aTHX_ b);
4191 7           xs_jit_assign(aTHX_ b, "other_hv", "(HV*)SvRV(other)");
4192 7           xs_jit_hv_fetch(aTHX_ b, "hv", compare_key, compare_key_len, "self_svp");
4193 7           xs_jit_hv_fetch(aTHX_ b, "other_hv", compare_key, compare_key_len, "other_svp");
4194 7           xs_jit_assign(aTHX_ b, "self_val", "(self_svp && *self_svp) ? *self_svp : &PL_sv_undef");
4195 7           xs_jit_assign(aTHX_ b, "other_val", "(other_svp && *other_svp) ? *other_svp : &PL_sv_undef");
4196 7           xs_jit_if(aTHX_ b, "sv_cmp(self_val, other_val) >= 0");
4197 7           xs_jit_return_yes(aTHX_ b);
4198 7           xs_jit_else(aTHX_ b);
4199 7           xs_jit_return_no(aTHX_ b);
4200 7           xs_jit_endif(aTHX_ b);
4201 7           xs_jit_xs_end(aTHX_ b);
4202 7           xs_jit_blank(aTHX_ b);
4203 7           }
4204              
4205             /* Generate Cloneable role methods */
4206 4           static void xs_jit_role_cloneable(pTHX_ XS_JIT_Builder* b, XS_JIT_RoleOpts* opts) {
4207             PERL_UNUSED_ARG(opts);
4208              
4209             /* jit_clone() - shallow clone of hash-based object
4210             * Note: We use "jit_clone" internally to avoid collision with
4211             * libc's clone() syscall wrapper on Linux.
4212             */
4213 4           xs_jit_xs_function(aTHX_ b, "jit_clone");
4214 4           xs_jit_xs_preamble(aTHX_ b);
4215 4           xs_jit_get_self_hv(aTHX_ b);
4216 4           xs_jit_comment(aTHX_ b, "Declare all variables at top for C89");
4217 4           xs_jit_declare_hv(aTHX_ b, "clone_hv", NULL);
4218 4           xs_jit_line(aTHX_ b, "HE* entry;");
4219 4           xs_jit_line(aTHX_ b, "SV* clone_ref;");
4220 4           xs_jit_line(aTHX_ b, "const char* classname;");
4221 4           xs_jit_line(aTHX_ b, "SV* key_sv;");
4222 4           xs_jit_line(aTHX_ b, "SV* val;");
4223 4           xs_jit_line(aTHX_ b, "STRLEN key_len;");
4224 4           xs_jit_line(aTHX_ b, "const char* key;");
4225 4           xs_jit_check_items(aTHX_ b, 1, 1, "$self");
4226 4           xs_jit_blank(aTHX_ b);
4227 4           xs_jit_comment(aTHX_ b, "Create new hash and copy all keys");
4228 4           xs_jit_assign(aTHX_ b, "clone_hv", "newHV()");
4229 4           xs_jit_line(aTHX_ b, "hv_iterinit(hv);");
4230 4           xs_jit_while(aTHX_ b, "(entry = hv_iternext(hv)) != NULL");
4231 4           xs_jit_assign(aTHX_ b, "key_sv", "hv_iterkeysv(entry)");
4232 4           xs_jit_assign(aTHX_ b, "val", "hv_iterval(hv, entry)");
4233 4           xs_jit_assign(aTHX_ b, "key", "SvPV(key_sv, key_len)");
4234 4           xs_jit_comment(aTHX_ b, "Use newSVsv to create a true copy of the value");
4235 4           xs_jit_line(aTHX_ b, "(void)hv_store(clone_hv, key, key_len, newSVsv(val), 0);");
4236 4           xs_jit_endloop(aTHX_ b);
4237 4           xs_jit_blank(aTHX_ b);
4238 4           xs_jit_comment(aTHX_ b, "Bless into same class and return");
4239 4           xs_jit_assign(aTHX_ b, "clone_ref", "sv_2mortal(newRV_noinc((SV*)clone_hv))");
4240 4           xs_jit_assign(aTHX_ b, "classname", "sv_reftype(SvRV(self), 1)");
4241 4           xs_jit_line(aTHX_ b, "sv_bless(clone_ref, gv_stashpv(classname, GV_ADD));");
4242 4           xs_jit_return_sv(aTHX_ b, "SvREFCNT_inc(clone_ref)");
4243 4           xs_jit_xs_end(aTHX_ b);
4244 4           xs_jit_blank(aTHX_ b);
4245 4           }
4246              
4247             /* Generate Serializable role methods */
4248 2           static void xs_jit_role_serializable(pTHX_ XS_JIT_Builder* b, XS_JIT_RoleOpts* opts) {
4249             PERL_UNUSED_ARG(opts);
4250              
4251             /* TO_JSON() - returns hashref copy for JSON::XS compatibility */
4252 2           xs_jit_xs_function(aTHX_ b, "TO_JSON");
4253 2           xs_jit_xs_preamble(aTHX_ b);
4254 2           xs_jit_get_self_hv(aTHX_ b);
4255 2           xs_jit_comment(aTHX_ b, "Declare all variables at top for C89");
4256 2           xs_jit_declare_hv(aTHX_ b, "copy", NULL);
4257 2           xs_jit_line(aTHX_ b, "HE* entry;");
4258 2           xs_jit_line(aTHX_ b, "SV* key_sv;");
4259 2           xs_jit_line(aTHX_ b, "SV* val;");
4260 2           xs_jit_line(aTHX_ b, "STRLEN key_len;");
4261 2           xs_jit_line(aTHX_ b, "const char* key;");
4262 2           xs_jit_check_items(aTHX_ b, 1, 1, "$self");
4263 2           xs_jit_blank(aTHX_ b);
4264 2           xs_jit_comment(aTHX_ b, "Create shallow copy of hash");
4265 2           xs_jit_assign(aTHX_ b, "copy", "newHV()");
4266 2           xs_jit_line(aTHX_ b, "hv_iterinit(hv);");
4267 2           xs_jit_while(aTHX_ b, "(entry = hv_iternext(hv)) != NULL");
4268 2           xs_jit_assign(aTHX_ b, "key_sv", "hv_iterkeysv(entry)");
4269 2           xs_jit_assign(aTHX_ b, "val", "hv_iterval(hv, entry)");
4270 2           xs_jit_assign(aTHX_ b, "key", "SvPV(key_sv, key_len)");
4271 2           xs_jit_comment(aTHX_ b, "Skip private attributes (starting with _)");
4272 2           xs_jit_if(aTHX_ b, "key_len > 0 && key[0] == '_'");
4273 2           xs_jit_line(aTHX_ b, "continue;");
4274 2           xs_jit_endif(aTHX_ b);
4275 2           xs_jit_line(aTHX_ b, "(void)hv_store(copy, key, key_len, SvREFCNT_inc(val), 0);");
4276 2           xs_jit_endloop(aTHX_ b);
4277 2           xs_jit_blank(aTHX_ b);
4278 2           xs_jit_return_sv(aTHX_ b, "sv_2mortal(newRV_noinc((SV*)copy))");
4279 2           xs_jit_xs_end(aTHX_ b);
4280 2           xs_jit_blank(aTHX_ b);
4281              
4282             /* TO_HASH() - returns hashref copy (all keys including private) */
4283 2           xs_jit_xs_function(aTHX_ b, "TO_HASH");
4284 2           xs_jit_xs_preamble(aTHX_ b);
4285 2           xs_jit_get_self_hv(aTHX_ b);
4286 2           xs_jit_comment(aTHX_ b, "Declare all variables at top for C89");
4287 2           xs_jit_declare_hv(aTHX_ b, "copy", NULL);
4288 2           xs_jit_line(aTHX_ b, "HE* entry;");
4289 2           xs_jit_line(aTHX_ b, "SV* key_sv;");
4290 2           xs_jit_line(aTHX_ b, "SV* val;");
4291 2           xs_jit_line(aTHX_ b, "STRLEN key_len;");
4292 2           xs_jit_line(aTHX_ b, "const char* key;");
4293 2           xs_jit_check_items(aTHX_ b, 1, 1, "$self");
4294 2           xs_jit_blank(aTHX_ b);
4295 2           xs_jit_comment(aTHX_ b, "Create shallow copy of hash (all keys)");
4296 2           xs_jit_assign(aTHX_ b, "copy", "newHV()");
4297 2           xs_jit_line(aTHX_ b, "hv_iterinit(hv);");
4298 2           xs_jit_while(aTHX_ b, "(entry = hv_iternext(hv)) != NULL");
4299 2           xs_jit_assign(aTHX_ b, "key_sv", "hv_iterkeysv(entry)");
4300 2           xs_jit_assign(aTHX_ b, "val", "hv_iterval(hv, entry)");
4301 2           xs_jit_assign(aTHX_ b, "key", "SvPV(key_sv, key_len)");
4302 2           xs_jit_line(aTHX_ b, "(void)hv_store(copy, key, key_len, SvREFCNT_inc(val), 0);");
4303 2           xs_jit_endloop(aTHX_ b);
4304 2           xs_jit_blank(aTHX_ b);
4305 2           xs_jit_return_sv(aTHX_ b, "sv_2mortal(newRV_noinc((SV*)copy))");
4306 2           xs_jit_xs_end(aTHX_ b);
4307 2           xs_jit_blank(aTHX_ b);
4308 2           }
4309              
4310             /* Generate Observable role methods */
4311 4           static void xs_jit_role_observable(pTHX_ XS_JIT_Builder* b, XS_JIT_RoleOpts* opts) {
4312 4           const char* observers_attr = "_observers";
4313 4           STRLEN observers_attr_len = 10;
4314             char len_buf[32];
4315              
4316 4 100         if (opts && opts->observers_attr) {
    50          
4317 2           observers_attr = opts->observers_attr;
4318 2           observers_attr_len = opts->observers_attr_len;
4319             }
4320              
4321 4           snprintf(len_buf, sizeof(len_buf), "%lu", (unsigned long)observers_attr_len);
4322              
4323             /* add_observer($callback) - adds callback to observers list */
4324 4           xs_jit_xs_function(aTHX_ b, "add_observer");
4325 4           xs_jit_xs_preamble(aTHX_ b);
4326 4           xs_jit_get_self_hv(aTHX_ b);
4327 4           xs_jit_comment(aTHX_ b, "Declare all variables at top for C89");
4328 4           xs_jit_line(aTHX_ b, "SV* callback;");
4329 4           xs_jit_declare_av(aTHX_ b, "observers", NULL);
4330 4           xs_jit_check_items(aTHX_ b, 2, 2, "$self, $callback");
4331 4           xs_jit_blank(aTHX_ b);
4332 4           xs_jit_assign(aTHX_ b, "callback", "ST(1)");
4333 4           xs_jit_if(aTHX_ b, "!SvROK(callback) || SvTYPE(SvRV(callback)) != SVt_PVCV");
4334 4           xs_jit_croak(aTHX_ b, "add_observer() requires a code reference");
4335 4           xs_jit_endif(aTHX_ b);
4336 4           xs_jit_blank(aTHX_ b);
4337 4           xs_jit_comment(aTHX_ b, "Get or create observers array");
4338 4           xs_jit_hv_fetch(aTHX_ b, "hv", observers_attr, observers_attr_len, "obs_svp");
4339 4           xs_jit_if(aTHX_ b, "obs_svp && SvROK(*obs_svp) && SvTYPE(SvRV(*obs_svp)) == SVt_PVAV");
4340 4           xs_jit_assign(aTHX_ b, "observers", "(AV*)SvRV(*obs_svp)");
4341 4           xs_jit_else(aTHX_ b);
4342 4           xs_jit_assign(aTHX_ b, "observers", "newAV()");
4343 4           xs_jit_hv_store(aTHX_ b, "hv", observers_attr, observers_attr_len, "newRV_noinc((SV*)observers)");
4344 4           xs_jit_endif(aTHX_ b);
4345 4           xs_jit_blank(aTHX_ b);
4346 4           xs_jit_comment(aTHX_ b, "Add callback to list");
4347 4           xs_jit_av_push(aTHX_ b, "observers", "SvREFCNT_inc(callback)");
4348 4           xs_jit_return_self(aTHX_ b);
4349 4           xs_jit_xs_end(aTHX_ b);
4350 4           xs_jit_blank(aTHX_ b);
4351              
4352             /* remove_observer($callback) - removes callback from list */
4353 4           xs_jit_xs_function(aTHX_ b, "remove_observer");
4354 4           xs_jit_xs_preamble(aTHX_ b);
4355 4           xs_jit_get_self_hv(aTHX_ b);
4356 4           xs_jit_comment(aTHX_ b, "Declare all variables at top for C89");
4357 4           xs_jit_line(aTHX_ b, "SV* callback;");
4358 4           xs_jit_declare_av(aTHX_ b, "observers", NULL);
4359 4           xs_jit_line(aTHX_ b, "SSize_t len;");
4360 4           xs_jit_line(aTHX_ b, "IV i;");
4361 4           xs_jit_check_items(aTHX_ b, 2, 2, "$self, $callback");
4362 4           xs_jit_blank(aTHX_ b);
4363 4           xs_jit_assign(aTHX_ b, "callback", "ST(1)");
4364 4           xs_jit_hv_fetch(aTHX_ b, "hv", observers_attr, observers_attr_len, "obs_svp");
4365 4           xs_jit_if(aTHX_ b, "!obs_svp || !SvROK(*obs_svp) || SvTYPE(SvRV(*obs_svp)) != SVt_PVAV");
4366 4           xs_jit_return_self(aTHX_ b);
4367 4           xs_jit_endif(aTHX_ b);
4368 4           xs_jit_blank(aTHX_ b);
4369 4           xs_jit_assign(aTHX_ b, "observers", "(AV*)SvRV(*obs_svp)");
4370 4           xs_jit_line(aTHX_ b, "len = av_len(observers);");
4371 4           xs_jit_for(aTHX_ b, "i = 0", "i <= len", "i++");
4372 4           xs_jit_av_fetch(aTHX_ b, "observers", "i", "elem_svp");
4373 4           xs_jit_if(aTHX_ b, "elem_svp && *elem_svp && sv_eq(*elem_svp, callback)");
4374 4           xs_jit_comment(aTHX_ b, "Remove this element - av_delete returns SV without changing refcnt");
4375 4           xs_jit_line(aTHX_ b, "(void)av_delete(observers, i, G_DISCARD);");
4376 4           xs_jit_line(aTHX_ b, "break;");
4377 4           xs_jit_endif(aTHX_ b);
4378 4           xs_jit_endloop(aTHX_ b);
4379 4           xs_jit_return_self(aTHX_ b);
4380 4           xs_jit_xs_end(aTHX_ b);
4381 4           xs_jit_blank(aTHX_ b);
4382              
4383             /* notify_observers(@args) - calls all observers with @args */
4384 4           xs_jit_xs_function(aTHX_ b, "notify_observers");
4385 4           xs_jit_xs_preamble(aTHX_ b);
4386 4           xs_jit_get_self_hv(aTHX_ b);
4387 4           xs_jit_comment(aTHX_ b, "Declare all variables at top for C89");
4388 4           xs_jit_declare_av(aTHX_ b, "observers", NULL);
4389 4           xs_jit_line(aTHX_ b, "SSize_t len;");
4390 4           xs_jit_line(aTHX_ b, "SSize_t args_len;");
4391 4           xs_jit_line(aTHX_ b, "IV i, j;");
4392 4           xs_jit_line(aTHX_ b, "AV* args_av;");
4393 4           xs_jit_line(aTHX_ b, "SV** arg_svp;");
4394 4           xs_jit_line(aTHX_ b, "PERL_UNUSED_VAR(items);");
4395 4           xs_jit_blank(aTHX_ b);
4396 4           xs_jit_hv_fetch(aTHX_ b, "hv", observers_attr, observers_attr_len, "obs_svp");
4397 4           xs_jit_if(aTHX_ b, "!obs_svp || !SvROK(*obs_svp) || SvTYPE(SvRV(*obs_svp)) != SVt_PVAV");
4398 4           xs_jit_return_self(aTHX_ b);
4399 4           xs_jit_endif(aTHX_ b);
4400 4           xs_jit_blank(aTHX_ b);
4401 4           xs_jit_assign(aTHX_ b, "observers", "(AV*)SvRV(*obs_svp)");
4402 4           xs_jit_line(aTHX_ b, "len = av_len(observers);");
4403 4           xs_jit_blank(aTHX_ b);
4404 4           xs_jit_comment(aTHX_ b, "Call each observer with all args passed to notify_observers");
4405 4           xs_jit_comment(aTHX_ b, "First, save args since we'll modify the stack");
4406 4           xs_jit_assign(aTHX_ b, "args_av", "NULL");
4407 4           xs_jit_if(aTHX_ b, "items > 1");
4408 4           xs_jit_assign(aTHX_ b, "args_av", "newAV()");
4409 4           xs_jit_for(aTHX_ b, "j = 1", "j < items", "j++");
4410 4           xs_jit_line(aTHX_ b, "av_push(args_av, SvREFCNT_inc(ST(j)));");
4411 4           xs_jit_endloop(aTHX_ b);
4412 4           xs_jit_endif(aTHX_ b);
4413 4           xs_jit_blank(aTHX_ b);
4414 4           xs_jit_for(aTHX_ b, "i = 0", "i <= len", "i++");
4415 4           xs_jit_av_fetch(aTHX_ b, "observers", "i", "cb_svp");
4416 4           xs_jit_if(aTHX_ b, "!cb_svp || !*cb_svp || !SvOK(*cb_svp)");
4417 4           xs_jit_line(aTHX_ b, "continue;");
4418 4           xs_jit_endif(aTHX_ b);
4419 4           xs_jit_blank(aTHX_ b);
4420 4           xs_jit_block_start(aTHX_ b);
4421 4           xs_jit_line(aTHX_ b, "ENTER;");
4422 4           xs_jit_line(aTHX_ b, "SAVETMPS;");
4423 4           xs_jit_line(aTHX_ b, "PUSHMARK(SP);");
4424 4           xs_jit_comment(aTHX_ b, "Push saved arguments");
4425 4           xs_jit_if(aTHX_ b, "args_av");
4426 4           xs_jit_assign(aTHX_ b, "args_len", "av_len(args_av)");
4427 4           xs_jit_for(aTHX_ b, "j = 0", "j <= args_len", "j++");
4428 4           xs_jit_assign(aTHX_ b, "arg_svp", "av_fetch(args_av, j, 0)");
4429 4           xs_jit_if(aTHX_ b, "arg_svp && *arg_svp");
4430 4           xs_jit_line(aTHX_ b, "XPUSHs(*arg_svp);");
4431 4           xs_jit_endif(aTHX_ b);
4432 4           xs_jit_endloop(aTHX_ b);
4433 4           xs_jit_endif(aTHX_ b);
4434 4           xs_jit_line(aTHX_ b, "PUTBACK;");
4435 4           xs_jit_line(aTHX_ b, "call_sv(*cb_svp, G_DISCARD);");
4436 4           xs_jit_line(aTHX_ b, "SPAGAIN;");
4437 4           xs_jit_line(aTHX_ b, "FREETMPS;");
4438 4           xs_jit_line(aTHX_ b, "LEAVE;");
4439 4           xs_jit_block_end(aTHX_ b);
4440 4           xs_jit_endloop(aTHX_ b);
4441 4           xs_jit_blank(aTHX_ b);
4442 4           xs_jit_comment(aTHX_ b, "Free saved args");
4443 4           xs_jit_if(aTHX_ b, "args_av");
4444 4           xs_jit_line(aTHX_ b, "SvREFCNT_dec((SV*)args_av);");
4445 4           xs_jit_endif(aTHX_ b);
4446 4           xs_jit_blank(aTHX_ b);
4447 4           xs_jit_return_self(aTHX_ b);
4448 4           xs_jit_xs_end(aTHX_ b);
4449 4           xs_jit_blank(aTHX_ b);
4450 4           }
4451              
4452             /* Main role dispatcher */
4453 17           void xs_jit_role(pTHX_ XS_JIT_Builder* b, XS_JIT_RoleType role, XS_JIT_RoleOpts* opts) {
4454 17 50         if (!b) return;
4455              
4456 17           switch (role) {
4457 7           case XS_JIT_ROLE_COMPARABLE:
4458 7           xs_jit_role_comparable(aTHX_ b, opts);
4459 7           break;
4460 4           case XS_JIT_ROLE_CLONEABLE:
4461 4           xs_jit_role_cloneable(aTHX_ b, opts);
4462 4           break;
4463 2           case XS_JIT_ROLE_SERIALIZABLE:
4464 2           xs_jit_role_serializable(aTHX_ b, opts);
4465 2           break;
4466 4           case XS_JIT_ROLE_OBSERVABLE:
4467 4           xs_jit_role_observable(aTHX_ b, opts);
4468 4           break;
4469 0           default:
4470 0           croak("Unknown role type: %d", (int)role);
4471             }
4472             }