-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathOpcodes.java
More file actions
1112 lines (882 loc) · 47.8 KB
/
Opcodes.java
File metadata and controls
1112 lines (882 loc) · 47.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
package org.perlonjava.backend.bytecode;
// To check for duplicate or out-of-order opcode numbers, run:
// perl dev/tools/check_opcodes.pl src/main/java/org/perlonjava/backend/bytecode/Opcodes.java
// To renumber the absolute block (284+) to fill gaps, add --renumber.
/**
* Bytecode opcodes for the PerlOnJava interpreter.
*
* Design: Pure register machine with 3-address code format.
* Uses SHORT opcodes (0-32767) to support unlimited operation space.
*
* CRITICAL: Keep opcodes CONTIGUOUS within functional groups for JVM
* tableswitch optimization (O(1) vs O(log n) lookupswitch).
*
* Register architecture is REQUIRED for control flow correctness:
* Perl's GOTO/last/next/redo would corrupt a stack-based architecture.
*
* Opcode Ranges:
* - 0-113: Core operations (current)
* - 114-199: Reserved for expansion
* - 200-299: Reserved
* - 300+: Future operator promotions (CONTIGUOUS blocks!)
*
* Infrastructure: Bytecode already uses short[] array, compiler already
* emits short values. Only the opcode type definitions changed.
*/
public class Opcodes {
// =================================================================
// CONTROL FLOW (0-4)
// =================================================================
/** No operation (padding/alignment) */
public static final short NOP = 0;
/** Return from subroutine: return rd
* May return RuntimeControlFlowList for last/next/redo/goto */
public static final short RETURN = 1;
/** Unconditional jump: pc = offset (absolute bytecode offset) */
public static final short GOTO = 2;
/** Conditional jump: if (!rs) pc = offset */
public static final short GOTO_IF_FALSE = 3;
/** Conditional jump: if (rs) pc = offset */
public static final short GOTO_IF_TRUE = 4;
// =================================================================
// REGISTER OPERATIONS (5-9)
// =================================================================
/** Register copy: rd = rs */
public static final short MOVE = 5;
/** Load from constant pool: rd = constants[index] */
public static final short LOAD_CONST = 6;
/** Load cached integer: rd = RuntimeScalarCache.getScalarInt(immediate32) */
public static final short LOAD_INT = 7;
/** Load string: rd = new RuntimeScalar(stringPool[index]) */
public static final short LOAD_STRING = 8;
/** Load undef: rd = new RuntimeScalar() */
public static final short LOAD_UNDEF = 9;
// =================================================================
// VARIABLE ACCESS - GLOBAL (10-16)
// =================================================================
/** Load global scalar: rd = GlobalVariable.getGlobalScalar(stringPool[index]) */
public static final short LOAD_GLOBAL_SCALAR = 10;
/** Store global scalar: GlobalVariable.getGlobalScalar(stringPool[index]).set(rs) */
public static final short STORE_GLOBAL_SCALAR = 11;
/** Load global array: rd = GlobalVariable.getGlobalArray(stringPool[index]) */
public static final short LOAD_GLOBAL_ARRAY = 12;
/** Store global array: GlobalVariable.getGlobalArray(stringPool[index]).elements = rs */
public static final short STORE_GLOBAL_ARRAY = 13;
/** Load global hash: rd = GlobalVariable.getGlobalHash(stringPool[index]) */
public static final short LOAD_GLOBAL_HASH = 14;
/** Store global hash: GlobalVariable.getGlobalHash(stringPool[index]).elements = rs */
public static final short STORE_GLOBAL_HASH = 15;
/** Load global code: rd = GlobalVariable.getGlobalCodeRef(stringPool[index]) */
public static final short LOAD_GLOBAL_CODE = 16;
// =================================================================
// ARITHMETIC OPERATORS (17-26) - call org.perlonjava.runtime.operators.MathOperators
// =================================================================
/** Addition: rd = MathOperators.add(rs1, rs2) */
public static final short ADD_SCALAR = 17;
/** Subtraction: rd = MathOperators.subtract(rs1, rs2) */
public static final short SUB_SCALAR = 18;
/** Multiplication: rd = MathOperators.multiply(rs1, rs2) */
public static final short MUL_SCALAR = 19;
/** Division: rd = MathOperators.divide(rs1, rs2) */
public static final short DIV_SCALAR = 20;
/** Modulus: rd = MathOperators.modulus(rs1, rs2) */
public static final short MOD_SCALAR = 21;
/** Exponentiation: rd = MathOperators.power(rs1, rs2) */
public static final short POW_SCALAR = 22;
/** Negation: rd = MathOperators.negate(rs) */
public static final short NEG_SCALAR = 23;
// Specialized unboxed operations (optimized for pure int math)
/** Addition with immediate: rd = rs + immediate32 (unboxed int fast path) */
public static final short ADD_SCALAR_INT = 24;
/** Subtraction with immediate: rd = rs - immediate32 (unboxed int fast path) */
public static final short SUB_SCALAR_INT = 25;
/** Multiplication with immediate: rd = rs * immediate32 (unboxed int fast path) */
public static final short MUL_SCALAR_INT = 26;
// =================================================================
// STRING OPERATORS (27-30) - call org.perlonjava.runtime.operators.StringOperators
// =================================================================
/** String concatenation: rd = StringOperators.concat(rs1, rs2) */
public static final short CONCAT = 27;
/** String repetition: rd = StringOperators.repeat(rs1, rs2) */
public static final short REPEAT = 28;
/** Substring: rd = StringOperators.substr(str_reg, offset_reg, length_reg) */
public static final short SUBSTR = 29;
/** String length: rd = StringOperators.length(rs) */
public static final short LENGTH = 30;
// =================================================================
// COMPARISON OPERATORS (31-38) - call org.perlonjava.runtime.operators.CompareOperators
// =================================================================
/** Numeric comparison: rd = CompareOperators.compareNum(rs1, rs2) */
public static final short COMPARE_NUM = 31;
/** String comparison: rd = CompareOperators.compareStr(rs1, rs2) */
public static final short COMPARE_STR = 32;
/** Numeric equality: rd = CompareOperators.numericEqual(rs1, rs2) */
public static final short EQ_NUM = 33;
/** Numeric inequality: rd = CompareOperators.numericNotEqual(rs1, rs2) */
public static final short NE_NUM = 34;
/** Less than: rd = CompareOperators.numericLessThan(rs1, rs2) */
public static final short LT_NUM = 35;
/** Greater than: rd = CompareOperators.numericGreaterThan(rs1, rs2) */
public static final short GT_NUM = 36;
/** String equality: rd = CompareOperators.stringEqual(rs1, rs2) */
public static final short EQ_STR = 37;
/** String inequality: rd = CompareOperators.stringNotEqual(rs1, rs2) */
public static final short NE_STR = 38;
// =================================================================
// LOGICAL OPERATORS (39-41)
// =================================================================
/** Logical NOT: rd = !rs */
public static final short NOT = 39;
/** Logical AND: rd = rs1 && rs2 (short-circuit handled in bytecode compiler) */
public static final short AND = 40;
/** Logical OR: rd = rs1 || rs2 (short-circuit handled in bytecode compiler) */
public static final short OR = 41;
// =================================================================
// ARRAY OPERATIONS (42-49) - use RuntimeArray API
// =================================================================
/** Array element access: rd = array_reg.get(index_reg) */
public static final short ARRAY_GET = 42;
/** Array element store: array_reg.set(index_reg, value_reg) */
public static final short ARRAY_SET = 43;
/** Array push: array_reg.push(value_reg) */
public static final short ARRAY_PUSH = 44;
/** Array pop: rd = array_reg.pop() */
public static final short ARRAY_POP = 45;
/** Array shift: rd = array_reg.shift() */
public static final short ARRAY_SHIFT = 46;
/** Array unshift: array_reg.unshift(value_reg) */
public static final short ARRAY_UNSHIFT = 47;
/** Array size: rd = new RuntimeScalar(array_reg.size()) */
public static final short ARRAY_SIZE = 48;
/** Create array: rd = new RuntimeArray() */
public static final short CREATE_ARRAY = 49;
// =================================================================
// HASH OPERATIONS (50-56) - use RuntimeHash API
// =================================================================
/** Hash element access: rd = hash_reg.get(key_reg) */
public static final short HASH_GET = 50;
/** Hash element store: hash_reg.put(key_reg, value_reg) */
public static final short HASH_SET = 51;
/** Hash exists: rd = hash_reg.exists(key_reg) */
public static final short HASH_EXISTS = 52;
/** Hash delete: rd = hash_reg.delete(key_reg) */
public static final short HASH_DELETE = 53;
/** Hash keys: rd = hash_reg.keys() */
public static final short HASH_KEYS = 54;
/** Hash values: rd = hash_reg.values() */
public static final short HASH_VALUES = 55;
/** Create hash reference from list: rd = RuntimeHash.createHash(rs_list).createReference() */
public static final short CREATE_HASH = 56;
// =================================================================
// SUBROUTINE CALLS (57-59) - RuntimeCode.apply
// =================================================================
/** Call subroutine: rd = RuntimeCode.apply(coderef_reg, args_reg, context)
* May return RuntimeControlFlowList for last/next/redo/goto */
public static final short CALL_SUB = 57;
/** Call method: rd = RuntimeCode.call(obj_reg, method_name, args_reg, context) */
public static final short CALL_METHOD = 58;
/** Call builtin: rd = BuiltinRegistry.call(builtin_id, args_reg, context) */
public static final short CALL_BUILTIN = 59;
// =================================================================
// CONTEXT OPERATIONS (60-61)
// =================================================================
/** List to scalar: rd = list_reg.scalar() */
public static final short LIST_TO_SCALAR = 60;
/** Scalar to list: rd = new RuntimeList(scalar_reg) */
public static final short SCALAR_TO_LIST = 61;
// =================================================================
// CONTROL FLOW - SPECIAL (62-67) - RuntimeControlFlowList
// =================================================================
/** Create LAST control flow: rd = new RuntimeControlFlowList(LAST, label_index) */
public static final short CREATE_LAST = 62;
/** Create NEXT control flow: rd = new RuntimeControlFlowList(NEXT, label_index) */
public static final short CREATE_NEXT = 63;
/** Create REDO control flow: rd = new RuntimeControlFlowList(REDO, label_index) */
public static final short CREATE_REDO = 64;
/** Create GOTO control flow: rd = new RuntimeControlFlowList(GOTO, label_index) */
public static final short CREATE_GOTO = 65;
/** Check if return value is control flow: rd = (rs instanceof RuntimeControlFlowList) */
public static final short IS_CONTROL_FLOW = 66;
/** Get control flow type: rd = ((RuntimeControlFlowList)rs).getControlFlowType().ordinal() */
public static final short GET_CONTROL_FLOW_TYPE = 67;
// =================================================================
// REFERENCE OPERATIONS (68-70)
// =================================================================
/** Create scalar reference: rd = new RuntimeScalar(rs) */
public static final short CREATE_REF = 68;
/** Dereference: rd = rs.dereference() */
public static final short DEREF = 69;
/** Type check: rd = new RuntimeScalar(rs.type.name()) */
public static final short GET_TYPE = 70;
// =================================================================
// MISCELLANEOUS (71-74)
// =================================================================
/** Print to filehandle: print(rs_content, rs_filehandle) */
public static final short PRINT = 71;
/** Say to filehandle: say(rs_content, rs_filehandle) */
public static final short SAY = 72;
/** Die with message: die(rs) */
public static final short DIE = 73;
/** Warn with message: warn(rs) */
public static final short WARN = 74;
// =================================================================
// SUPERINSTRUCTIONS (75-90) - Combine common opcode sequences
// These eliminate MOVE overhead by doing operation + store in one step
// =================================================================
/** Increment register in-place: rd = rd + 1 (combines ADD_SCALAR_INT + MOVE) */
public static final short INC_REG = 75;
/** Decrement register in-place: rd = rd - 1 (combines SUB_SCALAR_INT + MOVE) */
public static final short DEC_REG = 76;
/** Add and assign: rd = rd + rs (combines ADD_SCALAR + MOVE when dest == src1) */
public static final short ADD_ASSIGN = 77;
/** Add immediate and assign: rd = rd + imm (combines ADD_SCALAR_INT + MOVE when dest == src) */
public static final short ADD_ASSIGN_INT = 78;
/** Pre-increment: ++rd (calls RuntimeScalar.preAutoIncrement) */
public static final short PRE_AUTOINCREMENT = 79;
/** Post-increment: rd++ (calls RuntimeScalar.postAutoIncrement) */
public static final short POST_AUTOINCREMENT = 80;
/** Pre-decrement: --rd (calls RuntimeScalar.preAutoDecrement) */
public static final short PRE_AUTODECREMENT = 81;
/** Post-decrement: rd-- (calls RuntimeScalar.postAutoDecrement) */
public static final short POST_AUTODECREMENT = 82;
// =================================================================
// EVAL BLOCK SUPPORT (83-85) - Exception handling for eval blocks
// =================================================================
/**
* EVAL_TRY: Mark start of eval block with exception handling
* Format: [EVAL_TRY] [catch_offset_high] [catch_offset_low]
* Effect: Sets up exception handler. If exception occurs, jump to catch_offset.
* At start: Set $@ = ""
*/
public static final short EVAL_TRY = 83;
/**
* EVAL_CATCH: Mark start of catch block
* Format: [EVAL_CATCH] [rd]
* Effect: Exception object is captured, WarnDie.catchEval() is called to set $@,
* and undef is stored in rd as the eval result.
*/
public static final short EVAL_CATCH = 84;
/**
* EVAL_END: Mark end of successful eval block
* Format: [EVAL_END]
* Effect: Clear $@ = "" (nested evals may have set it)
*/
public static final short EVAL_END = 85;
/**
* CREATE_LIST: Create RuntimeList from registers
* Format: [CREATE_LIST] [rd] [count] [rs1] [rs2] ... [rsN]
* Effect: rd = new RuntimeList(registers[rs1], registers[rs2], ..., registers[rsN])
*
* Highly optimized for common cases:
* - count=0: Creates empty RuntimeList
* - count=1: Creates RuntimeList with single element
* - count>1: Creates RuntimeList and adds all elements
*
* This is the most performance-critical opcode for list operations.
*/
public static final short CREATE_LIST = 86;
// =================================================================
// SLOW OPERATIONS (87) - Single opcode for rarely-used operations
// =================================================================
/**
* SLOW_OP: Dispatch to rarely-used operation handler
* Format: [SLOW_OP] [slow_op_id] [operands...]
* Effect: Dispatches to SlowOpcodeHandler based on slow_op_id
*
* This uses only ONE opcode number but supports 256 slow operations
* via the slow_op_id byte parameter. Keeps main switch compact for
* CPU i-cache optimization while allowing unlimited rare operations.
*
* Philosophy:
* - Fast operations (0-90): Direct opcodes in main switch
* - Slow operations (via SLOW_OP): Delegated to SlowOpcodeHandler
*
* Performance: Adds ~5ns overhead but keeps main loop ~10-15% faster.
*/
public static final short SLOW_OP = 87;
// =================================================================
// STRING OPERATIONS (88)
// =================================================================
/** Join list elements with separator: rd = join(rs_separator, rs_list) */
public static final short JOIN = 88;
// =================================================================
// I/O OPERATIONS (89)
// =================================================================
/** Select default output filehandle: rd = IOOperator.select(rs_list, SCALAR) */
public static final short SELECT = 89;
/** Create range: rd = PerlRange.createRange(rs_start, rs_end) */
public static final short RANGE = 90;
/** Random number: rd = Random.rand(rs_max) */
public static final short RAND = 91;
/** Map operator: rd = ListOperators.map(list_reg, closure_reg, context) */
public static final short MAP = 92;
/** Create empty array: rd = new RuntimeArray() */
public static final short NEW_ARRAY = 93;
/** Create empty hash: rd = new RuntimeHash() */
public static final short NEW_HASH = 94;
/** Set array from list: array_reg.setFromList(list_reg) */
public static final short ARRAY_SET_FROM_LIST = 95;
/** Set hash from list: hash_reg = RuntimeHash.createHash(list_reg) then copy elements */
public static final short HASH_SET_FROM_LIST = 96;
/** Store global code: GlobalVariable.getGlobalCodeRef().put(stringPool[nameIdx], codeRef) */
public static final short STORE_GLOBAL_CODE = 97;
/** Create closure with captured variables: rd = createClosure(template, registers[rs1], registers[rs2], ...)
* Format: CREATE_CLOSURE rd template_const_idx num_captures reg1 reg2 ... */
public static final short CREATE_CLOSURE = 98;
/** Set scalar value: ((RuntimeScalar)registers[rd]).set((RuntimeScalar)registers[rs])
* Format: SET_SCALAR rd rs
* Used to set the value in a persistent scalar without overwriting the reference */
public static final short SET_SCALAR = 99;
/** Grep operator: rd = ListOperators.grep(list_reg, closure_reg, context) */
public static final short GREP = 100;
/** Sort operator: rd = ListOperators.sort(list_reg, closure_reg, package_name) */
public static final short SORT = 101;
/** Defined operator: rd = defined(rs) - check if value is defined */
public static final short DEFINED = 102;
/** Ref operator: rd = ref(rs) - get reference type as string */
public static final short REF = 103;
/** Bless operator: rd = bless(rs_ref, rs_package) - bless a reference into a package */
public static final short BLESS = 104;
/** ISA operator: rd = isa(rs_obj, rs_package) - check if object is instance of package */
public static final short ISA = 105;
// =================================================================
// ITERATOR OPERATIONS - For efficient foreach loops
// =================================================================
/** Create iterator: rd = rs.iterator() - get Iterator from Iterable */
public static final short ITERATOR_CREATE = 106;
/** Check iterator: rd = iterator.hasNext() - returns boolean as RuntimeScalar */
public static final short ITERATOR_HAS_NEXT = 107;
/** Get next element: rd = iterator.next() - returns RuntimeScalar */
public static final short ITERATOR_NEXT = 108;
/** Superinstruction for foreach loops: check hasNext, get next element, or jump to target if done
* Format: FOREACH_NEXT_OR_EXIT rd iter_reg exit_target(int)
* If iterator.hasNext(): rd = iterator.next(), continue to next instruction
* Else: pc = exit_target (absolute address, like GOTO) */
public static final short FOREACH_NEXT_OR_EXIT = 109;
// Compound assignment operators with overload support
public static final short SUBTRACT_ASSIGN = 110;
public static final short MULTIPLY_ASSIGN = 111;
public static final short DIVIDE_ASSIGN = 112;
public static final short MODULUS_ASSIGN = 113;
// =================================================================
// PHASE 2: SLOW_OP PROMOTIONS (114-154) - CONTIGUOUS RANGES
// =================================================================
// These operations were previously handled by SLOW_OP (opcode 87).
// Now promoted to direct opcodes for better performance (~5ns saved).
// IMPORTANT: Keep ranges CONTIGUOUS for JVM tableswitch optimization!
// Group 1: Dereferencing (114-115) - CONTIGUOUS
/** Dereference array for multidimensional access: rd = deref_array(rs) */
public static final short DEREF_ARRAY = 114;
/** Dereference hash for hashref access: rd = deref_hash(rs) */
public static final short DEREF_HASH = 115;
// Group 2: Slice Operations (116-121) - CONTIGUOUS
/** Array slice: rd = array.getSlice(indices_list) */
public static final short ARRAY_SLICE = 116;
/** Array slice assignment: array.setSlice(indices, values) */
public static final short ARRAY_SLICE_SET = 117;
/** Hash slice: rd = hash.getSlice(keys_list) */
public static final short HASH_SLICE = 118;
/** Hash slice assignment: hash.setSlice(keys, values) */
public static final short HASH_SLICE_SET = 119;
/** Hash slice delete: rd = hash.deleteSlice(keys_list) */
public static final short HASH_SLICE_DELETE = 120;
/** List slice from index: rd = list[start..] */
public static final short LIST_SLICE_FROM = 121;
// Group 3: Array/String Ops (122-125) - CONTIGUOUS
/** Splice array: rd = Operator.splice(array, args_list) */
public static final short SPLICE = 122;
/** Reverse array or string: rd = Operator.reverse(ctx, args...) */
public static final short REVERSE = 123;
/** Split string into array: rd = Operator.split(pattern, args, ctx) */
public static final short SPLIT = 124;
/** String length: rd = length(string) */
public static final short LENGTH_OP = 125;
// Group 4: Exists/Delete (126-127) - CONTIGUOUS
/** Exists operator: rd = exists(key) */
public static final short EXISTS = 126;
/** Delete operator: rd = delete(key) */
public static final short DELETE = 127;
// Group 5: Closure/Scope (128-131) - CONTIGUOUS
/** Retrieve BEGIN scalar: rd = PersistentVariable.retrieveBeginScalar(var_name, begin_id) */
public static final short RETRIEVE_BEGIN_SCALAR = 128;
/** Retrieve BEGIN array: rd = PersistentVariable.retrieveBeginArray(var_name, begin_id) */
public static final short RETRIEVE_BEGIN_ARRAY = 129;
/** Retrieve BEGIN hash: rd = PersistentVariable.retrieveBeginHash(var_name, begin_id) */
public static final short RETRIEVE_BEGIN_HASH = 130;
/** Localize global variable: rd = GlobalRuntimeScalar.makeLocal(var_name) */
public static final short LOCAL_SCALAR = 131;
// Group 6: System Calls (132-141) - CONTIGUOUS
/** chown(list, uid, gid) */
public static final short CHOWN = 132;
/** rd = waitpid(pid, flags) */
public static final short WAITPID = 133;
/** rd = fork() */
public static final short FORK = 134;
/** rd = getppid() */
public static final short GETPPID = 135;
/** rd = getpgrp(pid) */
public static final short GETPGRP = 136;
/** setpgrp(pid, pgrp) */
public static final short SETPGRP = 137;
/** rd = getpriority(which, who) */
public static final short GETPRIORITY = 138;
/** setpriority(which, who, priority) */
public static final short SETPRIORITY = 139;
/** rd = getsockopt(socket, level, optname) */
public static final short GETSOCKOPT = 140;
/** setsockopt(socket, level, optname, optval) */
public static final short SETSOCKOPT = 141;
// Group 7: IPC Operations (142-148) - CONTIGUOUS
/** rd = syscall(number, args...) */
public static final short SYSCALL = 142;
/** rd = semget(key, nsems, flags) */
public static final short SEMGET = 143;
/** rd = semop(semid, opstring) */
public static final short SEMOP = 144;
/** rd = msgget(key, flags) */
public static final short MSGGET = 145;
/** rd = msgsnd(id, msg, flags) */
public static final short MSGSND = 146;
/** rd = msgrcv(id, size, type, flags) */
public static final short MSGRCV = 147;
/** rd = shmget(key, size, flags) */
public static final short SHMGET = 148;
// Group 8: Shared Memory (149-150) - CONTIGUOUS
/** rd = shmread(id, pos, size) */
public static final short SHMREAD = 149;
/** shmwrite(id, pos, string) */
public static final short SHMWRITE = 150;
// Group 9: Special I/O (151-154) - CONTIGUOUS
/** rd = eval(string) - dynamic code evaluation */
public static final short EVAL_STRING = 151;
/** rd = select(list) - set/get default output filehandle */
public static final short SELECT_OP = 152;
/** rd = getGlobalIO(name) - load glob/filehandle from global variables */
public static final short LOAD_GLOB = 153;
/** rd = Time.sleep(seconds) - sleep for specified seconds */
public static final short SLEEP_OP = 154;
// =================================================================
// PHASE 3: OPERATORHANDLER PROMOTIONS (400-499) - Math Operators
// =================================================================
// IMPORTANT: Keep CONTIGUOUS for JVM tableswitch optimization!
// Math Operators (400-409) - CONTIGUOUS
/** Power operator: rd = MathOperators.pow(rs1, rs2) - equivalent to rs1 ** rs2 */
public static final short OP_POW = 155;
/** Absolute value: rd = MathOperators.abs(rs) - equivalent to abs(rs) */
public static final short OP_ABS = 156;
/** Integer conversion: rd = MathOperators.integer(rs) - equivalent to int(rs) */
public static final short OP_INT = 157;
/** Prototype operator: rd = RuntimeCode.prototype(rs_coderef, package_name)
* Format: PROTOTYPE rd rs package_name_idx(int) */
public static final short PROTOTYPE = 158;
/** Quote regex operator: rd = RuntimeRegex.getQuotedRegex(pattern_reg, flags_reg)
* Format: QUOTE_REGEX rd pattern_reg flags_reg */
public static final short QUOTE_REGEX = 159;
/** Less than or equal: rd = CompareOperators.numericLessThanOrEqual(rs1, rs2) */
public static final short LE_NUM = 160;
/** Greater than or equal: rd = CompareOperators.numericGreaterThanOrEqual(rs1, rs2) */
public static final short GE_NUM = 161;
/** String concatenation assignment: rd .= rs (appends rs to rd)
* Format: STRING_CONCAT_ASSIGN rd rs */
public static final short STRING_CONCAT_ASSIGN = 162;
/** Push variable to local stack: DynamicVariableManager.pushLocalVariable(rs)
* Format: PUSH_LOCAL_VARIABLE rs */
public static final short PUSH_LOCAL_VARIABLE = 163;
/** Store to glob: glob.set(rs)
* Format: STORE_GLOB globReg valueReg */
public static final short STORE_GLOB = 164;
/** Open file: rd = IOOperator.open(ctx, args...)
* Format: OPEN rd ctx argsReg */
public static final short OPEN = 165;
/** Read line from filehandle: rd = Readline.readline(fh_ref, ctx)
* Format: READLINE rd fhReg ctx */
public static final short READLINE = 166;
/** Match regex: rd = RuntimeRegex.matchRegex(string, regex, ctx)
* Format: MATCH_REGEX rd stringReg regexReg ctx */
public static final short MATCH_REGEX = 167;
/** Chomp: rd = rs.chomp()
* Format: CHOMP rd rs */
public static final short CHOMP = 168;
/** Get wantarray context: rd = Operator.wantarray(wantarrayReg)
* Format: WANTARRAY rd wantarrayReg */
public static final short WANTARRAY = 169;
/** Require module or version: rd = ModuleOperators.require(rs)
* Format: REQUIRE rd rs */
public static final short REQUIRE = 170;
/** Get regex position: rd = rs.pos() (returns lvalue for assignment)
* Format: POS rd rs */
public static final short POS = 171;
/** Find substring position: rd = StringOperators.index(str, substr, pos)
* Format: INDEX rd str substr pos */
public static final short INDEX = 172;
/** Find substring position from end: rd = StringOperators.rindex(str, substr, pos)
* Format: RINDEX rd str substr pos */
public static final short RINDEX = 173;
/** Bitwise AND assignment: target &= value
* Format: BITWISE_AND_ASSIGN target value */
public static final short BITWISE_AND_ASSIGN = 174;
/** Bitwise OR assignment: target |= value
* Format: BITWISE_OR_ASSIGN target value */
public static final short BITWISE_OR_ASSIGN = 175;
/** Bitwise XOR assignment: target ^= value
* Format: BITWISE_XOR_ASSIGN target value */
public static final short BITWISE_XOR_ASSIGN = 176;
/** String bitwise AND assignment: target &.= value
* Format: STRING_BITWISE_AND_ASSIGN target value */
public static final short STRING_BITWISE_AND_ASSIGN = 177;
/** String bitwise OR assignment: target |.= value
* Format: STRING_BITWISE_OR_ASSIGN target value */
public static final short STRING_BITWISE_OR_ASSIGN = 178;
/** String bitwise XOR assignment: target ^.= value
* Format: STRING_BITWISE_XOR_ASSIGN target value */
public static final short STRING_BITWISE_XOR_ASSIGN = 179;
/** Numeric bitwise AND: rd = rs1 binary& rs2
* Format: BITWISE_AND_BINARY rd rs1 rs2 */
public static final short BITWISE_AND_BINARY = 180;
/** Numeric bitwise OR: rd = rs1 binary| rs2
* Format: BITWISE_OR_BINARY rd rs1 rs2 */
public static final short BITWISE_OR_BINARY = 181;
/** Numeric bitwise XOR: rd = rs1 binary^ rs2
* Format: BITWISE_XOR_BINARY rd rs1 rs2 */
public static final short BITWISE_XOR_BINARY = 182;
/** String bitwise AND: rd = rs1 &. rs2
* Format: STRING_BITWISE_AND rd rs1 rs2 */
public static final short STRING_BITWISE_AND = 183;
/** String bitwise OR: rd = rs1 |. rs2
* Format: STRING_BITWISE_OR rd rs1 rs2 */
public static final short STRING_BITWISE_OR = 184;
/** String bitwise XOR: rd = rs1 ^. rs2
* Format: STRING_BITWISE_XOR rd rs1 rs2 */
public static final short STRING_BITWISE_XOR = 185;
/** Numeric bitwise NOT: rd = binary~ rs
* Format: BITWISE_NOT_BINARY rd rs */
public static final short BITWISE_NOT_BINARY = 186;
/** String bitwise NOT: rd = ~. rs
* Format: BITWISE_NOT_STRING rd rs */
public static final short BITWISE_NOT_STRING = 187;
// =================================================================
// FILE TEST AND STAT OPERATIONS
// =================================================================
/** stat operator: rd = stat(rs) [context]
* Format: STAT rd rs ctx */
public static final short STAT = 188;
/** lstat operator: rd = lstat(rs) [context]
* Format: LSTAT rd rs ctx */
public static final short LSTAT = 189;
// File test operators (unary operators returning boolean or value)
/** -r FILE: readable */
public static final short FILETEST_R = 190;
/** -w FILE: writable */
public static final short FILETEST_W = 191;
/** -x FILE: executable */
public static final short FILETEST_X = 192;
/** -o FILE: owned by effective uid */
public static final short FILETEST_O = 193;
/** -R FILE: readable by real uid */
public static final short FILETEST_R_REAL = 194;
/** -W FILE: writable by real uid */
public static final short FILETEST_W_REAL = 195;
/** -X FILE: executable by real uid */
public static final short FILETEST_X_REAL = 196;
/** -O FILE: owned by real uid */
public static final short FILETEST_O_REAL = 197;
/** -e FILE: exists */
public static final short FILETEST_E = 198;
/** -z FILE: zero size */
public static final short FILETEST_Z = 199;
/** -s FILE: size in bytes */
public static final short FILETEST_S = 200;
/** -f FILE: plain file */
public static final short FILETEST_F = 201;
/** -d FILE: directory */
public static final short FILETEST_D = 202;
/** -l FILE: symbolic link */
public static final short FILETEST_L = 203;
/** -p FILE: named pipe */
public static final short FILETEST_P = 204;
/** -S FILE: socket */
public static final short FILETEST_S_UPPER = 205;
/** -b FILE: block special */
public static final short FILETEST_B = 206;
/** -c FILE: character special */
public static final short FILETEST_C = 207;
/** -t FILE: tty */
public static final short FILETEST_T = 208;
/** -u FILE: setuid */
public static final short FILETEST_U = 209;
/** -g FILE: setgid */
public static final short FILETEST_G = 210;
/** -k FILE: sticky bit */
public static final short FILETEST_K = 211;
/** -T FILE: text file */
public static final short FILETEST_T_UPPER = 212;
/** -B FILE: binary file */
public static final short FILETEST_B_UPPER = 213;
/** -M FILE: modification age (days) */
public static final short FILETEST_M = 214;
/** -A FILE: access age (days) */
public static final short FILETEST_A = 215;
/** -C FILE: inode change age (days) */
public static final short FILETEST_C_UPPER = 216;
/** Match regex (negated): rd = !RuntimeRegex.matchRegex(string, regex, ctx)
* Format: MATCH_REGEX_NOT rd stringReg regexReg ctx */
public static final short MATCH_REGEX_NOT = 217;
// =================================================================
// LOOP CONTROL OPERATIONS - last/next/redo
// =================================================================
/** Loop last: Jump to end of loop or return RuntimeControlFlowList for non-local
* Format: LAST labelIndex
* labelIndex: index into stringPool for label name (or -1 for unlabeled) */
public static final short LAST = 218;
/** Loop next: Jump to continue/next label or return RuntimeControlFlowList for non-local
* Format: NEXT labelIndex
* labelIndex: index into stringPool for label name (or -1 for unlabeled) */
public static final short NEXT = 219;
/** Loop redo: Jump to start of loop or return RuntimeControlFlowList for non-local
* Format: REDO labelIndex
* labelIndex: index into stringPool for label name (or -1 for unlabeled) */
public static final short REDO = 220;
/** Transliterate operator: Apply tr/// or y/// pattern to string
* Format: TR_TRANSLITERATE rd searchReg replaceReg modifiersReg targetReg context
* rd: destination register for result (count of transliterated characters)
* searchReg: register containing search pattern (RuntimeScalar)
* replaceReg: register containing replacement pattern (RuntimeScalar)
* modifiersReg: register containing modifiers string (RuntimeScalar)
* targetReg: register containing target variable to modify (RuntimeScalar)
* context: call context (SCALAR/LIST/VOID) */
public static final short TR_TRANSLITERATE = 221;
// =================================================================
// SHIFT AND COMPOUND ASSIGNMENT OPERATORS (222-229) - CONTIGUOUS
// =================================================================
/** Left shift: rd = rs1 << rs2 */
public static final short LEFT_SHIFT = 222;
/** Right shift: rd = rs1 >> rs2 */
public static final short RIGHT_SHIFT = 223;
/** String repetition assignment: target x= value */
public static final short REPEAT_ASSIGN = 224;
/** Exponentiation assignment: target **= value */
public static final short POW_ASSIGN = 225;
/** Left shift assignment: target <<= value */
public static final short LEFT_SHIFT_ASSIGN = 226;
/** Right shift assignment: target >>= value */
public static final short RIGHT_SHIFT_ASSIGN = 227;
/** Logical AND assignment: target &&= value */
public static final short LOGICAL_AND_ASSIGN = 228;
/** Logical OR assignment: target ||= value */
public static final short LOGICAL_OR_ASSIGN = 229;
// =================================================================
// MANUAL OPCODE ADDITIONS
// Add new custom opcodes HERE (before LASTOP), not in the generated section below.
// The GENERATED_OPCODES section is automatically regenerated and will overwrite any manual additions.
// After adding an opcode here, increment LASTOP to match the highest opcode number.
// =================================================================
/** Glob slot access: rd = glob.hashDerefGetNonStrict(key, "main")
* Used for *X{HASH} style access to glob slots */
public static final short GLOB_SLOT_GET = 230;
/** Store via symbolic reference: GlobalVariable.getGlobalVariable(nameReg.toString()).set(valueReg)
* Format: STORE_SYMBOLIC_SCALAR nameReg valueReg */
public static final short STORE_SYMBOLIC_SCALAR = 231;
/** Load via symbolic reference: rd = GlobalVariable.getGlobalVariable(nameReg.toString()).get()
* Format: LOAD_SYMBOLIC_SCALAR rd nameReg */
public static final short LOAD_SYMBOLIC_SCALAR = 232;
/** File test on cached handle '_': rd = FileTestOperator.fileTestLastHandle(operator)
* Format: FILETEST_LASTHANDLE rd operator_string_idx */
public static final short FILETEST_LASTHANDLE = 233;
/** sprintf($format, @args): rd = SprintfOperator.sprintf(formatReg, argsListReg)
* Format: SPRINTF rd formatReg argsListReg */
public static final short SPRINTF = 234;
/** chop($x): rd = StringOperators.chopScalar(scalarReg) - modifies in place
* Format: CHOP rd scalarReg */
public static final short CHOP = 235;
/** Get replacement regex: rd = RuntimeRegex.getReplacementRegex(pattern, replacement, flags)
* Format: GET_REPLACEMENT_REGEX rd pattern_reg replacement_reg flags_reg */
public static final short GET_REPLACEMENT_REGEX = 236;
/** substr with variable args: rd = Operator.substr(ctx, args...)
* Format: SUBSTR_VAR rd argsListReg ctx */
public static final short SUBSTR_VAR = 237;
/** tie($var, $classname, @args): rd = TieOperators.tie(ctx, argsListReg)
* Format: TIE rd argsListReg context */
public static final short TIE = 238;
/** untie($var): rd = TieOperators.untie(ctx, argsListReg)
* Format: UNTIE rd argsListReg context */
public static final short UNTIE = 239;
/** tied($var): rd = TieOperators.tied(ctx, argsListReg)
* Format: TIED rd argsListReg context */
public static final short TIED = 240;
// =================================================================
// BUILT-IN FUNCTION OPCODES (241-283)
// Generated by dev/tools/generate_opcode_handlers.pl
// DO NOT EDIT MANUALLY - regenerate using the tool
// GENERATED_OPCODES_START
// scalar binary operations (atan2, eq, ne, lt, le, gt, ge, cmp, etc.)
public static final short ATAN2 = 241;
public static final short BINARY_AND = 242;
public static final short BINARY_OR = 243;
public static final short BINARY_XOR = 244;
public static final short EQ = 245;
public static final short NE = 246;
public static final short LT = 247;
public static final short LE = 248;
public static final short GT = 249;
public static final short GE = 250;
public static final short CMP = 251;
public static final short X = 252;
// scalar unary operations (chr, ord, abs, sin, cos, lc, uc, etc.)
public static final short INT = 253;
public static final short LOG = 254;
public static final short SQRT = 255;
public static final short COS = 256;
public static final short SIN = 257;
public static final short EXP = 258;
public static final short ABS = 259;
public static final short BINARY_NOT = 260;
public static final short INTEGER_BITWISE_NOT = 261;
public static final short ORD = 262;
public static final short ORD_BYTES = 263;
public static final short OCT = 264;
public static final short HEX = 265;
public static final short SRAND = 266;
public static final short CHR = 267;
public static final short CHR_BYTES = 268;
public static final short LENGTH_BYTES = 269;
public static final short QUOTEMETA = 270;
public static final short FC = 271;
public static final short LC = 272;
public static final short LCFIRST = 273;
public static final short UC = 274;
public static final short UCFIRST = 275;
public static final short SLEEP = 276;
public static final short TELL = 277;
public static final short RMDIR = 278;
public static final short CLOSEDIR = 279;
public static final short REWINDDIR = 280;
public static final short TELLDIR = 281;
public static final short CHDIR = 282;
public static final short EXIT = 283;
// GENERATED_OPCODES_END
// Miscellaneous operators with context-sensitive signatures (284-301)
// These use absolute numbers to avoid shifting generated opcodes
public static final short CHMOD = 284;
public static final short UNLINK = 285;
public static final short UTIME = 286;
public static final short RENAME = 287;
public static final short LINK = 288;
public static final short READLINK = 289;
public static final short UMASK = 290;
public static final short GETC = 291;
public static final short FILENO = 292;
public static final short QX = 293; // backticks
public static final short SYSTEM = 294;
public static final short CALLER = 295;
public static final short EACH = 296;
public static final short PACK = 297;
public static final short VEC = 298;
public static final short LOCALTIME = 299;
public static final short GMTIME = 300;
public static final short CRYPT = 301;
/** Superinstruction: save dynamic level BEFORE makeLocal, then localize global scalar.
* Atomically: levelReg = getLocalLevel(), rd = makeLocal(stringPool[nameIdx]).
* The saved pre-push level is used by POP_LOCAL_LEVEL after the loop to fully restore $_.
* Format: LOCAL_SCALAR_SAVE_LEVEL rd levelReg nameIdx */
public static final short LOCAL_SCALAR_SAVE_LEVEL = 302;
/** Restore DynamicVariableManager to a previously saved local level.
* Matches JVM compiler's DynamicVariableManager.popToLocalLevel(savedLevel) call.
* Format: POP_LOCAL_LEVEL rs */
public static final short POP_LOCAL_LEVEL = 303;
/** Superinstruction: foreach loop step for a global loop variable (e.g. $_).