numba-cuda 0.22.0__cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.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 (487) hide show
  1. _numba_cuda_redirector.pth +4 -0
  2. _numba_cuda_redirector.py +89 -0
  3. numba_cuda/VERSION +1 -0
  4. numba_cuda/__init__.py +6 -0
  5. numba_cuda/_version.py +11 -0
  6. numba_cuda/numba/cuda/__init__.py +70 -0
  7. numba_cuda/numba/cuda/_internal/cuda_bf16.py +16394 -0
  8. numba_cuda/numba/cuda/_internal/cuda_fp16.py +8112 -0
  9. numba_cuda/numba/cuda/api.py +580 -0
  10. numba_cuda/numba/cuda/api_util.py +76 -0
  11. numba_cuda/numba/cuda/args.py +72 -0
  12. numba_cuda/numba/cuda/bf16.py +397 -0
  13. numba_cuda/numba/cuda/cache_hints.py +287 -0
  14. numba_cuda/numba/cuda/cext/__init__.py +2 -0
  15. numba_cuda/numba/cuda/cext/_devicearray.cpp +159 -0
  16. numba_cuda/numba/cuda/cext/_devicearray.cpython-313-aarch64-linux-gnu.so +0 -0
  17. numba_cuda/numba/cuda/cext/_devicearray.h +29 -0
  18. numba_cuda/numba/cuda/cext/_dispatcher.cpp +1098 -0
  19. numba_cuda/numba/cuda/cext/_dispatcher.cpython-313-aarch64-linux-gnu.so +0 -0
  20. numba_cuda/numba/cuda/cext/_hashtable.cpp +532 -0
  21. numba_cuda/numba/cuda/cext/_hashtable.h +135 -0
  22. numba_cuda/numba/cuda/cext/_helperlib.c +71 -0
  23. numba_cuda/numba/cuda/cext/_helperlib.cpython-313-aarch64-linux-gnu.so +0 -0
  24. numba_cuda/numba/cuda/cext/_helpermod.c +82 -0
  25. numba_cuda/numba/cuda/cext/_pymodule.h +38 -0
  26. numba_cuda/numba/cuda/cext/_typeconv.cpp +206 -0
  27. numba_cuda/numba/cuda/cext/_typeconv.cpython-313-aarch64-linux-gnu.so +0 -0
  28. numba_cuda/numba/cuda/cext/_typeof.cpp +1159 -0
  29. numba_cuda/numba/cuda/cext/_typeof.h +19 -0
  30. numba_cuda/numba/cuda/cext/capsulethunk.h +111 -0
  31. numba_cuda/numba/cuda/cext/mviewbuf.c +385 -0
  32. numba_cuda/numba/cuda/cext/mviewbuf.cpython-313-aarch64-linux-gnu.so +0 -0
  33. numba_cuda/numba/cuda/cext/typeconv.cpp +212 -0
  34. numba_cuda/numba/cuda/cext/typeconv.hpp +101 -0
  35. numba_cuda/numba/cuda/cg.py +67 -0
  36. numba_cuda/numba/cuda/cgutils.py +1294 -0
  37. numba_cuda/numba/cuda/cloudpickle/__init__.py +21 -0
  38. numba_cuda/numba/cuda/cloudpickle/cloudpickle.py +1598 -0
  39. numba_cuda/numba/cuda/cloudpickle/cloudpickle_fast.py +17 -0
  40. numba_cuda/numba/cuda/codegen.py +541 -0
  41. numba_cuda/numba/cuda/compiler.py +1396 -0
  42. numba_cuda/numba/cuda/core/analysis.py +758 -0
  43. numba_cuda/numba/cuda/core/annotations/__init__.py +0 -0
  44. numba_cuda/numba/cuda/core/annotations/pretty_annotate.py +288 -0
  45. numba_cuda/numba/cuda/core/annotations/type_annotations.py +305 -0
  46. numba_cuda/numba/cuda/core/base.py +1332 -0
  47. numba_cuda/numba/cuda/core/boxing.py +1411 -0
  48. numba_cuda/numba/cuda/core/bytecode.py +728 -0
  49. numba_cuda/numba/cuda/core/byteflow.py +2346 -0
  50. numba_cuda/numba/cuda/core/caching.py +744 -0
  51. numba_cuda/numba/cuda/core/callconv.py +392 -0
  52. numba_cuda/numba/cuda/core/codegen.py +171 -0
  53. numba_cuda/numba/cuda/core/compiler.py +199 -0
  54. numba_cuda/numba/cuda/core/compiler_lock.py +85 -0
  55. numba_cuda/numba/cuda/core/compiler_machinery.py +497 -0
  56. numba_cuda/numba/cuda/core/config.py +650 -0
  57. numba_cuda/numba/cuda/core/consts.py +124 -0
  58. numba_cuda/numba/cuda/core/controlflow.py +989 -0
  59. numba_cuda/numba/cuda/core/entrypoints.py +57 -0
  60. numba_cuda/numba/cuda/core/environment.py +66 -0
  61. numba_cuda/numba/cuda/core/errors.py +917 -0
  62. numba_cuda/numba/cuda/core/event.py +511 -0
  63. numba_cuda/numba/cuda/core/funcdesc.py +330 -0
  64. numba_cuda/numba/cuda/core/generators.py +387 -0
  65. numba_cuda/numba/cuda/core/imputils.py +509 -0
  66. numba_cuda/numba/cuda/core/inline_closurecall.py +1787 -0
  67. numba_cuda/numba/cuda/core/interpreter.py +3617 -0
  68. numba_cuda/numba/cuda/core/ir.py +1812 -0
  69. numba_cuda/numba/cuda/core/ir_utils.py +2638 -0
  70. numba_cuda/numba/cuda/core/optional.py +129 -0
  71. numba_cuda/numba/cuda/core/options.py +262 -0
  72. numba_cuda/numba/cuda/core/postproc.py +249 -0
  73. numba_cuda/numba/cuda/core/pythonapi.py +1859 -0
  74. numba_cuda/numba/cuda/core/registry.py +46 -0
  75. numba_cuda/numba/cuda/core/removerefctpass.py +123 -0
  76. numba_cuda/numba/cuda/core/rewrites/__init__.py +26 -0
  77. numba_cuda/numba/cuda/core/rewrites/ir_print.py +91 -0
  78. numba_cuda/numba/cuda/core/rewrites/registry.py +104 -0
  79. numba_cuda/numba/cuda/core/rewrites/static_binop.py +41 -0
  80. numba_cuda/numba/cuda/core/rewrites/static_getitem.py +189 -0
  81. numba_cuda/numba/cuda/core/rewrites/static_raise.py +100 -0
  82. numba_cuda/numba/cuda/core/sigutils.py +68 -0
  83. numba_cuda/numba/cuda/core/ssa.py +498 -0
  84. numba_cuda/numba/cuda/core/targetconfig.py +330 -0
  85. numba_cuda/numba/cuda/core/tracing.py +231 -0
  86. numba_cuda/numba/cuda/core/transforms.py +956 -0
  87. numba_cuda/numba/cuda/core/typed_passes.py +867 -0
  88. numba_cuda/numba/cuda/core/typeinfer.py +1950 -0
  89. numba_cuda/numba/cuda/core/unsafe/__init__.py +0 -0
  90. numba_cuda/numba/cuda/core/unsafe/bytes.py +67 -0
  91. numba_cuda/numba/cuda/core/unsafe/eh.py +67 -0
  92. numba_cuda/numba/cuda/core/unsafe/refcount.py +98 -0
  93. numba_cuda/numba/cuda/core/untyped_passes.py +1979 -0
  94. numba_cuda/numba/cuda/cpython/builtins.py +1153 -0
  95. numba_cuda/numba/cuda/cpython/charseq.py +1218 -0
  96. numba_cuda/numba/cuda/cpython/cmathimpl.py +560 -0
  97. numba_cuda/numba/cuda/cpython/enumimpl.py +103 -0
  98. numba_cuda/numba/cuda/cpython/iterators.py +167 -0
  99. numba_cuda/numba/cuda/cpython/listobj.py +1326 -0
  100. numba_cuda/numba/cuda/cpython/mathimpl.py +499 -0
  101. numba_cuda/numba/cuda/cpython/numbers.py +1475 -0
  102. numba_cuda/numba/cuda/cpython/rangeobj.py +289 -0
  103. numba_cuda/numba/cuda/cpython/slicing.py +322 -0
  104. numba_cuda/numba/cuda/cpython/tupleobj.py +456 -0
  105. numba_cuda/numba/cuda/cpython/unicode.py +2865 -0
  106. numba_cuda/numba/cuda/cpython/unicode_support.py +1597 -0
  107. numba_cuda/numba/cuda/cpython/unsafe/__init__.py +0 -0
  108. numba_cuda/numba/cuda/cpython/unsafe/numbers.py +64 -0
  109. numba_cuda/numba/cuda/cpython/unsafe/tuple.py +92 -0
  110. numba_cuda/numba/cuda/cuda_paths.py +691 -0
  111. numba_cuda/numba/cuda/cudadecl.py +543 -0
  112. numba_cuda/numba/cuda/cudadrv/__init__.py +14 -0
  113. numba_cuda/numba/cuda/cudadrv/devicearray.py +954 -0
  114. numba_cuda/numba/cuda/cudadrv/devices.py +249 -0
  115. numba_cuda/numba/cuda/cudadrv/driver.py +3238 -0
  116. numba_cuda/numba/cuda/cudadrv/drvapi.py +435 -0
  117. numba_cuda/numba/cuda/cudadrv/dummyarray.py +562 -0
  118. numba_cuda/numba/cuda/cudadrv/enums.py +613 -0
  119. numba_cuda/numba/cuda/cudadrv/error.py +48 -0
  120. numba_cuda/numba/cuda/cudadrv/libs.py +220 -0
  121. numba_cuda/numba/cuda/cudadrv/linkable_code.py +184 -0
  122. numba_cuda/numba/cuda/cudadrv/mappings.py +14 -0
  123. numba_cuda/numba/cuda/cudadrv/ndarray.py +26 -0
  124. numba_cuda/numba/cuda/cudadrv/nvrtc.py +193 -0
  125. numba_cuda/numba/cuda/cudadrv/nvvm.py +756 -0
  126. numba_cuda/numba/cuda/cudadrv/rtapi.py +13 -0
  127. numba_cuda/numba/cuda/cudadrv/runtime.py +34 -0
  128. numba_cuda/numba/cuda/cudaimpl.py +983 -0
  129. numba_cuda/numba/cuda/cudamath.py +149 -0
  130. numba_cuda/numba/cuda/datamodel/__init__.py +7 -0
  131. numba_cuda/numba/cuda/datamodel/cuda_manager.py +66 -0
  132. numba_cuda/numba/cuda/datamodel/cuda_models.py +1446 -0
  133. numba_cuda/numba/cuda/datamodel/cuda_packer.py +224 -0
  134. numba_cuda/numba/cuda/datamodel/cuda_registry.py +22 -0
  135. numba_cuda/numba/cuda/datamodel/cuda_testing.py +153 -0
  136. numba_cuda/numba/cuda/datamodel/manager.py +11 -0
  137. numba_cuda/numba/cuda/datamodel/models.py +9 -0
  138. numba_cuda/numba/cuda/datamodel/packer.py +9 -0
  139. numba_cuda/numba/cuda/datamodel/registry.py +11 -0
  140. numba_cuda/numba/cuda/datamodel/testing.py +11 -0
  141. numba_cuda/numba/cuda/debuginfo.py +997 -0
  142. numba_cuda/numba/cuda/decorators.py +294 -0
  143. numba_cuda/numba/cuda/descriptor.py +35 -0
  144. numba_cuda/numba/cuda/device_init.py +155 -0
  145. numba_cuda/numba/cuda/deviceufunc.py +1021 -0
  146. numba_cuda/numba/cuda/dispatcher.py +2463 -0
  147. numba_cuda/numba/cuda/errors.py +72 -0
  148. numba_cuda/numba/cuda/extending.py +697 -0
  149. numba_cuda/numba/cuda/flags.py +178 -0
  150. numba_cuda/numba/cuda/fp16.py +357 -0
  151. numba_cuda/numba/cuda/include/12/cuda_bf16.h +5118 -0
  152. numba_cuda/numba/cuda/include/12/cuda_bf16.hpp +3865 -0
  153. numba_cuda/numba/cuda/include/12/cuda_fp16.h +5363 -0
  154. numba_cuda/numba/cuda/include/12/cuda_fp16.hpp +3483 -0
  155. numba_cuda/numba/cuda/include/13/cuda_bf16.h +5118 -0
  156. numba_cuda/numba/cuda/include/13/cuda_bf16.hpp +3865 -0
  157. numba_cuda/numba/cuda/include/13/cuda_fp16.h +5363 -0
  158. numba_cuda/numba/cuda/include/13/cuda_fp16.hpp +3483 -0
  159. numba_cuda/numba/cuda/initialize.py +24 -0
  160. numba_cuda/numba/cuda/intrinsics.py +531 -0
  161. numba_cuda/numba/cuda/itanium_mangler.py +214 -0
  162. numba_cuda/numba/cuda/kernels/__init__.py +2 -0
  163. numba_cuda/numba/cuda/kernels/reduction.py +265 -0
  164. numba_cuda/numba/cuda/kernels/transpose.py +65 -0
  165. numba_cuda/numba/cuda/libdevice.py +3386 -0
  166. numba_cuda/numba/cuda/libdevicedecl.py +20 -0
  167. numba_cuda/numba/cuda/libdevicefuncs.py +1060 -0
  168. numba_cuda/numba/cuda/libdeviceimpl.py +88 -0
  169. numba_cuda/numba/cuda/locks.py +19 -0
  170. numba_cuda/numba/cuda/lowering.py +1980 -0
  171. numba_cuda/numba/cuda/mathimpl.py +374 -0
  172. numba_cuda/numba/cuda/memory_management/__init__.py +4 -0
  173. numba_cuda/numba/cuda/memory_management/memsys.cu +99 -0
  174. numba_cuda/numba/cuda/memory_management/memsys.cuh +22 -0
  175. numba_cuda/numba/cuda/memory_management/nrt.cu +212 -0
  176. numba_cuda/numba/cuda/memory_management/nrt.cuh +48 -0
  177. numba_cuda/numba/cuda/memory_management/nrt.py +390 -0
  178. numba_cuda/numba/cuda/memory_management/nrt_context.py +438 -0
  179. numba_cuda/numba/cuda/misc/appdirs.py +594 -0
  180. numba_cuda/numba/cuda/misc/cffiimpl.py +24 -0
  181. numba_cuda/numba/cuda/misc/coverage_support.py +43 -0
  182. numba_cuda/numba/cuda/misc/dump_style.py +41 -0
  183. numba_cuda/numba/cuda/misc/findlib.py +75 -0
  184. numba_cuda/numba/cuda/misc/firstlinefinder.py +96 -0
  185. numba_cuda/numba/cuda/misc/gdb_hook.py +240 -0
  186. numba_cuda/numba/cuda/misc/literal.py +28 -0
  187. numba_cuda/numba/cuda/misc/llvm_pass_timings.py +412 -0
  188. numba_cuda/numba/cuda/misc/special.py +94 -0
  189. numba_cuda/numba/cuda/models.py +56 -0
  190. numba_cuda/numba/cuda/np/arraymath.py +5130 -0
  191. numba_cuda/numba/cuda/np/arrayobj.py +7635 -0
  192. numba_cuda/numba/cuda/np/extensions.py +11 -0
  193. numba_cuda/numba/cuda/np/linalg.py +3087 -0
  194. numba_cuda/numba/cuda/np/math/__init__.py +0 -0
  195. numba_cuda/numba/cuda/np/math/cmathimpl.py +558 -0
  196. numba_cuda/numba/cuda/np/math/mathimpl.py +487 -0
  197. numba_cuda/numba/cuda/np/math/numbers.py +1461 -0
  198. numba_cuda/numba/cuda/np/npdatetime.py +969 -0
  199. numba_cuda/numba/cuda/np/npdatetime_helpers.py +217 -0
  200. numba_cuda/numba/cuda/np/npyfuncs.py +1808 -0
  201. numba_cuda/numba/cuda/np/npyimpl.py +1027 -0
  202. numba_cuda/numba/cuda/np/numpy_support.py +798 -0
  203. numba_cuda/numba/cuda/np/polynomial/__init__.py +4 -0
  204. numba_cuda/numba/cuda/np/polynomial/polynomial_core.py +242 -0
  205. numba_cuda/numba/cuda/np/polynomial/polynomial_functions.py +380 -0
  206. numba_cuda/numba/cuda/np/ufunc/__init__.py +4 -0
  207. numba_cuda/numba/cuda/np/ufunc/decorators.py +203 -0
  208. numba_cuda/numba/cuda/np/ufunc/sigparse.py +68 -0
  209. numba_cuda/numba/cuda/np/ufunc/ufuncbuilder.py +65 -0
  210. numba_cuda/numba/cuda/np/ufunc_db.py +1282 -0
  211. numba_cuda/numba/cuda/np/unsafe/__init__.py +0 -0
  212. numba_cuda/numba/cuda/np/unsafe/ndarray.py +84 -0
  213. numba_cuda/numba/cuda/nvvmutils.py +254 -0
  214. numba_cuda/numba/cuda/printimpl.py +126 -0
  215. numba_cuda/numba/cuda/random.py +308 -0
  216. numba_cuda/numba/cuda/reshape_funcs.cu +156 -0
  217. numba_cuda/numba/cuda/serialize.py +267 -0
  218. numba_cuda/numba/cuda/simulator/__init__.py +63 -0
  219. numba_cuda/numba/cuda/simulator/_internal/__init__.py +4 -0
  220. numba_cuda/numba/cuda/simulator/_internal/cuda_bf16.py +2 -0
  221. numba_cuda/numba/cuda/simulator/api.py +179 -0
  222. numba_cuda/numba/cuda/simulator/bf16.py +4 -0
  223. numba_cuda/numba/cuda/simulator/compiler.py +38 -0
  224. numba_cuda/numba/cuda/simulator/cudadrv/__init__.py +11 -0
  225. numba_cuda/numba/cuda/simulator/cudadrv/devicearray.py +462 -0
  226. numba_cuda/numba/cuda/simulator/cudadrv/devices.py +122 -0
  227. numba_cuda/numba/cuda/simulator/cudadrv/driver.py +66 -0
  228. numba_cuda/numba/cuda/simulator/cudadrv/drvapi.py +7 -0
  229. numba_cuda/numba/cuda/simulator/cudadrv/dummyarray.py +7 -0
  230. numba_cuda/numba/cuda/simulator/cudadrv/error.py +10 -0
  231. numba_cuda/numba/cuda/simulator/cudadrv/libs.py +10 -0
  232. numba_cuda/numba/cuda/simulator/cudadrv/linkable_code.py +61 -0
  233. numba_cuda/numba/cuda/simulator/cudadrv/nvrtc.py +11 -0
  234. numba_cuda/numba/cuda/simulator/cudadrv/nvvm.py +32 -0
  235. numba_cuda/numba/cuda/simulator/cudadrv/runtime.py +22 -0
  236. numba_cuda/numba/cuda/simulator/dispatcher.py +11 -0
  237. numba_cuda/numba/cuda/simulator/kernel.py +320 -0
  238. numba_cuda/numba/cuda/simulator/kernelapi.py +509 -0
  239. numba_cuda/numba/cuda/simulator/memory_management/__init__.py +4 -0
  240. numba_cuda/numba/cuda/simulator/memory_management/nrt.py +21 -0
  241. numba_cuda/numba/cuda/simulator/reduction.py +19 -0
  242. numba_cuda/numba/cuda/simulator/tests/support.py +4 -0
  243. numba_cuda/numba/cuda/simulator/vector_types.py +65 -0
  244. numba_cuda/numba/cuda/simulator_init.py +18 -0
  245. numba_cuda/numba/cuda/stubs.py +624 -0
  246. numba_cuda/numba/cuda/target.py +505 -0
  247. numba_cuda/numba/cuda/testing.py +347 -0
  248. numba_cuda/numba/cuda/tests/__init__.py +62 -0
  249. numba_cuda/numba/cuda/tests/benchmarks/__init__.py +0 -0
  250. numba_cuda/numba/cuda/tests/benchmarks/test_kernel_launch.py +119 -0
  251. numba_cuda/numba/cuda/tests/cloudpickle_main_class.py +9 -0
  252. numba_cuda/numba/cuda/tests/core/serialize_usecases.py +113 -0
  253. numba_cuda/numba/cuda/tests/core/test_itanium_mangler.py +83 -0
  254. numba_cuda/numba/cuda/tests/core/test_serialize.py +371 -0
  255. numba_cuda/numba/cuda/tests/cudadrv/__init__.py +9 -0
  256. numba_cuda/numba/cuda/tests/cudadrv/test_array_attr.py +147 -0
  257. numba_cuda/numba/cuda/tests/cudadrv/test_context_stack.py +161 -0
  258. numba_cuda/numba/cuda/tests/cudadrv/test_cuda_array_slicing.py +397 -0
  259. numba_cuda/numba/cuda/tests/cudadrv/test_cuda_auto_context.py +24 -0
  260. numba_cuda/numba/cuda/tests/cudadrv/test_cuda_devicerecord.py +180 -0
  261. numba_cuda/numba/cuda/tests/cudadrv/test_cuda_driver.py +313 -0
  262. numba_cuda/numba/cuda/tests/cudadrv/test_cuda_memory.py +191 -0
  263. numba_cuda/numba/cuda/tests/cudadrv/test_cuda_ndarray.py +621 -0
  264. numba_cuda/numba/cuda/tests/cudadrv/test_deallocations.py +247 -0
  265. numba_cuda/numba/cuda/tests/cudadrv/test_detect.py +100 -0
  266. numba_cuda/numba/cuda/tests/cudadrv/test_emm_plugins.py +200 -0
  267. numba_cuda/numba/cuda/tests/cudadrv/test_events.py +53 -0
  268. numba_cuda/numba/cuda/tests/cudadrv/test_host_alloc.py +72 -0
  269. numba_cuda/numba/cuda/tests/cudadrv/test_init.py +138 -0
  270. numba_cuda/numba/cuda/tests/cudadrv/test_inline_ptx.py +43 -0
  271. numba_cuda/numba/cuda/tests/cudadrv/test_is_fp16.py +15 -0
  272. numba_cuda/numba/cuda/tests/cudadrv/test_linkable_code.py +58 -0
  273. numba_cuda/numba/cuda/tests/cudadrv/test_linker.py +348 -0
  274. numba_cuda/numba/cuda/tests/cudadrv/test_managed_alloc.py +128 -0
  275. numba_cuda/numba/cuda/tests/cudadrv/test_module_callbacks.py +301 -0
  276. numba_cuda/numba/cuda/tests/cudadrv/test_nvjitlink.py +174 -0
  277. numba_cuda/numba/cuda/tests/cudadrv/test_nvrtc.py +28 -0
  278. numba_cuda/numba/cuda/tests/cudadrv/test_nvvm_driver.py +185 -0
  279. numba_cuda/numba/cuda/tests/cudadrv/test_pinned.py +39 -0
  280. numba_cuda/numba/cuda/tests/cudadrv/test_profiler.py +23 -0
  281. numba_cuda/numba/cuda/tests/cudadrv/test_reset_device.py +38 -0
  282. numba_cuda/numba/cuda/tests/cudadrv/test_runtime.py +48 -0
  283. numba_cuda/numba/cuda/tests/cudadrv/test_select_device.py +44 -0
  284. numba_cuda/numba/cuda/tests/cudadrv/test_streams.py +127 -0
  285. numba_cuda/numba/cuda/tests/cudapy/__init__.py +9 -0
  286. numba_cuda/numba/cuda/tests/cudapy/cache_usecases.py +231 -0
  287. numba_cuda/numba/cuda/tests/cudapy/cache_with_cpu_usecases.py +50 -0
  288. numba_cuda/numba/cuda/tests/cudapy/cg_cache_usecases.py +36 -0
  289. numba_cuda/numba/cuda/tests/cudapy/complex_usecases.py +116 -0
  290. numba_cuda/numba/cuda/tests/cudapy/enum_usecases.py +59 -0
  291. numba_cuda/numba/cuda/tests/cudapy/extensions_usecases.py +62 -0
  292. numba_cuda/numba/cuda/tests/cudapy/jitlink.ptx +28 -0
  293. numba_cuda/numba/cuda/tests/cudapy/overload_usecases.py +33 -0
  294. numba_cuda/numba/cuda/tests/cudapy/recursion_usecases.py +104 -0
  295. numba_cuda/numba/cuda/tests/cudapy/test_alignment.py +47 -0
  296. numba_cuda/numba/cuda/tests/cudapy/test_analysis.py +1122 -0
  297. numba_cuda/numba/cuda/tests/cudapy/test_array.py +344 -0
  298. numba_cuda/numba/cuda/tests/cudapy/test_array_alignment.py +268 -0
  299. numba_cuda/numba/cuda/tests/cudapy/test_array_args.py +203 -0
  300. numba_cuda/numba/cuda/tests/cudapy/test_array_methods.py +63 -0
  301. numba_cuda/numba/cuda/tests/cudapy/test_array_reductions.py +360 -0
  302. numba_cuda/numba/cuda/tests/cudapy/test_atomics.py +1815 -0
  303. numba_cuda/numba/cuda/tests/cudapy/test_bfloat16.py +599 -0
  304. numba_cuda/numba/cuda/tests/cudapy/test_bfloat16_bindings.py +377 -0
  305. numba_cuda/numba/cuda/tests/cudapy/test_blackscholes.py +160 -0
  306. numba_cuda/numba/cuda/tests/cudapy/test_boolean.py +27 -0
  307. numba_cuda/numba/cuda/tests/cudapy/test_byteflow.py +98 -0
  308. numba_cuda/numba/cuda/tests/cudapy/test_cache_hints.py +210 -0
  309. numba_cuda/numba/cuda/tests/cudapy/test_caching.py +683 -0
  310. numba_cuda/numba/cuda/tests/cudapy/test_casting.py +265 -0
  311. numba_cuda/numba/cuda/tests/cudapy/test_cffi.py +42 -0
  312. numba_cuda/numba/cuda/tests/cudapy/test_compiler.py +718 -0
  313. numba_cuda/numba/cuda/tests/cudapy/test_complex.py +370 -0
  314. numba_cuda/numba/cuda/tests/cudapy/test_complex_kernel.py +23 -0
  315. numba_cuda/numba/cuda/tests/cudapy/test_const_string.py +142 -0
  316. numba_cuda/numba/cuda/tests/cudapy/test_constmem.py +178 -0
  317. numba_cuda/numba/cuda/tests/cudapy/test_cooperative_groups.py +193 -0
  318. numba_cuda/numba/cuda/tests/cudapy/test_copy_propagate.py +131 -0
  319. numba_cuda/numba/cuda/tests/cudapy/test_cuda_array_interface.py +438 -0
  320. numba_cuda/numba/cuda/tests/cudapy/test_cuda_jit_no_types.py +94 -0
  321. numba_cuda/numba/cuda/tests/cudapy/test_datetime.py +101 -0
  322. numba_cuda/numba/cuda/tests/cudapy/test_debug.py +105 -0
  323. numba_cuda/numba/cuda/tests/cudapy/test_debuginfo.py +978 -0
  324. numba_cuda/numba/cuda/tests/cudapy/test_debuginfo_types.py +476 -0
  325. numba_cuda/numba/cuda/tests/cudapy/test_device_func.py +500 -0
  326. numba_cuda/numba/cuda/tests/cudapy/test_dispatcher.py +820 -0
  327. numba_cuda/numba/cuda/tests/cudapy/test_enums.py +152 -0
  328. numba_cuda/numba/cuda/tests/cudapy/test_errors.py +111 -0
  329. numba_cuda/numba/cuda/tests/cudapy/test_exception.py +170 -0
  330. numba_cuda/numba/cuda/tests/cudapy/test_extending.py +1088 -0
  331. numba_cuda/numba/cuda/tests/cudapy/test_extending_types.py +71 -0
  332. numba_cuda/numba/cuda/tests/cudapy/test_fastmath.py +265 -0
  333. numba_cuda/numba/cuda/tests/cudapy/test_flow_control.py +1433 -0
  334. numba_cuda/numba/cuda/tests/cudapy/test_forall.py +57 -0
  335. numba_cuda/numba/cuda/tests/cudapy/test_freevar.py +34 -0
  336. numba_cuda/numba/cuda/tests/cudapy/test_frexp_ldexp.py +69 -0
  337. numba_cuda/numba/cuda/tests/cudapy/test_globals.py +62 -0
  338. numba_cuda/numba/cuda/tests/cudapy/test_gufunc.py +474 -0
  339. numba_cuda/numba/cuda/tests/cudapy/test_gufunc_scalar.py +167 -0
  340. numba_cuda/numba/cuda/tests/cudapy/test_gufunc_scheduling.py +92 -0
  341. numba_cuda/numba/cuda/tests/cudapy/test_idiv.py +39 -0
  342. numba_cuda/numba/cuda/tests/cudapy/test_inline.py +170 -0
  343. numba_cuda/numba/cuda/tests/cudapy/test_inspect.py +255 -0
  344. numba_cuda/numba/cuda/tests/cudapy/test_intrinsics.py +1219 -0
  345. numba_cuda/numba/cuda/tests/cudapy/test_ipc.py +263 -0
  346. numba_cuda/numba/cuda/tests/cudapy/test_ir.py +598 -0
  347. numba_cuda/numba/cuda/tests/cudapy/test_ir_utils.py +276 -0
  348. numba_cuda/numba/cuda/tests/cudapy/test_iterators.py +101 -0
  349. numba_cuda/numba/cuda/tests/cudapy/test_lang.py +68 -0
  350. numba_cuda/numba/cuda/tests/cudapy/test_laplace.py +123 -0
  351. numba_cuda/numba/cuda/tests/cudapy/test_libdevice.py +194 -0
  352. numba_cuda/numba/cuda/tests/cudapy/test_lineinfo.py +220 -0
  353. numba_cuda/numba/cuda/tests/cudapy/test_localmem.py +173 -0
  354. numba_cuda/numba/cuda/tests/cudapy/test_make_function_to_jit_function.py +364 -0
  355. numba_cuda/numba/cuda/tests/cudapy/test_mandel.py +47 -0
  356. numba_cuda/numba/cuda/tests/cudapy/test_math.py +842 -0
  357. numba_cuda/numba/cuda/tests/cudapy/test_matmul.py +76 -0
  358. numba_cuda/numba/cuda/tests/cudapy/test_minmax.py +78 -0
  359. numba_cuda/numba/cuda/tests/cudapy/test_montecarlo.py +25 -0
  360. numba_cuda/numba/cuda/tests/cudapy/test_multigpu.py +145 -0
  361. numba_cuda/numba/cuda/tests/cudapy/test_multiprocessing.py +39 -0
  362. numba_cuda/numba/cuda/tests/cudapy/test_multithreads.py +82 -0
  363. numba_cuda/numba/cuda/tests/cudapy/test_nondet.py +53 -0
  364. numba_cuda/numba/cuda/tests/cudapy/test_operator.py +504 -0
  365. numba_cuda/numba/cuda/tests/cudapy/test_optimization.py +93 -0
  366. numba_cuda/numba/cuda/tests/cudapy/test_overload.py +402 -0
  367. numba_cuda/numba/cuda/tests/cudapy/test_powi.py +128 -0
  368. numba_cuda/numba/cuda/tests/cudapy/test_print.py +193 -0
  369. numba_cuda/numba/cuda/tests/cudapy/test_py2_div_issue.py +37 -0
  370. numba_cuda/numba/cuda/tests/cudapy/test_random.py +117 -0
  371. numba_cuda/numba/cuda/tests/cudapy/test_record_dtype.py +614 -0
  372. numba_cuda/numba/cuda/tests/cudapy/test_recursion.py +130 -0
  373. numba_cuda/numba/cuda/tests/cudapy/test_reduction.py +94 -0
  374. numba_cuda/numba/cuda/tests/cudapy/test_retrieve_autoconverted_arrays.py +83 -0
  375. numba_cuda/numba/cuda/tests/cudapy/test_serialize.py +86 -0
  376. numba_cuda/numba/cuda/tests/cudapy/test_slicing.py +40 -0
  377. numba_cuda/numba/cuda/tests/cudapy/test_sm.py +457 -0
  378. numba_cuda/numba/cuda/tests/cudapy/test_sm_creation.py +233 -0
  379. numba_cuda/numba/cuda/tests/cudapy/test_ssa.py +454 -0
  380. numba_cuda/numba/cuda/tests/cudapy/test_stream_api.py +56 -0
  381. numba_cuda/numba/cuda/tests/cudapy/test_sync.py +277 -0
  382. numba_cuda/numba/cuda/tests/cudapy/test_tracing.py +200 -0
  383. numba_cuda/numba/cuda/tests/cudapy/test_transpose.py +90 -0
  384. numba_cuda/numba/cuda/tests/cudapy/test_typeconv.py +333 -0
  385. numba_cuda/numba/cuda/tests/cudapy/test_typeinfer.py +538 -0
  386. numba_cuda/numba/cuda/tests/cudapy/test_ufuncs.py +585 -0
  387. numba_cuda/numba/cuda/tests/cudapy/test_userexc.py +42 -0
  388. numba_cuda/numba/cuda/tests/cudapy/test_vector_type.py +485 -0
  389. numba_cuda/numba/cuda/tests/cudapy/test_vectorize.py +312 -0
  390. numba_cuda/numba/cuda/tests/cudapy/test_vectorize_complex.py +23 -0
  391. numba_cuda/numba/cuda/tests/cudapy/test_vectorize_decor.py +183 -0
  392. numba_cuda/numba/cuda/tests/cudapy/test_vectorize_device.py +40 -0
  393. numba_cuda/numba/cuda/tests/cudapy/test_vectorize_scalar_arg.py +40 -0
  394. numba_cuda/numba/cuda/tests/cudapy/test_warning.py +206 -0
  395. numba_cuda/numba/cuda/tests/cudapy/test_warp_ops.py +446 -0
  396. numba_cuda/numba/cuda/tests/cudasim/__init__.py +9 -0
  397. numba_cuda/numba/cuda/tests/cudasim/support.py +9 -0
  398. numba_cuda/numba/cuda/tests/cudasim/test_cudasim_issues.py +111 -0
  399. numba_cuda/numba/cuda/tests/data/__init__.py +2 -0
  400. numba_cuda/numba/cuda/tests/data/cta_barrier.cu +28 -0
  401. numba_cuda/numba/cuda/tests/data/cuda_include.cu +10 -0
  402. numba_cuda/numba/cuda/tests/data/error.cu +12 -0
  403. numba_cuda/numba/cuda/tests/data/include/add.cuh +8 -0
  404. numba_cuda/numba/cuda/tests/data/jitlink.cu +28 -0
  405. numba_cuda/numba/cuda/tests/data/jitlink.ptx +49 -0
  406. numba_cuda/numba/cuda/tests/data/warn.cu +12 -0
  407. numba_cuda/numba/cuda/tests/doc_examples/__init__.py +9 -0
  408. numba_cuda/numba/cuda/tests/doc_examples/ffi/__init__.py +2 -0
  409. numba_cuda/numba/cuda/tests/doc_examples/ffi/functions.cu +54 -0
  410. numba_cuda/numba/cuda/tests/doc_examples/ffi/include/mul.cuh +8 -0
  411. numba_cuda/numba/cuda/tests/doc_examples/ffi/saxpy.cu +14 -0
  412. numba_cuda/numba/cuda/tests/doc_examples/test_cg.py +86 -0
  413. numba_cuda/numba/cuda/tests/doc_examples/test_cpointer.py +68 -0
  414. numba_cuda/numba/cuda/tests/doc_examples/test_cpu_gpu_compat.py +81 -0
  415. numba_cuda/numba/cuda/tests/doc_examples/test_ffi.py +141 -0
  416. numba_cuda/numba/cuda/tests/doc_examples/test_laplace.py +160 -0
  417. numba_cuda/numba/cuda/tests/doc_examples/test_matmul.py +180 -0
  418. numba_cuda/numba/cuda/tests/doc_examples/test_montecarlo.py +119 -0
  419. numba_cuda/numba/cuda/tests/doc_examples/test_random.py +66 -0
  420. numba_cuda/numba/cuda/tests/doc_examples/test_reduction.py +80 -0
  421. numba_cuda/numba/cuda/tests/doc_examples/test_sessionize.py +206 -0
  422. numba_cuda/numba/cuda/tests/doc_examples/test_ufunc.py +53 -0
  423. numba_cuda/numba/cuda/tests/doc_examples/test_vecadd.py +76 -0
  424. numba_cuda/numba/cuda/tests/nocuda/__init__.py +9 -0
  425. numba_cuda/numba/cuda/tests/nocuda/test_dummyarray.py +452 -0
  426. numba_cuda/numba/cuda/tests/nocuda/test_function_resolution.py +48 -0
  427. numba_cuda/numba/cuda/tests/nocuda/test_import.py +63 -0
  428. numba_cuda/numba/cuda/tests/nocuda/test_library_lookup.py +252 -0
  429. numba_cuda/numba/cuda/tests/nocuda/test_nvvm.py +59 -0
  430. numba_cuda/numba/cuda/tests/nrt/__init__.py +9 -0
  431. numba_cuda/numba/cuda/tests/nrt/test_nrt.py +387 -0
  432. numba_cuda/numba/cuda/tests/nrt/test_nrt_refct.py +124 -0
  433. numba_cuda/numba/cuda/tests/support.py +900 -0
  434. numba_cuda/numba/cuda/typeconv/__init__.py +4 -0
  435. numba_cuda/numba/cuda/typeconv/castgraph.py +137 -0
  436. numba_cuda/numba/cuda/typeconv/rules.py +63 -0
  437. numba_cuda/numba/cuda/typeconv/typeconv.py +121 -0
  438. numba_cuda/numba/cuda/types/__init__.py +233 -0
  439. numba_cuda/numba/cuda/types/__init__.pyi +167 -0
  440. numba_cuda/numba/cuda/types/abstract.py +9 -0
  441. numba_cuda/numba/cuda/types/common.py +9 -0
  442. numba_cuda/numba/cuda/types/containers.py +9 -0
  443. numba_cuda/numba/cuda/types/cuda_abstract.py +533 -0
  444. numba_cuda/numba/cuda/types/cuda_common.py +110 -0
  445. numba_cuda/numba/cuda/types/cuda_containers.py +971 -0
  446. numba_cuda/numba/cuda/types/cuda_function_type.py +230 -0
  447. numba_cuda/numba/cuda/types/cuda_functions.py +798 -0
  448. numba_cuda/numba/cuda/types/cuda_iterators.py +120 -0
  449. numba_cuda/numba/cuda/types/cuda_misc.py +569 -0
  450. numba_cuda/numba/cuda/types/cuda_npytypes.py +690 -0
  451. numba_cuda/numba/cuda/types/cuda_scalars.py +280 -0
  452. numba_cuda/numba/cuda/types/ext_types.py +101 -0
  453. numba_cuda/numba/cuda/types/function_type.py +11 -0
  454. numba_cuda/numba/cuda/types/functions.py +9 -0
  455. numba_cuda/numba/cuda/types/iterators.py +9 -0
  456. numba_cuda/numba/cuda/types/misc.py +9 -0
  457. numba_cuda/numba/cuda/types/npytypes.py +9 -0
  458. numba_cuda/numba/cuda/types/scalars.py +9 -0
  459. numba_cuda/numba/cuda/typing/__init__.py +19 -0
  460. numba_cuda/numba/cuda/typing/arraydecl.py +939 -0
  461. numba_cuda/numba/cuda/typing/asnumbatype.py +130 -0
  462. numba_cuda/numba/cuda/typing/bufproto.py +70 -0
  463. numba_cuda/numba/cuda/typing/builtins.py +1209 -0
  464. numba_cuda/numba/cuda/typing/cffi_utils.py +219 -0
  465. numba_cuda/numba/cuda/typing/cmathdecl.py +47 -0
  466. numba_cuda/numba/cuda/typing/collections.py +138 -0
  467. numba_cuda/numba/cuda/typing/context.py +782 -0
  468. numba_cuda/numba/cuda/typing/ctypes_utils.py +125 -0
  469. numba_cuda/numba/cuda/typing/dictdecl.py +63 -0
  470. numba_cuda/numba/cuda/typing/enumdecl.py +74 -0
  471. numba_cuda/numba/cuda/typing/listdecl.py +147 -0
  472. numba_cuda/numba/cuda/typing/mathdecl.py +158 -0
  473. numba_cuda/numba/cuda/typing/npdatetime.py +322 -0
  474. numba_cuda/numba/cuda/typing/npydecl.py +749 -0
  475. numba_cuda/numba/cuda/typing/setdecl.py +115 -0
  476. numba_cuda/numba/cuda/typing/templates.py +1446 -0
  477. numba_cuda/numba/cuda/typing/typeof.py +301 -0
  478. numba_cuda/numba/cuda/ufuncs.py +746 -0
  479. numba_cuda/numba/cuda/utils.py +724 -0
  480. numba_cuda/numba/cuda/vector_types.py +214 -0
  481. numba_cuda/numba/cuda/vectorizers.py +260 -0
  482. numba_cuda-0.22.0.dist-info/METADATA +109 -0
  483. numba_cuda-0.22.0.dist-info/RECORD +487 -0
  484. numba_cuda-0.22.0.dist-info/WHEEL +6 -0
  485. numba_cuda-0.22.0.dist-info/licenses/LICENSE +26 -0
  486. numba_cuda-0.22.0.dist-info/licenses/LICENSE.numba +24 -0
  487. numba_cuda-0.22.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,2346 @@
1
+ # SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2
+ # SPDX-License-Identifier: BSD-2-Clause
3
+
4
+ """
5
+ Implement python 3.8+ bytecode analysis
6
+ """
7
+
8
+ import dis
9
+ import logging
10
+ from collections import namedtuple, defaultdict, deque
11
+ from functools import total_ordering
12
+
13
+ from numba.cuda.utils import (
14
+ UniqueDict,
15
+ PYVERSION,
16
+ ALL_BINOPS_TO_OPERATORS,
17
+ _lazy_pformat,
18
+ )
19
+ from numba.cuda.core.controlflow import NEW_BLOCKERS, CFGraph
20
+ from numba.cuda.core.ir import Loc
21
+ from numba.cuda.errors import UnsupportedBytecodeError
22
+
23
+
24
+ _logger = logging.getLogger(__name__)
25
+
26
+ _EXCEPT_STACK_OFFSET = 6
27
+ _FINALLY_POP = _EXCEPT_STACK_OFFSET
28
+ _NO_RAISE_OPS = frozenset(
29
+ {
30
+ "LOAD_CONST",
31
+ "NOP",
32
+ "LOAD_DEREF",
33
+ "PRECALL",
34
+ }
35
+ )
36
+
37
+ if PYVERSION in ((3, 12), (3, 13)):
38
+ from enum import Enum
39
+
40
+ # Operands for CALL_INTRINSIC_1
41
+ class CALL_INTRINSIC_1_Operand(Enum):
42
+ INTRINSIC_STOPITERATION_ERROR = 3
43
+ UNARY_POSITIVE = 5
44
+ INTRINSIC_LIST_TO_TUPLE = 6
45
+
46
+ ci1op = CALL_INTRINSIC_1_Operand
47
+ elif PYVERSION in ((3, 9), (3, 10), (3, 11)):
48
+ pass
49
+ else:
50
+ raise NotImplementedError(PYVERSION)
51
+
52
+
53
+ @total_ordering
54
+ class BlockKind(object):
55
+ """Kinds of block to make related code safer than just `str`."""
56
+
57
+ _members = frozenset(
58
+ {
59
+ "LOOP",
60
+ "TRY",
61
+ "EXCEPT",
62
+ "FINALLY",
63
+ "WITH",
64
+ "WITH_FINALLY",
65
+ }
66
+ )
67
+
68
+ def __init__(self, value):
69
+ assert value in self._members
70
+ self._value = value
71
+
72
+ def __hash__(self):
73
+ return hash((type(self), self._value))
74
+
75
+ def __lt__(self, other):
76
+ if isinstance(other, BlockKind):
77
+ return self._value < other._value
78
+ else:
79
+ raise TypeError("cannot compare to {!r}".format(type(other)))
80
+
81
+ def __eq__(self, other):
82
+ if isinstance(other, BlockKind):
83
+ return self._value == other._value
84
+ else:
85
+ raise TypeError("cannot compare to {!r}".format(type(other)))
86
+
87
+ def __repr__(self):
88
+ return "BlockKind({})".format(self._value)
89
+
90
+
91
+ class Flow(object):
92
+ """Data+Control Flow analysis.
93
+
94
+ Simulate execution to recover dataflow and controlflow information.
95
+ """
96
+
97
+ def __init__(self, bytecode):
98
+ _logger.debug(
99
+ "bytecode dump:\n%s",
100
+ _lazy_pformat(bytecode, lazy_func=lambda x: x.dump()),
101
+ )
102
+ self._bytecode = bytecode
103
+ self.block_infos = UniqueDict()
104
+
105
+ def run(self):
106
+ """Run a trace over the bytecode over all reachable path.
107
+
108
+ The trace starts at bytecode offset 0 and gathers stack and control-
109
+ flow information by partially interpreting each bytecode.
110
+ Each ``State`` instance in the trace corresponds to a basic-block.
111
+ The State instances forks when a jump instruction is encountered.
112
+ A newly forked state is then added to the list of pending states.
113
+ The trace ends when there are no more pending states.
114
+ """
115
+ firststate = State(
116
+ bytecode=self._bytecode, pc=0, nstack=0, blockstack=()
117
+ )
118
+ runner = TraceRunner(debug_filename=self._bytecode.func_id.filename)
119
+ runner.pending.append(firststate)
120
+
121
+ # Enforce unique-ness on initial PC to avoid re-entering the PC with
122
+ # a different stack-depth. We don't know if such a case is ever
123
+ # possible, but no such case has been encountered in our tests.
124
+ first_encounter = UniqueDict()
125
+ # Loop over each pending state at a initial PC.
126
+ # Each state is tracing a basic block
127
+ while runner.pending:
128
+ _logger.debug("pending: %s", runner.pending)
129
+ state = runner.pending.popleft()
130
+ if state not in runner.finished:
131
+ _logger.debug("stack: %s", state._stack)
132
+ _logger.debug("state.pc_initial: %s", state)
133
+ first_encounter[state.pc_initial] = state
134
+ # Loop over the state until it is terminated.
135
+ while True:
136
+ runner.dispatch(state)
137
+ # Terminated?
138
+ if state.has_terminated():
139
+ break
140
+ else:
141
+ if self._run_handle_exception(runner, state):
142
+ break
143
+
144
+ if self._is_implicit_new_block(state):
145
+ # check if this is a with...as, abort if so
146
+ self._guard_with_as(state)
147
+ # else split
148
+ state.split_new_block()
149
+ break
150
+ _logger.debug("end state. edges=%s", state.outgoing_edges)
151
+ runner.finished.add(state)
152
+ out_states = state.get_outgoing_states()
153
+ runner.pending.extend(out_states)
154
+
155
+ # Complete controlflow
156
+ self._build_cfg(runner.finished)
157
+ # Prune redundant PHI-nodes
158
+ self._prune_phis(runner)
159
+ # Post process
160
+ for state in sorted(runner.finished, key=lambda x: x.pc_initial):
161
+ self.block_infos[state.pc_initial] = si = adapt_state_infos(state)
162
+ _logger.debug("block_infos %s:\n%s", state, si)
163
+
164
+ if PYVERSION in ((3, 11), (3, 12), (3, 13)):
165
+
166
+ def _run_handle_exception(self, runner, state):
167
+ if not state.in_with() and (
168
+ state.has_active_try()
169
+ and state.get_inst().opname not in _NO_RAISE_OPS
170
+ ):
171
+ # Is in a *try* block
172
+ state.fork(pc=state.get_inst().next)
173
+ runner._adjust_except_stack(state)
174
+ return True
175
+ else:
176
+ state.advance_pc()
177
+
178
+ # Must the new PC be a new block?
179
+ if not state.in_with() and state.is_in_exception():
180
+ _logger.debug(
181
+ "3.11 exception %s PC=%s",
182
+ state.get_exception(),
183
+ state._pc,
184
+ )
185
+ eh = state.get_exception()
186
+ eh_top = state.get_top_block("TRY")
187
+ if eh_top and eh_top["end"] == eh.target:
188
+ # Same exception
189
+ eh_block = None
190
+ else:
191
+ eh_block = state.make_block("TRY", end=eh.target)
192
+ eh_block["end_offset"] = eh.end
193
+ eh_block["stack_depth"] = eh.depth
194
+ eh_block["push_lasti"] = eh.lasti
195
+ state.fork(pc=state._pc, extra_block=eh_block)
196
+ return True
197
+ elif PYVERSION in (
198
+ (3, 9),
199
+ (3, 10),
200
+ ):
201
+
202
+ def _run_handle_exception(self, runner, state):
203
+ if (
204
+ state.has_active_try()
205
+ and state.get_inst().opname not in _NO_RAISE_OPS
206
+ ):
207
+ # Is in a *try* block
208
+ state.fork(pc=state.get_inst().next)
209
+ tryblk = state.get_top_block("TRY")
210
+ state.pop_block_and_above(tryblk)
211
+ nstack = state.stack_depth
212
+ kwargs = {}
213
+ if nstack > tryblk["entry_stack"]:
214
+ kwargs["npop"] = nstack - tryblk["entry_stack"]
215
+ handler = tryblk["handler"]
216
+ kwargs["npush"] = {
217
+ BlockKind("EXCEPT"): _EXCEPT_STACK_OFFSET,
218
+ BlockKind("FINALLY"): _FINALLY_POP,
219
+ }[handler["kind"]]
220
+ kwargs["extra_block"] = handler
221
+ state.fork(pc=tryblk["end"], **kwargs)
222
+ return True
223
+ else:
224
+ state.advance_pc()
225
+ else:
226
+ raise NotImplementedError(PYVERSION)
227
+
228
+ def _build_cfg(self, all_states):
229
+ graph = CFGraph()
230
+ for state in all_states:
231
+ b = state.pc_initial
232
+ graph.add_node(b)
233
+ for state in all_states:
234
+ for edge in state.outgoing_edges:
235
+ graph.add_edge(state.pc_initial, edge.pc, 0)
236
+ graph.set_entry_point(0)
237
+ graph.process()
238
+ self.cfgraph = graph
239
+
240
+ def _prune_phis(self, runner):
241
+ # Find phis that are unused in the local block
242
+ _logger.debug("Prune PHIs".center(60, "-"))
243
+
244
+ # Compute dataflow for used phis and propagate
245
+
246
+ # 1. Get used-phis for each block
247
+ # Map block to used_phis
248
+ def get_used_phis_per_state():
249
+ used_phis = defaultdict(set)
250
+ phi_set = set()
251
+ for state in runner.finished:
252
+ used = set(state._used_regs)
253
+ phis = set(state._phis)
254
+ used_phis[state] |= phis & used
255
+ phi_set |= phis
256
+ return used_phis, phi_set
257
+
258
+ # Find use-defs
259
+ def find_use_defs():
260
+ defmap = {}
261
+ phismap = defaultdict(set)
262
+ for state in runner.finished:
263
+ for phi, rhs in state._outgoing_phis.items():
264
+ if rhs not in phi_set:
265
+ # Is a definition
266
+ defmap[phi] = state
267
+ phismap[phi].add((rhs, state))
268
+ _logger.debug("defmap: %s", _lazy_pformat(defmap))
269
+ _logger.debug("phismap: %s", _lazy_pformat(phismap))
270
+ return defmap, phismap
271
+
272
+ def propagate_phi_map(phismap):
273
+ """An iterative dataflow algorithm to find the definition
274
+ (the source) of each PHI node.
275
+ """
276
+ blacklist = defaultdict(set)
277
+
278
+ while True:
279
+ changing = False
280
+ for phi, defsites in sorted(list(phismap.items())):
281
+ for rhs, state in sorted(list(defsites)):
282
+ if rhs in phi_set:
283
+ defsites |= phismap[rhs]
284
+ blacklist[phi].add((rhs, state))
285
+ to_remove = blacklist[phi]
286
+ if to_remove & defsites:
287
+ defsites -= to_remove
288
+ changing = True
289
+
290
+ _logger.debug("changing phismap: %s", _lazy_pformat(phismap))
291
+ if not changing:
292
+ break
293
+
294
+ def apply_changes(used_phis, phismap):
295
+ keep = {}
296
+ for state, used_set in used_phis.items():
297
+ for phi in used_set:
298
+ keep[phi] = phismap[phi]
299
+ _logger.debug("keep phismap: %s", _lazy_pformat(keep))
300
+ new_out = defaultdict(dict)
301
+ for phi in keep:
302
+ for rhs, state in keep[phi]:
303
+ new_out[state][phi] = rhs
304
+
305
+ _logger.debug("new_out: %s", _lazy_pformat(new_out))
306
+ for state in runner.finished:
307
+ state._outgoing_phis.clear()
308
+ state._outgoing_phis.update(new_out[state])
309
+
310
+ used_phis, phi_set = get_used_phis_per_state()
311
+ _logger.debug("Used_phis: %s", _lazy_pformat(used_phis))
312
+ defmap, phismap = find_use_defs()
313
+ propagate_phi_map(phismap)
314
+ apply_changes(used_phis, phismap)
315
+ _logger.debug("DONE Prune PHIs".center(60, "-"))
316
+
317
+ def _is_implicit_new_block(self, state):
318
+ inst = state.get_inst()
319
+
320
+ if inst.offset in self._bytecode.labels:
321
+ return True
322
+ elif inst.opname in NEW_BLOCKERS:
323
+ return True
324
+ else:
325
+ return False
326
+
327
+ def _guard_with_as(self, state):
328
+ """Checks if the next instruction after a SETUP_WITH is something other
329
+ than a POP_TOP, if it is something else it'll be some sort of store
330
+ which is not supported (this corresponds to `with CTXMGR as VAR(S)`)."""
331
+ current_inst = state.get_inst()
332
+ if current_inst.opname in {"SETUP_WITH", "BEFORE_WITH"}:
333
+ next_op = self._bytecode[current_inst.next].opname
334
+ if next_op != "POP_TOP":
335
+ msg = (
336
+ "The 'with (context manager) as "
337
+ "(variable):' construct is not "
338
+ "supported."
339
+ )
340
+ raise UnsupportedBytecodeError(msg)
341
+
342
+
343
+ def _is_null_temp_reg(reg):
344
+ return reg.startswith("$null$")
345
+
346
+
347
+ class TraceRunner(object):
348
+ """Trace runner contains the states for the trace and the opcode dispatch."""
349
+
350
+ def __init__(self, debug_filename):
351
+ self.debug_filename = debug_filename
352
+ self.pending = deque()
353
+ self.finished = set()
354
+
355
+ def get_debug_loc(self, lineno):
356
+ return Loc(self.debug_filename, lineno)
357
+
358
+ def dispatch(self, state):
359
+ if PYVERSION in ((3, 11), (3, 12), (3, 13)):
360
+ if state._blockstack:
361
+ state: State
362
+ while state._blockstack:
363
+ topblk = state._blockstack[-1]
364
+ blk_end = topblk["end"]
365
+ if blk_end is not None and blk_end <= state.pc_initial:
366
+ state._blockstack.pop()
367
+ else:
368
+ break
369
+ elif PYVERSION in (
370
+ (3, 9),
371
+ (3, 10),
372
+ ):
373
+ pass
374
+ else:
375
+ raise NotImplementedError(PYVERSION)
376
+ inst = state.get_inst()
377
+ if inst.opname != "CACHE":
378
+ _logger.debug("dispatch pc=%s, inst=%s", state._pc, inst)
379
+ _logger.debug("stack %s", state._stack)
380
+ fn = getattr(self, "op_{}".format(inst.opname), None)
381
+ if fn is not None:
382
+ fn(state, inst)
383
+ else:
384
+ msg = "Use of unsupported opcode (%s) found" % inst.opname
385
+ raise UnsupportedBytecodeError(
386
+ msg, loc=self.get_debug_loc(inst.lineno)
387
+ )
388
+
389
+ def _adjust_except_stack(self, state):
390
+ """
391
+ Adjust stack when entering an exception handler to match expectation
392
+ by the bytecode.
393
+ """
394
+ tryblk = state.get_top_block("TRY")
395
+ state.pop_block_and_above(tryblk)
396
+ nstack = state.stack_depth
397
+ kwargs = {}
398
+ expected_depth = tryblk["stack_depth"]
399
+ if nstack > expected_depth:
400
+ # Pop extra item in the stack
401
+ kwargs["npop"] = nstack - expected_depth
402
+ # Set extra stack itemcount due to the exception values.
403
+ extra_stack = 1
404
+ if tryblk["push_lasti"]:
405
+ extra_stack += 1
406
+ kwargs["npush"] = extra_stack
407
+ state.fork(pc=tryblk["end"], **kwargs)
408
+
409
+ def op_NOP(self, state, inst):
410
+ state.append(inst)
411
+
412
+ def op_RESUME(self, state, inst):
413
+ state.append(inst)
414
+
415
+ def op_CACHE(self, state, inst):
416
+ state.append(inst)
417
+
418
+ def op_PRECALL(self, state, inst):
419
+ state.append(inst)
420
+
421
+ def op_PUSH_NULL(self, state, inst):
422
+ state.push(state.make_null())
423
+ state.append(inst)
424
+
425
+ def op_RETURN_GENERATOR(self, state, inst):
426
+ # This impl doesn't follow what CPython does. CPython is hacking
427
+ # the frame stack in the interpreter. From usage, it always
428
+ # has a POP_TOP after it so we push a dummy value to the stack.
429
+ #
430
+ # Example bytecode:
431
+ # > 0 NOP(arg=None, lineno=80)
432
+ # 2 RETURN_GENERATOR(arg=None, lineno=80)
433
+ # 4 POP_TOP(arg=None, lineno=80)
434
+ # 6 RESUME(arg=0, lineno=80)
435
+ state.push(state.make_temp())
436
+ state.append(inst)
437
+
438
+ if PYVERSION in ((3, 13),):
439
+
440
+ def op_FORMAT_SIMPLE(self, state, inst):
441
+ assert PYVERSION == (3, 13)
442
+ value = state.pop()
443
+ strvar = state.make_temp()
444
+ res = state.make_temp()
445
+ state.append(inst, value=value, res=res, strvar=strvar)
446
+ state.push(res)
447
+
448
+ def op_FORMAT_VALUE(self, state, inst):
449
+ """
450
+ FORMAT_VALUE(flags): flags argument specifies format spec which is
451
+ not supported yet. Currently, we just call str() on the value.
452
+ Pops a value from stack and pushes results back.
453
+ Required for supporting f-strings.
454
+ https://docs.python.org/3/library/dis.html#opcode-FORMAT_VALUE
455
+ """
456
+ if inst.arg != 0:
457
+ msg = "format spec in f-strings not supported yet"
458
+ raise UnsupportedBytecodeError(
459
+ msg, loc=self.get_debug_loc(inst.lineno)
460
+ )
461
+ value = state.pop()
462
+ strvar = state.make_temp()
463
+ res = state.make_temp()
464
+ state.append(inst, value=value, res=res, strvar=strvar)
465
+ state.push(res)
466
+
467
+ def op_BUILD_STRING(self, state, inst):
468
+ """
469
+ BUILD_STRING(count): Concatenates count strings from the stack and
470
+ pushes the resulting string onto the stack.
471
+ Required for supporting f-strings.
472
+ https://docs.python.org/3/library/dis.html#opcode-BUILD_STRING
473
+ """
474
+ count = inst.arg
475
+ strings = list(reversed([state.pop() for _ in range(count)]))
476
+ # corner case: f""
477
+ if count == 0:
478
+ tmps = [state.make_temp()]
479
+ else:
480
+ tmps = [state.make_temp() for _ in range(count - 1)]
481
+ state.append(inst, strings=strings, tmps=tmps)
482
+ state.push(tmps[-1])
483
+
484
+ def op_POP_TOP(self, state, inst):
485
+ state.pop()
486
+
487
+ if PYVERSION in ((3, 13),):
488
+
489
+ def op_TO_BOOL(self, state, inst):
490
+ res = state.make_temp()
491
+ tos = state.pop()
492
+ state.append(inst, val=tos, res=res)
493
+ state.push(res)
494
+
495
+ elif PYVERSION < (3, 13):
496
+ pass
497
+
498
+ if PYVERSION in ((3, 13),):
499
+
500
+ def op_LOAD_GLOBAL(self, state, inst):
501
+ # Ordering of the global value and NULL is swapped in Py3.13
502
+ res = state.make_temp()
503
+ idx = inst.arg >> 1
504
+ state.append(inst, idx=idx, res=res)
505
+ state.push(res)
506
+ # ignoring the NULL
507
+ if inst.arg & 1:
508
+ state.push(state.make_null())
509
+ elif PYVERSION in ((3, 11), (3, 12)):
510
+
511
+ def op_LOAD_GLOBAL(self, state, inst):
512
+ res = state.make_temp()
513
+ idx = inst.arg >> 1
514
+ state.append(inst, idx=idx, res=res)
515
+ # ignoring the NULL
516
+ if inst.arg & 1:
517
+ state.push(state.make_null())
518
+ state.push(res)
519
+ elif PYVERSION in (
520
+ (3, 9),
521
+ (3, 10),
522
+ ):
523
+
524
+ def op_LOAD_GLOBAL(self, state, inst):
525
+ res = state.make_temp()
526
+ state.append(inst, res=res)
527
+ state.push(res)
528
+ else:
529
+ raise NotImplementedError(PYVERSION)
530
+
531
+ def op_COPY_FREE_VARS(self, state, inst):
532
+ state.append(inst)
533
+
534
+ def op_MAKE_CELL(self, state, inst):
535
+ state.append(inst)
536
+
537
+ def op_LOAD_DEREF(self, state, inst):
538
+ res = state.make_temp()
539
+ state.append(inst, res=res)
540
+ state.push(res)
541
+
542
+ def op_LOAD_CONST(self, state, inst):
543
+ # append const index for interpreter to read the const value
544
+ res = state.make_temp("const") + f".{inst.arg}"
545
+ state.push(res)
546
+ state.append(inst, res=res)
547
+
548
+ def op_LOAD_ATTR(self, state, inst):
549
+ item = state.pop()
550
+ res = state.make_temp()
551
+ if PYVERSION in ((3, 13),):
552
+ state.push(res) # the attr
553
+ if inst.arg & 1:
554
+ state.push(state.make_null())
555
+ elif PYVERSION in ((3, 12),):
556
+ if inst.arg & 1:
557
+ state.push(state.make_null())
558
+ state.push(res)
559
+ elif PYVERSION in ((3, 9), (3, 10), (3, 11)):
560
+ state.push(res)
561
+ else:
562
+ raise NotImplementedError(PYVERSION)
563
+ state.append(inst, item=item, res=res)
564
+
565
+ def op_LOAD_FAST(self, state, inst):
566
+ assert PYVERSION <= (3, 13)
567
+ if PYVERSION in ((3, 13),):
568
+ try:
569
+ name = state.get_varname(inst)
570
+ except IndexError: # oparg is out of range
571
+ # Handle this like a LOAD_DEREF
572
+ # Assume MAKE_CELL and COPY_FREE_VARS has correctly setup the
573
+ # states.
574
+ # According to https://github.com/python/cpython/blob/9ac606080a0074cdf7589d9b7c9413a73e0ddf37/Objects/codeobject.c#L730C9-L759 # noqa E501
575
+ # localsplus is locals + cells + freevars
576
+ bc = state._bytecode
577
+ num_varnames = len(bc.co_varnames)
578
+ num_freevars = len(bc.co_freevars)
579
+ num_cellvars = len(bc.co_cellvars)
580
+ max_fast_local = num_cellvars + num_freevars
581
+ assert 0 <= inst.arg - num_varnames < max_fast_local
582
+ res = state.make_temp()
583
+ state.append(inst, res=res, as_load_deref=True)
584
+ state.push(res)
585
+ return
586
+ else:
587
+ name = state.get_varname(inst)
588
+ res = state.make_temp(name)
589
+ state.append(inst, res=res)
590
+ state.push(res)
591
+
592
+ if PYVERSION in ((3, 13),):
593
+
594
+ def op_LOAD_FAST_LOAD_FAST(self, state, inst):
595
+ oparg = inst.arg
596
+ oparg1 = oparg >> 4
597
+ oparg2 = oparg & 15
598
+ name1 = state.get_varname_by_arg(oparg1)
599
+ name2 = state.get_varname_by_arg(oparg2)
600
+ res1 = state.make_temp(name1)
601
+ res2 = state.make_temp(name2)
602
+ state.append(inst, res1=res1, res2=res2)
603
+ state.push(res1)
604
+ state.push(res2)
605
+
606
+ def op_STORE_FAST_LOAD_FAST(self, state, inst):
607
+ oparg = inst.arg
608
+ # oparg1 = oparg >> 4 # not needed
609
+ oparg2 = oparg & 15
610
+ store_value = state.pop()
611
+ load_name = state.get_varname_by_arg(oparg2)
612
+ load_res = state.make_temp(load_name)
613
+ state.append(inst, store_value=store_value, load_res=load_res)
614
+ state.push(load_res)
615
+
616
+ def op_STORE_FAST_STORE_FAST(self, state, inst):
617
+ value1 = state.pop()
618
+ value2 = state.pop()
619
+ state.append(inst, value1=value1, value2=value2)
620
+
621
+ elif PYVERSION in ((3, 9), (3, 10), (3, 11), (3, 12)):
622
+ pass
623
+ else:
624
+ raise NotImplementedError(PYVERSION)
625
+
626
+ if PYVERSION in ((3, 12), (3, 13)):
627
+ op_LOAD_FAST_CHECK = op_LOAD_FAST
628
+ op_LOAD_FAST_AND_CLEAR = op_LOAD_FAST
629
+ elif PYVERSION in ((3, 9), (3, 10), (3, 11)):
630
+ pass
631
+ else:
632
+ raise NotImplementedError(PYVERSION)
633
+
634
+ def op_DELETE_FAST(self, state, inst):
635
+ state.append(inst)
636
+
637
+ def op_DELETE_ATTR(self, state, inst):
638
+ target = state.pop()
639
+ state.append(inst, target=target)
640
+
641
+ def op_STORE_ATTR(self, state, inst):
642
+ target = state.pop()
643
+ value = state.pop()
644
+ state.append(inst, target=target, value=value)
645
+
646
+ def op_STORE_DEREF(self, state, inst):
647
+ value = state.pop()
648
+ state.append(inst, value=value)
649
+
650
+ def op_STORE_FAST(self, state, inst):
651
+ value = state.pop()
652
+ state.append(inst, value=value)
653
+
654
+ def op_SLICE_1(self, state, inst):
655
+ """
656
+ TOS = TOS1[TOS:]
657
+ """
658
+ tos = state.pop()
659
+ tos1 = state.pop()
660
+ res = state.make_temp()
661
+ slicevar = state.make_temp()
662
+ indexvar = state.make_temp()
663
+ nonevar = state.make_temp()
664
+ state.append(
665
+ inst,
666
+ base=tos1,
667
+ start=tos,
668
+ res=res,
669
+ slicevar=slicevar,
670
+ indexvar=indexvar,
671
+ nonevar=nonevar,
672
+ )
673
+ state.push(res)
674
+
675
+ def op_SLICE_2(self, state, inst):
676
+ """
677
+ TOS = TOS1[:TOS]
678
+ """
679
+ tos = state.pop()
680
+ tos1 = state.pop()
681
+ res = state.make_temp()
682
+ slicevar = state.make_temp()
683
+ indexvar = state.make_temp()
684
+ nonevar = state.make_temp()
685
+ state.append(
686
+ inst,
687
+ base=tos1,
688
+ stop=tos,
689
+ res=res,
690
+ slicevar=slicevar,
691
+ indexvar=indexvar,
692
+ nonevar=nonevar,
693
+ )
694
+ state.push(res)
695
+
696
+ def op_SLICE_3(self, state, inst):
697
+ """
698
+ TOS = TOS2[TOS1:TOS]
699
+ """
700
+ tos = state.pop()
701
+ tos1 = state.pop()
702
+ tos2 = state.pop()
703
+ res = state.make_temp()
704
+ slicevar = state.make_temp()
705
+ indexvar = state.make_temp()
706
+ state.append(
707
+ inst,
708
+ base=tos2,
709
+ start=tos1,
710
+ stop=tos,
711
+ res=res,
712
+ slicevar=slicevar,
713
+ indexvar=indexvar,
714
+ )
715
+ state.push(res)
716
+
717
+ def op_STORE_SLICE_0(self, state, inst):
718
+ """
719
+ TOS[:] = TOS1
720
+ """
721
+ tos = state.pop()
722
+ value = state.pop()
723
+ slicevar = state.make_temp()
724
+ indexvar = state.make_temp()
725
+ nonevar = state.make_temp()
726
+ state.append(
727
+ inst,
728
+ base=tos,
729
+ value=value,
730
+ slicevar=slicevar,
731
+ indexvar=indexvar,
732
+ nonevar=nonevar,
733
+ )
734
+
735
+ def op_STORE_SLICE_1(self, state, inst):
736
+ """
737
+ TOS1[TOS:] = TOS2
738
+ """
739
+ tos = state.pop()
740
+ tos1 = state.pop()
741
+ value = state.pop()
742
+ slicevar = state.make_temp()
743
+ indexvar = state.make_temp()
744
+ nonevar = state.make_temp()
745
+ state.append(
746
+ inst,
747
+ base=tos1,
748
+ start=tos,
749
+ slicevar=slicevar,
750
+ value=value,
751
+ indexvar=indexvar,
752
+ nonevar=nonevar,
753
+ )
754
+
755
+ def op_STORE_SLICE_2(self, state, inst):
756
+ """
757
+ TOS1[:TOS] = TOS2
758
+ """
759
+ tos = state.pop()
760
+ tos1 = state.pop()
761
+ value = state.pop()
762
+ slicevar = state.make_temp()
763
+ indexvar = state.make_temp()
764
+ nonevar = state.make_temp()
765
+ state.append(
766
+ inst,
767
+ base=tos1,
768
+ stop=tos,
769
+ value=value,
770
+ slicevar=slicevar,
771
+ indexvar=indexvar,
772
+ nonevar=nonevar,
773
+ )
774
+
775
+ def op_STORE_SLICE_3(self, state, inst):
776
+ """
777
+ TOS2[TOS1:TOS] = TOS3
778
+ """
779
+ tos = state.pop()
780
+ tos1 = state.pop()
781
+ tos2 = state.pop()
782
+ value = state.pop()
783
+ slicevar = state.make_temp()
784
+ indexvar = state.make_temp()
785
+ state.append(
786
+ inst,
787
+ base=tos2,
788
+ start=tos1,
789
+ stop=tos,
790
+ value=value,
791
+ slicevar=slicevar,
792
+ indexvar=indexvar,
793
+ )
794
+
795
+ def op_DELETE_SLICE_0(self, state, inst):
796
+ """
797
+ del TOS[:]
798
+ """
799
+ tos = state.pop()
800
+ slicevar = state.make_temp()
801
+ indexvar = state.make_temp()
802
+ nonevar = state.make_temp()
803
+ state.append(
804
+ inst,
805
+ base=tos,
806
+ slicevar=slicevar,
807
+ indexvar=indexvar,
808
+ nonevar=nonevar,
809
+ )
810
+
811
+ def op_DELETE_SLICE_1(self, state, inst):
812
+ """
813
+ del TOS1[TOS:]
814
+ """
815
+ tos = state.pop()
816
+ tos1 = state.pop()
817
+ slicevar = state.make_temp()
818
+ indexvar = state.make_temp()
819
+ nonevar = state.make_temp()
820
+ state.append(
821
+ inst,
822
+ base=tos1,
823
+ start=tos,
824
+ slicevar=slicevar,
825
+ indexvar=indexvar,
826
+ nonevar=nonevar,
827
+ )
828
+
829
+ def op_DELETE_SLICE_2(self, state, inst):
830
+ """
831
+ del TOS1[:TOS]
832
+ """
833
+ tos = state.pop()
834
+ tos1 = state.pop()
835
+ slicevar = state.make_temp()
836
+ indexvar = state.make_temp()
837
+ nonevar = state.make_temp()
838
+ state.append(
839
+ inst,
840
+ base=tos1,
841
+ stop=tos,
842
+ slicevar=slicevar,
843
+ indexvar=indexvar,
844
+ nonevar=nonevar,
845
+ )
846
+
847
+ def op_DELETE_SLICE_3(self, state, inst):
848
+ """
849
+ del TOS2[TOS1:TOS]
850
+ """
851
+ tos = state.pop()
852
+ tos1 = state.pop()
853
+ tos2 = state.pop()
854
+ slicevar = state.make_temp()
855
+ indexvar = state.make_temp()
856
+ state.append(
857
+ inst,
858
+ base=tos2,
859
+ start=tos1,
860
+ stop=tos,
861
+ slicevar=slicevar,
862
+ indexvar=indexvar,
863
+ )
864
+
865
+ def op_BUILD_SLICE(self, state, inst):
866
+ """
867
+ slice(TOS1, TOS) or slice(TOS2, TOS1, TOS)
868
+ """
869
+ argc = inst.arg
870
+ if argc == 2:
871
+ tos = state.pop()
872
+ tos1 = state.pop()
873
+ start = tos1
874
+ stop = tos
875
+ step = None
876
+ elif argc == 3:
877
+ tos = state.pop()
878
+ tos1 = state.pop()
879
+ tos2 = state.pop()
880
+ start = tos2
881
+ stop = tos1
882
+ step = tos
883
+ else:
884
+ raise Exception("unreachable")
885
+ slicevar = state.make_temp()
886
+ res = state.make_temp()
887
+ state.append(
888
+ inst, start=start, stop=stop, step=step, res=res, slicevar=slicevar
889
+ )
890
+ state.push(res)
891
+
892
+ if PYVERSION in ((3, 12), (3, 13)):
893
+
894
+ def op_BINARY_SLICE(self, state, inst):
895
+ end = state.pop()
896
+ start = state.pop()
897
+ container = state.pop()
898
+ temp_res = state.make_temp()
899
+ res = state.make_temp()
900
+ slicevar = state.make_temp()
901
+ state.append(
902
+ inst,
903
+ start=start,
904
+ end=end,
905
+ container=container,
906
+ res=res,
907
+ slicevar=slicevar,
908
+ temp_res=temp_res,
909
+ )
910
+ state.push(res)
911
+ elif PYVERSION in ((3, 9), (3, 10), (3, 11)):
912
+ pass
913
+ else:
914
+ raise NotImplementedError(PYVERSION)
915
+
916
+ if PYVERSION in ((3, 12), (3, 13)):
917
+
918
+ def op_STORE_SLICE(self, state, inst):
919
+ end = state.pop()
920
+ start = state.pop()
921
+ container = state.pop()
922
+ value = state.pop()
923
+
924
+ slicevar = state.make_temp()
925
+ res = state.make_temp()
926
+ state.append(
927
+ inst,
928
+ start=start,
929
+ end=end,
930
+ container=container,
931
+ value=value,
932
+ res=res,
933
+ slicevar=slicevar,
934
+ )
935
+ elif PYVERSION in ((3, 9), (3, 10), (3, 11)):
936
+ pass
937
+ else:
938
+ raise NotImplementedError(PYVERSION)
939
+
940
+ def _op_POP_JUMP_IF(self, state, inst):
941
+ pred = state.pop()
942
+ state.append(inst, pred=pred)
943
+
944
+ target_inst = inst.get_jump_target()
945
+ next_inst = inst.next
946
+ # if the next inst and the jump target are the same location, issue one
947
+ # fork else issue a fork for the next and the target.
948
+ state.fork(pc=next_inst)
949
+ if target_inst != next_inst:
950
+ state.fork(pc=target_inst)
951
+
952
+ op_POP_JUMP_IF_TRUE = _op_POP_JUMP_IF
953
+ op_POP_JUMP_IF_FALSE = _op_POP_JUMP_IF
954
+
955
+ if PYVERSION in ((3, 12), (3, 13)):
956
+ op_POP_JUMP_IF_NONE = _op_POP_JUMP_IF
957
+ op_POP_JUMP_IF_NOT_NONE = _op_POP_JUMP_IF
958
+ elif PYVERSION in ((3, 9), (3, 10), (3, 11)):
959
+ pass
960
+ else:
961
+ raise NotImplementedError(PYVERSION)
962
+
963
+ def _op_JUMP_IF_OR_POP(self, state, inst):
964
+ pred = state.get_tos()
965
+ state.append(inst, pred=pred)
966
+ state.fork(pc=inst.next, npop=1)
967
+ state.fork(pc=inst.get_jump_target())
968
+
969
+ op_JUMP_IF_FALSE_OR_POP = _op_JUMP_IF_OR_POP
970
+ op_JUMP_IF_TRUE_OR_POP = _op_JUMP_IF_OR_POP
971
+
972
+ def op_POP_JUMP_FORWARD_IF_NONE(self, state, inst):
973
+ self._op_POP_JUMP_IF(state, inst)
974
+
975
+ def op_POP_JUMP_FORWARD_IF_NOT_NONE(self, state, inst):
976
+ self._op_POP_JUMP_IF(state, inst)
977
+
978
+ def op_POP_JUMP_BACKWARD_IF_NONE(self, state, inst):
979
+ self._op_POP_JUMP_IF(state, inst)
980
+
981
+ def op_POP_JUMP_BACKWARD_IF_NOT_NONE(self, state, inst):
982
+ self._op_POP_JUMP_IF(state, inst)
983
+
984
+ def op_POP_JUMP_FORWARD_IF_FALSE(self, state, inst):
985
+ self._op_POP_JUMP_IF(state, inst)
986
+
987
+ def op_POP_JUMP_FORWARD_IF_TRUE(self, state, inst):
988
+ self._op_POP_JUMP_IF(state, inst)
989
+
990
+ def op_POP_JUMP_BACKWARD_IF_FALSE(self, state, inst):
991
+ self._op_POP_JUMP_IF(state, inst)
992
+
993
+ def op_POP_JUMP_BACKWARD_IF_TRUE(self, state, inst):
994
+ self._op_POP_JUMP_IF(state, inst)
995
+
996
+ def op_JUMP_FORWARD(self, state, inst):
997
+ state.append(inst)
998
+ state.fork(pc=inst.get_jump_target())
999
+
1000
+ def op_JUMP_BACKWARD(self, state, inst):
1001
+ state.append(inst)
1002
+ state.fork(pc=inst.get_jump_target())
1003
+
1004
+ op_JUMP_BACKWARD_NO_INTERRUPT = op_JUMP_BACKWARD
1005
+
1006
+ def op_JUMP_ABSOLUTE(self, state, inst):
1007
+ state.append(inst)
1008
+ state.fork(pc=inst.get_jump_target())
1009
+
1010
+ def op_BREAK_LOOP(self, state, inst):
1011
+ # NOTE: bytecode removed since py3.8
1012
+ end = state.get_top_block("LOOP")["end"]
1013
+ state.append(inst, end=end)
1014
+ state.pop_block()
1015
+ state.fork(pc=end)
1016
+
1017
+ def op_RETURN_VALUE(self, state, inst):
1018
+ state.append(inst, retval=state.pop(), castval=state.make_temp())
1019
+ state.terminate()
1020
+
1021
+ if PYVERSION in ((3, 12), (3, 13)):
1022
+
1023
+ def op_RETURN_CONST(self, state, inst):
1024
+ res = state.make_temp("const")
1025
+ state.append(inst, retval=res, castval=state.make_temp())
1026
+ state.terminate()
1027
+ elif PYVERSION in ((3, 9), (3, 10), (3, 11)):
1028
+ pass
1029
+ else:
1030
+ raise NotImplementedError(PYVERSION)
1031
+
1032
+ def op_YIELD_VALUE(self, state, inst):
1033
+ val = state.pop()
1034
+ res = state.make_temp()
1035
+ state.append(inst, value=val, res=res)
1036
+ state.push(res)
1037
+
1038
+ if PYVERSION in ((3, 11), (3, 12), (3, 13)):
1039
+
1040
+ def op_RAISE_VARARGS(self, state, inst):
1041
+ if inst.arg == 0:
1042
+ exc = None
1043
+ # No re-raising within a try-except block.
1044
+ # But we allow bare reraise.
1045
+ if state.has_active_try():
1046
+ raise UnsupportedBytecodeError(
1047
+ "The re-raising of an exception is not yet supported.",
1048
+ loc=self.get_debug_loc(inst.lineno),
1049
+ )
1050
+ elif inst.arg == 1:
1051
+ exc = state.pop()
1052
+ else:
1053
+ raise ValueError("Multiple argument raise is not supported.")
1054
+ state.append(inst, exc=exc)
1055
+
1056
+ if state.has_active_try():
1057
+ self._adjust_except_stack(state)
1058
+ else:
1059
+ state.terminate()
1060
+
1061
+ elif PYVERSION in (
1062
+ (3, 9),
1063
+ (3, 10),
1064
+ ):
1065
+
1066
+ def op_RAISE_VARARGS(self, state, inst):
1067
+ in_exc_block = any(
1068
+ [
1069
+ state.get_top_block("EXCEPT") is not None,
1070
+ state.get_top_block("FINALLY") is not None,
1071
+ ]
1072
+ )
1073
+ if inst.arg == 0:
1074
+ exc = None
1075
+ if in_exc_block:
1076
+ raise UnsupportedBytecodeError(
1077
+ "The re-raising of an exception is not yet supported.",
1078
+ loc=self.get_debug_loc(inst.lineno),
1079
+ )
1080
+ elif inst.arg == 1:
1081
+ exc = state.pop()
1082
+ else:
1083
+ raise ValueError("Multiple argument raise is not supported.")
1084
+ state.append(inst, exc=exc)
1085
+ state.terminate()
1086
+ else:
1087
+ raise NotImplementedError(PYVERSION)
1088
+
1089
+ def op_BEGIN_FINALLY(self, state, inst):
1090
+ temps = []
1091
+ for i in range(_EXCEPT_STACK_OFFSET):
1092
+ tmp = state.make_temp()
1093
+ temps.append(tmp)
1094
+ state.push(tmp)
1095
+ state.append(inst, temps=temps)
1096
+
1097
+ def op_END_FINALLY(self, state, inst):
1098
+ blk = state.pop_block()
1099
+ state.reset_stack(blk["entry_stack"])
1100
+
1101
+ if PYVERSION in ((3, 13),):
1102
+
1103
+ def op_END_FOR(self, state, inst):
1104
+ state.pop()
1105
+ elif PYVERSION in ((3, 12),):
1106
+
1107
+ def op_END_FOR(self, state, inst):
1108
+ state.pop()
1109
+ state.pop()
1110
+ elif PYVERSION in ((3, 9), (3, 10), (3, 11)):
1111
+ pass
1112
+ else:
1113
+ raise NotImplementedError(PYVERSION)
1114
+
1115
+ def op_POP_FINALLY(self, state, inst):
1116
+ # we don't emulate the exact stack behavior
1117
+ if inst.arg != 0:
1118
+ msg = (
1119
+ "Unsupported use of a bytecode related to try..finally"
1120
+ " or a with-context"
1121
+ )
1122
+ raise UnsupportedBytecodeError(
1123
+ msg, loc=self.get_debug_loc(inst.lineno)
1124
+ )
1125
+
1126
+ def op_CALL_FINALLY(self, state, inst):
1127
+ pass
1128
+
1129
+ def op_WITH_EXCEPT_START(self, state, inst):
1130
+ state.terminate() # do not support
1131
+
1132
+ def op_WITH_CLEANUP_START(self, state, inst):
1133
+ # we don't emulate the exact stack behavior
1134
+ state.append(inst)
1135
+
1136
+ def op_WITH_CLEANUP_FINISH(self, state, inst):
1137
+ # we don't emulate the exact stack behavior
1138
+ state.append(inst)
1139
+
1140
+ def op_SETUP_LOOP(self, state, inst):
1141
+ # NOTE: bytecode removed since py3.8
1142
+ state.push_block(
1143
+ state.make_block(
1144
+ kind="LOOP",
1145
+ end=inst.get_jump_target(),
1146
+ )
1147
+ )
1148
+
1149
+ def op_BEFORE_WITH(self, state, inst):
1150
+ # Almost the same as py3.10 SETUP_WITH just lacking the finally block.
1151
+ cm = state.pop() # the context-manager
1152
+
1153
+ yielded = state.make_temp()
1154
+ exitfn = state.make_temp(prefix="setup_with_exitfn")
1155
+
1156
+ state.push(exitfn)
1157
+ state.push(yielded)
1158
+
1159
+ # Gather all exception entries for this WITH. There maybe multiple
1160
+ # entries; esp. for nested WITHs.
1161
+ bc = state._bytecode
1162
+ ehhead = bc.find_exception_entry(inst.next)
1163
+ ehrelated = [ehhead]
1164
+ for eh in bc.exception_entries:
1165
+ if eh.target == ehhead.target:
1166
+ ehrelated.append(eh)
1167
+ end = max(eh.end for eh in ehrelated)
1168
+ state.append(inst, contextmanager=cm, exitfn=exitfn, end=end)
1169
+
1170
+ state.push_block(
1171
+ state.make_block(
1172
+ kind="WITH",
1173
+ end=end,
1174
+ )
1175
+ )
1176
+ # Forces a new block
1177
+ state.fork(pc=inst.next)
1178
+
1179
+ def op_SETUP_WITH(self, state, inst):
1180
+ cm = state.pop() # the context-manager
1181
+
1182
+ yielded = state.make_temp()
1183
+ exitfn = state.make_temp(prefix="setup_with_exitfn")
1184
+ state.append(inst, contextmanager=cm, exitfn=exitfn)
1185
+
1186
+ state.push(exitfn)
1187
+ state.push(yielded)
1188
+
1189
+ state.push_block(
1190
+ state.make_block(
1191
+ kind="WITH",
1192
+ end=inst.get_jump_target(),
1193
+ )
1194
+ )
1195
+ # Forces a new block
1196
+ state.fork(pc=inst.next)
1197
+
1198
+ def _setup_try(self, kind, state, next, end):
1199
+ # Forces a new block
1200
+ # Fork to the body of the finally
1201
+ handler_block = state.make_block(
1202
+ kind=kind,
1203
+ end=None,
1204
+ reset_stack=False,
1205
+ )
1206
+ # Forces a new block
1207
+ # Fork to the body of the finally
1208
+ state.fork(
1209
+ pc=next,
1210
+ extra_block=state.make_block(
1211
+ kind="TRY",
1212
+ end=end,
1213
+ reset_stack=False,
1214
+ handler=handler_block,
1215
+ ),
1216
+ )
1217
+
1218
+ def op_PUSH_EXC_INFO(self, state, inst):
1219
+ tos = state.pop()
1220
+ state.push(state.make_temp("exception"))
1221
+ state.push(tos)
1222
+
1223
+ def op_SETUP_FINALLY(self, state, inst):
1224
+ state.append(inst)
1225
+ self._setup_try(
1226
+ "FINALLY",
1227
+ state,
1228
+ next=inst.next,
1229
+ end=inst.get_jump_target(),
1230
+ )
1231
+
1232
+ if PYVERSION in ((3, 11), (3, 12), (3, 13)):
1233
+
1234
+ def op_POP_EXCEPT(self, state, inst):
1235
+ state.pop()
1236
+
1237
+ elif PYVERSION in (
1238
+ (3, 9),
1239
+ (3, 10),
1240
+ ):
1241
+
1242
+ def op_POP_EXCEPT(self, state, inst):
1243
+ blk = state.pop_block()
1244
+ if blk["kind"] not in {BlockKind("EXCEPT"), BlockKind("FINALLY")}:
1245
+ raise UnsupportedBytecodeError(
1246
+ f"POP_EXCEPT got an unexpected block: {blk['kind']}",
1247
+ loc=self.get_debug_loc(inst.lineno),
1248
+ )
1249
+ state.pop()
1250
+ state.pop()
1251
+ state.pop()
1252
+ # Forces a new block
1253
+ state.fork(pc=inst.next)
1254
+ else:
1255
+ raise NotImplementedError(PYVERSION)
1256
+
1257
+ def op_POP_BLOCK(self, state, inst):
1258
+ blk = state.pop_block()
1259
+ if blk["kind"] == BlockKind("TRY"):
1260
+ state.append(inst, kind="try")
1261
+ elif blk["kind"] == BlockKind("WITH"):
1262
+ state.append(inst, kind="with")
1263
+ state.fork(pc=inst.next)
1264
+
1265
+ def op_BINARY_SUBSCR(self, state, inst):
1266
+ index = state.pop()
1267
+ target = state.pop()
1268
+ res = state.make_temp()
1269
+ state.append(inst, index=index, target=target, res=res)
1270
+ state.push(res)
1271
+
1272
+ def op_STORE_SUBSCR(self, state, inst):
1273
+ index = state.pop()
1274
+ target = state.pop()
1275
+ value = state.pop()
1276
+ state.append(inst, target=target, index=index, value=value)
1277
+
1278
+ def op_DELETE_SUBSCR(self, state, inst):
1279
+ index = state.pop()
1280
+ target = state.pop()
1281
+ state.append(inst, target=target, index=index)
1282
+
1283
+ def op_CALL(self, state, inst):
1284
+ narg = inst.arg
1285
+ args = list(reversed([state.pop() for _ in range(narg)]))
1286
+ if PYVERSION == (3, 13):
1287
+ null_or_self = state.pop()
1288
+ # position of the callable is fixed
1289
+ callable = state.pop()
1290
+ if not _is_null_temp_reg(null_or_self):
1291
+ args = [null_or_self, *args]
1292
+ kw_names = None
1293
+ elif PYVERSION < (3, 13):
1294
+ callable_or_firstarg = state.pop()
1295
+ null_or_callable = state.pop()
1296
+ if _is_null_temp_reg(null_or_callable):
1297
+ callable = callable_or_firstarg
1298
+ else:
1299
+ callable = null_or_callable
1300
+ args = [callable_or_firstarg, *args]
1301
+ kw_names = state.pop_kw_names()
1302
+ res = state.make_temp()
1303
+
1304
+ state.append(inst, func=callable, args=args, kw_names=kw_names, res=res)
1305
+ state.push(res)
1306
+
1307
+ def op_KW_NAMES(self, state, inst):
1308
+ state.set_kw_names(inst.arg)
1309
+
1310
+ def op_CALL_FUNCTION(self, state, inst):
1311
+ narg = inst.arg
1312
+ args = list(reversed([state.pop() for _ in range(narg)]))
1313
+ func = state.pop()
1314
+
1315
+ res = state.make_temp()
1316
+ state.append(inst, func=func, args=args, res=res)
1317
+ state.push(res)
1318
+
1319
+ def op_CALL_FUNCTION_KW(self, state, inst):
1320
+ narg = inst.arg
1321
+ names = state.pop() # tuple of names
1322
+ args = list(reversed([state.pop() for _ in range(narg)]))
1323
+ func = state.pop()
1324
+
1325
+ res = state.make_temp()
1326
+ state.append(inst, func=func, args=args, names=names, res=res)
1327
+ state.push(res)
1328
+
1329
+ if PYVERSION in ((3, 13),):
1330
+
1331
+ def op_CALL_KW(self, state, inst):
1332
+ narg = inst.arg
1333
+ kw_names = state.pop()
1334
+ args = list(reversed([state.pop() for _ in range(narg)]))
1335
+ null_or_firstarg = state.pop()
1336
+ callable = state.pop()
1337
+ if not _is_null_temp_reg(null_or_firstarg):
1338
+ args = [null_or_firstarg, *args]
1339
+
1340
+ res = state.make_temp()
1341
+ state.append(
1342
+ inst, func=callable, args=args, kw_names=kw_names, res=res
1343
+ )
1344
+ state.push(res)
1345
+
1346
+ elif PYVERSION in ((3, 9), (3, 10), (3, 11), (3, 12)):
1347
+ pass
1348
+ else:
1349
+ raise NotImplementedError(PYVERSION)
1350
+
1351
+ if PYVERSION in ((3, 13),):
1352
+
1353
+ def op_CALL_FUNCTION_EX(self, state, inst):
1354
+ # (func, unused, callargs, kwargs if (oparg & 1) -- result))
1355
+ if inst.arg & 1:
1356
+ varkwarg = state.pop()
1357
+ else:
1358
+ varkwarg = None
1359
+
1360
+ vararg = state.pop()
1361
+ state.pop() # unused
1362
+ func = state.pop()
1363
+
1364
+ res = state.make_temp()
1365
+ state.append(
1366
+ inst, func=func, vararg=vararg, varkwarg=varkwarg, res=res
1367
+ )
1368
+ state.push(res)
1369
+
1370
+ elif PYVERSION in ((3, 9), (3, 10), (3, 11), (3, 12)):
1371
+
1372
+ def op_CALL_FUNCTION_EX(self, state, inst):
1373
+ if inst.arg & 1:
1374
+ varkwarg = state.pop()
1375
+ else:
1376
+ varkwarg = None
1377
+ vararg = state.pop()
1378
+ func = state.pop()
1379
+
1380
+ if PYVERSION in ((3, 11), (3, 12)):
1381
+ if _is_null_temp_reg(state.peek(1)):
1382
+ state.pop() # pop NULL, it's not used
1383
+ elif PYVERSION in (
1384
+ (3, 9),
1385
+ (3, 10),
1386
+ ):
1387
+ pass
1388
+ else:
1389
+ raise NotImplementedError(PYVERSION)
1390
+
1391
+ res = state.make_temp()
1392
+ state.append(
1393
+ inst, func=func, vararg=vararg, varkwarg=varkwarg, res=res
1394
+ )
1395
+ state.push(res)
1396
+ else:
1397
+ raise NotImplementedError(PYVERSION)
1398
+
1399
+ def _dup_topx(self, state, inst, count):
1400
+ orig = [state.pop() for _ in range(count)]
1401
+ orig.reverse()
1402
+ # We need to actually create new temporaries if we want the
1403
+ # IR optimization pass to work correctly (see issue #580)
1404
+ duped = [state.make_temp() for _ in range(count)]
1405
+ state.append(inst, orig=orig, duped=duped)
1406
+ for val in orig:
1407
+ state.push(val)
1408
+ for val in duped:
1409
+ state.push(val)
1410
+
1411
+ if PYVERSION in ((3, 12), (3, 13)):
1412
+
1413
+ def op_CALL_INTRINSIC_1(self, state, inst):
1414
+ # See https://github.com/python/cpython/blob/v3.12.0rc2/Include/
1415
+ # internal/pycore_intrinsics.h#L3-L17C36
1416
+ try:
1417
+ operand = CALL_INTRINSIC_1_Operand(inst.arg)
1418
+ except TypeError:
1419
+ msg = f"op_CALL_INTRINSIC_1({inst.arg})"
1420
+ loc = self.get_debug_loc(inst.lineno)
1421
+ raise UnsupportedBytecodeError(msg, loc=loc)
1422
+ if operand == ci1op.INTRINSIC_STOPITERATION_ERROR:
1423
+ state.append(inst, operand=operand)
1424
+ state.terminate()
1425
+ return
1426
+ elif operand == ci1op.UNARY_POSITIVE:
1427
+ val = state.pop()
1428
+ res = state.make_temp()
1429
+ state.append(inst, operand=operand, value=val, res=res)
1430
+ state.push(res)
1431
+ return
1432
+ elif operand == ci1op.INTRINSIC_LIST_TO_TUPLE:
1433
+ tos = state.pop()
1434
+ res = state.make_temp()
1435
+ state.append(inst, operand=operand, const_list=tos, res=res)
1436
+ state.push(res)
1437
+ return
1438
+ else:
1439
+ raise NotImplementedError(operand)
1440
+
1441
+ elif PYVERSION in ((3, 9), (3, 10), (3, 11)):
1442
+ pass
1443
+ else:
1444
+ raise NotImplementedError(PYVERSION)
1445
+
1446
+ def op_DUP_TOPX(self, state, inst):
1447
+ count = inst.arg
1448
+ assert 1 <= count <= 5, "Invalid DUP_TOPX count"
1449
+ self._dup_topx(state, inst, count)
1450
+
1451
+ def op_DUP_TOP(self, state, inst):
1452
+ self._dup_topx(state, inst, count=1)
1453
+
1454
+ def op_DUP_TOP_TWO(self, state, inst):
1455
+ self._dup_topx(state, inst, count=2)
1456
+
1457
+ def op_COPY(self, state, inst):
1458
+ state.push(state.peek(inst.arg))
1459
+
1460
+ def op_SWAP(self, state, inst):
1461
+ state.swap(inst.arg)
1462
+
1463
+ def op_ROT_TWO(self, state, inst):
1464
+ first = state.pop()
1465
+ second = state.pop()
1466
+ state.push(first)
1467
+ state.push(second)
1468
+
1469
+ def op_ROT_THREE(self, state, inst):
1470
+ first = state.pop()
1471
+ second = state.pop()
1472
+ third = state.pop()
1473
+ state.push(first)
1474
+ state.push(third)
1475
+ state.push(second)
1476
+
1477
+ def op_ROT_FOUR(self, state, inst):
1478
+ first = state.pop()
1479
+ second = state.pop()
1480
+ third = state.pop()
1481
+ forth = state.pop()
1482
+ state.push(first)
1483
+ state.push(forth)
1484
+ state.push(third)
1485
+ state.push(second)
1486
+
1487
+ def op_UNPACK_SEQUENCE(self, state, inst):
1488
+ count = inst.arg
1489
+ iterable = state.pop()
1490
+ stores = [state.make_temp() for _ in range(count)]
1491
+ tupleobj = state.make_temp()
1492
+ state.append(inst, iterable=iterable, stores=stores, tupleobj=tupleobj)
1493
+ for st in reversed(stores):
1494
+ state.push(st)
1495
+
1496
+ def op_BUILD_TUPLE(self, state, inst):
1497
+ count = inst.arg
1498
+ items = list(reversed([state.pop() for _ in range(count)]))
1499
+ tup = state.make_temp()
1500
+ state.append(inst, items=items, res=tup)
1501
+ state.push(tup)
1502
+
1503
+ def _build_tuple_unpack(self, state, inst):
1504
+ # Builds tuple from other tuples on the stack
1505
+ tuples = list(reversed([state.pop() for _ in range(inst.arg)]))
1506
+ temps = [state.make_temp() for _ in range(len(tuples) - 1)]
1507
+
1508
+ # if the unpack is assign-like, e.g. x = (*y,), it needs handling
1509
+ # differently.
1510
+ is_assign = len(tuples) == 1
1511
+ if is_assign:
1512
+ temps = [
1513
+ state.make_temp(),
1514
+ ]
1515
+
1516
+ state.append(inst, tuples=tuples, temps=temps, is_assign=is_assign)
1517
+ # The result is in the last temp var
1518
+ state.push(temps[-1])
1519
+
1520
+ def op_BUILD_TUPLE_UNPACK_WITH_CALL(self, state, inst):
1521
+ # just unpack the input tuple, call inst will be handled afterwards
1522
+ self._build_tuple_unpack(state, inst)
1523
+
1524
+ def op_BUILD_TUPLE_UNPACK(self, state, inst):
1525
+ self._build_tuple_unpack(state, inst)
1526
+
1527
+ def op_LIST_TO_TUPLE(self, state, inst):
1528
+ # "Pops a list from the stack and pushes a tuple containing the same
1529
+ # values."
1530
+ tos = state.pop()
1531
+ res = state.make_temp() # new tuple var
1532
+ state.append(inst, const_list=tos, res=res)
1533
+ state.push(res)
1534
+
1535
+ def op_BUILD_CONST_KEY_MAP(self, state, inst):
1536
+ keys = state.pop()
1537
+ vals = list(reversed([state.pop() for _ in range(inst.arg)]))
1538
+ keytmps = [state.make_temp() for _ in range(inst.arg)]
1539
+ res = state.make_temp()
1540
+ state.append(inst, keys=keys, keytmps=keytmps, values=vals, res=res)
1541
+ state.push(res)
1542
+
1543
+ def op_BUILD_LIST(self, state, inst):
1544
+ count = inst.arg
1545
+ items = list(reversed([state.pop() for _ in range(count)]))
1546
+ lst = state.make_temp()
1547
+ state.append(inst, items=items, res=lst)
1548
+ state.push(lst)
1549
+
1550
+ def op_LIST_APPEND(self, state, inst):
1551
+ value = state.pop()
1552
+ index = inst.arg
1553
+ target = state.peek(index)
1554
+ appendvar = state.make_temp()
1555
+ res = state.make_temp()
1556
+ state.append(
1557
+ inst, target=target, value=value, appendvar=appendvar, res=res
1558
+ )
1559
+
1560
+ def op_LIST_EXTEND(self, state, inst):
1561
+ value = state.pop()
1562
+ index = inst.arg
1563
+ target = state.peek(index)
1564
+ extendvar = state.make_temp()
1565
+ res = state.make_temp()
1566
+ state.append(
1567
+ inst, target=target, value=value, extendvar=extendvar, res=res
1568
+ )
1569
+
1570
+ def op_BUILD_MAP(self, state, inst):
1571
+ dct = state.make_temp()
1572
+ count = inst.arg
1573
+ items = []
1574
+ # In 3.5+, BUILD_MAP takes <count> pairs from the stack
1575
+ for i in range(count):
1576
+ v, k = state.pop(), state.pop()
1577
+ items.append((k, v))
1578
+ state.append(inst, items=items[::-1], size=count, res=dct)
1579
+ state.push(dct)
1580
+
1581
+ def op_MAP_ADD(self, state, inst):
1582
+ TOS = state.pop()
1583
+ TOS1 = state.pop()
1584
+ key, value = (TOS1, TOS)
1585
+ index = inst.arg
1586
+ target = state.peek(index)
1587
+ setitemvar = state.make_temp()
1588
+ res = state.make_temp()
1589
+ state.append(
1590
+ inst,
1591
+ target=target,
1592
+ key=key,
1593
+ value=value,
1594
+ setitemvar=setitemvar,
1595
+ res=res,
1596
+ )
1597
+
1598
+ def op_BUILD_SET(self, state, inst):
1599
+ count = inst.arg
1600
+ # Note: related python bug http://bugs.python.org/issue26020
1601
+ items = list(reversed([state.pop() for _ in range(count)]))
1602
+ res = state.make_temp()
1603
+ state.append(inst, items=items, res=res)
1604
+ state.push(res)
1605
+
1606
+ def op_SET_UPDATE(self, state, inst):
1607
+ value = state.pop()
1608
+ index = inst.arg
1609
+ target = state.peek(index)
1610
+ updatevar = state.make_temp()
1611
+ res = state.make_temp()
1612
+ state.append(
1613
+ inst, target=target, value=value, updatevar=updatevar, res=res
1614
+ )
1615
+
1616
+ def op_DICT_UPDATE(self, state, inst):
1617
+ value = state.pop()
1618
+ index = inst.arg
1619
+ target = state.peek(index)
1620
+ updatevar = state.make_temp()
1621
+ res = state.make_temp()
1622
+ state.append(
1623
+ inst, target=target, value=value, updatevar=updatevar, res=res
1624
+ )
1625
+
1626
+ def op_GET_ITER(self, state, inst):
1627
+ value = state.pop()
1628
+ res = state.make_temp()
1629
+ state.append(inst, value=value, res=res)
1630
+ state.push(res)
1631
+
1632
+ def op_FOR_ITER(self, state, inst):
1633
+ iterator = state.get_tos()
1634
+ pair = state.make_temp()
1635
+ indval = state.make_temp()
1636
+ pred = state.make_temp()
1637
+ state.append(
1638
+ inst, iterator=iterator, pair=pair, indval=indval, pred=pred
1639
+ )
1640
+ state.push(indval)
1641
+ end = inst.get_jump_target()
1642
+ if PYVERSION in ((3, 12), (3, 13)):
1643
+ # Changed in version 3.12: Up until 3.11 the iterator was
1644
+ # popped when it was exhausted. Now this is handled using END_FOR
1645
+ # op code.
1646
+ state.fork(pc=end)
1647
+ elif PYVERSION in ((3, 9), (3, 10), (3, 11)):
1648
+ state.fork(pc=end, npop=2)
1649
+ else:
1650
+ raise NotImplementedError(PYVERSION)
1651
+ state.fork(pc=inst.next)
1652
+
1653
+ def op_GEN_START(self, state, inst):
1654
+ """Pops TOS. If TOS was not None, raises an exception. The kind
1655
+ operand corresponds to the type of generator or coroutine and
1656
+ determines the error message. The legal kinds are 0 for generator,
1657
+ 1 for coroutine, and 2 for async generator.
1658
+
1659
+ New in version 3.10.
1660
+ """
1661
+ # no-op in Numba
1662
+ pass
1663
+
1664
+ def op_BINARY_OP(self, state, inst):
1665
+ op = dis._nb_ops[inst.arg][1]
1666
+ rhs = state.pop()
1667
+ lhs = state.pop()
1668
+ op_name = ALL_BINOPS_TO_OPERATORS[op].__name__
1669
+ res = state.make_temp(prefix=f"binop_{op_name}")
1670
+ state.append(inst, op=op, lhs=lhs, rhs=rhs, res=res)
1671
+ state.push(res)
1672
+
1673
+ def _unaryop(self, state, inst):
1674
+ val = state.pop()
1675
+ res = state.make_temp()
1676
+ state.append(inst, value=val, res=res)
1677
+ state.push(res)
1678
+
1679
+ op_UNARY_NEGATIVE = _unaryop
1680
+ op_UNARY_POSITIVE = _unaryop
1681
+ op_UNARY_NOT = _unaryop
1682
+ op_UNARY_INVERT = _unaryop
1683
+
1684
+ def _binaryop(self, state, inst):
1685
+ rhs = state.pop()
1686
+ lhs = state.pop()
1687
+ res = state.make_temp()
1688
+ state.append(inst, lhs=lhs, rhs=rhs, res=res)
1689
+ state.push(res)
1690
+
1691
+ op_COMPARE_OP = _binaryop
1692
+ op_IS_OP = _binaryop
1693
+ op_CONTAINS_OP = _binaryop
1694
+
1695
+ op_INPLACE_ADD = _binaryop
1696
+ op_INPLACE_SUBTRACT = _binaryop
1697
+ op_INPLACE_MULTIPLY = _binaryop
1698
+ op_INPLACE_DIVIDE = _binaryop
1699
+ op_INPLACE_TRUE_DIVIDE = _binaryop
1700
+ op_INPLACE_FLOOR_DIVIDE = _binaryop
1701
+ op_INPLACE_MODULO = _binaryop
1702
+ op_INPLACE_POWER = _binaryop
1703
+ op_INPLACE_MATRIX_MULTIPLY = _binaryop
1704
+
1705
+ op_INPLACE_LSHIFT = _binaryop
1706
+ op_INPLACE_RSHIFT = _binaryop
1707
+ op_INPLACE_AND = _binaryop
1708
+ op_INPLACE_OR = _binaryop
1709
+ op_INPLACE_XOR = _binaryop
1710
+
1711
+ op_BINARY_ADD = _binaryop
1712
+ op_BINARY_SUBTRACT = _binaryop
1713
+ op_BINARY_MULTIPLY = _binaryop
1714
+ op_BINARY_DIVIDE = _binaryop
1715
+ op_BINARY_TRUE_DIVIDE = _binaryop
1716
+ op_BINARY_FLOOR_DIVIDE = _binaryop
1717
+ op_BINARY_MODULO = _binaryop
1718
+ op_BINARY_POWER = _binaryop
1719
+ op_BINARY_MATRIX_MULTIPLY = _binaryop
1720
+
1721
+ op_BINARY_LSHIFT = _binaryop
1722
+ op_BINARY_RSHIFT = _binaryop
1723
+ op_BINARY_AND = _binaryop
1724
+ op_BINARY_OR = _binaryop
1725
+ op_BINARY_XOR = _binaryop
1726
+
1727
+ def op_MAKE_FUNCTION(self, state, inst, MAKE_CLOSURE=False):
1728
+ if PYVERSION in ((3, 11), (3, 12), (3, 13)):
1729
+ # https://github.com/python/cpython/commit/2f180ce
1730
+ # name set via co_qualname
1731
+ name = None
1732
+ elif PYVERSION in (
1733
+ (3, 9),
1734
+ (3, 10),
1735
+ ):
1736
+ name = state.pop()
1737
+ else:
1738
+ raise NotImplementedError(PYVERSION)
1739
+ code = state.pop()
1740
+ closure = annotations = kwdefaults = defaults = None
1741
+ if PYVERSION in ((3, 13),):
1742
+ assert inst.arg is None
1743
+ # SET_FUNCTION_ATTRIBUTE is responsible for setting
1744
+ # closure, annotations, kwdefaults and defaults.
1745
+ else:
1746
+ if inst.arg & 0x8:
1747
+ closure = state.pop()
1748
+ if inst.arg & 0x4:
1749
+ annotations = state.pop()
1750
+ if inst.arg & 0x2:
1751
+ kwdefaults = state.pop()
1752
+ if inst.arg & 0x1:
1753
+ defaults = state.pop()
1754
+ res = state.make_temp()
1755
+ state.append(
1756
+ inst,
1757
+ name=name,
1758
+ code=code,
1759
+ closure=closure,
1760
+ annotations=annotations,
1761
+ kwdefaults=kwdefaults,
1762
+ defaults=defaults,
1763
+ res=res,
1764
+ )
1765
+ state.push(res)
1766
+
1767
+ def op_SET_FUNCTION_ATTRIBUTE(self, state, inst):
1768
+ assert PYVERSION in ((3, 13),)
1769
+ make_func_stack = state.pop()
1770
+ data = state.pop()
1771
+ if inst.arg == 0x1:
1772
+ # 0x01 a tuple of default values for positional-only and
1773
+ # positional-or-keyword parameters in positional order
1774
+ state.set_function_attribute(make_func_stack, defaults=data)
1775
+ elif inst.arg & 0x2:
1776
+ # 0x02 a tuple of strings containing parameters’ annotations
1777
+ state.set_function_attribute(make_func_stack, kwdefaults=data)
1778
+ elif inst.arg & 0x4:
1779
+ # 0x04 a tuple of strings containing parameters’ annotations
1780
+ state.set_function_attribute(make_func_stack, annotations=data)
1781
+ elif inst.arg == 0x8:
1782
+ # 0x08 a tuple containing cells for free variables, making a closure
1783
+ state.set_function_attribute(make_func_stack, closure=data)
1784
+ else:
1785
+ raise AssertionError("unreachable")
1786
+ state.push(make_func_stack)
1787
+
1788
+ def op_MAKE_CLOSURE(self, state, inst):
1789
+ self.op_MAKE_FUNCTION(state, inst, MAKE_CLOSURE=True)
1790
+
1791
+ def op_LOAD_CLOSURE(self, state, inst):
1792
+ res = state.make_temp()
1793
+ state.append(inst, res=res)
1794
+ state.push(res)
1795
+
1796
+ def op_LOAD_ASSERTION_ERROR(self, state, inst):
1797
+ res = state.make_temp("assertion_error")
1798
+ state.append(inst, res=res)
1799
+ state.push(res)
1800
+
1801
+ def op_CHECK_EXC_MATCH(self, state, inst):
1802
+ pred = state.make_temp("predicate")
1803
+ tos = state.pop()
1804
+ tos1 = state.get_tos()
1805
+ state.append(inst, pred=pred, tos=tos, tos1=tos1)
1806
+ state.push(pred)
1807
+
1808
+ def op_JUMP_IF_NOT_EXC_MATCH(self, state, inst):
1809
+ # Tests whether the second value on the stack is an exception matching
1810
+ # TOS, and jumps if it is not. Pops two values from the stack.
1811
+ pred = state.make_temp("predicate")
1812
+ tos = state.pop()
1813
+ tos1 = state.pop()
1814
+ state.append(inst, pred=pred, tos=tos, tos1=tos1)
1815
+ state.fork(pc=inst.next)
1816
+ state.fork(pc=inst.get_jump_target())
1817
+
1818
+ if PYVERSION in ((3, 11), (3, 12), (3, 13)):
1819
+
1820
+ def op_RERAISE(self, state, inst):
1821
+ # This isn't handled, but the state is set up anyway
1822
+ exc = state.pop()
1823
+ if inst.arg != 0:
1824
+ state.pop() # lasti
1825
+ state.append(inst, exc=exc)
1826
+
1827
+ if state.has_active_try():
1828
+ self._adjust_except_stack(state)
1829
+ else:
1830
+ state.terminate()
1831
+
1832
+ elif PYVERSION in (
1833
+ (3, 9),
1834
+ (3, 10),
1835
+ ):
1836
+
1837
+ def op_RERAISE(self, state, inst):
1838
+ # This isn't handled, but the state is set up anyway
1839
+ exc = state.pop()
1840
+ state.append(inst, exc=exc)
1841
+ state.terminate()
1842
+ else:
1843
+ raise NotImplementedError(PYVERSION)
1844
+
1845
+ # NOTE: Please see notes in `interpreter.py` surrounding the implementation
1846
+ # of LOAD_METHOD and CALL_METHOD.
1847
+
1848
+ if PYVERSION in ((3, 12), (3, 13)):
1849
+ # LOAD_METHOD has become a pseudo-instruction in 3.12
1850
+ pass
1851
+ elif PYVERSION in ((3, 11),):
1852
+
1853
+ def op_LOAD_METHOD(self, state, inst):
1854
+ item = state.pop()
1855
+ extra = state.make_null()
1856
+ state.push(extra)
1857
+ res = state.make_temp()
1858
+ state.append(inst, item=item, res=res)
1859
+ state.push(res)
1860
+ elif PYVERSION in (
1861
+ (3, 9),
1862
+ (3, 10),
1863
+ ):
1864
+
1865
+ def op_LOAD_METHOD(self, state, inst):
1866
+ self.op_LOAD_ATTR(state, inst)
1867
+ else:
1868
+ raise NotImplementedError(PYVERSION)
1869
+
1870
+ def op_CALL_METHOD(self, state, inst):
1871
+ self.op_CALL_FUNCTION(state, inst)
1872
+
1873
+
1874
+ @total_ordering
1875
+ class _State(object):
1876
+ """State of the trace"""
1877
+
1878
+ def __init__(self, bytecode, pc, nstack, blockstack, nullvals=()):
1879
+ """
1880
+ Parameters
1881
+ ----------
1882
+ bytecode : numba.bytecode.ByteCode
1883
+ function bytecode
1884
+ pc : int
1885
+ program counter
1886
+ nstack : int
1887
+ stackdepth at entry
1888
+ blockstack : Sequence[Dict]
1889
+ A sequence of dictionary denoting entries on the blockstack.
1890
+ """
1891
+ self._bytecode = bytecode
1892
+ self._pc_initial = pc
1893
+ self._pc = pc
1894
+ self._nstack_initial = nstack
1895
+ self._stack = []
1896
+ self._blockstack_initial = tuple(blockstack)
1897
+ self._blockstack = list(blockstack)
1898
+ self._temp_registers = []
1899
+ self._insts = []
1900
+ self._outedges = []
1901
+ self._terminated = False
1902
+ self._phis = {}
1903
+ self._outgoing_phis = UniqueDict()
1904
+ self._used_regs = set()
1905
+ for i in range(nstack):
1906
+ if i in nullvals:
1907
+ phi = self.make_temp("null$")
1908
+ else:
1909
+ phi = self.make_temp("phi")
1910
+ self._phis[phi] = i
1911
+ self.push(phi)
1912
+
1913
+ def __repr__(self):
1914
+ return "State(pc_initial={} nstack_initial={})".format(
1915
+ self._pc_initial, self._nstack_initial
1916
+ )
1917
+
1918
+ def get_identity(self):
1919
+ return (self._pc_initial, self._nstack_initial)
1920
+
1921
+ def __hash__(self):
1922
+ return hash(self.get_identity())
1923
+
1924
+ def __lt__(self, other):
1925
+ return self.get_identity() < other.get_identity()
1926
+
1927
+ def __eq__(self, other):
1928
+ return self.get_identity() == other.get_identity()
1929
+
1930
+ @property
1931
+ def pc_initial(self):
1932
+ """The starting bytecode offset of this State.
1933
+ The PC given to the constructor.
1934
+ """
1935
+ return self._pc_initial
1936
+
1937
+ @property
1938
+ def instructions(self):
1939
+ """The list of instructions information as a 2-tuple of
1940
+ ``(pc : int, register_map : Dict)``
1941
+ """
1942
+ return self._insts
1943
+
1944
+ @property
1945
+ def outgoing_edges(self):
1946
+ """The list of outgoing edges.
1947
+
1948
+ Returns
1949
+ -------
1950
+ edges : List[State]
1951
+ """
1952
+ return self._outedges
1953
+
1954
+ @property
1955
+ def outgoing_phis(self):
1956
+ """The dictionary of outgoing phi nodes.
1957
+
1958
+ The keys are the name of the PHI nodes.
1959
+ The values are the outgoing states.
1960
+ """
1961
+ return self._outgoing_phis
1962
+
1963
+ @property
1964
+ def blockstack_initial(self):
1965
+ """A copy of the initial state of the blockstack"""
1966
+ return self._blockstack_initial
1967
+
1968
+ @property
1969
+ def stack_depth(self):
1970
+ """The current size of the stack
1971
+
1972
+ Returns
1973
+ -------
1974
+ res : int
1975
+ """
1976
+ return len(self._stack)
1977
+
1978
+ def find_initial_try_block(self):
1979
+ """Find the initial *try* block."""
1980
+ for blk in reversed(self._blockstack_initial):
1981
+ if blk["kind"] == BlockKind("TRY"):
1982
+ return blk
1983
+
1984
+ def has_terminated(self):
1985
+ return self._terminated
1986
+
1987
+ def get_inst(self):
1988
+ return self._bytecode[self._pc]
1989
+
1990
+ def advance_pc(self):
1991
+ inst = self.get_inst()
1992
+ self._pc = inst.next
1993
+
1994
+ def make_temp(self, prefix=""):
1995
+ if not prefix:
1996
+ name = "${prefix}{offset}{opname}.{tempct}".format(
1997
+ prefix=prefix,
1998
+ offset=self._pc,
1999
+ opname=self.get_inst().opname.lower(),
2000
+ tempct=len(self._temp_registers),
2001
+ )
2002
+ else:
2003
+ name = "${prefix}{offset}.{tempct}".format(
2004
+ prefix=prefix,
2005
+ offset=self._pc,
2006
+ tempct=len(self._temp_registers),
2007
+ )
2008
+
2009
+ self._temp_registers.append(name)
2010
+ return name
2011
+
2012
+ def append(self, inst, **kwargs):
2013
+ """Append new inst"""
2014
+ self._insts.append((inst.offset, kwargs))
2015
+ self._used_regs |= set(_flatten_inst_regs(kwargs.values()))
2016
+
2017
+ def get_tos(self):
2018
+ return self.peek(1)
2019
+
2020
+ def peek(self, k):
2021
+ """Return the k'th element on the stack"""
2022
+ return self._stack[-k]
2023
+
2024
+ def push(self, item):
2025
+ """Push to stack"""
2026
+ self._stack.append(item)
2027
+
2028
+ def pop(self):
2029
+ """Pop the stack"""
2030
+ return self._stack.pop()
2031
+
2032
+ def swap(self, idx):
2033
+ """Swap stack[idx] with the tos"""
2034
+ s = self._stack
2035
+ s[-1], s[-idx] = s[-idx], s[-1]
2036
+
2037
+ def push_block(self, synblk):
2038
+ """Push a block to blockstack"""
2039
+ assert "stack_depth" in synblk
2040
+ self._blockstack.append(synblk)
2041
+
2042
+ def reset_stack(self, depth):
2043
+ """Reset the stack to the given stack depth.
2044
+ Returning the popped items.
2045
+ """
2046
+ self._stack, popped = self._stack[:depth], self._stack[depth:]
2047
+ return popped
2048
+
2049
+ def make_block(self, kind, end, reset_stack=True, handler=None):
2050
+ """Make a new block"""
2051
+ d = {
2052
+ "kind": BlockKind(kind),
2053
+ "end": end,
2054
+ "entry_stack": len(self._stack),
2055
+ }
2056
+ if reset_stack:
2057
+ d["stack_depth"] = len(self._stack)
2058
+ else:
2059
+ d["stack_depth"] = None
2060
+ d["handler"] = handler
2061
+ return d
2062
+
2063
+ def pop_block(self):
2064
+ """Pop a block and unwind the stack"""
2065
+ b = self._blockstack.pop()
2066
+ self.reset_stack(b["stack_depth"])
2067
+ return b
2068
+
2069
+ def pop_block_and_above(self, blk):
2070
+ """Find *blk* in the blockstack and remove it and all blocks above it
2071
+ from the stack.
2072
+ """
2073
+ idx = self._blockstack.index(blk)
2074
+ assert 0 <= idx < len(self._blockstack)
2075
+ self._blockstack = self._blockstack[:idx]
2076
+
2077
+ def get_top_block(self, kind):
2078
+ """Find the first block that matches *kind*"""
2079
+ kind = BlockKind(kind)
2080
+ for bs in reversed(self._blockstack):
2081
+ if bs["kind"] == kind:
2082
+ return bs
2083
+
2084
+ def get_top_block_either(self, *kinds):
2085
+ """Find the first block that matches *kind*"""
2086
+ kinds = {BlockKind(kind) for kind in kinds}
2087
+ for bs in reversed(self._blockstack):
2088
+ if bs["kind"] in kinds:
2089
+ return bs
2090
+
2091
+ def has_active_try(self):
2092
+ """Returns a boolean indicating if the top-block is a *try* block"""
2093
+ return self.get_top_block("TRY") is not None
2094
+
2095
+ def get_varname(self, inst):
2096
+ """Get referenced variable name from the instruction's oparg"""
2097
+ return self.get_varname_by_arg(inst.arg)
2098
+
2099
+ def get_varname_by_arg(self, oparg: int):
2100
+ """Get referenced variable name from the oparg"""
2101
+ return self._bytecode.co_varnames[oparg]
2102
+
2103
+ def terminate(self):
2104
+ """Mark block as terminated"""
2105
+ self._terminated = True
2106
+
2107
+ def fork(self, pc, npop=0, npush=0, extra_block=None):
2108
+ """Fork the state"""
2109
+ # Handle changes on the stack
2110
+ stack = list(self._stack)
2111
+ if npop:
2112
+ assert 0 <= npop <= len(self._stack)
2113
+ nstack = len(self._stack) - npop
2114
+ stack = stack[:nstack]
2115
+ if npush:
2116
+ assert 0 <= npush
2117
+ for i in range(npush):
2118
+ stack.append(self.make_temp())
2119
+ # Handle changes on the blockstack
2120
+ blockstack = list(self._blockstack)
2121
+ if PYVERSION in ((3, 11), (3, 12), (3, 13)):
2122
+ # pop expired block in destination pc
2123
+ while blockstack:
2124
+ top = blockstack[-1]
2125
+ end = top.get("end_offset") or top["end"]
2126
+ if pc >= end:
2127
+ blockstack.pop()
2128
+ else:
2129
+ break
2130
+ elif PYVERSION in (
2131
+ (3, 9),
2132
+ (3, 10),
2133
+ ):
2134
+ pass # intentionally bypass
2135
+ else:
2136
+ raise NotImplementedError(PYVERSION)
2137
+
2138
+ if extra_block:
2139
+ blockstack.append(extra_block)
2140
+ self._outedges.append(
2141
+ Edge(
2142
+ pc=pc,
2143
+ stack=tuple(stack),
2144
+ npush=npush,
2145
+ blockstack=tuple(blockstack),
2146
+ )
2147
+ )
2148
+ self.terminate()
2149
+
2150
+ def split_new_block(self):
2151
+ """Split the state"""
2152
+ self.fork(pc=self._pc)
2153
+
2154
+ def get_outgoing_states(self):
2155
+ """Get states for each outgoing edges"""
2156
+ # Should only call once
2157
+ assert not self._outgoing_phis
2158
+ ret = []
2159
+ for edge in self._outedges:
2160
+ state = State(
2161
+ bytecode=self._bytecode,
2162
+ pc=edge.pc,
2163
+ nstack=len(edge.stack),
2164
+ blockstack=edge.blockstack,
2165
+ nullvals=[
2166
+ i for i, v in enumerate(edge.stack) if _is_null_temp_reg(v)
2167
+ ],
2168
+ )
2169
+ ret.append(state)
2170
+ # Map outgoing_phis
2171
+ for phi, i in state._phis.items():
2172
+ self._outgoing_phis[phi] = edge.stack[i]
2173
+ return ret
2174
+
2175
+ def get_outgoing_edgepushed(self):
2176
+ """
2177
+ Returns
2178
+ -------
2179
+ Dict[int, int]
2180
+ where keys are the PC
2181
+ values are the edge-pushed stack values
2182
+ """
2183
+
2184
+ return {
2185
+ edge.pc: tuple(edge.stack[-edge.npush :]) for edge in self._outedges
2186
+ }
2187
+
2188
+
2189
+ class StatePy311(_State):
2190
+ def __init__(self, *args, **kwargs):
2191
+ super().__init__(*args, **kwargs)
2192
+ self._kw_names = None
2193
+
2194
+ def pop_kw_names(self):
2195
+ out = self._kw_names
2196
+ self._kw_names = None
2197
+ return out
2198
+
2199
+ def set_kw_names(self, val):
2200
+ assert self._kw_names is None
2201
+ self._kw_names = val
2202
+
2203
+ def is_in_exception(self):
2204
+ bc = self._bytecode
2205
+ return bc.find_exception_entry(self._pc) is not None
2206
+
2207
+ def get_exception(self):
2208
+ bc = self._bytecode
2209
+ return bc.find_exception_entry(self._pc)
2210
+
2211
+ def in_with(self):
2212
+ for ent in self._blockstack_initial:
2213
+ if ent["kind"] == BlockKind("WITH"):
2214
+ return True
2215
+
2216
+ def make_null(self):
2217
+ return self.make_temp(prefix="null$")
2218
+
2219
+
2220
+ class StatePy313(StatePy311):
2221
+ def __init__(self, *args, **kwargs):
2222
+ super().__init__(*args, **kwargs)
2223
+ self._make_func_attrs = defaultdict(dict)
2224
+
2225
+ def set_function_attribute(self, make_func_res, **kwargs):
2226
+ self._make_func_attrs[make_func_res].update(kwargs)
2227
+
2228
+ def get_function_attributes(self, make_func_res):
2229
+ return self._make_func_attrs[make_func_res]
2230
+
2231
+
2232
+ if PYVERSION in ((3, 13),):
2233
+ State = StatePy313
2234
+ elif PYVERSION in ((3, 11), (3, 12)):
2235
+ State = StatePy311
2236
+ elif PYVERSION < (3, 11):
2237
+ State = _State
2238
+ else:
2239
+ raise NotImplementedError(PYVERSION)
2240
+
2241
+
2242
+ Edge = namedtuple("Edge", ["pc", "stack", "blockstack", "npush"])
2243
+
2244
+
2245
+ class AdaptDFA(object):
2246
+ """Adapt Flow to the old DFA class expected by Interpreter"""
2247
+
2248
+ def __init__(self, flow):
2249
+ self._flow = flow
2250
+
2251
+ @property
2252
+ def infos(self):
2253
+ return self._flow.block_infos
2254
+
2255
+
2256
+ AdaptBlockInfo = namedtuple(
2257
+ "AdaptBlockInfo",
2258
+ [
2259
+ "insts",
2260
+ "outgoing_phis",
2261
+ "blockstack",
2262
+ "active_try_block",
2263
+ "outgoing_edgepushed",
2264
+ ],
2265
+ )
2266
+
2267
+
2268
+ def adapt_state_infos(state):
2269
+ def process_function_attributes(inst_pair):
2270
+ offset, data = inst_pair
2271
+ inst = state._bytecode[offset]
2272
+ if inst.opname == "MAKE_FUNCTION":
2273
+ data.update(state.get_function_attributes(data["res"]))
2274
+ return offset, data
2275
+
2276
+ if PYVERSION in ((3, 13),):
2277
+ insts = tuple(map(process_function_attributes, state.instructions))
2278
+ elif PYVERSION in ((3, 9), (3, 10), (3, 11), (3, 12)):
2279
+ insts = tuple(state.instructions)
2280
+ else:
2281
+ raise NotImplementedError(PYVERSION)
2282
+ return AdaptBlockInfo(
2283
+ insts=insts,
2284
+ outgoing_phis=state.outgoing_phis,
2285
+ blockstack=state.blockstack_initial,
2286
+ active_try_block=state.find_initial_try_block(),
2287
+ outgoing_edgepushed=state.get_outgoing_edgepushed(),
2288
+ )
2289
+
2290
+
2291
+ def _flatten_inst_regs(iterable):
2292
+ """Flatten an iterable of registers used in an instruction"""
2293
+ for item in iterable:
2294
+ if isinstance(item, str):
2295
+ yield item
2296
+ elif isinstance(item, (tuple, list)):
2297
+ for x in _flatten_inst_regs(item):
2298
+ yield x
2299
+
2300
+
2301
+ class AdaptCFA(object):
2302
+ """Adapt Flow to the old CFA class expected by Interpreter"""
2303
+
2304
+ def __init__(self, flow):
2305
+ self._flow = flow
2306
+ self._blocks = {}
2307
+ for offset, blockinfo in flow.block_infos.items():
2308
+ self._blocks[offset] = AdaptCFBlock(blockinfo, offset)
2309
+ backbone = self._flow.cfgraph.backbone()
2310
+
2311
+ graph = flow.cfgraph
2312
+ # Find backbone
2313
+ backbone = graph.backbone()
2314
+ # Filter out in loop blocks (Assuming no other cyclic control blocks)
2315
+ # This is to unavoid variables defined in loops being considered as
2316
+ # function scope.
2317
+ inloopblocks = set()
2318
+ for b in self.blocks.keys():
2319
+ if graph.in_loops(b):
2320
+ inloopblocks.add(b)
2321
+ self._backbone = backbone - inloopblocks
2322
+
2323
+ @property
2324
+ def graph(self):
2325
+ return self._flow.cfgraph
2326
+
2327
+ @property
2328
+ def backbone(self):
2329
+ return self._backbone
2330
+
2331
+ @property
2332
+ def blocks(self):
2333
+ return self._blocks
2334
+
2335
+ def iterliveblocks(self):
2336
+ for b in sorted(self.blocks):
2337
+ yield self.blocks[b]
2338
+
2339
+ def dump(self):
2340
+ self._flow.cfgraph.dump()
2341
+
2342
+
2343
+ class AdaptCFBlock(object):
2344
+ def __init__(self, blockinfo, offset):
2345
+ self.offset = offset
2346
+ self.body = tuple(i for i, _ in blockinfo.insts)