33**
44** This fixture is intentionally built without either ARM64 side test seam.
55** The no-helper build is an embedded-Lua smoke test. The helper build adds
6- ** white-box checks for three independently recorded prototype/root/child pairs,
6+ ** white-box checks for four independently recorded prototype/root/child pairs,
77** native entry, authenticated exit-table representation, and retirement.
88*/
99
@@ -101,17 +101,25 @@ static void define_probes(lua_State *L)
101101 "end "
102102 "return i "
103103 "end "
104- "local function unsupported (n, bias) "
104+ "local function fourth (n, bias) "
105105 "local i=0 "
106106 "while i<n do "
107107 "i=(i~=0 and i or i)+2 "
108108 "end "
109109 "return i "
110110 "end "
111+ "local function unsupported(n, bias) "
112+ "local i=0 "
113+ "while i<n do "
114+ "i=(i~=0 and i or i)+3 "
115+ "end "
116+ "return i "
117+ "end "
111118 "__arm64_first_side_production_decoy=decoy; "
112119 "__arm64_first_side_production_first=first; "
113120 "__arm64_first_side_production_second=second; "
114121 "__arm64_first_side_production_third=third; "
122+ "__arm64_first_side_production_fourth=fourth; "
115123 "__arm64_first_side_production_unsupported=unsupported" );
116124}
117125
@@ -127,6 +135,19 @@ static int smoke_main(void)
127135 luaL_openlibs (L );
128136 define_probes (L );
129137
138+ /* Run the two same-bytecode exit-6 variants before unrelated hot-count
139+ ** slots can collide. The +2 root is recorded with n=3 and its admitted
140+ ** root-linked child with n=5; repeated +3 calls retain only the root. */
141+ assert (call_named (L , "__arm64_first_side_production_fourth" , 3 , 0 ) == 4 );
142+ assert (call_named (L , "__arm64_first_side_production_fourth" , 3 , 0 ) == 4 );
143+ assert (call_named (L , "__arm64_first_side_production_fourth" , 5 , 0 ) == 6 );
144+ assert (call_named (L , "__arm64_first_side_production_fourth" , 5 , 0 ) == 6 );
145+ assert (call_named (L , "__arm64_first_side_production_fourth" , 5 , 0 ) == 6 );
146+ assert (call_named (L , "__arm64_first_side_production_fourth" , 5 , 0 ) == 6 );
147+ for (attempt = 0 ; attempt < PRODUCTION_ROOT_ATTEMPTS ; attempt ++ )
148+ assert (call_named (L , "__arm64_first_side_production_unsupported" ,
149+ 4 , 0 ) == 6 );
150+
130151 assert (call_named (L , "__arm64_first_side_production_decoy" , 3 , 0 ) == 3 );
131152 assert (call_named (L , "__arm64_first_side_production_first" , 3 , 0 ) == 3 );
132153 assert (call_named (L , "__arm64_first_side_production_first" , 3 , 1 ) == 4 );
@@ -138,20 +159,16 @@ static int smoke_main(void)
138159 assert (call_named (L , "__arm64_first_side_production_third" , 4 , 0 ) == 4 );
139160 assert (call_named (L , "__arm64_first_side_production_third" , 4 , 0 ) == 4 );
140161 assert (call_named (L , "__arm64_first_side_production_third" , 3 , 0 ) == 3 );
141- for (attempt = 0 ; attempt < PRODUCTION_ROOT_ATTEMPTS ; attempt ++ )
142- assert (call_named (L , "__arm64_first_side_production_unsupported" ,
143- 3 , 0 ) == 4 );
144-
145162 run_lua (L ,
146163 "local util=require('jit.util'); local live, roots, sides=0,0,0; "
147164 "for tr=1,32 do local i=util.traceinfo(tr); if i then "
148165 "live=live+1; "
149166 "if i.linktype=='loop' then roots=roots+1 "
150167 "elseif i.linktype=='root' then sides=sides+1 end "
151168 "end end; "
152- "assert(live==8 , 'expected eight production traces, got '..live); "
153- "assert(roots==5 , 'expected five roots, got '..roots); "
154- "assert(sides==3 , 'expected three first sides, got '..sides)" );
169+ "assert(live==10 , 'expected ten production traces, got '..live); "
170+ "assert(roots==6 , 'expected six roots, got '..roots); "
171+ "assert(sides==4 , 'expected four first sides, got '..sides)" );
155172
156173 lua_close (L );
157174 puts ("t-arm64-jit-first-side-production smoke OK" );
@@ -174,12 +191,12 @@ static int smoke_main(void)
174191#include "lj_trace.h"
175192
176193enum {
177- PRODUCTION_PAIR_COUNT = 3 ,
194+ PRODUCTION_PAIR_COUNT = 4 ,
178195 PRODUCTION_CHILD_EXIT = 3 ,
179196 PRODUCTION_TOPSLOT = 5 ,
180197 PRODUCTION_CHILD_NSNAP = 5 ,
181198 PRODUCTION_CHILD_NSNAPMAP = 17 ,
182- PRODUCTION_CHILD_K_ONE = REF_TRUE - 1u ,
199+ PRODUCTION_CHILD_K_ADDEND = REF_TRUE - 1u ,
183200 PRODUCTION_CHILD_R_PARENT = REF_BASE + 1u ,
184201 PRODUCTION_CHILD_R_CGET = REF_BASE + 2u ,
185202 PRODUCTION_CHILD_R_ADD = REF_BASE + 3u ,
@@ -206,6 +223,7 @@ typedef struct ProductionPair {
206223 MSize child_pcpos [PRODUCTION_CHILD_NSNAP ];
207224 Reg inherited_reg ;
208225 Reg sload_reg ;
226+ int32_t addend ;
209227 GCproto * pt ;
210228 TraceNo rootno ;
211229 TraceNo childno ;
@@ -501,7 +519,7 @@ static void expect_child_shape(jit_State *J, global_State *g,
501519 assert (trace_exittab_nslots_acq (pair -> child ) ==
502520 PRODUCTION_CHILD_NSNAP + 1u );
503521 assert (ir != NULL && snap != NULL && snapmap != NULL && exittab != NULL );
504- assert (trace_nk_acq (pair -> child ) == PRODUCTION_CHILD_K_ONE );
522+ assert (trace_nk_acq (pair -> child ) == PRODUCTION_CHILD_K_ADDEND );
505523 assert (trace_nins_acq (pair -> child ) ==
506524 PRODUCTION_CHILD_SEMANTIC_NINS + 1u );
507525 assert (la_load8_acq (& pair -> child -> unused1 ) ==
@@ -521,7 +539,7 @@ static void expect_child_shape(jit_State *J, global_State *g,
521539 IRSLOAD_PARENT |IRSLOAD_INHERIT );
522540 EXPECT_CHILD_IR (PRODUCTION_CHILD_R_CGET , IR_NOP , IRT_NIL , 0 , 0 );
523541 EXPECT_CHILD_IR (PRODUCTION_CHILD_R_ADD , IR_ADDOV , IRT_INT |IRT_GUARD ,
524- PRODUCTION_CHILD_R_PARENT , PRODUCTION_CHILD_K_ONE );
542+ PRODUCTION_CHILD_R_PARENT , PRODUCTION_CHILD_K_ADDEND );
525543 EXPECT_CHILD_IR (PRODUCTION_CHILD_R_LIMIT , IR_SLOAD , IRT_INT |IRT_GUARD , 2 ,
526544 IRSLOAD_TYPECHECK );
527545 EXPECT_CHILD_IR (PRODUCTION_CHILD_R_GT , IR_GT , IRT_INT |IRT_GUARD ,
@@ -530,8 +548,9 @@ static void expect_child_shape(jit_State *J, global_State *g,
530548 1 , 0 );
531549 EXPECT_CHILD_IR (PRODUCTION_CHILD_SEMANTIC_NINS , IR_NOP , IRT_NIL , 0 , 0 );
532550#undef EXPECT_CHILD_IR
533- ins = ir_load_acq (& ir [PRODUCTION_CHILD_K_ONE ]);
534- assert (ins .o == IR_KINT && ins .t .irt == IRT_INT && ins .i == 1 );
551+ ins = ir_load_acq (& ir [PRODUCTION_CHILD_K_ADDEND ]);
552+ assert (ins .o == IR_KINT && ins .t .irt == IRT_INT &&
553+ ins .i == pair -> addend );
535554 ins = ir_load_acq (& ir [REF_BASE ]);
536555 assert (ins .r == RID_BASE && ins .s == SPS_NONE );
537556 ins = ir_load_acq (& ir [PRODUCTION_CHILD_R_PARENT ]);
@@ -619,6 +638,18 @@ static void expect_native_child(lua_State *L, jit_State *J,
619638 lj_trace_test_reset_exit_stats ();
620639 assert (call_named (L , pair -> name , pair -> native_n , pair -> native_bias ) ==
621640 pair -> native_result );
641+ if (lj_trace_test_exit_calls () != 1 ||
642+ lj_trace_test_first_exit_parent () != pair -> childno ||
643+ lj_trace_test_first_exitno () != PRODUCTION_CHILD_EXIT ||
644+ lj_trace_test_last_exit_parent () != pair -> childno ||
645+ lj_trace_test_last_exitno () != PRODUCTION_CHILD_EXIT )
646+ fprintf (stderr ,
647+ "native child %s: calls=%u first=%u/%u last=%u/%u child=%u\n" ,
648+ pair -> name , (unsigned )lj_trace_test_exit_calls (),
649+ (unsigned )lj_trace_test_first_exit_parent (),
650+ (unsigned )lj_trace_test_first_exitno (),
651+ (unsigned )lj_trace_test_last_exit_parent (),
652+ (unsigned )lj_trace_test_last_exitno (), (unsigned )pair -> childno );
622653 assert (lj_trace_test_exit_calls () == 1 );
623654 assert (lj_trace_test_first_exit_parent () == pair -> childno );
624655 assert (lj_trace_test_first_exitno () == PRODUCTION_CHILD_EXIT );
@@ -652,6 +683,28 @@ static void expect_unsupported_first_side_closed(lua_State *L, jit_State *J,
652683 expect_edge (g , pair , pair -> root_fallback );
653684}
654685
686+ static void expect_return_linked_variant_closed (lua_State * L , jit_State * J ,
687+ global_State * g , ProductionPair * pair )
688+ {
689+ uint32_t before = live_trace_count (J );
690+ MSize count_before = snap_count_acq (& pair -> root_snap [pair -> exitno ]);
691+ MSize count_after ;
692+ assert (pair -> exitno == 6 && pair -> addend == 2 );
693+ assert (count_before < SNAPCOUNT_DONE - 2u );
694+ lj_trace_test_reset_exittab_stats ();
695+ assert (call_named (L , pair -> name , 3 , 0 ) == 4 );
696+ assert (call_named (L , pair -> name , 3 , 0 ) == 4 );
697+ count_after = snap_count_acq (& pair -> root_snap [pair -> exitno ]);
698+ assert (lj_trace_test_abort_count () == 2 );
699+ assert (lj_trace_test_last_abort_error () == LJ_TRERR_NYIIR );
700+ assert (count_after == count_before + 2u && count_after < SNAPCOUNT_DONE );
701+ assert (live_trace_count (J ) == before );
702+ assert (trace_runnable_acq (pair -> root , pair -> rootno ));
703+ assert (trace_nchild_acq (pair -> root ) == 0 );
704+ assert (trace_nextside_acq (pair -> root ) == 0 );
705+ expect_edge (g , pair , pair -> root_fallback );
706+ }
707+
655708static void expect_quiescent (lua_State * L , jit_State * J , global_State * g ,
656709 TGState * tg , void * saved_cframe , int32_t saved_vmstate )
657710{
@@ -735,7 +788,7 @@ static void expect_full_flush(lua_State *L, jit_State *J, global_State *g,
735788 unsigned i ;
736789 lj_trace_test_reset_retire_publish_calls ();
737790 assert (lj_trace_flushall_gc (L ) == 0 );
738- assert (lj_trace_test_retire_publish_calls () == 8u );
791+ assert (lj_trace_test_retire_publish_calls () == 10u );
739792 assert (trace_traceno_acq (decoy ) == 0 );
740793 assert (proto_trace_acq (decoy_pt ) == 0 );
741794 for (i = 0 ; i < PRODUCTION_PAIR_COUNT ; i ++ ) {
@@ -778,7 +831,7 @@ static int detailed_main(int argc, char **argv)
778831 .native_n = 3 , .native_bias = 1 , .native_result = 4 ,
779832 .exitno = 2 , .root_nsnap = 8 , .continuation_pos = 13 ,
780833 .child_pcpos = { 13 , 14 , 3 , 17 , 7 },
781- .inherited_reg = RID_X28 , .sload_reg = RID_X27
834+ .inherited_reg = RID_X28 , .sload_reg = RID_X27 , . addend = 1
782835 },
783836 {
784837 .name = "__arm64_first_side_production_second" ,
@@ -787,7 +840,7 @@ static int detailed_main(int argc, char **argv)
787840 .native_n = 2 , .native_bias = 0 , .native_result = 2 ,
788841 .exitno = 6 , .root_nsnap = 9 , .continuation_pos = 10 ,
789842 .child_pcpos = { 10 , 11 , 3 , 17 , 7 },
790- .inherited_reg = RID_X27 , .sload_reg = RID_X28
843+ .inherited_reg = RID_X27 , .sload_reg = RID_X28 , . addend = 1
791844 },
792845 {
793846 .name = "__arm64_first_side_production_third" ,
@@ -796,16 +849,25 @@ static int detailed_main(int argc, char **argv)
796849 .native_n = 3 , .native_bias = 0 , .native_result = 3 ,
797850 .exitno = 7 , .root_nsnap = 11 , .continuation_pos = 13 ,
798851 .child_pcpos = { 13 , 14 , 3 , 17 , 7 },
799- .inherited_reg = RID_X28 , .sload_reg = RID_X27
852+ .inherited_reg = RID_X28 , .sload_reg = RID_X27 , .addend = 1
853+ },
854+ {
855+ .name = "__arm64_first_side_production_fourth" ,
856+ .root_n = 3 , .root_bias = 0 , .root_result = 4 ,
857+ .side_n = 5 , .side_bias = 0 , .side_result = 6 ,
858+ .native_n = 3 , .native_bias = 0 , .native_result = 4 ,
859+ .exitno = 6 , .root_nsnap = 9 , .continuation_pos = 10 ,
860+ .child_pcpos = { 10 , 11 , 3 , 17 , 7 },
861+ .inherited_reg = RID_X27 , .sload_reg = RID_X28 , .addend = 2
800862 }
801863 };
802864 ProductionPair unsupported = {
803865 .name = "__arm64_first_side_production_unsupported" ,
804- .root_n = 3 , .root_bias = 0 , .root_result = 4 ,
805- .side_n = 3 , .side_bias = 0 , .side_result = 4 ,
866+ .root_n = 4 , .root_bias = 0 , .root_result = 6 ,
867+ .side_n = 7 , .side_bias = 0 , .side_result = 9 ,
806868 .exitno = 6 , .root_nsnap = 9 , .continuation_pos = 10 ,
807869 .child_pcpos = { 10 , 11 , 3 , 17 , 7 },
808- .inherited_reg = RID_X27 , .sload_reg = RID_X28
870+ .inherited_reg = RID_X27 , .sload_reg = RID_X28 , . addend = 3
809871 };
810872 void * saved_cframe ;
811873 int32_t saved_vmstate ;
@@ -834,26 +896,31 @@ static int detailed_main(int argc, char **argv)
834896 record_root (L , J , & pairs [i ]);
835897 expect_root_shape (J , g , & pairs [i ]);
836898 assert (pairs [i ].rootno > (i == 0 ? decoy_no : pairs [i - 1u ].childno ));
899+ if (pairs [i ].addend == 2 )
900+ expect_return_linked_variant_closed (L , J , g , & pairs [i ]);
837901 expect_post_token_request_cleanup (L , J , g , tg , & pairs [i ]);
838902 record_child (L , J , & pairs [i ]);
839903 expect_child_shape (J , g , & pairs [i ]);
840904 for (j = 0 ; j < i ; j ++ ) {
841905 assert (pairs [i ].rootno != pairs [j ].rootno );
842906 assert (pairs [i ].rootno != pairs [j ].childno );
843907 assert (pairs [i ].childno != pairs [j ].childno );
844- assert (pairs [i ].exitno != pairs [j ].exitno );
908+ assert (pairs [i ].exitno != pairs [j ].exitno ||
909+ pairs [i ].addend != pairs [j ].addend );
845910 }
846911 }
912+ assert (pairs [1 ].exitno == 6 && pairs [1 ].addend == 1 );
913+ assert (pairs [3 ].exitno == 6 && pairs [3 ].addend == 2 );
847914 assert (pairs [0 ].rootno != 1 && pairs [0 ].childno != 2 );
848915 expect_unsupported_first_side_closed (L , J , g , & unsupported );
849916 assert (unsupported .rootno > pairs [PRODUCTION_PAIR_COUNT - 1u ].childno );
850- assert (live_trace_count (J ) == 8u );
917+ assert (live_trace_count (J ) == 10u );
851918
852919 expect_quiescent (L , J , g , tg , saved_cframe , saved_vmstate );
853920 for (j = 0 ; j < 2 ; j ++ )
854921 for (i = 0 ; i < PRODUCTION_PAIR_COUNT ; i ++ )
855922 expect_native_child (L , J , & pairs [i ]);
856- assert (live_trace_count (J ) == 8u );
923+ assert (live_trace_count (J ) == 10u );
857924 for (i = 0 ; i < PRODUCTION_PAIR_COUNT ; i ++ )
858925 expect_edge (g , & pairs [i ], pairs [i ].child_mcode );
859926 expect_quiescent (L , J , g , tg , saved_cframe , saved_vmstate );
0 commit comments