numba-cuda 0.22.0__cp312-cp312-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.
Potentially problematic release.
This version of numba-cuda might be problematic. Click here for more details.
- _numba_cuda_redirector.pth +4 -0
- _numba_cuda_redirector.py +89 -0
- numba_cuda/VERSION +1 -0
- numba_cuda/__init__.py +6 -0
- numba_cuda/_version.py +11 -0
- numba_cuda/numba/cuda/__init__.py +70 -0
- numba_cuda/numba/cuda/_internal/cuda_bf16.py +16394 -0
- numba_cuda/numba/cuda/_internal/cuda_fp16.py +8112 -0
- numba_cuda/numba/cuda/api.py +580 -0
- numba_cuda/numba/cuda/api_util.py +76 -0
- numba_cuda/numba/cuda/args.py +72 -0
- numba_cuda/numba/cuda/bf16.py +397 -0
- numba_cuda/numba/cuda/cache_hints.py +287 -0
- numba_cuda/numba/cuda/cext/__init__.py +2 -0
- numba_cuda/numba/cuda/cext/_devicearray.cpp +159 -0
- numba_cuda/numba/cuda/cext/_devicearray.cpython-312-aarch64-linux-gnu.so +0 -0
- numba_cuda/numba/cuda/cext/_devicearray.h +29 -0
- numba_cuda/numba/cuda/cext/_dispatcher.cpp +1098 -0
- numba_cuda/numba/cuda/cext/_dispatcher.cpython-312-aarch64-linux-gnu.so +0 -0
- numba_cuda/numba/cuda/cext/_hashtable.cpp +532 -0
- numba_cuda/numba/cuda/cext/_hashtable.h +135 -0
- numba_cuda/numba/cuda/cext/_helperlib.c +71 -0
- numba_cuda/numba/cuda/cext/_helperlib.cpython-312-aarch64-linux-gnu.so +0 -0
- numba_cuda/numba/cuda/cext/_helpermod.c +82 -0
- numba_cuda/numba/cuda/cext/_pymodule.h +38 -0
- numba_cuda/numba/cuda/cext/_typeconv.cpp +206 -0
- numba_cuda/numba/cuda/cext/_typeconv.cpython-312-aarch64-linux-gnu.so +0 -0
- numba_cuda/numba/cuda/cext/_typeof.cpp +1159 -0
- numba_cuda/numba/cuda/cext/_typeof.h +19 -0
- numba_cuda/numba/cuda/cext/capsulethunk.h +111 -0
- numba_cuda/numba/cuda/cext/mviewbuf.c +385 -0
- numba_cuda/numba/cuda/cext/mviewbuf.cpython-312-aarch64-linux-gnu.so +0 -0
- numba_cuda/numba/cuda/cext/typeconv.cpp +212 -0
- numba_cuda/numba/cuda/cext/typeconv.hpp +101 -0
- numba_cuda/numba/cuda/cg.py +67 -0
- numba_cuda/numba/cuda/cgutils.py +1294 -0
- numba_cuda/numba/cuda/cloudpickle/__init__.py +21 -0
- numba_cuda/numba/cuda/cloudpickle/cloudpickle.py +1598 -0
- numba_cuda/numba/cuda/cloudpickle/cloudpickle_fast.py +17 -0
- numba_cuda/numba/cuda/codegen.py +541 -0
- numba_cuda/numba/cuda/compiler.py +1396 -0
- numba_cuda/numba/cuda/core/analysis.py +758 -0
- numba_cuda/numba/cuda/core/annotations/__init__.py +0 -0
- numba_cuda/numba/cuda/core/annotations/pretty_annotate.py +288 -0
- numba_cuda/numba/cuda/core/annotations/type_annotations.py +305 -0
- numba_cuda/numba/cuda/core/base.py +1332 -0
- numba_cuda/numba/cuda/core/boxing.py +1411 -0
- numba_cuda/numba/cuda/core/bytecode.py +728 -0
- numba_cuda/numba/cuda/core/byteflow.py +2346 -0
- numba_cuda/numba/cuda/core/caching.py +744 -0
- numba_cuda/numba/cuda/core/callconv.py +392 -0
- numba_cuda/numba/cuda/core/codegen.py +171 -0
- numba_cuda/numba/cuda/core/compiler.py +199 -0
- numba_cuda/numba/cuda/core/compiler_lock.py +85 -0
- numba_cuda/numba/cuda/core/compiler_machinery.py +497 -0
- numba_cuda/numba/cuda/core/config.py +650 -0
- numba_cuda/numba/cuda/core/consts.py +124 -0
- numba_cuda/numba/cuda/core/controlflow.py +989 -0
- numba_cuda/numba/cuda/core/entrypoints.py +57 -0
- numba_cuda/numba/cuda/core/environment.py +66 -0
- numba_cuda/numba/cuda/core/errors.py +917 -0
- numba_cuda/numba/cuda/core/event.py +511 -0
- numba_cuda/numba/cuda/core/funcdesc.py +330 -0
- numba_cuda/numba/cuda/core/generators.py +387 -0
- numba_cuda/numba/cuda/core/imputils.py +509 -0
- numba_cuda/numba/cuda/core/inline_closurecall.py +1787 -0
- numba_cuda/numba/cuda/core/interpreter.py +3617 -0
- numba_cuda/numba/cuda/core/ir.py +1812 -0
- numba_cuda/numba/cuda/core/ir_utils.py +2638 -0
- numba_cuda/numba/cuda/core/optional.py +129 -0
- numba_cuda/numba/cuda/core/options.py +262 -0
- numba_cuda/numba/cuda/core/postproc.py +249 -0
- numba_cuda/numba/cuda/core/pythonapi.py +1859 -0
- numba_cuda/numba/cuda/core/registry.py +46 -0
- numba_cuda/numba/cuda/core/removerefctpass.py +123 -0
- numba_cuda/numba/cuda/core/rewrites/__init__.py +26 -0
- numba_cuda/numba/cuda/core/rewrites/ir_print.py +91 -0
- numba_cuda/numba/cuda/core/rewrites/registry.py +104 -0
- numba_cuda/numba/cuda/core/rewrites/static_binop.py +41 -0
- numba_cuda/numba/cuda/core/rewrites/static_getitem.py +189 -0
- numba_cuda/numba/cuda/core/rewrites/static_raise.py +100 -0
- numba_cuda/numba/cuda/core/sigutils.py +68 -0
- numba_cuda/numba/cuda/core/ssa.py +498 -0
- numba_cuda/numba/cuda/core/targetconfig.py +330 -0
- numba_cuda/numba/cuda/core/tracing.py +231 -0
- numba_cuda/numba/cuda/core/transforms.py +956 -0
- numba_cuda/numba/cuda/core/typed_passes.py +867 -0
- numba_cuda/numba/cuda/core/typeinfer.py +1950 -0
- numba_cuda/numba/cuda/core/unsafe/__init__.py +0 -0
- numba_cuda/numba/cuda/core/unsafe/bytes.py +67 -0
- numba_cuda/numba/cuda/core/unsafe/eh.py +67 -0
- numba_cuda/numba/cuda/core/unsafe/refcount.py +98 -0
- numba_cuda/numba/cuda/core/untyped_passes.py +1979 -0
- numba_cuda/numba/cuda/cpython/builtins.py +1153 -0
- numba_cuda/numba/cuda/cpython/charseq.py +1218 -0
- numba_cuda/numba/cuda/cpython/cmathimpl.py +560 -0
- numba_cuda/numba/cuda/cpython/enumimpl.py +103 -0
- numba_cuda/numba/cuda/cpython/iterators.py +167 -0
- numba_cuda/numba/cuda/cpython/listobj.py +1326 -0
- numba_cuda/numba/cuda/cpython/mathimpl.py +499 -0
- numba_cuda/numba/cuda/cpython/numbers.py +1475 -0
- numba_cuda/numba/cuda/cpython/rangeobj.py +289 -0
- numba_cuda/numba/cuda/cpython/slicing.py +322 -0
- numba_cuda/numba/cuda/cpython/tupleobj.py +456 -0
- numba_cuda/numba/cuda/cpython/unicode.py +2865 -0
- numba_cuda/numba/cuda/cpython/unicode_support.py +1597 -0
- numba_cuda/numba/cuda/cpython/unsafe/__init__.py +0 -0
- numba_cuda/numba/cuda/cpython/unsafe/numbers.py +64 -0
- numba_cuda/numba/cuda/cpython/unsafe/tuple.py +92 -0
- numba_cuda/numba/cuda/cuda_paths.py +691 -0
- numba_cuda/numba/cuda/cudadecl.py +543 -0
- numba_cuda/numba/cuda/cudadrv/__init__.py +14 -0
- numba_cuda/numba/cuda/cudadrv/devicearray.py +954 -0
- numba_cuda/numba/cuda/cudadrv/devices.py +249 -0
- numba_cuda/numba/cuda/cudadrv/driver.py +3238 -0
- numba_cuda/numba/cuda/cudadrv/drvapi.py +435 -0
- numba_cuda/numba/cuda/cudadrv/dummyarray.py +562 -0
- numba_cuda/numba/cuda/cudadrv/enums.py +613 -0
- numba_cuda/numba/cuda/cudadrv/error.py +48 -0
- numba_cuda/numba/cuda/cudadrv/libs.py +220 -0
- numba_cuda/numba/cuda/cudadrv/linkable_code.py +184 -0
- numba_cuda/numba/cuda/cudadrv/mappings.py +14 -0
- numba_cuda/numba/cuda/cudadrv/ndarray.py +26 -0
- numba_cuda/numba/cuda/cudadrv/nvrtc.py +193 -0
- numba_cuda/numba/cuda/cudadrv/nvvm.py +756 -0
- numba_cuda/numba/cuda/cudadrv/rtapi.py +13 -0
- numba_cuda/numba/cuda/cudadrv/runtime.py +34 -0
- numba_cuda/numba/cuda/cudaimpl.py +983 -0
- numba_cuda/numba/cuda/cudamath.py +149 -0
- numba_cuda/numba/cuda/datamodel/__init__.py +7 -0
- numba_cuda/numba/cuda/datamodel/cuda_manager.py +66 -0
- numba_cuda/numba/cuda/datamodel/cuda_models.py +1446 -0
- numba_cuda/numba/cuda/datamodel/cuda_packer.py +224 -0
- numba_cuda/numba/cuda/datamodel/cuda_registry.py +22 -0
- numba_cuda/numba/cuda/datamodel/cuda_testing.py +153 -0
- numba_cuda/numba/cuda/datamodel/manager.py +11 -0
- numba_cuda/numba/cuda/datamodel/models.py +9 -0
- numba_cuda/numba/cuda/datamodel/packer.py +9 -0
- numba_cuda/numba/cuda/datamodel/registry.py +11 -0
- numba_cuda/numba/cuda/datamodel/testing.py +11 -0
- numba_cuda/numba/cuda/debuginfo.py +997 -0
- numba_cuda/numba/cuda/decorators.py +294 -0
- numba_cuda/numba/cuda/descriptor.py +35 -0
- numba_cuda/numba/cuda/device_init.py +155 -0
- numba_cuda/numba/cuda/deviceufunc.py +1021 -0
- numba_cuda/numba/cuda/dispatcher.py +2463 -0
- numba_cuda/numba/cuda/errors.py +72 -0
- numba_cuda/numba/cuda/extending.py +697 -0
- numba_cuda/numba/cuda/flags.py +178 -0
- numba_cuda/numba/cuda/fp16.py +357 -0
- numba_cuda/numba/cuda/include/12/cuda_bf16.h +5118 -0
- numba_cuda/numba/cuda/include/12/cuda_bf16.hpp +3865 -0
- numba_cuda/numba/cuda/include/12/cuda_fp16.h +5363 -0
- numba_cuda/numba/cuda/include/12/cuda_fp16.hpp +3483 -0
- numba_cuda/numba/cuda/include/13/cuda_bf16.h +5118 -0
- numba_cuda/numba/cuda/include/13/cuda_bf16.hpp +3865 -0
- numba_cuda/numba/cuda/include/13/cuda_fp16.h +5363 -0
- numba_cuda/numba/cuda/include/13/cuda_fp16.hpp +3483 -0
- numba_cuda/numba/cuda/initialize.py +24 -0
- numba_cuda/numba/cuda/intrinsics.py +531 -0
- numba_cuda/numba/cuda/itanium_mangler.py +214 -0
- numba_cuda/numba/cuda/kernels/__init__.py +2 -0
- numba_cuda/numba/cuda/kernels/reduction.py +265 -0
- numba_cuda/numba/cuda/kernels/transpose.py +65 -0
- numba_cuda/numba/cuda/libdevice.py +3386 -0
- numba_cuda/numba/cuda/libdevicedecl.py +20 -0
- numba_cuda/numba/cuda/libdevicefuncs.py +1060 -0
- numba_cuda/numba/cuda/libdeviceimpl.py +88 -0
- numba_cuda/numba/cuda/locks.py +19 -0
- numba_cuda/numba/cuda/lowering.py +1980 -0
- numba_cuda/numba/cuda/mathimpl.py +374 -0
- numba_cuda/numba/cuda/memory_management/__init__.py +4 -0
- numba_cuda/numba/cuda/memory_management/memsys.cu +99 -0
- numba_cuda/numba/cuda/memory_management/memsys.cuh +22 -0
- numba_cuda/numba/cuda/memory_management/nrt.cu +212 -0
- numba_cuda/numba/cuda/memory_management/nrt.cuh +48 -0
- numba_cuda/numba/cuda/memory_management/nrt.py +390 -0
- numba_cuda/numba/cuda/memory_management/nrt_context.py +438 -0
- numba_cuda/numba/cuda/misc/appdirs.py +594 -0
- numba_cuda/numba/cuda/misc/cffiimpl.py +24 -0
- numba_cuda/numba/cuda/misc/coverage_support.py +43 -0
- numba_cuda/numba/cuda/misc/dump_style.py +41 -0
- numba_cuda/numba/cuda/misc/findlib.py +75 -0
- numba_cuda/numba/cuda/misc/firstlinefinder.py +96 -0
- numba_cuda/numba/cuda/misc/gdb_hook.py +240 -0
- numba_cuda/numba/cuda/misc/literal.py +28 -0
- numba_cuda/numba/cuda/misc/llvm_pass_timings.py +412 -0
- numba_cuda/numba/cuda/misc/special.py +94 -0
- numba_cuda/numba/cuda/models.py +56 -0
- numba_cuda/numba/cuda/np/arraymath.py +5130 -0
- numba_cuda/numba/cuda/np/arrayobj.py +7635 -0
- numba_cuda/numba/cuda/np/extensions.py +11 -0
- numba_cuda/numba/cuda/np/linalg.py +3087 -0
- numba_cuda/numba/cuda/np/math/__init__.py +0 -0
- numba_cuda/numba/cuda/np/math/cmathimpl.py +558 -0
- numba_cuda/numba/cuda/np/math/mathimpl.py +487 -0
- numba_cuda/numba/cuda/np/math/numbers.py +1461 -0
- numba_cuda/numba/cuda/np/npdatetime.py +969 -0
- numba_cuda/numba/cuda/np/npdatetime_helpers.py +217 -0
- numba_cuda/numba/cuda/np/npyfuncs.py +1808 -0
- numba_cuda/numba/cuda/np/npyimpl.py +1027 -0
- numba_cuda/numba/cuda/np/numpy_support.py +798 -0
- numba_cuda/numba/cuda/np/polynomial/__init__.py +4 -0
- numba_cuda/numba/cuda/np/polynomial/polynomial_core.py +242 -0
- numba_cuda/numba/cuda/np/polynomial/polynomial_functions.py +380 -0
- numba_cuda/numba/cuda/np/ufunc/__init__.py +4 -0
- numba_cuda/numba/cuda/np/ufunc/decorators.py +203 -0
- numba_cuda/numba/cuda/np/ufunc/sigparse.py +68 -0
- numba_cuda/numba/cuda/np/ufunc/ufuncbuilder.py +65 -0
- numba_cuda/numba/cuda/np/ufunc_db.py +1282 -0
- numba_cuda/numba/cuda/np/unsafe/__init__.py +0 -0
- numba_cuda/numba/cuda/np/unsafe/ndarray.py +84 -0
- numba_cuda/numba/cuda/nvvmutils.py +254 -0
- numba_cuda/numba/cuda/printimpl.py +126 -0
- numba_cuda/numba/cuda/random.py +308 -0
- numba_cuda/numba/cuda/reshape_funcs.cu +156 -0
- numba_cuda/numba/cuda/serialize.py +267 -0
- numba_cuda/numba/cuda/simulator/__init__.py +63 -0
- numba_cuda/numba/cuda/simulator/_internal/__init__.py +4 -0
- numba_cuda/numba/cuda/simulator/_internal/cuda_bf16.py +2 -0
- numba_cuda/numba/cuda/simulator/api.py +179 -0
- numba_cuda/numba/cuda/simulator/bf16.py +4 -0
- numba_cuda/numba/cuda/simulator/compiler.py +38 -0
- numba_cuda/numba/cuda/simulator/cudadrv/__init__.py +11 -0
- numba_cuda/numba/cuda/simulator/cudadrv/devicearray.py +462 -0
- numba_cuda/numba/cuda/simulator/cudadrv/devices.py +122 -0
- numba_cuda/numba/cuda/simulator/cudadrv/driver.py +66 -0
- numba_cuda/numba/cuda/simulator/cudadrv/drvapi.py +7 -0
- numba_cuda/numba/cuda/simulator/cudadrv/dummyarray.py +7 -0
- numba_cuda/numba/cuda/simulator/cudadrv/error.py +10 -0
- numba_cuda/numba/cuda/simulator/cudadrv/libs.py +10 -0
- numba_cuda/numba/cuda/simulator/cudadrv/linkable_code.py +61 -0
- numba_cuda/numba/cuda/simulator/cudadrv/nvrtc.py +11 -0
- numba_cuda/numba/cuda/simulator/cudadrv/nvvm.py +32 -0
- numba_cuda/numba/cuda/simulator/cudadrv/runtime.py +22 -0
- numba_cuda/numba/cuda/simulator/dispatcher.py +11 -0
- numba_cuda/numba/cuda/simulator/kernel.py +320 -0
- numba_cuda/numba/cuda/simulator/kernelapi.py +509 -0
- numba_cuda/numba/cuda/simulator/memory_management/__init__.py +4 -0
- numba_cuda/numba/cuda/simulator/memory_management/nrt.py +21 -0
- numba_cuda/numba/cuda/simulator/reduction.py +19 -0
- numba_cuda/numba/cuda/simulator/tests/support.py +4 -0
- numba_cuda/numba/cuda/simulator/vector_types.py +65 -0
- numba_cuda/numba/cuda/simulator_init.py +18 -0
- numba_cuda/numba/cuda/stubs.py +624 -0
- numba_cuda/numba/cuda/target.py +505 -0
- numba_cuda/numba/cuda/testing.py +347 -0
- numba_cuda/numba/cuda/tests/__init__.py +62 -0
- numba_cuda/numba/cuda/tests/benchmarks/__init__.py +0 -0
- numba_cuda/numba/cuda/tests/benchmarks/test_kernel_launch.py +119 -0
- numba_cuda/numba/cuda/tests/cloudpickle_main_class.py +9 -0
- numba_cuda/numba/cuda/tests/core/serialize_usecases.py +113 -0
- numba_cuda/numba/cuda/tests/core/test_itanium_mangler.py +83 -0
- numba_cuda/numba/cuda/tests/core/test_serialize.py +371 -0
- numba_cuda/numba/cuda/tests/cudadrv/__init__.py +9 -0
- numba_cuda/numba/cuda/tests/cudadrv/test_array_attr.py +147 -0
- numba_cuda/numba/cuda/tests/cudadrv/test_context_stack.py +161 -0
- numba_cuda/numba/cuda/tests/cudadrv/test_cuda_array_slicing.py +397 -0
- numba_cuda/numba/cuda/tests/cudadrv/test_cuda_auto_context.py +24 -0
- numba_cuda/numba/cuda/tests/cudadrv/test_cuda_devicerecord.py +180 -0
- numba_cuda/numba/cuda/tests/cudadrv/test_cuda_driver.py +313 -0
- numba_cuda/numba/cuda/tests/cudadrv/test_cuda_memory.py +191 -0
- numba_cuda/numba/cuda/tests/cudadrv/test_cuda_ndarray.py +621 -0
- numba_cuda/numba/cuda/tests/cudadrv/test_deallocations.py +247 -0
- numba_cuda/numba/cuda/tests/cudadrv/test_detect.py +100 -0
- numba_cuda/numba/cuda/tests/cudadrv/test_emm_plugins.py +200 -0
- numba_cuda/numba/cuda/tests/cudadrv/test_events.py +53 -0
- numba_cuda/numba/cuda/tests/cudadrv/test_host_alloc.py +72 -0
- numba_cuda/numba/cuda/tests/cudadrv/test_init.py +138 -0
- numba_cuda/numba/cuda/tests/cudadrv/test_inline_ptx.py +43 -0
- numba_cuda/numba/cuda/tests/cudadrv/test_is_fp16.py +15 -0
- numba_cuda/numba/cuda/tests/cudadrv/test_linkable_code.py +58 -0
- numba_cuda/numba/cuda/tests/cudadrv/test_linker.py +348 -0
- numba_cuda/numba/cuda/tests/cudadrv/test_managed_alloc.py +128 -0
- numba_cuda/numba/cuda/tests/cudadrv/test_module_callbacks.py +301 -0
- numba_cuda/numba/cuda/tests/cudadrv/test_nvjitlink.py +174 -0
- numba_cuda/numba/cuda/tests/cudadrv/test_nvrtc.py +28 -0
- numba_cuda/numba/cuda/tests/cudadrv/test_nvvm_driver.py +185 -0
- numba_cuda/numba/cuda/tests/cudadrv/test_pinned.py +39 -0
- numba_cuda/numba/cuda/tests/cudadrv/test_profiler.py +23 -0
- numba_cuda/numba/cuda/tests/cudadrv/test_reset_device.py +38 -0
- numba_cuda/numba/cuda/tests/cudadrv/test_runtime.py +48 -0
- numba_cuda/numba/cuda/tests/cudadrv/test_select_device.py +44 -0
- numba_cuda/numba/cuda/tests/cudadrv/test_streams.py +127 -0
- numba_cuda/numba/cuda/tests/cudapy/__init__.py +9 -0
- numba_cuda/numba/cuda/tests/cudapy/cache_usecases.py +231 -0
- numba_cuda/numba/cuda/tests/cudapy/cache_with_cpu_usecases.py +50 -0
- numba_cuda/numba/cuda/tests/cudapy/cg_cache_usecases.py +36 -0
- numba_cuda/numba/cuda/tests/cudapy/complex_usecases.py +116 -0
- numba_cuda/numba/cuda/tests/cudapy/enum_usecases.py +59 -0
- numba_cuda/numba/cuda/tests/cudapy/extensions_usecases.py +62 -0
- numba_cuda/numba/cuda/tests/cudapy/jitlink.ptx +28 -0
- numba_cuda/numba/cuda/tests/cudapy/overload_usecases.py +33 -0
- numba_cuda/numba/cuda/tests/cudapy/recursion_usecases.py +104 -0
- numba_cuda/numba/cuda/tests/cudapy/test_alignment.py +47 -0
- numba_cuda/numba/cuda/tests/cudapy/test_analysis.py +1122 -0
- numba_cuda/numba/cuda/tests/cudapy/test_array.py +344 -0
- numba_cuda/numba/cuda/tests/cudapy/test_array_alignment.py +268 -0
- numba_cuda/numba/cuda/tests/cudapy/test_array_args.py +203 -0
- numba_cuda/numba/cuda/tests/cudapy/test_array_methods.py +63 -0
- numba_cuda/numba/cuda/tests/cudapy/test_array_reductions.py +360 -0
- numba_cuda/numba/cuda/tests/cudapy/test_atomics.py +1815 -0
- numba_cuda/numba/cuda/tests/cudapy/test_bfloat16.py +599 -0
- numba_cuda/numba/cuda/tests/cudapy/test_bfloat16_bindings.py +377 -0
- numba_cuda/numba/cuda/tests/cudapy/test_blackscholes.py +160 -0
- numba_cuda/numba/cuda/tests/cudapy/test_boolean.py +27 -0
- numba_cuda/numba/cuda/tests/cudapy/test_byteflow.py +98 -0
- numba_cuda/numba/cuda/tests/cudapy/test_cache_hints.py +210 -0
- numba_cuda/numba/cuda/tests/cudapy/test_caching.py +683 -0
- numba_cuda/numba/cuda/tests/cudapy/test_casting.py +265 -0
- numba_cuda/numba/cuda/tests/cudapy/test_cffi.py +42 -0
- numba_cuda/numba/cuda/tests/cudapy/test_compiler.py +718 -0
- numba_cuda/numba/cuda/tests/cudapy/test_complex.py +370 -0
- numba_cuda/numba/cuda/tests/cudapy/test_complex_kernel.py +23 -0
- numba_cuda/numba/cuda/tests/cudapy/test_const_string.py +142 -0
- numba_cuda/numba/cuda/tests/cudapy/test_constmem.py +178 -0
- numba_cuda/numba/cuda/tests/cudapy/test_cooperative_groups.py +193 -0
- numba_cuda/numba/cuda/tests/cudapy/test_copy_propagate.py +131 -0
- numba_cuda/numba/cuda/tests/cudapy/test_cuda_array_interface.py +438 -0
- numba_cuda/numba/cuda/tests/cudapy/test_cuda_jit_no_types.py +94 -0
- numba_cuda/numba/cuda/tests/cudapy/test_datetime.py +101 -0
- numba_cuda/numba/cuda/tests/cudapy/test_debug.py +105 -0
- numba_cuda/numba/cuda/tests/cudapy/test_debuginfo.py +978 -0
- numba_cuda/numba/cuda/tests/cudapy/test_debuginfo_types.py +476 -0
- numba_cuda/numba/cuda/tests/cudapy/test_device_func.py +500 -0
- numba_cuda/numba/cuda/tests/cudapy/test_dispatcher.py +820 -0
- numba_cuda/numba/cuda/tests/cudapy/test_enums.py +152 -0
- numba_cuda/numba/cuda/tests/cudapy/test_errors.py +111 -0
- numba_cuda/numba/cuda/tests/cudapy/test_exception.py +170 -0
- numba_cuda/numba/cuda/tests/cudapy/test_extending.py +1088 -0
- numba_cuda/numba/cuda/tests/cudapy/test_extending_types.py +71 -0
- numba_cuda/numba/cuda/tests/cudapy/test_fastmath.py +265 -0
- numba_cuda/numba/cuda/tests/cudapy/test_flow_control.py +1433 -0
- numba_cuda/numba/cuda/tests/cudapy/test_forall.py +57 -0
- numba_cuda/numba/cuda/tests/cudapy/test_freevar.py +34 -0
- numba_cuda/numba/cuda/tests/cudapy/test_frexp_ldexp.py +69 -0
- numba_cuda/numba/cuda/tests/cudapy/test_globals.py +62 -0
- numba_cuda/numba/cuda/tests/cudapy/test_gufunc.py +474 -0
- numba_cuda/numba/cuda/tests/cudapy/test_gufunc_scalar.py +167 -0
- numba_cuda/numba/cuda/tests/cudapy/test_gufunc_scheduling.py +92 -0
- numba_cuda/numba/cuda/tests/cudapy/test_idiv.py +39 -0
- numba_cuda/numba/cuda/tests/cudapy/test_inline.py +170 -0
- numba_cuda/numba/cuda/tests/cudapy/test_inspect.py +255 -0
- numba_cuda/numba/cuda/tests/cudapy/test_intrinsics.py +1219 -0
- numba_cuda/numba/cuda/tests/cudapy/test_ipc.py +263 -0
- numba_cuda/numba/cuda/tests/cudapy/test_ir.py +598 -0
- numba_cuda/numba/cuda/tests/cudapy/test_ir_utils.py +276 -0
- numba_cuda/numba/cuda/tests/cudapy/test_iterators.py +101 -0
- numba_cuda/numba/cuda/tests/cudapy/test_lang.py +68 -0
- numba_cuda/numba/cuda/tests/cudapy/test_laplace.py +123 -0
- numba_cuda/numba/cuda/tests/cudapy/test_libdevice.py +194 -0
- numba_cuda/numba/cuda/tests/cudapy/test_lineinfo.py +220 -0
- numba_cuda/numba/cuda/tests/cudapy/test_localmem.py +173 -0
- numba_cuda/numba/cuda/tests/cudapy/test_make_function_to_jit_function.py +364 -0
- numba_cuda/numba/cuda/tests/cudapy/test_mandel.py +47 -0
- numba_cuda/numba/cuda/tests/cudapy/test_math.py +842 -0
- numba_cuda/numba/cuda/tests/cudapy/test_matmul.py +76 -0
- numba_cuda/numba/cuda/tests/cudapy/test_minmax.py +78 -0
- numba_cuda/numba/cuda/tests/cudapy/test_montecarlo.py +25 -0
- numba_cuda/numba/cuda/tests/cudapy/test_multigpu.py +145 -0
- numba_cuda/numba/cuda/tests/cudapy/test_multiprocessing.py +39 -0
- numba_cuda/numba/cuda/tests/cudapy/test_multithreads.py +82 -0
- numba_cuda/numba/cuda/tests/cudapy/test_nondet.py +53 -0
- numba_cuda/numba/cuda/tests/cudapy/test_operator.py +504 -0
- numba_cuda/numba/cuda/tests/cudapy/test_optimization.py +93 -0
- numba_cuda/numba/cuda/tests/cudapy/test_overload.py +402 -0
- numba_cuda/numba/cuda/tests/cudapy/test_powi.py +128 -0
- numba_cuda/numba/cuda/tests/cudapy/test_print.py +193 -0
- numba_cuda/numba/cuda/tests/cudapy/test_py2_div_issue.py +37 -0
- numba_cuda/numba/cuda/tests/cudapy/test_random.py +117 -0
- numba_cuda/numba/cuda/tests/cudapy/test_record_dtype.py +614 -0
- numba_cuda/numba/cuda/tests/cudapy/test_recursion.py +130 -0
- numba_cuda/numba/cuda/tests/cudapy/test_reduction.py +94 -0
- numba_cuda/numba/cuda/tests/cudapy/test_retrieve_autoconverted_arrays.py +83 -0
- numba_cuda/numba/cuda/tests/cudapy/test_serialize.py +86 -0
- numba_cuda/numba/cuda/tests/cudapy/test_slicing.py +40 -0
- numba_cuda/numba/cuda/tests/cudapy/test_sm.py +457 -0
- numba_cuda/numba/cuda/tests/cudapy/test_sm_creation.py +233 -0
- numba_cuda/numba/cuda/tests/cudapy/test_ssa.py +454 -0
- numba_cuda/numba/cuda/tests/cudapy/test_stream_api.py +56 -0
- numba_cuda/numba/cuda/tests/cudapy/test_sync.py +277 -0
- numba_cuda/numba/cuda/tests/cudapy/test_tracing.py +200 -0
- numba_cuda/numba/cuda/tests/cudapy/test_transpose.py +90 -0
- numba_cuda/numba/cuda/tests/cudapy/test_typeconv.py +333 -0
- numba_cuda/numba/cuda/tests/cudapy/test_typeinfer.py +538 -0
- numba_cuda/numba/cuda/tests/cudapy/test_ufuncs.py +585 -0
- numba_cuda/numba/cuda/tests/cudapy/test_userexc.py +42 -0
- numba_cuda/numba/cuda/tests/cudapy/test_vector_type.py +485 -0
- numba_cuda/numba/cuda/tests/cudapy/test_vectorize.py +312 -0
- numba_cuda/numba/cuda/tests/cudapy/test_vectorize_complex.py +23 -0
- numba_cuda/numba/cuda/tests/cudapy/test_vectorize_decor.py +183 -0
- numba_cuda/numba/cuda/tests/cudapy/test_vectorize_device.py +40 -0
- numba_cuda/numba/cuda/tests/cudapy/test_vectorize_scalar_arg.py +40 -0
- numba_cuda/numba/cuda/tests/cudapy/test_warning.py +206 -0
- numba_cuda/numba/cuda/tests/cudapy/test_warp_ops.py +446 -0
- numba_cuda/numba/cuda/tests/cudasim/__init__.py +9 -0
- numba_cuda/numba/cuda/tests/cudasim/support.py +9 -0
- numba_cuda/numba/cuda/tests/cudasim/test_cudasim_issues.py +111 -0
- numba_cuda/numba/cuda/tests/data/__init__.py +2 -0
- numba_cuda/numba/cuda/tests/data/cta_barrier.cu +28 -0
- numba_cuda/numba/cuda/tests/data/cuda_include.cu +10 -0
- numba_cuda/numba/cuda/tests/data/error.cu +12 -0
- numba_cuda/numba/cuda/tests/data/include/add.cuh +8 -0
- numba_cuda/numba/cuda/tests/data/jitlink.cu +28 -0
- numba_cuda/numba/cuda/tests/data/jitlink.ptx +49 -0
- numba_cuda/numba/cuda/tests/data/warn.cu +12 -0
- numba_cuda/numba/cuda/tests/doc_examples/__init__.py +9 -0
- numba_cuda/numba/cuda/tests/doc_examples/ffi/__init__.py +2 -0
- numba_cuda/numba/cuda/tests/doc_examples/ffi/functions.cu +54 -0
- numba_cuda/numba/cuda/tests/doc_examples/ffi/include/mul.cuh +8 -0
- numba_cuda/numba/cuda/tests/doc_examples/ffi/saxpy.cu +14 -0
- numba_cuda/numba/cuda/tests/doc_examples/test_cg.py +86 -0
- numba_cuda/numba/cuda/tests/doc_examples/test_cpointer.py +68 -0
- numba_cuda/numba/cuda/tests/doc_examples/test_cpu_gpu_compat.py +81 -0
- numba_cuda/numba/cuda/tests/doc_examples/test_ffi.py +141 -0
- numba_cuda/numba/cuda/tests/doc_examples/test_laplace.py +160 -0
- numba_cuda/numba/cuda/tests/doc_examples/test_matmul.py +180 -0
- numba_cuda/numba/cuda/tests/doc_examples/test_montecarlo.py +119 -0
- numba_cuda/numba/cuda/tests/doc_examples/test_random.py +66 -0
- numba_cuda/numba/cuda/tests/doc_examples/test_reduction.py +80 -0
- numba_cuda/numba/cuda/tests/doc_examples/test_sessionize.py +206 -0
- numba_cuda/numba/cuda/tests/doc_examples/test_ufunc.py +53 -0
- numba_cuda/numba/cuda/tests/doc_examples/test_vecadd.py +76 -0
- numba_cuda/numba/cuda/tests/nocuda/__init__.py +9 -0
- numba_cuda/numba/cuda/tests/nocuda/test_dummyarray.py +452 -0
- numba_cuda/numba/cuda/tests/nocuda/test_function_resolution.py +48 -0
- numba_cuda/numba/cuda/tests/nocuda/test_import.py +63 -0
- numba_cuda/numba/cuda/tests/nocuda/test_library_lookup.py +252 -0
- numba_cuda/numba/cuda/tests/nocuda/test_nvvm.py +59 -0
- numba_cuda/numba/cuda/tests/nrt/__init__.py +9 -0
- numba_cuda/numba/cuda/tests/nrt/test_nrt.py +387 -0
- numba_cuda/numba/cuda/tests/nrt/test_nrt_refct.py +124 -0
- numba_cuda/numba/cuda/tests/support.py +900 -0
- numba_cuda/numba/cuda/typeconv/__init__.py +4 -0
- numba_cuda/numba/cuda/typeconv/castgraph.py +137 -0
- numba_cuda/numba/cuda/typeconv/rules.py +63 -0
- numba_cuda/numba/cuda/typeconv/typeconv.py +121 -0
- numba_cuda/numba/cuda/types/__init__.py +233 -0
- numba_cuda/numba/cuda/types/__init__.pyi +167 -0
- numba_cuda/numba/cuda/types/abstract.py +9 -0
- numba_cuda/numba/cuda/types/common.py +9 -0
- numba_cuda/numba/cuda/types/containers.py +9 -0
- numba_cuda/numba/cuda/types/cuda_abstract.py +533 -0
- numba_cuda/numba/cuda/types/cuda_common.py +110 -0
- numba_cuda/numba/cuda/types/cuda_containers.py +971 -0
- numba_cuda/numba/cuda/types/cuda_function_type.py +230 -0
- numba_cuda/numba/cuda/types/cuda_functions.py +798 -0
- numba_cuda/numba/cuda/types/cuda_iterators.py +120 -0
- numba_cuda/numba/cuda/types/cuda_misc.py +569 -0
- numba_cuda/numba/cuda/types/cuda_npytypes.py +690 -0
- numba_cuda/numba/cuda/types/cuda_scalars.py +280 -0
- numba_cuda/numba/cuda/types/ext_types.py +101 -0
- numba_cuda/numba/cuda/types/function_type.py +11 -0
- numba_cuda/numba/cuda/types/functions.py +9 -0
- numba_cuda/numba/cuda/types/iterators.py +9 -0
- numba_cuda/numba/cuda/types/misc.py +9 -0
- numba_cuda/numba/cuda/types/npytypes.py +9 -0
- numba_cuda/numba/cuda/types/scalars.py +9 -0
- numba_cuda/numba/cuda/typing/__init__.py +19 -0
- numba_cuda/numba/cuda/typing/arraydecl.py +939 -0
- numba_cuda/numba/cuda/typing/asnumbatype.py +130 -0
- numba_cuda/numba/cuda/typing/bufproto.py +70 -0
- numba_cuda/numba/cuda/typing/builtins.py +1209 -0
- numba_cuda/numba/cuda/typing/cffi_utils.py +219 -0
- numba_cuda/numba/cuda/typing/cmathdecl.py +47 -0
- numba_cuda/numba/cuda/typing/collections.py +138 -0
- numba_cuda/numba/cuda/typing/context.py +782 -0
- numba_cuda/numba/cuda/typing/ctypes_utils.py +125 -0
- numba_cuda/numba/cuda/typing/dictdecl.py +63 -0
- numba_cuda/numba/cuda/typing/enumdecl.py +74 -0
- numba_cuda/numba/cuda/typing/listdecl.py +147 -0
- numba_cuda/numba/cuda/typing/mathdecl.py +158 -0
- numba_cuda/numba/cuda/typing/npdatetime.py +322 -0
- numba_cuda/numba/cuda/typing/npydecl.py +749 -0
- numba_cuda/numba/cuda/typing/setdecl.py +115 -0
- numba_cuda/numba/cuda/typing/templates.py +1446 -0
- numba_cuda/numba/cuda/typing/typeof.py +301 -0
- numba_cuda/numba/cuda/ufuncs.py +746 -0
- numba_cuda/numba/cuda/utils.py +724 -0
- numba_cuda/numba/cuda/vector_types.py +214 -0
- numba_cuda/numba/cuda/vectorizers.py +260 -0
- numba_cuda-0.22.0.dist-info/METADATA +109 -0
- numba_cuda-0.22.0.dist-info/RECORD +487 -0
- numba_cuda-0.22.0.dist-info/WHEEL +6 -0
- numba_cuda-0.22.0.dist-info/licenses/LICENSE +26 -0
- numba_cuda-0.22.0.dist-info/licenses/LICENSE.numba +24 -0
- 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)
|