forked from IronLanguages/ironpython3
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path_opcode.cs
More file actions
441 lines (407 loc) · 16.6 KB
/
_opcode.cs
File metadata and controls
441 lines (407 loc) · 16.6 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
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Numerics;
using System.Text;
using Microsoft.Scripting.Runtime;
using Microsoft.Scripting.Utils;
using IronPython.Runtime;
using IronPython.Runtime.Exceptions;
using IronPython.Runtime.Operations;
using IronPython.Runtime.Types;
[assembly: PythonModule("_opcode", typeof(IronPython.Modules.PythonOpcode))]
namespace IronPython.Modules {
public static class PythonOpcode {
/* Instruction opcodes for compiled code */
private const int POP_TOP = 1;
private const int ROT_TWO = 2;
private const int ROT_THREE = 3;
private const int DUP_TOP = 4;
private const int DUP_TOP_TWO = 5;
private const int ROT_FOUR = 6;
private const int NOP = 9;
private const int UNARY_POSITIVE = 10;
private const int UNARY_NEGATIVE = 11;
private const int UNARY_NOT = 12;
private const int UNARY_INVERT = 15;
private const int BINARY_MATRIX_MULTIPLY = 16;
private const int INPLACE_MATRIX_MULTIPLY = 17;
private const int BINARY_POWER = 19;
private const int BINARY_MULTIPLY = 20;
private const int BINARY_MODULO = 22;
private const int BINARY_ADD = 23;
private const int BINARY_SUBTRACT = 24;
private const int BINARY_SUBSCR = 25;
private const int BINARY_FLOOR_DIVIDE = 26;
private const int BINARY_TRUE_DIVIDE = 27;
private const int INPLACE_FLOOR_DIVIDE = 28;
private const int INPLACE_TRUE_DIVIDE = 29;
private const int GET_AITER = 50;
private const int GET_ANEXT = 51;
private const int BEFORE_ASYNC_WITH = 52;
private const int BEGIN_FINALLY = 53;
private const int END_ASYNC_FOR = 54;
private const int INPLACE_ADD = 55;
private const int INPLACE_SUBTRACT = 56;
private const int INPLACE_MULTIPLY = 57;
private const int INPLACE_MODULO = 59;
private const int STORE_SUBSCR = 60;
private const int DELETE_SUBSCR = 61;
private const int BINARY_LSHIFT = 62;
private const int BINARY_RSHIFT = 63;
private const int BINARY_AND = 64;
private const int BINARY_XOR = 65;
private const int BINARY_OR = 66;
private const int INPLACE_POWER = 67;
private const int GET_ITER = 68;
private const int GET_YIELD_FROM_ITER = 69;
private const int PRINT_EXPR = 70;
private const int LOAD_BUILD_CLASS = 71;
private const int YIELD_FROM = 72;
private const int GET_AWAITABLE = 73;
private const int INPLACE_LSHIFT = 75;
private const int INPLACE_RSHIFT = 76;
private const int INPLACE_AND = 77;
private const int INPLACE_XOR = 78;
private const int INPLACE_OR = 79;
private const int WITH_CLEANUP_START = 81;
private const int WITH_CLEANUP_FINISH = 82;
private const int RETURN_VALUE = 83;
private const int IMPORT_STAR = 84;
private const int SETUP_ANNOTATIONS = 85;
private const int YIELD_VALUE = 86;
private const int POP_BLOCK = 87;
private const int END_FINALLY = 88;
private const int POP_EXCEPT = 89;
private const int HAVE_ARGUMENT = 90;
private const int STORE_NAME = 90;
private const int DELETE_NAME = 91;
private const int UNPACK_SEQUENCE = 92;
private const int FOR_ITER = 93;
private const int UNPACK_EX = 94;
private const int STORE_ATTR = 95;
private const int DELETE_ATTR = 96;
private const int STORE_GLOBAL = 97;
private const int DELETE_GLOBAL = 98;
private const int LOAD_CONST = 100;
private const int LOAD_NAME = 101;
private const int BUILD_TUPLE = 102;
private const int BUILD_LIST = 103;
private const int BUILD_SET = 104;
private const int BUILD_MAP = 105;
private const int LOAD_ATTR = 106;
private const int COMPARE_OP = 107;
private const int IMPORT_NAME = 108;
private const int IMPORT_FROM = 109;
private const int JUMP_FORWARD = 110;
private const int JUMP_IF_FALSE_OR_POP = 111;
private const int JUMP_IF_TRUE_OR_POP = 112;
private const int JUMP_ABSOLUTE = 113;
private const int POP_JUMP_IF_FALSE = 114;
private const int POP_JUMP_IF_TRUE = 115;
private const int LOAD_GLOBAL = 116;
private const int SETUP_FINALLY = 122;
private const int LOAD_FAST = 124;
private const int STORE_FAST = 125;
private const int DELETE_FAST = 126;
private const int RAISE_VARARGS = 130;
private const int CALL_FUNCTION = 131;
private const int MAKE_FUNCTION = 132;
private const int BUILD_SLICE = 133;
private const int LOAD_CLOSURE = 135;
private const int LOAD_DEREF = 136;
private const int STORE_DEREF = 137;
private const int DELETE_DEREF = 138;
private const int CALL_FUNCTION_KW = 141;
private const int CALL_FUNCTION_EX = 142;
private const int SETUP_WITH = 143;
private const int EXTENDED_ARG = 144;
private const int LIST_APPEND = 145;
private const int SET_ADD = 146;
private const int MAP_ADD = 147;
private const int LOAD_CLASSDEREF = 148;
private const int BUILD_LIST_UNPACK = 149;
private const int BUILD_MAP_UNPACK = 150;
private const int BUILD_MAP_UNPACK_WITH_CALL = 151;
private const int BUILD_TUPLE_UNPACK = 152;
private const int BUILD_SET_UNPACK = 153;
private const int SETUP_ASYNC_WITH = 154;
private const int FORMAT_VALUE = 155;
private const int BUILD_CONST_KEY_MAP = 156;
private const int BUILD_STRING = 157;
private const int BUILD_TUPLE_UNPACK_WITH_CALL = 158;
private const int LOAD_METHOD = 160;
private const int CALL_METHOD = 161;
private const int CALL_FINALLY = 162;
private const int POP_FINALLY = 163;
private static readonly int PY_INVALID_STACK_EFFECT = int.MaxValue;
/* Masks and values used by FORMAT_VALUE opcode. */
private const int FVC_MASK = 0x3;
private const int FVC_NONE = 0x0;
private const int FVC_STR = 0x1;
private const int FVC_REPR = 0x2;
private const int FVC_ASCII = 0x3;
private const int FVS_MASK = 0x4;
private const int FVS_HAVE_SPEC = 0x4;
public static int stack_effect(CodeContext context, int opcode, object oparg=null) {
int ioparg = 0;
if (opcode >= HAVE_ARGUMENT) {
if (oparg == null) {
throw PythonOps.ValueError("stack_effect: opcode requires oparg but oparg was not specified");
}
if (!Converter.TryConvertToIndex(oparg, out ioparg)) { // supported since CPython 3.8
ioparg = Converter.ImplicitConvertToInt32(oparg) ?? // warning since CPython 3.8, unsupported in 3.10
throw PythonOps.TypeError($"an integer is required (got type {PythonOps.GetPythonTypeName(oparg)})");
}
} else if (oparg != null) {
throw PythonOps.ValueError("stack_effect: opcode does not permit oparg but oparg was specified");
}
int effect = stack_effect(opcode, ioparg);
if (effect == PY_INVALID_STACK_EFFECT) {
throw PythonOps.ValueError("invalid opcode or oparg");
}
return effect;
}
private static int stack_effect(int opcode, int oparg, int jump = -1) {
switch (opcode) {
case NOP:
case EXTENDED_ARG:
return 0;
/* Stack manipulation */
case POP_TOP:
return -1;
case ROT_TWO:
case ROT_THREE:
case ROT_FOUR:
return 0;
case DUP_TOP:
return 1;
case DUP_TOP_TWO:
return 2;
/* Unary operators */
case UNARY_POSITIVE:
case UNARY_NEGATIVE:
case UNARY_NOT:
case UNARY_INVERT:
return 0;
case SET_ADD:
case LIST_APPEND:
return -1;
case MAP_ADD:
return -2;
/* Binary operators */
case BINARY_POWER:
case BINARY_MULTIPLY:
case BINARY_MATRIX_MULTIPLY:
case BINARY_MODULO:
case BINARY_ADD:
case BINARY_SUBTRACT:
case BINARY_SUBSCR:
case BINARY_FLOOR_DIVIDE:
case BINARY_TRUE_DIVIDE:
return -1;
case INPLACE_FLOOR_DIVIDE:
case INPLACE_TRUE_DIVIDE:
return -1;
case INPLACE_ADD:
case INPLACE_SUBTRACT:
case INPLACE_MULTIPLY:
case INPLACE_MATRIX_MULTIPLY:
case INPLACE_MODULO:
return -1;
case STORE_SUBSCR:
return -3;
case DELETE_SUBSCR:
return -2;
case BINARY_LSHIFT:
case BINARY_RSHIFT:
case BINARY_AND:
case BINARY_XOR:
case BINARY_OR:
return -1;
case INPLACE_POWER:
return -1;
case GET_ITER:
return 0;
case PRINT_EXPR:
return -1;
case LOAD_BUILD_CLASS:
return 1;
case INPLACE_LSHIFT:
case INPLACE_RSHIFT:
case INPLACE_AND:
case INPLACE_XOR:
case INPLACE_OR:
return -1;
case SETUP_WITH:
/* 1 in the normal flow.
* Restore the stack position and push 6 values before jumping to
* the handler if an exception be raised. */
return jump != 0 ? 6 : 1;
case WITH_CLEANUP_START:
return 2; /* or 1, depending on TOS */
case WITH_CLEANUP_FINISH:
/* Pop a variable number of values pushed by WITH_CLEANUP_START
* + __exit__ or __aexit__. */
return -3;
case RETURN_VALUE:
return -1;
case IMPORT_STAR:
return -1;
case SETUP_ANNOTATIONS:
return 0;
case YIELD_VALUE:
return 0;
case YIELD_FROM:
return -1;
case POP_BLOCK:
return 0;
case POP_EXCEPT:
return -3;
case END_FINALLY:
case POP_FINALLY:
/* Pop 6 values when an exception was raised. */
return -6;
case STORE_NAME:
return -1;
case DELETE_NAME:
return 0;
case UNPACK_SEQUENCE:
return oparg - 1;
case UNPACK_EX:
return (oparg & 0xFF) + (oparg >> 8);
case FOR_ITER:
/* -1 at end of iterator, 1 if continue iterating. */
return jump > 0 ? -1 : 1;
case STORE_ATTR:
return -2;
case DELETE_ATTR:
return -1;
case STORE_GLOBAL:
return -1;
case DELETE_GLOBAL:
return 0;
case LOAD_CONST:
return 1;
case LOAD_NAME:
return 1;
case BUILD_TUPLE:
case BUILD_LIST:
case BUILD_SET:
case BUILD_STRING:
return 1 - oparg;
case BUILD_LIST_UNPACK:
case BUILD_TUPLE_UNPACK:
case BUILD_TUPLE_UNPACK_WITH_CALL:
case BUILD_SET_UNPACK:
case BUILD_MAP_UNPACK:
case BUILD_MAP_UNPACK_WITH_CALL:
return 1 - oparg;
case BUILD_MAP:
return 1 - 2 * oparg;
case BUILD_CONST_KEY_MAP:
return -oparg;
case LOAD_ATTR:
return 0;
case COMPARE_OP:
return -1;
case IMPORT_NAME:
return -1;
case IMPORT_FROM:
return 1;
/* Jumps */
case JUMP_FORWARD:
case JUMP_ABSOLUTE:
return 0;
case JUMP_IF_TRUE_OR_POP:
case JUMP_IF_FALSE_OR_POP:
return jump != 0 ? 0 : -1;
case POP_JUMP_IF_FALSE:
case POP_JUMP_IF_TRUE:
return -1;
case LOAD_GLOBAL:
return 1;
/* Exception handling */
case SETUP_FINALLY:
/* 0 in the normal flow.
* Restore the stack position and push 6 values before jumping to
* the handler if an exception be raised. */
return jump != 0 ? 6 : 0;
case BEGIN_FINALLY:
/* Actually pushes 1 value, but count 6 for balancing with
* END_FINALLY and POP_FINALLY.
* This is the main reason of using this opcode instead of
* "LOAD_CONST None". */
return 6;
case CALL_FINALLY:
return jump != 0 ? 1 : 0;
case LOAD_FAST:
return 1;
case STORE_FAST:
return -1;
case DELETE_FAST:
return 0;
case RAISE_VARARGS:
return -oparg;
/* Functions and calls */
case CALL_FUNCTION:
return -oparg;
case CALL_METHOD:
return -oparg - 1;
case CALL_FUNCTION_KW:
return -oparg - 1;
case CALL_FUNCTION_EX:
return -1 - (((oparg & 0x01) != 0) ? 1 : 0);
case MAKE_FUNCTION:
return -1 - (((oparg & 0x01) != 0) ? 1 : 0) - (((oparg & 0x02) != 0) ? 1 : 0) -
(((oparg & 0x04) != 0) ? 1 : 0) - (((oparg & 0x08) != 0) ? 1 : 0);
case BUILD_SLICE:
if (oparg == 3)
return -2;
else
return -1;
/* Closures */
case LOAD_CLOSURE:
return 1;
case LOAD_DEREF:
case LOAD_CLASSDEREF:
return 1;
case STORE_DEREF:
return -1;
case DELETE_DEREF:
return 0;
/* Iterators and generators */
case GET_AWAITABLE:
return 0;
case SETUP_ASYNC_WITH:
/* 0 in the normal flow.
* Restore the stack position to the position before the result
* of __aenter__ and push 6 values before jumping to the handler
* if an exception be raised. */
return jump != 0 ? -1 + 6 : 0;
case BEFORE_ASYNC_WITH:
return 1;
case GET_AITER:
return 0;
case GET_ANEXT:
return 1;
case GET_YIELD_FROM_ITER:
return 0;
case END_ASYNC_FOR:
return -7;
case FORMAT_VALUE:
/* If there's a fmt_spec on the stack, we go from 2->1,
else 1->1. */
return (oparg & FVS_MASK) == FVS_HAVE_SPEC ? -1 : 0;
case LOAD_METHOD:
return 1;
default:
return PY_INVALID_STACK_EFFECT;
}
}
}
}