cinderx 2026.1.16.2__cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl

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.
Files changed (68) hide show
  1. __static__/__init__.py +641 -0
  2. __static__/compiler_flags.py +8 -0
  3. __static__/enum.py +160 -0
  4. __static__/native_utils.py +77 -0
  5. __static__/type_code.py +48 -0
  6. __strict__/__init__.py +39 -0
  7. _cinderx.so +0 -0
  8. cinderx/__init__.py +577 -0
  9. cinderx/__pycache__/__init__.cpython-314.pyc +0 -0
  10. cinderx/_asyncio.py +156 -0
  11. cinderx/compileall.py +710 -0
  12. cinderx/compiler/__init__.py +40 -0
  13. cinderx/compiler/__main__.py +137 -0
  14. cinderx/compiler/config.py +7 -0
  15. cinderx/compiler/consts.py +72 -0
  16. cinderx/compiler/debug.py +70 -0
  17. cinderx/compiler/dis_stable.py +283 -0
  18. cinderx/compiler/errors.py +151 -0
  19. cinderx/compiler/flow_graph_optimizer.py +1287 -0
  20. cinderx/compiler/future.py +91 -0
  21. cinderx/compiler/misc.py +32 -0
  22. cinderx/compiler/opcode_cinder.py +18 -0
  23. cinderx/compiler/opcode_static.py +100 -0
  24. cinderx/compiler/opcodebase.py +158 -0
  25. cinderx/compiler/opcodes.py +991 -0
  26. cinderx/compiler/optimizer.py +547 -0
  27. cinderx/compiler/pyassem.py +3711 -0
  28. cinderx/compiler/pycodegen.py +7660 -0
  29. cinderx/compiler/pysourceloader.py +62 -0
  30. cinderx/compiler/static/__init__.py +1404 -0
  31. cinderx/compiler/static/compiler.py +629 -0
  32. cinderx/compiler/static/declaration_visitor.py +335 -0
  33. cinderx/compiler/static/definite_assignment_checker.py +280 -0
  34. cinderx/compiler/static/effects.py +160 -0
  35. cinderx/compiler/static/module_table.py +666 -0
  36. cinderx/compiler/static/type_binder.py +2176 -0
  37. cinderx/compiler/static/types.py +10580 -0
  38. cinderx/compiler/static/util.py +81 -0
  39. cinderx/compiler/static/visitor.py +91 -0
  40. cinderx/compiler/strict/__init__.py +69 -0
  41. cinderx/compiler/strict/class_conflict_checker.py +249 -0
  42. cinderx/compiler/strict/code_gen_base.py +409 -0
  43. cinderx/compiler/strict/common.py +507 -0
  44. cinderx/compiler/strict/compiler.py +352 -0
  45. cinderx/compiler/strict/feature_extractor.py +130 -0
  46. cinderx/compiler/strict/flag_extractor.py +97 -0
  47. cinderx/compiler/strict/loader.py +827 -0
  48. cinderx/compiler/strict/preprocessor.py +11 -0
  49. cinderx/compiler/strict/rewriter/__init__.py +5 -0
  50. cinderx/compiler/strict/rewriter/remove_annotations.py +84 -0
  51. cinderx/compiler/strict/rewriter/rewriter.py +975 -0
  52. cinderx/compiler/strict/runtime.py +77 -0
  53. cinderx/compiler/symbols.py +1754 -0
  54. cinderx/compiler/unparse.py +414 -0
  55. cinderx/compiler/visitor.py +194 -0
  56. cinderx/jit.py +230 -0
  57. cinderx/opcode.py +202 -0
  58. cinderx/static.py +113 -0
  59. cinderx/strictmodule.py +6 -0
  60. cinderx/test_support.py +341 -0
  61. cinderx-2026.1.16.2.dist-info/METADATA +15 -0
  62. cinderx-2026.1.16.2.dist-info/RECORD +68 -0
  63. cinderx-2026.1.16.2.dist-info/WHEEL +6 -0
  64. cinderx-2026.1.16.2.dist-info/licenses/LICENSE +21 -0
  65. cinderx-2026.1.16.2.dist-info/top_level.txt +5 -0
  66. opcodes/__init__.py +0 -0
  67. opcodes/assign_opcode_numbers.py +272 -0
  68. opcodes/cinderx_opcodes.py +121 -0
@@ -0,0 +1,272 @@
1
+ # Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ # pyre-strict
4
+
5
+ # Assign opcode numbers for python 3.12
6
+
7
+ # Run from cinderx directory:
8
+ # buck run PythonLib/opcodes:assign_opcode_numbers -- \
9
+ # PythonLib/opcodes/opcode_312.py
10
+
11
+ import opcode
12
+ import re
13
+ import sys
14
+
15
+ from . import cinderx_opcodes as cx
16
+
17
+
18
+ # From inspection of the 3.12 opcodes we have a large empty range starting
19
+ # here, so we can keep the cinderx opcodes contiguous.
20
+ #
21
+ # NOTE: When upgrading to python 3.13+ the easiest thing to do would be to find
22
+ # a similar range of unassigned numbers; if that is not possible, we will need
23
+ # to scrape opcodes from Include/opcode.h and fit our opcodes into the gaps.
24
+ START_NUM = 184
25
+ END_NUM = 236
26
+
27
+
28
+ HEADER: str = """
29
+ # Copyright (c) Meta Platforms, Inc. and affiliates.
30
+
31
+ # Generated via assign_opcode_numbers.py, do not edit.
32
+
33
+ # This is an addition to python/3.12/Lib/opcode.py, and is intended to be run
34
+ # via `exec` in generate_opcode_h.py with the globals dict obtained from
35
+ # running Lib/opcode.py.
36
+
37
+ # flake8: noqa
38
+
39
+
40
+ # Lib/opcode.py deletes these functions so we need to define them again here.
41
+ # We also need to update opname when we call def_op().
42
+ def init(
43
+ opname,
44
+ opmap,
45
+ hasname,
46
+ hasjrel,
47
+ hasjabs,
48
+ hasconst,
49
+ hasarg,
50
+ cache_format,
51
+ specializations,
52
+ inline_cache_entries,
53
+ interp_only=False,
54
+ ):
55
+ def def_op(name, op):
56
+ opmap[name] = op
57
+ opname[op] = name
58
+
59
+ def name_op(name, op):
60
+ def_op(name, op)
61
+ hasname.append(op)
62
+
63
+ def jrel_op(name, op):
64
+ def_op(name, op)
65
+ hasjrel.append(op)
66
+
67
+ def jabs_op(name, op):
68
+ def_op(name, op)
69
+ hasjabs.append(op)
70
+
71
+ """.lstrip()
72
+
73
+
74
+ def process_opcode(
75
+ name: str,
76
+ flags: int,
77
+ out: list[str],
78
+ opcode_idx: int,
79
+ cache_size: int = 0,
80
+ cache_format: dict[str, int] | None = None,
81
+ parent: str | None = None,
82
+ ) -> None:
83
+ if flags & cx.NAME:
84
+ f = "name_op"
85
+ elif flags & cx.JREL:
86
+ f = "jrel_op"
87
+ elif flags & cx.JABS:
88
+ f = "jabs_op"
89
+ else:
90
+ f = "def_op"
91
+ if flags & cx.IMPLEMENTED_IN_INTERPRETER:
92
+ out.append(f' {f}("{name}", {opcode_idx})')
93
+ if flags & cx.CONST:
94
+ out.append(f" hasconst.append({opcode_idx})")
95
+ if flags & (cx.ARG | cx.CONST):
96
+ out.append(f" hasarg.append({opcode_idx})")
97
+ if cache_format is not None:
98
+ out.append(f' cache_format["{name}"] = "{cache_format}"')
99
+ if parent:
100
+ out.append(f' if "{parent}" not in specializations:')
101
+ out.append(f' specializations["{parent}"] = []')
102
+ out.append(f' specializations["{parent}"].append("{name}")')
103
+ if cache_size:
104
+ if sys.version_info >= (3, 14):
105
+ out.append(f' inline_cache_entries["{name}"] = {cache_size}')
106
+ else:
107
+ out.append(f" inline_cache_entries[{opcode_idx}] = {cache_size}")
108
+
109
+ else:
110
+ out.append(" if not interp_only:")
111
+ out.append(f' {f}("{name}", {opcode_idx})')
112
+ if flags & cx.CONST:
113
+ out.append(f" hasconst.append({opcode_idx})")
114
+ if flags & (cx.ARG | cx.CONST):
115
+ out.append(f" hasarg.append({opcode_idx})")
116
+
117
+
118
+ def assign_numbers312() -> list[str]:
119
+ i = START_NUM
120
+ out: list[str] = []
121
+
122
+ def inc() -> None:
123
+ nonlocal i
124
+ i += 1
125
+ if i == 229:
126
+ # skip 229 which is used as an invalid byte code in test_code.
127
+ i += 1
128
+ if i > END_NUM:
129
+ raise ValueError("Not enough free space for cinderx opcodes!")
130
+
131
+ for name, val in cx.CINDER_OPS.items():
132
+ inc()
133
+ if isinstance(val, cx.Family):
134
+ cache_size = sum(val.cache_format.values())
135
+ process_opcode(name, val.flags, out, i, cache_size, val.cache_format)
136
+ for specialization in val.specializations:
137
+ inc()
138
+ process_opcode(
139
+ specialization, val.flags, out, i, cache_size, parent=name
140
+ )
141
+ else:
142
+ process_opcode(name, val, out, i)
143
+
144
+ return out
145
+
146
+
147
+ def build_size_map() -> dict[int, list[int]]:
148
+ size_by_name: dict[str, int] = {}
149
+
150
+ def add_one(name: str, size_from: str) -> None:
151
+ # pyre-ignore[16]: unknown attribute
152
+ size_by_name[name] = opcode._inline_cache_entries.get(size_from, 0)
153
+
154
+ # First add add the specialized opcodes based upon their parent
155
+ # pyre-ignore[16]: unknown attribute
156
+ for op, specializations in opcode._specializations.items():
157
+ add_one(op, op)
158
+ for specialization in specializations:
159
+ add_one(specialization, op)
160
+
161
+ # Then add all of the remaining non specialized opcodes
162
+ for op in opcode.opname:
163
+ if op == "POP_JUMP_IF_FALSE" or op == "POP_JUMP_IF_TRUE":
164
+ continue
165
+ if op not in size_by_name:
166
+ add_one(op, op)
167
+
168
+ size_groups: dict[int, list[int]] = {}
169
+ for op, size in size_by_name.items():
170
+ opnum = opcode.opname.index(op)
171
+ if opnum > 255 or opnum == 0:
172
+ continue
173
+ if size not in size_groups:
174
+ size_groups[size] = [opnum]
175
+ else:
176
+ size_groups[size].append(opnum)
177
+
178
+ for val in size_groups.values():
179
+ val.sort()
180
+ return size_groups
181
+
182
+
183
+ def assign_numbers314() -> list[str]:
184
+ size_groups: dict[int, list[int]] = build_size_map()
185
+ start_num = 1
186
+ out: list[str] = []
187
+
188
+ def inc(cache_size: int, flags: int) -> int:
189
+ group = size_groups[cache_size]
190
+ i = None
191
+ # Try and assign our extended opcodes into instructions with like
192
+ # attributes so that things that naively look at extended ops see
193
+ # the something similar to what they expect.
194
+ for i, op in enumerate(group):
195
+ if flags & (cx.JABS | cx.JREL):
196
+ if op in opcode.hasjrel:
197
+ break
198
+ elif flags & cx.NAME:
199
+ if op in opcode.hasname:
200
+ break
201
+ elif (
202
+ op not in opcode.hasjrel
203
+ and op not in opcode.hasname
204
+ and op not in opcode.hasconst
205
+ ):
206
+ break
207
+ else:
208
+ raise NotImplementedError(
209
+ f"Couldn't find compatible opcode: {name} {flags:x} {group} {opcode.hasjrel}"
210
+ )
211
+
212
+ assert i is not None
213
+ res = group[i]
214
+ del group[i]
215
+ return res
216
+
217
+ name: str
218
+ for name, val in cx.CINDER_OPS.items():
219
+ if name in ("JUMP_IF_ZERO_OR_POP", "JUMP_IF_NONZERO_OR_POP"):
220
+ # special case - these are not used in 3.14.
221
+ continue
222
+
223
+ if isinstance(val, cx.Family):
224
+ # TODO: Enable cache formats eventually
225
+ cache_size = 0 # sum(val.cache_format.values())
226
+ cache_format = {} # val.cache_format
227
+
228
+ process_opcode(
229
+ name,
230
+ val.flags,
231
+ out,
232
+ inc(cache_size, val.flags),
233
+ cache_size,
234
+ val.cache_format,
235
+ )
236
+ for specialization in val.specializations:
237
+ process_opcode(
238
+ specialization,
239
+ val.flags,
240
+ out,
241
+ inc(cache_size, val.flags),
242
+ cache_size,
243
+ parent=name,
244
+ )
245
+ elif name == "POP_JUMP_IF_ZERO":
246
+ process_opcode(name, val, out, opcode.opmap["POP_JUMP_IF_FALSE"], 1)
247
+ elif name == "POP_JUMP_IF_NONZERO":
248
+ process_opcode(name, val, out, opcode.opmap["POP_JUMP_IF_TRUE"], 1)
249
+ else:
250
+ process_opcode(name, val, out, inc(0, val))
251
+
252
+ return out
253
+
254
+
255
+ def main() -> None:
256
+ if len(sys.argv) != 2:
257
+ print("Usage:\n fbpython assign_opcode_numbers.py <outfile>")
258
+ sys.exit()
259
+
260
+ outfile = sys.argv[1]
261
+ if sys.version_info >= (3, 14):
262
+ out = assign_numbers314()
263
+ else:
264
+ out = assign_numbers312()
265
+ with open(outfile, "w") as f:
266
+ f.write(HEADER)
267
+ f.write("\n".join(out))
268
+ f.write("\n")
269
+
270
+
271
+ if __name__ == "__main__":
272
+ main()
@@ -0,0 +1,121 @@
1
+ # Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ # pyre-strict
4
+
5
+ # Opcodes defined by cinderx
6
+
7
+ # Cinderx defines its own set of opcodes, which need to be added to the cpython
8
+ # ones. Since cpython does not have a stable map of opcode numbers to opcodes,
9
+ # we have to assign numbers to these opcodes on a per-version basis. This file
10
+ # serves as the source of truth for the cinderx opcodes and their attributes,
11
+ # and should be combined with the opcode map for each python version to
12
+ # allocate opcode numbers for that version.
13
+
14
+
15
+ # Bitflags for opcode attributes.
16
+ NONE = 0
17
+ NAME = 1
18
+ JREL = 2
19
+ JABS = 4
20
+ CONST = 8
21
+ ARG = 16
22
+ IMPLEMENTED_IN_INTERPRETER = 32
23
+
24
+
25
+ class Family:
26
+ def __init__(
27
+ self, flags: int, cache_format: dict[str, int], *specializations: str
28
+ ) -> None:
29
+ self.flags = flags
30
+ self.cache_format = cache_format
31
+ self.specializations: tuple[str, ...] = specializations
32
+
33
+
34
+ CINDER_OPS: dict[str, int | Family] = {
35
+ "INVOKE_METHOD": CONST | IMPLEMENTED_IN_INTERPRETER,
36
+ "LOAD_FIELD": Family(
37
+ CONST | IMPLEMENTED_IN_INTERPRETER,
38
+ {
39
+ "cache": 2,
40
+ },
41
+ "LOAD_OBJ_FIELD",
42
+ "LOAD_PRIMITIVE_FIELD",
43
+ ),
44
+ "STORE_FIELD": Family(
45
+ CONST | IMPLEMENTED_IN_INTERPRETER,
46
+ {
47
+ "cache": 2,
48
+ },
49
+ "STORE_OBJ_FIELD",
50
+ "STORE_PRIMITIVE_FIELD",
51
+ ),
52
+ "BUILD_CHECKED_LIST": Family(
53
+ CONST | IMPLEMENTED_IN_INTERPRETER,
54
+ {
55
+ "cache": 2,
56
+ },
57
+ "BUILD_CHECKED_LIST_CACHED",
58
+ ),
59
+ "LOAD_TYPE": CONST | IMPLEMENTED_IN_INTERPRETER,
60
+ "CAST": Family(
61
+ CONST | IMPLEMENTED_IN_INTERPRETER,
62
+ {
63
+ "cache": 2,
64
+ },
65
+ "CAST_CACHED",
66
+ ),
67
+ "LOAD_LOCAL": CONST | IMPLEMENTED_IN_INTERPRETER,
68
+ "STORE_LOCAL": Family(
69
+ CONST | IMPLEMENTED_IN_INTERPRETER,
70
+ {
71
+ "cache": 1,
72
+ },
73
+ "STORE_LOCAL_CACHED",
74
+ ),
75
+ "PRIMITIVE_BOX": NONE | IMPLEMENTED_IN_INTERPRETER | ARG,
76
+ "POP_JUMP_IF_ZERO": JREL | ARG | IMPLEMENTED_IN_INTERPRETER,
77
+ "POP_JUMP_IF_NONZERO": JREL | ARG | IMPLEMENTED_IN_INTERPRETER,
78
+ "PRIMITIVE_UNBOX": NONE | IMPLEMENTED_IN_INTERPRETER | ARG,
79
+ "PRIMITIVE_BINARY_OP": NONE | IMPLEMENTED_IN_INTERPRETER | ARG,
80
+ "PRIMITIVE_UNARY_OP": NONE | IMPLEMENTED_IN_INTERPRETER | ARG,
81
+ "PRIMITIVE_COMPARE_OP": NONE | IMPLEMENTED_IN_INTERPRETER | ARG,
82
+ "LOAD_ITERABLE_ARG": NONE | IMPLEMENTED_IN_INTERPRETER | ARG,
83
+ "LOAD_MAPPING_ARG": NONE | IMPLEMENTED_IN_INTERPRETER | ARG,
84
+ "INVOKE_FUNCTION": Family(
85
+ CONST | IMPLEMENTED_IN_INTERPRETER,
86
+ {
87
+ "cache": 4,
88
+ },
89
+ "INVOKE_FUNCTION_CACHED",
90
+ "INVOKE_INDIRECT_CACHED",
91
+ ),
92
+ "JUMP_IF_ZERO_OR_POP": JABS,
93
+ "JUMP_IF_NONZERO_OR_POP": JABS,
94
+ "FAST_LEN": NONE | IMPLEMENTED_IN_INTERPRETER | ARG,
95
+ "CONVERT_PRIMITIVE": NONE | IMPLEMENTED_IN_INTERPRETER | ARG,
96
+ "INVOKE_NATIVE": CONST | IMPLEMENTED_IN_INTERPRETER,
97
+ "LOAD_CLASS": CONST | IMPLEMENTED_IN_INTERPRETER,
98
+ "BUILD_CHECKED_MAP": Family(
99
+ CONST | IMPLEMENTED_IN_INTERPRETER,
100
+ {
101
+ "cache": 2,
102
+ },
103
+ "BUILD_CHECKED_MAP_CACHED",
104
+ ),
105
+ "SEQUENCE_GET": NONE | IMPLEMENTED_IN_INTERPRETER | ARG,
106
+ "SEQUENCE_SET": NONE | IMPLEMENTED_IN_INTERPRETER | ARG,
107
+ "LIST_DEL": NONE | IMPLEMENTED_IN_INTERPRETER,
108
+ "REFINE_TYPE": CONST | IMPLEMENTED_IN_INTERPRETER,
109
+ "PRIMITIVE_LOAD_CONST": CONST | IMPLEMENTED_IN_INTERPRETER,
110
+ "RETURN_PRIMITIVE": NONE | IMPLEMENTED_IN_INTERPRETER | ARG,
111
+ "TP_ALLOC": Family(
112
+ CONST | IMPLEMENTED_IN_INTERPRETER,
113
+ {
114
+ "cache": 2,
115
+ },
116
+ "TP_ALLOC_CACHED",
117
+ ),
118
+ "LOAD_METHOD_STATIC": Family(
119
+ CONST | IMPLEMENTED_IN_INTERPRETER, {"cache": 2}, "LOAD_METHOD_STATIC_CACHED"
120
+ ),
121
+ }