depyo 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +97 -0
- package/depyo.js +213 -0
- package/lib/BinaryReader.js +153 -0
- package/lib/OpCode.js +90 -0
- package/lib/OpCodes.js +940 -0
- package/lib/PycDecompiler.js +2031 -0
- package/lib/PycDisassembler.js +55 -0
- package/lib/PycReader.js +905 -0
- package/lib/PycResult.js +82 -0
- package/lib/PythonObject.js +242 -0
- package/lib/Unpickle.js +173 -0
- package/lib/ast/ast_node.js +3442 -0
- package/lib/bytecode/python_1_0.js +116 -0
- package/lib/bytecode/python_1_1.js +116 -0
- package/lib/bytecode/python_1_3.js +119 -0
- package/lib/bytecode/python_1_4.js +121 -0
- package/lib/bytecode/python_1_5.js +120 -0
- package/lib/bytecode/python_1_6.js +124 -0
- package/lib/bytecode/python_2_0.js +137 -0
- package/lib/bytecode/python_2_1.js +142 -0
- package/lib/bytecode/python_2_2.js +147 -0
- package/lib/bytecode/python_2_3.js +145 -0
- package/lib/bytecode/python_2_4.js +147 -0
- package/lib/bytecode/python_2_5.js +147 -0
- package/lib/bytecode/python_2_6.js +147 -0
- package/lib/bytecode/python_2_7.js +151 -0
- package/lib/bytecode/python_3_0.js +132 -0
- package/lib/bytecode/python_3_1.js +135 -0
- package/lib/bytecode/python_3_10.js +312 -0
- package/lib/bytecode/python_3_11.js +284 -0
- package/lib/bytecode/python_3_12.js +327 -0
- package/lib/bytecode/python_3_13.js +173 -0
- package/lib/bytecode/python_3_14.js +177 -0
- package/lib/bytecode/python_3_2.js +136 -0
- package/lib/bytecode/python_3_3.js +136 -0
- package/lib/bytecode/python_3_4.js +137 -0
- package/lib/bytecode/python_3_5.js +149 -0
- package/lib/bytecode/python_3_6.js +153 -0
- package/lib/bytecode/python_3_7.js +292 -0
- package/lib/bytecode/python_3_8.js +294 -0
- package/lib/bytecode/python_3_9.js +296 -0
- package/lib/code_reader.js +146 -0
- package/lib/handlers/binary_ops.js +174 -0
- package/lib/handlers/collections_update.js +239 -0
- package/lib/handlers/comparisons.js +95 -0
- package/lib/handlers/context_managers.js +250 -0
- package/lib/handlers/control_flow_jumps.js +954 -0
- package/lib/handlers/exceptions_blocks.js +952 -0
- package/lib/handlers/formatting.js +31 -0
- package/lib/handlers/function_calls.js +496 -0
- package/lib/handlers/function_class_build.js +330 -0
- package/lib/handlers/generators_async.js +172 -0
- package/lib/handlers/imports.js +53 -0
- package/lib/handlers/load_store_names.js +711 -0
- package/lib/handlers/loop_iterator.js +318 -0
- package/lib/handlers/misc_other.js +1201 -0
- package/lib/handlers/pattern_matching.js +226 -0
- package/lib/handlers/stack_ops.js +280 -0
- package/lib/handlers/subscript_slice.js +394 -0
- package/lib/handlers/unary_ops.js +91 -0
- package/lib/handlers/unpack.js +141 -0
- package/lib/stack_history.js +63 -0
- package/lib/zip_reader.js +217 -0
- package/package.json +35 -0
package/lib/OpCodes.js
ADDED
|
@@ -0,0 +1,940 @@
|
|
|
1
|
+
const OpCode = require('./OpCode');
|
|
2
|
+
|
|
3
|
+
class OpCodes
|
|
4
|
+
{
|
|
5
|
+
|
|
6
|
+
/* No parameter word */
|
|
7
|
+
static STOP_CODE = 0; // Python 1.0 - 3.2
|
|
8
|
+
static POP_TOP = 1; // Python 1.0 ->
|
|
9
|
+
static ROT_TWO = 2; // Python 1.0 - 3.10
|
|
10
|
+
static ROT_THREE = 3; // Python 1.0 - 3.10
|
|
11
|
+
static DUP_TOP = 4; // Python 1.0 - 3.10
|
|
12
|
+
static DUP_TOP_TWO = 5; // Python 3.2 - 3.10
|
|
13
|
+
static UNARY_POSITIVE = 6; // Python 1.0 - 3.11
|
|
14
|
+
static UNARY_NEGATIVE = 7; // Python 1.0 ->
|
|
15
|
+
static UNARY_NOT = 8; // Python 1.0 ->
|
|
16
|
+
static UNARY_CONVERT = 9; // Python 1.0 - 2.7
|
|
17
|
+
static UNARY_CALL = 10; // Python 1.0 - 1.2
|
|
18
|
+
static UNARY_INVERT = 11; // Python 1.0 ->
|
|
19
|
+
static BINARY_POWER = 12; // Python 1.4 - 3.10
|
|
20
|
+
static BINARY_MULTIPLY = 13; // Python 1.0 - 3.10
|
|
21
|
+
static BINARY_DIVIDE = 14; // Python 1.0 - 2.7
|
|
22
|
+
static BINARY_MODULO = 15; // Python 1.0 - 3.10
|
|
23
|
+
static BINARY_ADD = 16; // Python 1.0 - 3.10
|
|
24
|
+
static BINARY_SUBTRACT = 17; // Python 1.0 - 3.10
|
|
25
|
+
static BINARY_SUBSCR = 18; // Python 1.0 ->
|
|
26
|
+
static BINARY_CALL = 19; // Python 1.0 - 1.2
|
|
27
|
+
static SLICE_0 = 20; // Python 1.0 - 2.7
|
|
28
|
+
static SLICE_1 = 21; // Python 1.0 - 2.7
|
|
29
|
+
static SLICE_2 = 22; // Python 1.0 - 2.7
|
|
30
|
+
static SLICE_3 = 23; // Python 1.0 - 2.7
|
|
31
|
+
static STORE_SLICE_0 = 24; // Python 1.0 - 2.7
|
|
32
|
+
static STORE_SLICE_1 = 25; // Python 1.0 - 2.7
|
|
33
|
+
static STORE_SLICE_2 = 26; // Python 1.0 - 2.7
|
|
34
|
+
static STORE_SLICE_3 = 27; // Python 1.0 - 2.7
|
|
35
|
+
static DELETE_SLICE_0 = 28; // Python 1.0 - 2.7
|
|
36
|
+
static DELETE_SLICE_1 = 29; // Python 1.0 - 2.7
|
|
37
|
+
static DELETE_SLICE_2 = 30; // Python 1.0 - 2.7
|
|
38
|
+
static DELETE_SLICE_3 = 31; // Python 1.0 - 2.7
|
|
39
|
+
static STORE_SUBSCR = 32; // Python 1.0 ->
|
|
40
|
+
static DELETE_SUBSCR = 33; // Python 1.0 ->
|
|
41
|
+
static BINARY_LSHIFT = 34; // Python 1.0 - 3.10
|
|
42
|
+
static BINARY_RSHIFT = 35; // Python 1.0 - 3.10
|
|
43
|
+
static BINARY_AND = 36; // Python 1.0 - 3.10
|
|
44
|
+
static BINARY_XOR = 37; // Python 1.0 - 3.10
|
|
45
|
+
static BINARY_OR = 38; // Python 1.0 - 3.10
|
|
46
|
+
static PRINT_EXPR = 39; // Python 1.0 - 3.11
|
|
47
|
+
static PRINT_ITEM = 40; // Python 1.0 - 2.7
|
|
48
|
+
static PRINT_NEWLINE = 41; // Python 1.0 - 2.7
|
|
49
|
+
static BREAK_LOOP = 42; // Python 1.0 - 3.7
|
|
50
|
+
static RAISE_EXCEPTION = 43; // Python 1.0 - 1.2
|
|
51
|
+
static LOAD_LOCALS = 44; // Python 1.0 - 2.7, 3.12 ->
|
|
52
|
+
static RETURN_VALUE = 45; // Python 1.0 ->
|
|
53
|
+
static LOAD_GLOBALS = 46; // Python 1.0 - 1.2
|
|
54
|
+
static EXEC_STMT = 47; // Python 1.0 - 2.7
|
|
55
|
+
static BUILD_FUNCTION = 48; // Python 1.0 - 1.2
|
|
56
|
+
static POP_BLOCK = 49; // Python 1.0 - 3.10
|
|
57
|
+
static END_FINALLY = 50; // Python 1.0 - 3.8
|
|
58
|
+
static BUILD_CLASS = 51; // Python 1.0 - 2.7
|
|
59
|
+
static ROT_FOUR = 52; // Python 2.0 - 3.1, 3.8 - 3.10
|
|
60
|
+
static NOP = 53; // Python 2.4 ->
|
|
61
|
+
static LIST_APPEND = 54; // Python 2.4 - 2.6, 3.0
|
|
62
|
+
static BINARY_FLOOR_DIVIDE = 55; // Python 2.2 - 3.10
|
|
63
|
+
static BINARY_TRUE_DIVIDE = 56; // Python 2.2 - 3.10
|
|
64
|
+
static INPLACE_FLOOR_DIVIDE = 57; // Python 2.2 - 3.10
|
|
65
|
+
static INPLACE_TRUE_DIVIDE = 58; // Python 2.2 - 3.10
|
|
66
|
+
static GET_LEN = 59; // Python 3.10 ->
|
|
67
|
+
static MATCH_MAPPING = 60; // Python 3.10 ->
|
|
68
|
+
static MATCH_SEQUENCE = 61; // Python 3.10 ->
|
|
69
|
+
static MATCH_KEYS = 62; // Python 3.10 ->
|
|
70
|
+
// Keep NOT_TAKEN distinct from legacy DELETE_SLICE_0 to avoid handler collisions.
|
|
71
|
+
static NOT_TAKEN = 400; // Python 3.13+ instrumentation hint
|
|
72
|
+
static COPY_DICT_WITHOUT_KEYS = 63; // Python 3.10
|
|
73
|
+
static STORE_MAP = 64; // Python 2.6 - 3.4
|
|
74
|
+
static INPLACE_ADD = 65; // Python 2.0 - 3.10
|
|
75
|
+
static INPLACE_SUBTRACT = 66; // Python 2.0 - 3.10
|
|
76
|
+
static INPLACE_MULTIPLY = 67; // Python 2.0 - 3.10
|
|
77
|
+
static INPLACE_DIVIDE = 68; // Python 2.0 - 2.7
|
|
78
|
+
static INPLACE_MODULO = 69; // Python 2.0 - 3.10
|
|
79
|
+
static INPLACE_POWER = 70; // Python 2.0 - 3.10
|
|
80
|
+
static GET_ITER = 71; // Python 2.2 ->
|
|
81
|
+
static PRINT_ITEM_TO = 72; // Python 2.0 - 2.7
|
|
82
|
+
static PRINT_NEWLINE_TO = 73; // Python 2.0 - 2.7
|
|
83
|
+
static INPLACE_LSHIFT = 74; // Python 2.0 - 3.10
|
|
84
|
+
static INPLACE_RSHIFT = 75; // Python 2.0 - 3.10
|
|
85
|
+
static INPLACE_AND = 76; // Python 2.0 - 3.10
|
|
86
|
+
static INPLACE_XOR = 77; // Python 2.0 - 3.10
|
|
87
|
+
static INPLACE_OR = 78; // Python 2.0 - 3.10
|
|
88
|
+
static WITH_CLEANUP = 79; // Python 2.5 - 3.4
|
|
89
|
+
static WITH_CLEANUP_START = 80; // Python 3.5 - 3.8
|
|
90
|
+
static WITH_CLEANUP_FINISH = 81; // Python 3.5 - 3.8
|
|
91
|
+
static IMPORT_STAR = 82; // Python 2.0 - 3.11
|
|
92
|
+
static SETUP_ANNOTATIONS = 83; // Python 3.6 ->
|
|
93
|
+
static YIELD_VALUE = 84; // Python 2.2 - 3.11
|
|
94
|
+
static LOAD_BUILD_CLASS = 85; // Python 3.0 ->
|
|
95
|
+
static STORE_LOCALS = 86; // Python 3.0 - 3.3
|
|
96
|
+
static POP_EXCEPT = 87; // Python 3.0 ->
|
|
97
|
+
static SET_ADD = 88; // Python 3.0
|
|
98
|
+
static YIELD_FROM = 89; // Python 3.3 - 3.10
|
|
99
|
+
static BINARY_MATRIX_MULTIPLY = 90; // Python 3.5 - 3.10
|
|
100
|
+
static INPLACE_MATRIX_MULTIPLY = 91; // Python 3.5 - 3.10
|
|
101
|
+
static GET_AITER = 92; // Python 3.5 ->
|
|
102
|
+
static GET_ANEXT = 93; // Python 3.5 ->
|
|
103
|
+
static BEFORE_ASYNC_WITH = 94; // Python 3.5 ->
|
|
104
|
+
static GET_YIELD_FROM_ITER = 95; // Python 3.5 ->
|
|
105
|
+
static GET_AWAITABLE = 96; // Python 3.5 - 3.10
|
|
106
|
+
static BEGIN_FINALLY = 97; // Python 3.8
|
|
107
|
+
static END_ASYNC_FOR = 98; // Python 3.8 ->
|
|
108
|
+
static RERAISE = 99; // Python 3.9
|
|
109
|
+
static WITH_EXCEPT_START = 100; // Python 3.9 ->
|
|
110
|
+
static LOAD_ASSERTION_ERROR = 101; // Python 3.9 ->
|
|
111
|
+
static LIST_TO_TUPLE = 102; // Python 3.9 - 3.11
|
|
112
|
+
static CACHE = 103; // Python 3.11 ->
|
|
113
|
+
static PUSH_NULL = 104; // Python 3.11 ->
|
|
114
|
+
static PUSH_EXC_INFO = 105; // Python 3.11 ->
|
|
115
|
+
static CHECK_EXC_MATCH = 106; // Python 3.11 ->
|
|
116
|
+
static CHECK_EG_MATCH = 107; // Python 3.11 ->
|
|
117
|
+
static BEFORE_WITH = 108; // Python 3.11 ->
|
|
118
|
+
static RETURN_GENERATOR = 109; // Python 3.11 ->
|
|
119
|
+
static ASYNC_GEN_WRAP = 110; // Python 3.11
|
|
120
|
+
static PREP_RERAISE_STAR = 111; // Python 3.11
|
|
121
|
+
static INTERPRETER_EXIT = 112; // Python 3.12 ->
|
|
122
|
+
static END_FOR = 113; // Python 3.12 ->
|
|
123
|
+
static END_SEND = 114; // Python 3.12 ->
|
|
124
|
+
static RESERVED = 115; // Python 3.12 ->
|
|
125
|
+
static BINARY_SLICE = 116; // Python 3.12 ->
|
|
126
|
+
static STORE_SLICE = 117; // Python 3.12 ->
|
|
127
|
+
static CLEANUP_THROW = 118; // Python 3.12 ->
|
|
128
|
+
|
|
129
|
+
/* Has parameter word */
|
|
130
|
+
static PYC_HAVE_ARG = 119;
|
|
131
|
+
static STORE_NAME_A = OpCodes.PYC_HAVE_ARG; // Python 1.0 -> names[A]
|
|
132
|
+
static DELETE_NAME_A = 120; // Python 1.0 -> names[A]
|
|
133
|
+
static UNPACK_TUPLE_A = 121; // Python 1.0 - 1.6 A=count
|
|
134
|
+
static UNPACK_LIST_A = 122; // Python 1.0 - 1.6 A=count
|
|
135
|
+
static UNPACK_ARG_A = 123; // Python 1.0 - 1.4 A=count
|
|
136
|
+
static STORE_ATTR_A = 124; // Python 1.0 -> names[A]
|
|
137
|
+
static DELETE_ATTR_A = 125; // Python 1.0 -> names[A]
|
|
138
|
+
static STORE_GLOBAL_A = 126; // Python 1.0 -> names[A]
|
|
139
|
+
static DELETE_GLOBAL_A = 127; // Python 1.0 -> names[A]
|
|
140
|
+
static ROT_N_A = 128; // Python 3.10 A=count
|
|
141
|
+
static UNPACK_VARARG_A = 129; // Python 1.0 - 1.4 A=count
|
|
142
|
+
static LOAD_CONST_A = 130; // Python 1.0 -> consts[A]
|
|
143
|
+
static LOAD_NAME_A = 131; // Python 1.0 -> names[A]
|
|
144
|
+
static BUILD_TUPLE_A = 132; // Python 1.0 -> A=size
|
|
145
|
+
static BUILD_LIST_A = 133; // Python 1.0 -> A=size
|
|
146
|
+
static BUILD_MAP_A = 134; // Python 1.0 -> A=size
|
|
147
|
+
static LOAD_ATTR_A = 135; // Python 1.0 -> names[A]
|
|
148
|
+
static COMPARE_OP_A = 136; // Python 1.0 -> cmp_ops[A]
|
|
149
|
+
static IMPORT_NAME_A = 137; // Python 1.0 -> names[A]
|
|
150
|
+
static IMPORT_FROM_A = 138; // Python 1.0 -> names[A]
|
|
151
|
+
static ACCESS_MODE_A = 139; // Python 1.0 - 1.4 names[A]
|
|
152
|
+
static JUMP_FORWARD_A = 140; // Python 1.0 -> rel jmp +A
|
|
153
|
+
static JUMP_IF_FALSE_A = 141; // Python 1.0 - 2.6, 3.0 rel jmp +A
|
|
154
|
+
static JUMP_IF_TRUE_A = 142; // Python 1.0 - 2.6, 3.0 rel jmp +A
|
|
155
|
+
static JUMP_ABSOLUTE_A = 143; // Python 1.0 - 3.10 abs jmp A
|
|
156
|
+
static FOR_LOOP_A = 144; // Python 1.0 - 2.2 rel jmp +A
|
|
157
|
+
static LOAD_LOCAL_A = 145; // Python 1.0 - 1.4 names[A]
|
|
158
|
+
static LOAD_GLOBAL_A = 146; // Python 1.0 -> names[A]
|
|
159
|
+
static SET_FUNC_ARGS_A = 147; // Python 1.1 - 1.4 A=count
|
|
160
|
+
static SETUP_LOOP_A = 148; // Python 1.0 - 3.7 rel jmp +A
|
|
161
|
+
static SETUP_EXCEPT_A = 149; // Python 1.0 - 3.7 rel jmp +A
|
|
162
|
+
static SETUP_FINALLY_A = 150; // Python 1.0 - 3.10 rel jmp +A
|
|
163
|
+
static RESERVE_FAST_A = 151; // Python 1.0 - 1.2 A=count
|
|
164
|
+
static LOAD_FAST_A = 152; // Python 1.0 -> locals[A]
|
|
165
|
+
static STORE_FAST_A = 153; // Python 1.0 -> locals[A]
|
|
166
|
+
static DELETE_FAST_A = 154; // Python 1.0 -> locals[A]
|
|
167
|
+
static GEN_START_A = 155; // Python 3.10 ???
|
|
168
|
+
static SET_LINENO_A = 156; // Python 1.0 - 2.2 A=line
|
|
169
|
+
static STORE_ANNOTATION_A = 157; // Python 3.6 names[A]
|
|
170
|
+
static RAISE_VARARGS_A = 158; // Python 1.3 -> A=count
|
|
171
|
+
static CALL_FUNCTION_A = 159; // Python 1.3 - 3.5 A=(#args)+(#kwargs<<8)
|
|
172
|
+
// Python 3.6 - 3.10 A=#args
|
|
173
|
+
static MAKE_FUNCTION_A = 160; // Python 1.3 - 2.7 A=#defaults
|
|
174
|
+
// Python 3.0 - 3.5 A=(#defaults)+(#kwdefaults<<8)+(#annotations<<16)
|
|
175
|
+
// Python 3.6 -> A=flags
|
|
176
|
+
static MAKE_FUNCTION = 272; // Python 3.13+ -> A=flags
|
|
177
|
+
static BUILD_SLICE_A = 161; // Python 1.4 -> A=count
|
|
178
|
+
static CALL_FUNCTION_VAR_A = 162; // Python 1.6 - 3.5 A=(#args)+(#kwargs<<8)
|
|
179
|
+
static CALL_FUNCTION_KW_A = 163; // Python 1.6 - 3.5 A=(#args)+(#kwargs<<8)
|
|
180
|
+
// Python 3.6 - 3.10 A=#args
|
|
181
|
+
static CALL_FUNCTION_VAR_KW_A = 164; // Python 1.6 - 3.5 A=(#args)+(#kwargs<<8)
|
|
182
|
+
static CALL_FUNCTION_EX_A = 165; // Python 3.6 -> A=flags
|
|
183
|
+
static UNPACK_SEQUENCE_A = 166; // Python 2.0 -> A=count
|
|
184
|
+
static FOR_ITER_A = 167; // Python 2.0 -> rel jmp +A
|
|
185
|
+
static DUP_TOPX_A = 168; // Python 2.0 - 3.1 A=count
|
|
186
|
+
static BUILD_SET_A = 169; // Python 2.7 -> A=size
|
|
187
|
+
static JUMP_IF_FALSE_OR_POP_A = 170; // Python 2.7, 3.1 - 3.11 abs jmp A
|
|
188
|
+
static JUMP_IF_TRUE_OR_POP_A = 171; // Python 2.7, 3.1 - 3.11 abs jmp A
|
|
189
|
+
static POP_JUMP_IF_FALSE_A = 172; // Python 2.7, 3.1 - 3.10 abs jmp A
|
|
190
|
+
// Python 3.12 -> rel jmp +A
|
|
191
|
+
static POP_JUMP_IF_TRUE_A = 173; // Python 2.7, 3.1 - 3.10 abs jmp A
|
|
192
|
+
// Python 3.12 -> rel jmp +A
|
|
193
|
+
static CONTINUE_LOOP_A = 174; // Python 2.1 - 3.7 abs jmp A
|
|
194
|
+
static MAKE_CLOSURE_A = 175; // Python 2.1 - 2.7 A=#defaults
|
|
195
|
+
// Python 3.0 - 3.5 A=(#defaults)+(#kwdefaults<<8)+(#annotations<<16)
|
|
196
|
+
static LOAD_CLOSURE_A = 176; // Python 2.1 -> freevars[A]
|
|
197
|
+
static LOAD_DEREF_A = 177; // Python 2.1 -> freevars[A]
|
|
198
|
+
static STORE_DEREF_A = 178; // Python 2.1 -> freevars[A]
|
|
199
|
+
static DELETE_DEREF_A = 179; // Python 3.2 -> freevars[A]
|
|
200
|
+
static EXTENDED_ARG_A = 180; // Python 2.0 -> A=extended_arg
|
|
201
|
+
static SETUP_WITH_A = 181; // Python 2.7, 3.2 - 3.10 rel jmp +A
|
|
202
|
+
static SET_ADD_A = 182; // Python 2.7, 3.1 -> stack[A]
|
|
203
|
+
static MAP_ADD_A = 183; // Python 2.7, 3.1 -> stack[A]
|
|
204
|
+
static UNPACK_EX_A = 184; // Python 3.0 -> A=(before)+(after<<8)
|
|
205
|
+
static LIST_APPEND_A = 185; // Python 2.7, 3.1 -> stack[A]
|
|
206
|
+
static LOAD_CLASSDEREF_A = 186; // Python 3.4 - 3.10 (cellvars+freevars)[A]
|
|
207
|
+
// Python 3.11 localsplusnames[A]
|
|
208
|
+
static MATCH_CLASS_A = 187; // Python 3.10 -> A=#args
|
|
209
|
+
static BUILD_LIST_UNPACK_A = 188; // Python 3.5 - 3.8 A=count
|
|
210
|
+
static BUILD_MAP_UNPACK_A = 189; // Python 3.5 - 3.8 A=count
|
|
211
|
+
static BUILD_MAP_UNPACK_WITH_CALL_A = 190; // Python 3.5 A=(count)+(fnloc<<8)
|
|
212
|
+
// Python 3.6 - 3.8 A=count
|
|
213
|
+
static BUILD_TUPLE_UNPACK_A = 191; // Python 3.5 - 3.8 A=count
|
|
214
|
+
static BUILD_SET_UNPACK_A = 192; // Python 3.5 - 3.8 A=count
|
|
215
|
+
static SETUP_ASYNC_WITH_A = 193; // Python 3.5 - 3.10 rel jmp +A
|
|
216
|
+
static FORMAT_VALUE_A = 194; // Python 3.6 -> A=conversion_type
|
|
217
|
+
static BUILD_CONST_KEY_MAP_A = 195; // Python 3.6 -> A=count
|
|
218
|
+
static BUILD_STRING_A = 196; // Python 3.6 -> A=count
|
|
219
|
+
static BUILD_TUPLE_UNPACK_WITH_CALL_A = 197; // Python 3.6 - 3.8 A=count
|
|
220
|
+
static LOAD_METHOD_A = 198; // Python 3.7 - 3.11 names[A]
|
|
221
|
+
static CALL_METHOD_A = 199; // Python 3.7 - 3.10 A=#args
|
|
222
|
+
static CALL_FINALLY_A = 200; // Python 3.8 rel jmp +A
|
|
223
|
+
static POP_FINALLY_A = 201; // Python 3.8 A=flags
|
|
224
|
+
static IS_OP_A = 202; // Python 3.9 -> A=inverted
|
|
225
|
+
static CONTAINS_OP_A = 203; // Python 3.9 -> A=inverted
|
|
226
|
+
static RERAISE_A = 204; // Python 3.10 -> A=flag
|
|
227
|
+
static JUMP_IF_NOT_EXC_MATCH_A = 205; // Python 3.9 - 3.10 abs jmp A
|
|
228
|
+
static LIST_EXTEND_A = 206; // Python 3.9 -> stack[A]
|
|
229
|
+
static SET_UPDATE_A = 207; // Python 3.9 -> stack[A]
|
|
230
|
+
static DICT_MERGE_A = 208; // Python 3.9 -> stack[A]
|
|
231
|
+
static DICT_UPDATE_A = 209; // Python 3.9 -> stack[A]
|
|
232
|
+
static SWAP_A = 210; // Python 3.11 -> stack[A]
|
|
233
|
+
static POP_JUMP_FORWARD_IF_FALSE_A = 211; // Python 3.11 rel jmp +A
|
|
234
|
+
static POP_JUMP_FORWARD_IF_TRUE_A = 212; // Python 3.11 rel jmp +A
|
|
235
|
+
static COPY_A = 213; // Python 3.11 -> stack[A]
|
|
236
|
+
static BINARY_OP_A = 214; // Python 3.11 -> bin_ops[A]
|
|
237
|
+
static SEND_A = 215; // Python 3.11 -> rel jmp +A
|
|
238
|
+
static POP_JUMP_FORWARD_IF_NOT_NONE_A = 216; // Python 3.11 rel jmp +A
|
|
239
|
+
static POP_JUMP_FORWARD_IF_NONE_A = 217; // Python 3.11 rel jmp +A
|
|
240
|
+
static GET_AWAITABLE_A = 218; // Python 3.11 -> A=awaitable_type
|
|
241
|
+
static JUMP_BACKWARD_NO_INTERRUPT_A = 219; // Python 3.11 -> rel jmp -A
|
|
242
|
+
static MAKE_CELL_A = 220; // Python 3.11 -> locals[A]
|
|
243
|
+
static JUMP_BACKWARD_A = 221; // Python 3.11 -> rel jmp -A
|
|
244
|
+
static COPY_FREE_VARS_A = 222; // Python 3.11 -> A=count
|
|
245
|
+
static RESUME_A = 223; // Python 3.11 -> ???
|
|
246
|
+
static PRECALL_A = 224; // Python 3.11 A=#args
|
|
247
|
+
static CALL_A = 225; // Python 3.11 -> A=#args
|
|
248
|
+
static KW_NAMES_A = 226; // Python 3.11 -> consts[A]
|
|
249
|
+
static POP_JUMP_BACKWARD_IF_NOT_NONE_A = 227; // Python 3.11 jmp rel -A
|
|
250
|
+
static POP_JUMP_BACKWARD_IF_NONE_A = 228; // Python 3.11 jmp rel -A
|
|
251
|
+
static POP_JUMP_BACKWARD_IF_FALSE_A = 229; // Python 3.11 jmp rel -A
|
|
252
|
+
static POP_JUMP_BACKWARD_IF_TRUE_A = 230; // Python 3.11 jmp rel -A
|
|
253
|
+
static RETURN_CONST_A = 231; // Python 3.12 -> consts[A]
|
|
254
|
+
static LOAD_FAST_CHECK_A = 232; // Python 3.12 -> locals[A]
|
|
255
|
+
static POP_JUMP_IF_NOT_NONE_A = 233; // Python 3.12 -> rel jmp +A
|
|
256
|
+
static POP_JUMP_IF_NONE_A = 234; // Python 3.12 -> rel jmp +A
|
|
257
|
+
static LOAD_SUPER_ATTR_A = 235; // Python 3.12 -> A=(flags&0x3)+names[A<<2]
|
|
258
|
+
static LOAD_FAST_AND_CLEAR_A = 236; // Python 3.12 -> locals[A]
|
|
259
|
+
static YIELD_VALUE_A = 237; // Python 3.12 -> ???
|
|
260
|
+
static CALL_INTRINSIC_1_A = 238; // Python 3.12 -> intrinsics_1[A]
|
|
261
|
+
static CALL_INTRINSIC_2_A = 239; // Python 3.12 -> intrinsics_2[A]
|
|
262
|
+
static LOAD_FROM_DICT_OR_GLOBALS_A = 240; // Python 3.12 -> names[A]
|
|
263
|
+
static LOAD_FROM_DICT_OR_DEREF_A = 241; // Python 3.12 -> localsplusnames[A]
|
|
264
|
+
|
|
265
|
+
/* Instrumented opcodes */
|
|
266
|
+
static INSTRUMENTED_NOT_TAKEN_A = 401; // Python 3.14 -> no-op marker
|
|
267
|
+
static INSTRUMENTED_POP_ITER_A = 402; // Python 3.14 -> (see POP_ITER)
|
|
268
|
+
static INSTRUMENTED_END_ASYNC_FOR_A = 403; // Python 3.14 -> (see END_ASYNC_FOR)
|
|
269
|
+
static INSTRUMENTED_CALL_KW_A = 404; // Python 3.14 -> (see CALL_KW)
|
|
270
|
+
static INSTRUMENTED_LOAD_SUPER_ATTR_A = 242; // Python 3.12 -> (see LOAD_SUPER_ATTR)
|
|
271
|
+
static INSTRUMENTED_POP_JUMP_IF_NONE_A = 243; // Python 3.12 -> (see POP_JUMP_IF_NONE)
|
|
272
|
+
static INSTRUMENTED_POP_JUMP_IF_NOT_NONE_A = 244; // Python 3.12 -> (see POP_JUMP_IF_NOT_NONE)
|
|
273
|
+
static INSTRUMENTED_RESUME_A = 245; // Python 3.12 -> (see RESUME)
|
|
274
|
+
static INSTRUMENTED_CALL_A = 246; // Python 3.12 -> (see CALL)
|
|
275
|
+
static INSTRUMENTED_RETURN_VALUE_A = 247; // Python 3.12 -> (see RETURN_VALUE)
|
|
276
|
+
static INSTRUMENTED_YIELD_VALUE_A = 248; // Python 3.12 -> (see YIELD_VALUE)
|
|
277
|
+
static INSTRUMENTED_CALL_FUNCTION_EX_A = 249; // Python 3.12 -> (see CALL_FUNCTION_EX)
|
|
278
|
+
static INSTRUMENTED_JUMP_FORWARD_A = 250; // Python 3.12 -> (see JUMP_FORWARD)
|
|
279
|
+
static INSTRUMENTED_JUMP_BACKWARD_A = 251; // Python 3.12 -> (see JUMP_BACKWARD)
|
|
280
|
+
static INSTRUMENTED_RETURN_CONST_A = 252; // Python 3.12 -> (see RETURN_CONST)
|
|
281
|
+
static INSTRUMENTED_FOR_ITER_A = 253; // Python 3.12 -> (see FOR_ITER)
|
|
282
|
+
static INSTRUMENTED_POP_JUMP_IF_FALSE_A = 254; // Python 3.12 -> (see POP_JUMP_IF_FALSE)
|
|
283
|
+
static INSTRUMENTED_POP_JUMP_IF_TRUE_A = 255; // Python 3.12 -> (see POP_JUMP_IF_TRUE)
|
|
284
|
+
static INSTRUMENTED_END_FOR_A = 256; // Python 3.12 -> (see END_FOR)
|
|
285
|
+
static INSTRUMENTED_END_SEND_A = 257; // Python 3.12 -> (see END_SEND)
|
|
286
|
+
static INSTRUMENTED_INSTRUCTION_A = 258; // Python 3.12 -> ???
|
|
287
|
+
static INSTRUMENTED_LINE_A = 259; // Python 3.12 -> ???
|
|
288
|
+
|
|
289
|
+
// Python 3.12 intrinsic function calls
|
|
290
|
+
static CALL_INTRINSIC_1 = 265; // Python 3.12 -> intrinsics_1[A]
|
|
291
|
+
static CALL_INTRINSIC_2 = 266; // Python 3.12 -> intrinsics_2[A]
|
|
292
|
+
|
|
293
|
+
// Aliases for handler name mapping
|
|
294
|
+
static CALL_INTRINSIC_1A = 238; // Alias for CALL_INTRINSIC_1_A
|
|
295
|
+
static CALL_INTRINSIC_2A = 239; // Alias for CALL_INTRINSIC_2_A
|
|
296
|
+
|
|
297
|
+
// Python 3.13/3.14 new opcodes
|
|
298
|
+
static EXIT_INIT_CHECK = 267; // Python 3.13 -> exit __init__ check
|
|
299
|
+
static FORMAT_SIMPLE = 268; // Python 3.13 -> format without spec
|
|
300
|
+
static FORMAT_WITH_SPEC = 269; // Python 3.13 -> format with spec
|
|
301
|
+
static TO_BOOL = 270; // Python 3.13 -> convert to bool
|
|
302
|
+
static BUILD_TEMPLATE = 271; // Python 3.14 -> build template object
|
|
303
|
+
static LOAD_FAST_BORROW_A = 274; // Python 3.14 -> optimized LOAD_FAST (distinct ID from MAKE_FUNCTION=272)
|
|
304
|
+
static LOAD_SMALL_INT_A = 275; // Python 3.14 -> load small integer
|
|
305
|
+
static LOAD_FAST_LOAD_FAST_A = 276; // Python 3.13+ -> packed two locals
|
|
306
|
+
static STORE_FAST_LOAD_FAST_A = 277; // Python 3.13+ -> store then load packed locals
|
|
307
|
+
static SET_FUNCTION_ATTRIBUTE_A = 278; // Python 3.13+ -> set function attribute
|
|
308
|
+
|
|
309
|
+
// Aliases / placeholders for 3.13+ opcodes with distinct IDs to avoid collisions
|
|
310
|
+
static POP_ITER = 300; // Python 3.14 instrumentation helper
|
|
311
|
+
static WITH_EXCEPT_START_A = 301; // Python 3.13+ arg variant
|
|
312
|
+
static END_ASYNC_FOR_A = 302; // Python 3.13+ encoded end async for
|
|
313
|
+
static POP_BLOCK_A = 303; // Python 3.13+ encoded pop block
|
|
314
|
+
static CALL_FUNCTION_EX = 304; // Python 3.14 CALL (EX) wrapper
|
|
315
|
+
static CALL_KW_A = 305; // Python 3.14 CALL_KW wrapper
|
|
316
|
+
static CONVERT_VALUE_A = 306; // Python 3.14 conversion helper
|
|
317
|
+
static JUMP_A = 307; // Python 3.14 generic jump
|
|
318
|
+
static JUMP_NO_INTERRUPT_A = 308; // Python 3.14 jump without signal checks
|
|
319
|
+
static LOAD_COMMON_CONSTANT_A = 309; // Python 3.14 common constants table
|
|
320
|
+
static LOAD_FAST_BORROW_LOAD_FAST_BORROW_A = 310; // Python 3.14 packed borrow load
|
|
321
|
+
static LOAD_SPECIAL_A = 311; // Python 3.14 LOAD_SPECIAL
|
|
322
|
+
static SETUP_CLEANUP_A = 312; // Python 3.13+ cleanup setup
|
|
323
|
+
static STORE_FAST_MAYBE_NULL_A = 313; // Python 3.13+ tolerant store
|
|
324
|
+
static STORE_FAST_STORE_FAST_A = 314; // Python 3.13+ packed store/store
|
|
325
|
+
static ANNOTATIONS_PLACEHOLDER_A = 315; // Python 3.14 placeholder
|
|
326
|
+
static BUILD_INTERPOLATION_A = 316; // Python 3.14 string template builder
|
|
327
|
+
static ENTER_EXECUTOR_A = 317; // Python 3.14 executor entry (ignore)
|
|
328
|
+
static LOAD_SUPER_METHOD_A = 318; // Python 3.13+ super method load
|
|
329
|
+
static LOAD_ZERO_SUPER_ATTR_A = 319; // Python 3.13+ zero-cost super attr
|
|
330
|
+
static LOAD_ZERO_SUPER_METHOD_A = 320; // Python 3.13+ zero-cost super method
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
// enum cmp_op
|
|
334
|
+
// {
|
|
335
|
+
// PyCmp_LT, PyCmp_LE, PyCmp_EQ, PyCmp_NE, PyCmp_GT, PyCmp_GE,
|
|
336
|
+
// PyCmp_IN, PyCmp_NOT_IN, PyCmp_IS, PyCmp_IS_NOT, PyCmp_EXC_MATCH, PyCmp_BAD
|
|
337
|
+
// };
|
|
338
|
+
|
|
339
|
+
OpCodeList = [];
|
|
340
|
+
|
|
341
|
+
static CompareOpNames = ["<", "<=", "==", "!=", ">", ">=", "in", "not in", "is", "is not", "exception match", "BAD"];
|
|
342
|
+
|
|
343
|
+
Instructions = [];
|
|
344
|
+
CurrentInstructionIndex = -1;
|
|
345
|
+
|
|
346
|
+
get HasInstructionsToProcess() {
|
|
347
|
+
return this.CurrentInstructionIndex < this.Instructions.length - 1;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
CodeObject = [];
|
|
351
|
+
|
|
352
|
+
constructor() {
|
|
353
|
+
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
get Current() {
|
|
357
|
+
return (this.CurrentInstructionIndex < 0 || this.CurrentInstructionIndex >= this.Instructions.length) ? null : this.Instructions[this.CurrentInstructionIndex];
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
GetOpCodeID(code, offset) {
|
|
361
|
+
// Bounds checking for bytecode array access
|
|
362
|
+
if (offset < 0 || offset >= code.length) {
|
|
363
|
+
if (global.g_cliArgs?.debug) {
|
|
364
|
+
console.error(`GetOpCodeID: offset ${offset} out of bounds [0, ${code.length})`);
|
|
365
|
+
}
|
|
366
|
+
return null;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
let opcode = code[offset];
|
|
370
|
+
let opcodeEntry = this.OpCodeList[opcode];
|
|
371
|
+
|
|
372
|
+
if (!opcodeEntry) {
|
|
373
|
+
if (global.g_cliArgs?.debug) {
|
|
374
|
+
console.error(`GetOpCodeID: unknown opcode ${opcode} (0x${opcode?.toString(16)}) at offset ${offset}`);
|
|
375
|
+
}
|
|
376
|
+
return null;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
return opcodeEntry.OpCodeID;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
ReadExtendedArg(code, opOffset) {
|
|
383
|
+
let reader = this.CodeObject.Reader;
|
|
384
|
+
let argument = 0;
|
|
385
|
+
let opCodeID = this.GetOpCodeID(code, opOffset);
|
|
386
|
+
|
|
387
|
+
// If opCodeID is null, bytecode is truncated/corrupted
|
|
388
|
+
if (opCodeID === null) {
|
|
389
|
+
return [0, opOffset];
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
if (reader.versionCompare(3, 6) >= 0) {
|
|
393
|
+
while (opCodeID == OpCodes.EXTENDED_ARG_A) {
|
|
394
|
+
argument = argument | code[++opOffset] << 8;
|
|
395
|
+
opCodeID = this.GetOpCodeID(code, ++opOffset);
|
|
396
|
+
|
|
397
|
+
// Break if we hit end of bytecode
|
|
398
|
+
if (opCodeID === null) {
|
|
399
|
+
break;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
argument <<= 8;
|
|
403
|
+
} else {
|
|
404
|
+
if (opCodeID == OpCodes.EXTENDED_ARG_A) {
|
|
405
|
+
argument = code[++opOffset] | code[++opOffset] << 8;
|
|
406
|
+
argument <<= 16;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
return [argument, opOffset];
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
SetupByteCode(co)
|
|
414
|
+
{
|
|
415
|
+
if (!co || !co.Code || !co.Code.Value) {
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
this.CodeObject = co;
|
|
420
|
+
let opOffset = 0;
|
|
421
|
+
let opCodeID = 0;
|
|
422
|
+
let extendedArg = 0;
|
|
423
|
+
let instructionIndex = 0;
|
|
424
|
+
let code = this.CodeObject.Code.Value;
|
|
425
|
+
|
|
426
|
+
while (opOffset < code.length) {
|
|
427
|
+
[extendedArg, opOffset] = this.ReadExtendedArg(code, opOffset);
|
|
428
|
+
|
|
429
|
+
let bytecode = code[opOffset];
|
|
430
|
+
let opcodeEntry = this.OpCodeList[bytecode];
|
|
431
|
+
|
|
432
|
+
// Skip unknown/invalid opcodes
|
|
433
|
+
if (!opcodeEntry) {
|
|
434
|
+
if (global.g_cliArgs?.debug) {
|
|
435
|
+
console.error(`SetupByteCode: unknown opcode ${bytecode} (0x${bytecode?.toString(16)}) at offset ${opOffset}`);
|
|
436
|
+
}
|
|
437
|
+
opOffset++; // Skip this byte and continue
|
|
438
|
+
continue;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
let opCode = opcodeEntry.Clone();
|
|
442
|
+
opCode.Offset = opOffset++;
|
|
443
|
+
opCode.CodeBlock = this;
|
|
444
|
+
opCode.InstructionIndex = instructionIndex++;
|
|
445
|
+
|
|
446
|
+
// Set instruction size based on Python version
|
|
447
|
+
if (this.CodeObject.Reader.versionCompare(3, 6) >= 0) {
|
|
448
|
+
opCode.Size = 2; // Python 3.6+ uses 2-byte word-aligned instructions
|
|
449
|
+
opCode.Argument = extendedArg | code[opOffset++];
|
|
450
|
+
} else if (opCode.HasArgument) {
|
|
451
|
+
opCode.Size = 3; // Python < 3.6 with argument: opcode + 2 arg bytes
|
|
452
|
+
opCode.Argument = extendedArg | code[opOffset++] | code[opOffset++] << 8;
|
|
453
|
+
} else {
|
|
454
|
+
opCode.Size = 1; // Python < 3.6 without argument: just opcode
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
if (opCode.HasArgument) {
|
|
458
|
+
if (opCode.OpCodeID == OpCodes.SET_LINENO_A) {
|
|
459
|
+
this.CodeObject.CachedLineNo = opCode.Argument;
|
|
460
|
+
} else {
|
|
461
|
+
opCode.LineNo = this.CodeObject.getLineNumber(opCode.Offset);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
if (opCode.HasConstant) {
|
|
465
|
+
let val = this.CodeObject.Consts.Value[opCode.Argument];
|
|
466
|
+
if (global.g_cliArgs?.debug && opCode.Offset < 20) {
|
|
467
|
+
console.log(`[SetupByteCode] offset=${opCode.Offset}, arg=${opCode.Argument}, Consts.length=${this.CodeObject.Consts?.Value?.length}, val=${val?.ClassName || 'null'}`);
|
|
468
|
+
}
|
|
469
|
+
if (val) {
|
|
470
|
+
opCode.ConstantObject = val;
|
|
471
|
+
switch(val.ClassName) {
|
|
472
|
+
case "Py_CodeObject":
|
|
473
|
+
opCode.Constant = opCode.Argument;
|
|
474
|
+
break;
|
|
475
|
+
case "Py_Unicode":
|
|
476
|
+
case "Py_String":
|
|
477
|
+
let strVal = val.toString();
|
|
478
|
+
if (!["\"", "\'"].includes(strVal[0])) {
|
|
479
|
+
strVal = strVal.replaceAll("\\", "\\\\").replaceAll("\"", "\\\"").replaceAll("\n", "\\n");
|
|
480
|
+
if (strVal.indexOf("'")) {
|
|
481
|
+
opCode.Constant = `"${strVal}"`;
|
|
482
|
+
} else {
|
|
483
|
+
opCode.Constant = `'${strVal}'`;
|
|
484
|
+
}
|
|
485
|
+
} else {
|
|
486
|
+
opCode.Constant = strVal;
|
|
487
|
+
}
|
|
488
|
+
break;
|
|
489
|
+
default:
|
|
490
|
+
opCode.Constant = val.toString();
|
|
491
|
+
}
|
|
492
|
+
} else {
|
|
493
|
+
// Malformed bytecode: oparg beyond consts. Keep placeholder instead of crashing.
|
|
494
|
+
opCode.Constant = `##CONST_${opCode.Argument}##`;
|
|
495
|
+
}
|
|
496
|
+
} else if (opCode.HasName) {
|
|
497
|
+
let nameIndex = opCode.Argument;
|
|
498
|
+
|
|
499
|
+
// Python 3.11+ LOAD_GLOBAL uses oparg>>1 as name index
|
|
500
|
+
if (opCode.InstructionName === 'LOAD_GLOBAL' &&
|
|
501
|
+
this.CodeObject.Reader.versionCompare(3, 11) >= 0) {
|
|
502
|
+
nameIndex = opCode.Argument >> 1;
|
|
503
|
+
} else if (['LOAD_ATTR', 'LOAD_METHOD'].includes(opCode.InstructionName) &&
|
|
504
|
+
this.CodeObject.Reader.versionCompare(3, 12) >= 0) {
|
|
505
|
+
nameIndex = opCode.Argument >> 1;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
if (nameIndex < this.CodeObject.Names.Value.length) {
|
|
509
|
+
opCode.Name = this.CodeObject.Names.Value[nameIndex].toString();
|
|
510
|
+
} else {
|
|
511
|
+
if (global.g_cliArgs?.debug) {
|
|
512
|
+
console.error(`HasName: opCode.Argument ${opCode.Argument} out of bounds (Names.length=${this.CodeObject.Names.Value.length})`);
|
|
513
|
+
}
|
|
514
|
+
opCode.Name = `##NAME_${opCode.Argument}##`;
|
|
515
|
+
}
|
|
516
|
+
} else if (opCode.HasCompare) {
|
|
517
|
+
opCode.CompareOperator = OpCodes.CompareOpNames[opCode.Argument];
|
|
518
|
+
} else if (opCode.HasLocal) {
|
|
519
|
+
if (opCode.Argument < this.CodeObject.VarNames.Value.length) {
|
|
520
|
+
opCode.Name = this.CodeObject.VarNames.Value[opCode.Argument].toString();
|
|
521
|
+
} else if (opCode.Argument < this.CodeObject.Names.Value.length) {
|
|
522
|
+
opCode.Name = this.CodeObject.Names.Value[opCode.Argument].toString();
|
|
523
|
+
}
|
|
524
|
+
} else if (opCode.HasFree) {
|
|
525
|
+
if (opCode.Argument < this.CodeObject.CellVars.Value.length) {
|
|
526
|
+
opCode.FreeName = this.CodeObject.CellVars.Value[opCode.Argument].toString();
|
|
527
|
+
} else if ((opCode.Argument - this.CodeObject.CellVars.Value.length) < this.CodeObject.FreeVars.Value.length) {
|
|
528
|
+
opCode.FreeName = this.CodeObject.FreeVars.Value[opCode.Argument - this.CodeObject.CellVars.Value.length].toString();
|
|
529
|
+
} else {
|
|
530
|
+
opCode.FreeName = `##FREEVAR_${opCode.Argument}##`;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
this.Instructions.push(opCode);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
CanGoNext(offset = 1) {
|
|
539
|
+
if (this.CurrentInstructionIndex + offset >= 0 && this.CurrentInstructionIndex + offset < this.Instructions.length) {
|
|
540
|
+
return true;
|
|
541
|
+
}
|
|
542
|
+
return false;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
GoNext(offset = 1) {
|
|
546
|
+
if (this.CanGoNext(offset)) {
|
|
547
|
+
this.CurrentInstructionIndex += offset;
|
|
548
|
+
return true;
|
|
549
|
+
}
|
|
550
|
+
return false;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
GoToOffset(offset) {
|
|
554
|
+
let instructionIndex = this.GetIndexByOffset(offset);
|
|
555
|
+
if (instructionIndex < 0) {
|
|
556
|
+
return false;
|
|
557
|
+
}
|
|
558
|
+
this.CurrentInstructionIndex = instructionIndex;
|
|
559
|
+
return true;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
MoveBack() {
|
|
563
|
+
this.GoNext(-1);
|
|
564
|
+
return "";
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
GetNextInstruction(offset = 1) {
|
|
568
|
+
if (!this.GoNext(offset)) {
|
|
569
|
+
return null;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
return this.Instructions[this.CurrentInstructionIndex];
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
//
|
|
576
|
+
// Look behind and look ahead functions
|
|
577
|
+
//
|
|
578
|
+
get Prev() {
|
|
579
|
+
if (this.CanGoNext(-1)) {
|
|
580
|
+
return this.Instructions[this.CurrentInstructionIndex - 1];
|
|
581
|
+
}
|
|
582
|
+
return null;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
get Next()
|
|
586
|
+
{
|
|
587
|
+
return this.PeekNextInstruction();
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
PeekNextInstruction(position = 1)
|
|
591
|
+
{
|
|
592
|
+
if (this.CurrentInstructionIndex + position >= this.Instructions.length) {
|
|
593
|
+
return null;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
return this.Instructions[this.CurrentInstructionIndex + position];
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
PeekInstructionAt(position) {
|
|
600
|
+
if (position >= this.Instructions.length || position < 0) {
|
|
601
|
+
return null;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
return this.Instructions[position];
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
PeekInstructionAtOffset(offset) {
|
|
608
|
+
let startPos = 0;
|
|
609
|
+
if (offset > this.Instructions[this.CurrentInstructionIndex].Offset) {
|
|
610
|
+
startPos = this.CurrentInstructionIndex + 1;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
for (let position = startPos; position < this.Instructions.length; position++) {
|
|
614
|
+
if (this.Instructions[position].Offset == offset) {
|
|
615
|
+
return this.Instructions[position];
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
return null;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
PeekInstructionBeforeOffset(offset, backOffset = 1) {
|
|
623
|
+
offset = this.GetIndexByOffset(offset);
|
|
624
|
+
|
|
625
|
+
return this.PeekInstructionAt(offset - backOffset);
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
get LastOffset() {
|
|
629
|
+
return this.Instructions[this.Instructions.length - 1].Offset;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
GetIndexByOffset(offset) {
|
|
633
|
+
// TODO: Refactor this code to use binary search
|
|
634
|
+
if (offset < 0) {
|
|
635
|
+
return -1;
|
|
636
|
+
}
|
|
637
|
+
for (let position = 0; position < this.Instructions.length; position++) {
|
|
638
|
+
if (this.Instructions[position].Offset == offset) {
|
|
639
|
+
return position;
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
return -1;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
GetIndexByOpCode(opCodeID) {
|
|
647
|
+
for (let position = this.CurrentInstructionIndex + 1; position < this.Instructions.length; position++) {
|
|
648
|
+
if (this.Instructions[position].OpCodeID == opCodeID)
|
|
649
|
+
return position;
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
return -1;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
GetOpCodeByID(opCodeID, fromOffset = -1, toOffset = -1) {
|
|
656
|
+
let startPosition = fromOffset < 0 ? this.CurrentInstructionIndex + 1 : this.GetIndexByOffset(fromOffset);
|
|
657
|
+
let endPosition = toOffset <= 0 ? this.Instructions.length - 1 : this.GetIndexByOffset(toOffset);
|
|
658
|
+
if (startPosition > endPosition) {
|
|
659
|
+
let tempPosition = startPosition;
|
|
660
|
+
startPosition = endPosition;
|
|
661
|
+
endPosition = tempPosition;
|
|
662
|
+
}
|
|
663
|
+
for (let position = startPosition; position <= endPosition; position++) {
|
|
664
|
+
if (this.Instructions[position].OpCodeID == opCodeID)
|
|
665
|
+
return this.Instructions[position];
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
return null;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
GetOpCodeByName(opCodeName, fromOffset = -1, toOffset = -1) {
|
|
672
|
+
let partialMatch = false;
|
|
673
|
+
let startPosition = fromOffset < 0 ? this.CurrentInstructionIndex + 1 : this.GetIndexByOffset(fromOffset);
|
|
674
|
+
let endPosition = toOffset <= 0 ? this.Instructions.length - 1 : this.GetIndexByOffset(toOffset);
|
|
675
|
+
if (startPosition > endPosition) {
|
|
676
|
+
let tempPosition = startPosition;
|
|
677
|
+
startPosition = endPosition;
|
|
678
|
+
endPosition = tempPosition;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
if (opCodeName.endsWith("*")) {
|
|
682
|
+
partialMatch = true;
|
|
683
|
+
opCodeName = opCodeName.substring(0, opCodeName.length - 1);
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
for (let position = startPosition; position <= endPosition; position++) {
|
|
687
|
+
if (partialMatch) {
|
|
688
|
+
if (this.Instructions[position].InstructionName.startsWith(opCodeName)) {
|
|
689
|
+
return this.Instructions[position];
|
|
690
|
+
}
|
|
691
|
+
} else if (this.Instructions[position].InstructionName == opCodeName) {
|
|
692
|
+
return this.Instructions[position];
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
return null;
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
|
|
700
|
+
GetOffsetByOpCode(opCodeID, fromOffset = -1, toOffset = -1) {
|
|
701
|
+
let startPosition = fromOffset < 0 ? this.CurrentInstructionIndex + 1 : this.GetIndexByOffset(fromOffset);
|
|
702
|
+
let endPosition = toOffset <= 0 ? this.Instructions.length - 1 : this.GetIndexByOffset(toOffset);
|
|
703
|
+
if (startPosition > endPosition) {
|
|
704
|
+
let tempPosition = startPosition;
|
|
705
|
+
startPosition = endPosition;
|
|
706
|
+
endPosition = tempPosition;
|
|
707
|
+
}
|
|
708
|
+
for (let position = startPosition; position <= endPosition; position++) {
|
|
709
|
+
if (this.Instructions[position].OpCodeID == opCodeID)
|
|
710
|
+
return this.Instructions[position].Offset;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
return -1;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
GetReversedOffsetByOpCode(opCodeID, startOffset = -1, endOffset = -1) {
|
|
717
|
+
let startPosition = this.CurrentInstructionIndex - 1;
|
|
718
|
+
let endPosition = 0;
|
|
719
|
+
|
|
720
|
+
if (startOffset > 0) {
|
|
721
|
+
startPosition = this.GetIndexByOffset(startOffset);
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
if (startPosition < 0 && startPosition >= this.Instructions.length) {
|
|
725
|
+
return -1;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
if (endOffset > 0) {
|
|
729
|
+
endPosition = this.GetIndexByOffset(endOffset);
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
if (endPosition < 0 && endPosition >= this.Instructions.length) {
|
|
733
|
+
return -1;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
for (let position = startPosition; position >= endPosition; position--) {
|
|
737
|
+
if (this.Instructions[position].OpCodeID == opCodeID)
|
|
738
|
+
return this.Instructions[position].Offset;
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
return -1;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
GetOffsetByOpCodeName(opName) {
|
|
745
|
+
for (let position = this.CurrentInstructionIndex + 1; position < this.Instructions.length; position++) {
|
|
746
|
+
if (this.Instructions[position].InstructionName.startsWith(opName)) {
|
|
747
|
+
return this.Instructions[position].Offset;
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
return -1;
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
GetBackOffsetByOpCodeName(opName) {
|
|
755
|
+
for (let position = this.CurrentInstructionIndex - 1; position >= 0; position--) {
|
|
756
|
+
if (this.Instructions[position].InstructionName.startsWith(opName)) {
|
|
757
|
+
return this.Instructions[position].Offset;
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
return -1;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
GetLineOffsetRangeForOffset(offset) {
|
|
765
|
+
let startOffset = this.GetIndexByOffset(offset);
|
|
766
|
+
let endOffset = startOffset;
|
|
767
|
+
let line = this.CodeObject.LineNoTab[offset];
|
|
768
|
+
|
|
769
|
+
while (startOffset > 0) {
|
|
770
|
+
startOffset--;
|
|
771
|
+
if (this.CodeObject.LineNoTab[this.Instructions[startOffset].Offset] != line) {
|
|
772
|
+
startOffset++;
|
|
773
|
+
break;
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
while (endOffset < this.Instructions.length - 1) {
|
|
778
|
+
endOffset++;
|
|
779
|
+
if (this.CodeObject.LineNoTab[this.Instructions[endOffset].Offset] != line) {
|
|
780
|
+
endOffset--;
|
|
781
|
+
break;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
startOffset = this.Instructions[startOffset].Offset;
|
|
786
|
+
endOffset = this.Instructions[endOffset].Offset;
|
|
787
|
+
|
|
788
|
+
return [line, startOffset, endOffset];
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
CountSpecificOpCodes(opCodes, offset = -1, endOffset = -1) {
|
|
792
|
+
let startPos = offset == -1 ? 0 : this.GetIndexByOffset(offset);
|
|
793
|
+
let endPos = endOffset == -1 ? this.Instructions.length : this.GetIndexByOffset(endOffset);
|
|
794
|
+
let count = 0;
|
|
795
|
+
|
|
796
|
+
|
|
797
|
+
if (!Array.isArray(opCodes)) {
|
|
798
|
+
opCodes = [opCodes];
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
for (let position = startPos; position < endPos; position++) {
|
|
802
|
+
if (opCodes.includes(this.Instructions[position].OpCodeID)) {
|
|
803
|
+
count++;
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
return count;
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
CheckIfOpCodesExistsInLine(opCodes, startOffset, endOffset) {
|
|
811
|
+
let startPosition = this.GetIndexByOffset(startOffset);
|
|
812
|
+
let endPosition = this.GetIndexByOffset(endOffset);
|
|
813
|
+
let mapExists = {};
|
|
814
|
+
|
|
815
|
+
for (let opCode of opCodes) {
|
|
816
|
+
mapExists[opCode] = false;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
for (let position = startPosition; position <= endPosition; position++) {
|
|
820
|
+
if (opCodes.includes(this.Instructions[position].OpCodeID)) {
|
|
821
|
+
mapExists[this.Instructions[position].OpCodeID] = true;
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
for (let item of Object.values(mapExists)) {
|
|
826
|
+
if (item == false) {
|
|
827
|
+
return false;
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
return true;
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
DOMINATORS = [OpCodes.SETUP_LOOP_A, OpCodes.SETUP_EXCEPT_A, OpCodes.SETUP_FINALLY_A, OpCodes.SETUP_WITH_A, OpCodes.FOR_ITER_A];
|
|
834
|
+
|
|
835
|
+
FindEndOfBlock(originalOffset, currentOffset = -1){
|
|
836
|
+
currentOffset = currentOffset == -1 ? this.Instructions[this.CurrentInstructionIndex].Offset : currentOffset;
|
|
837
|
+
|
|
838
|
+
if (global.g_cliArgs?.debug) {
|
|
839
|
+
console.log(`FindEndOfBlock(originalOffset=${originalOffset}, currentOffset=${currentOffset})`);
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
// NEW LOGIC: For backward jumps (loop/branch returns), scan forward to find
|
|
843
|
+
// the actual end of the block by looking for JUMP instructions
|
|
844
|
+
if (originalOffset < currentOffset) {
|
|
845
|
+
// Try to find the end by scanning forward for JUMP instructions
|
|
846
|
+
// The block ends where we find a JUMP to a DIFFERENT target
|
|
847
|
+
let lastMatchingJump = -1;
|
|
848
|
+
let searchLimit = 50; // reasonable limit to avoid infinite loops
|
|
849
|
+
|
|
850
|
+
// Start scanning from current instruction index forward
|
|
851
|
+
let startIdx = this.CurrentInstructionIndex;
|
|
852
|
+
for (let i = 0; i < searchLimit; i++) {
|
|
853
|
+
let instr = this.PeekInstructionAt(startIdx + i);
|
|
854
|
+
if (!instr) break;
|
|
855
|
+
|
|
856
|
+
// Found unconditional JUMP
|
|
857
|
+
if (instr.InstructionName === 'JUMP_ABSOLUTE' || instr.InstructionName === 'JUMP_FORWARD') {
|
|
858
|
+
let jumpTarget = instr.JumpTarget;
|
|
859
|
+
|
|
860
|
+
if (global.g_cliArgs?.debug) {
|
|
861
|
+
console.log(` Checking JUMP at offset ${instr.Offset}: target=${jumpTarget} vs originalOffset=${originalOffset}`);
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
// If JUMP target matches originalOffset, this is a loop-back jump
|
|
865
|
+
// Mark it as potential end, but keep scanning
|
|
866
|
+
if (jumpTarget === originalOffset) {
|
|
867
|
+
lastMatchingJump = instr.Offset;
|
|
868
|
+
if (global.g_cliArgs?.debug) {
|
|
869
|
+
console.log(` → Matching jump found at ${instr.Offset}`);
|
|
870
|
+
}
|
|
871
|
+
} else if (lastMatchingJump > 0) {
|
|
872
|
+
// Found a JUMP with DIFFERENT target after a matching jump
|
|
873
|
+
// This means the matching jump was the end of the block
|
|
874
|
+
if (global.g_cliArgs?.debug) {
|
|
875
|
+
console.log(` → Different target! Block ends at ${lastMatchingJump}`);
|
|
876
|
+
}
|
|
877
|
+
// Return the offset AFTER the matching jump as block end
|
|
878
|
+
return [lastMatchingJump + 3, null];
|
|
879
|
+
} else {
|
|
880
|
+
// First JUMP has different target - this might be the block end
|
|
881
|
+
if (global.g_cliArgs?.debug) {
|
|
882
|
+
console.log(` → First JUMP has different target, block might end at ${instr.Offset}`);
|
|
883
|
+
}
|
|
884
|
+
return [instr.Offset, null];
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
// If we found matching jumps but no different target, use last matching jump
|
|
890
|
+
if (lastMatchingJump > 0) {
|
|
891
|
+
if (global.g_cliArgs?.debug) {
|
|
892
|
+
console.log(` Using last matching jump at ${lastMatchingJump + 3} as block end`);
|
|
893
|
+
}
|
|
894
|
+
return [lastMatchingJump + 3, null];
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
// FALLBACK: Old dominator-based logic
|
|
898
|
+
let dominatorOp = this.PeekInstructionAtOffset(originalOffset);
|
|
899
|
+
if (this.DOMINATORS.includes(dominatorOp?.OpCodeID)) {
|
|
900
|
+
if (global.g_cliArgs?.debug) {
|
|
901
|
+
console.log(` Fallback: Found dominator at ${originalOffset}: ${dominatorOp.InstructionName} → JumpTarget=${dominatorOp.JumpTarget}`);
|
|
902
|
+
}
|
|
903
|
+
return [dominatorOp.JumpTarget, dominatorOp];
|
|
904
|
+
}
|
|
905
|
+
dominatorOp = this.PeekInstructionAtOffset(originalOffset - 3);
|
|
906
|
+
if (this.DOMINATORS.includes(dominatorOp?.OpCodeID)) {
|
|
907
|
+
if (global.g_cliArgs?.debug) {
|
|
908
|
+
console.log(` Fallback: Found dominator at ${originalOffset - 3}: ${dominatorOp.InstructionName} → JumpTarget=${dominatorOp.JumpTarget}`);
|
|
909
|
+
}
|
|
910
|
+
return [dominatorOp.JumpTarget, dominatorOp];
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
if (global.g_cliArgs?.debug) {
|
|
915
|
+
console.log(` No dominator found, returning originalOffset=${originalOffset}`);
|
|
916
|
+
}
|
|
917
|
+
return [originalOffset, null];
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
extractImportNames(fromlist, callback) {
|
|
921
|
+
let count = fromlist.Value.length;
|
|
922
|
+
let partIdx = 0;
|
|
923
|
+
for (let idx = this.CurrentInstructionIndex + 1; idx < this.Instructions.length; idx++) {
|
|
924
|
+
let opCode = this.Instructions[idx];
|
|
925
|
+
|
|
926
|
+
if (opCode.OpCodeID == OpCodes.POP_TOP) {
|
|
927
|
+
this.CurrentInstructionIndex = idx;
|
|
928
|
+
if (partIdx != count) {
|
|
929
|
+
console.log(`WARNING: `);
|
|
930
|
+
}
|
|
931
|
+
return;
|
|
932
|
+
} else if (opCode.InstructionName.startsWith("STORE_")) {
|
|
933
|
+
callback(fromlist.Value[partIdx].toString(), opCode.Label);
|
|
934
|
+
partIdx++;
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
module.exports = OpCodes;
|