├── .github └── workflows │ └── actions.yml ├── .gitignore ├── API_CHANGES ├── CMakeLists.txt ├── GNUmakefile ├── INTERNAL_CHANGES ├── LICENSE ├── README.md ├── docs ├── README.md ├── general │ ├── architecture.md │ ├── contributing.md │ ├── getting-started │ │ ├── _category_.json │ │ ├── configuration.md │ │ └── setup.md │ ├── introduction.md │ └── use-cases │ │ ├── _category_.json │ │ ├── bytecode-interpreters.md │ │ ├── overview.md │ │ └── pattern-matching │ │ ├── _category_.json │ │ ├── figure1.svg │ │ ├── performance-comparison.md │ │ ├── regular-expression-engine-types.md │ │ └── speeding-up-pcre2-with-sljit.md ├── tutorial │ ├── 01-overview.md │ ├── 02-your-first-program.md │ ├── 03-branching.md │ ├── 04-calling-external-functions.md │ ├── 05-accessing-structures.md │ ├── 06-accessing-arrays.md │ ├── 07-local-variables.md │ ├── 08-where-to-go-from-here.md │ └── sources │ │ ├── 99bottles.bf │ │ ├── array_access.c │ │ ├── brainfuck.c │ │ ├── branch.c │ │ ├── first_program.c │ │ ├── func_call.c │ │ ├── hello.bf │ │ ├── loop.c │ │ ├── struct_access.c │ │ └── temp_var.c └── website │ ├── .gitignore │ ├── README.md │ ├── docusaurus.config.js │ ├── package-lock.json │ ├── package.json │ ├── sidebars.js │ ├── src │ ├── components │ │ └── HomepageFeatures │ │ │ ├── index.js │ │ │ └── styles.module.css │ ├── css │ │ └── custom.css │ └── pages │ │ ├── index.js │ │ └── index.module.css │ └── static │ ├── .nojekyll │ └── assets │ └── regex-test.tgz ├── regex_src ├── regexJIT.c ├── regexJIT.h └── regexMain.c ├── sljit_src ├── allocator_src │ ├── sljitExecAllocatorApple.c │ ├── sljitExecAllocatorCore.c │ ├── sljitExecAllocatorFreeBSD.c │ ├── sljitExecAllocatorPosix.c │ ├── sljitExecAllocatorWindows.c │ ├── sljitProtExecAllocatorNetBSD.c │ ├── sljitProtExecAllocatorPosix.c │ ├── sljitWXExecAllocatorPosix.c │ └── sljitWXExecAllocatorWindows.c ├── sljitConfig.h ├── sljitConfigCPU.h ├── sljitConfigInternal.h ├── sljitLir.c ├── sljitLir.h ├── sljitNativeARM_32.c ├── sljitNativeARM_64.c ├── sljitNativeARM_T2_32.c ├── sljitNativeLOONGARCH_64.c ├── sljitNativeMIPS_32.c ├── sljitNativeMIPS_64.c ├── sljitNativeMIPS_common.c ├── sljitNativePPC_32.c ├── sljitNativePPC_64.c ├── sljitNativePPC_common.c ├── sljitNativeRISCV_32.c ├── sljitNativeRISCV_64.c ├── sljitNativeRISCV_common.c ├── sljitNativeS390X.c ├── sljitNativeX86_32.c ├── sljitNativeX86_64.c ├── sljitNativeX86_common.c ├── sljitSerialize.c └── sljitUtils.c └── test_src ├── sljitConfigPost.h ├── sljitConfigPre.h ├── sljitMain.c ├── sljitTest.c ├── sljitTestBuffers.h ├── sljitTestCall.h ├── sljitTestFloat.h ├── sljitTestSerialize.h └── sljitTestSimd.h /.github/workflows/actions.yml: -------------------------------------------------------------------------------- 1 | name: Actions 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | pull_request: 7 | branches: [master] 8 | 9 | jobs: 10 | build-test-on-arches-with-qemu: 11 | name: Build and test on ${{ matrix.arch.name }} 12 | strategy: 13 | fail-fast: false 14 | matrix: 15 | arch: 16 | - name: armt2 17 | toolchain: 18 | url: https://toolchains.bootlin.com/downloads/releases/toolchains/armv7-eabihf/tarballs/armv7-eabihf--glibc--stable-2024.05-1.tar.xz 19 | name: armv7-eabihf--glibc--stable-2024.05-1.tar.xz 20 | CC: arm-buildroot-linux-gnueabihf-gcc-13.3.0.br_real 21 | CFLAGS: -mthumb 22 | qemu: 23 | target: arm-linux-user 24 | name: qemu-arm 25 | - name: armv7 26 | toolchain: 27 | url: https://toolchains.bootlin.com/downloads/releases/toolchains/armv7-eabihf/tarballs/armv7-eabihf--glibc--stable-2024.05-1.tar.xz 28 | name: armv7-eabihf--glibc--stable-2024.05-1.tar.xz 29 | CC: arm-buildroot-linux-gnueabihf-gcc-13.3.0.br_real 30 | CFLAGS: -marm 31 | qemu: 32 | target: arm-linux-user 33 | name: qemu-arm 34 | - name: aarch64 35 | toolchain: 36 | url: https://toolchains.bootlin.com/downloads/releases/toolchains/aarch64/tarballs/aarch64--glibc--stable-2024.05-1.tar.xz 37 | name: aarch64--glibc--stable-2024.05-1.tar.xz 38 | CC: aarch64-buildroot-linux-gnu-gcc-13.3.0.br_real 39 | qemu: 40 | target: aarch64-linux-user 41 | name: qemu-aarch64 42 | - name: riscv64 with extensions 43 | toolchain: 44 | url: https://toolchains.bootlin.com/downloads/releases/toolchains/riscv64-lp64d/tarballs/riscv64-lp64d--glibc--stable-2024.05-1.tar.xz 45 | name: riscv64-lp64d--glibc--stable-2024.05-1.tar.xz 46 | CC: riscv64-buildroot-linux-gnu-gcc-13.3.0.br_real 47 | CFLAGS: -march=rv64gv_zba_zbb 48 | qemu: 49 | target: riscv64-linux-user 50 | name: qemu-riscv64 51 | - name: riscv64 52 | toolchain: 53 | url: https://toolchains.bootlin.com/downloads/releases/toolchains/riscv64-lp64d/tarballs/riscv64-lp64d--glibc--stable-2024.05-1.tar.xz 54 | name: riscv64-lp64d--glibc--stable-2024.05-1.tar.xz 55 | CC: riscv64-buildroot-linux-gnu-gcc-13.3.0.br_real 56 | CFLAGS: -march=rv64g 57 | qemu: 58 | target: riscv64-linux-user 59 | name: qemu-riscv64 60 | - name: riscv32 with extensions 61 | toolchain: 62 | url: https://toolchains.bootlin.com/downloads/releases/toolchains/riscv32-ilp32d/tarballs/riscv32-ilp32d--glibc--stable-2024.05-1.tar.xz 63 | name: riscv32-ilp32d--glibc--stable-2024.05-1.tar.xz 64 | CC: riscv32-buildroot-linux-gnu-gcc-13.3.0.br_real 65 | CFLAGS: -march=rv32gcv_zba_zbb 66 | qemu: 67 | target: riscv32-linux-user 68 | name: qemu-riscv32 69 | - name: riscv32 70 | toolchain: 71 | url: https://toolchains.bootlin.com/downloads/releases/toolchains/riscv32-ilp32d/tarballs/riscv32-ilp32d--glibc--stable-2024.05-1.tar.xz 72 | name: riscv32-ilp32d--glibc--stable-2024.05-1.tar.xz 73 | CC: riscv32-buildroot-linux-gnu-gcc-13.3.0.br_real 74 | CFLAGS: -march=rv32g 75 | qemu: 76 | target: riscv32-linux-user 77 | name: qemu-riscv32 78 | - name: loongarch64 79 | toolchain: 80 | url: https://github.com/loongson/build-tools/releases/download/2025.02.21/x86_64-cross-tools-loongarch64-binutils_2.44-gcc_14.2.0-glibc_2.41.tar.xz 81 | name: x86_64-cross-tools-loongarch64-binutils_2.44-gcc_14.2.0-glibc_2.41.tar.xz 82 | CC: loongarch64-unknown-linux-gnu-gcc-14.2.0 83 | CFLAGS: -march=la464 84 | qemu: 85 | target: loongarch64-linux-user 86 | name: qemu-loongarch64 87 | - name: s390x 88 | toolchain: 89 | url: https://toolchains.bootlin.com/downloads/releases/toolchains/s390x-z13/tarballs/s390x-z13--glibc--stable-2024.05-1.tar.xz 90 | name: s390x-z13--glibc--stable-2024.05-1.tar.xz 91 | CC: s390x-buildroot-linux-gnu-gcc-13.3.0.br_real 92 | qemu: 93 | target: s390x-linux-user 94 | name: qemu-s390x 95 | 96 | runs-on: ubuntu-latest 97 | steps: 98 | - uses: actions/checkout@v4 99 | with: 100 | submodules: true 101 | - name: Install compiler 102 | run: | 103 | sudo apt update 104 | sudo apt install -y make wget gcc g++ ninja-build libglib2.0-dev 105 | wget ${{ matrix.arch.toolchain.url }} 106 | mkdir toolchain 107 | tar -xvf ${{ matrix.arch.toolchain.name }} -C toolchain --strip-components=1 108 | - name: Install qemu 109 | run: | 110 | wget https://download.qemu.org/qemu-9.0.2.tar.xz 111 | tar -xvf qemu-9.0.2.tar.xz 112 | cd qemu-9.0.2 113 | ./configure --target-list="${{ matrix.arch.qemu.target }}" 114 | make -j4 115 | - name: Build 116 | env: 117 | CROSS_COMPILER: ./toolchain/bin/${{ matrix.arch.toolchain.CC }} 118 | CFLAGS: ${{ matrix.arch.toolchain.CFLAGS }} 119 | EXTRA_LDFLAGS: -static 120 | run: | 121 | make all 122 | - name: Run tests 123 | run: | 124 | ./qemu-9.0.2/build/${{ matrix.arch.qemu.name }} ./bin/sljit_test -v 125 | 126 | build-test-on-x86_x64: 127 | strategy: 128 | fail-fast: false 129 | matrix: 130 | arch: 131 | - name: x86 132 | CFLAGS: -m32 133 | - name: x64 134 | name: Build and test on ${{ matrix.arch.name }} 135 | runs-on: ubuntu-latest 136 | steps: 137 | - uses: actions/checkout@v4 138 | with: 139 | submodules: true 140 | - name: Install Packages 141 | run: | 142 | sudo apt update 143 | sudo apt install -y gcc-multilib make 144 | - name: Build 145 | env: 146 | CFLAGS: ${{ matrix.arch.CFLAGS }} 147 | run: | 148 | make all 149 | - name: Run Tests 150 | run: | 151 | ./bin/sljit_test -v 152 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | taring 3 | -------------------------------------------------------------------------------- /API_CHANGES: -------------------------------------------------------------------------------- 1 | This file is the short summary of the API changes: 2 | 3 | 05.02.2025 - Non-backward compatible 4 | Rename sljit_emit_mov_addr to sljit_emit_op_addr 5 | and SLJIT_LABEL_ALIGN_SW to SLJIT_LABEL_ALIGN_W 6 | 7 | 11.02.2025 - Non-backward compatible 8 | An operation argument is added to 9 | sljit_emit_mov_addr function. 10 | 11 | 31.01.2025 - Non-backward compatible 12 | The sljit_emit_const and sljit_set_const 13 | functions can specify the operation type. 14 | 15 | 17.07.2024 - Non-backward compatible 16 | Passing float scratch or saved register count 17 | to emit_enter / set_context is reworked. 18 | 19 | 21.06.2024 - Non-backward compatible 20 | Atomic instructions are reworked. 21 | Different forms are optional now. 22 | 23 | 10.06.2024 - Non-backward compatible 24 | The sljit_emit_simd_op2() has a generic 25 | second operand. 26 | 27 | 20.03.2024 - Non-backward compatible 28 | The sljit_p type is renamed to sljit_up. 29 | 30 | 26.02.2024 - Non-backward compatible 31 | Arguments of sljit_create_compiler() and 32 | sljit_generate_code() are changed and 33 | sljit_get_exec_allocator_data() is removed. 34 | The sljit_get_allocator_data() is renamed 35 | to sljit_compiler_get_allocator_data(). 36 | 37 | 21.02.2024 - Non-backward compatible 38 | The sljit_set_put_label() function is renamed 39 | to sljit_emit_mov_addr() and sljit_put_label 40 | is merged into sljit_jump and removed. 41 | 42 | 01.11.2023 - Non-backward compatible 43 | The SLJIT_ARG_TYPE_VOID definition is changed 44 | to SLJIT_ARG_TYPE_RET_VOID to improve Windows 45 | compatibility. 46 | 47 | 05.09.2023 - Non-backward compatible 48 | Turn SLJIT_IMM from a flag to a single value. 49 | 50 | 10.08.2023 - Non-backward compatible 51 | Rename SLJIT_INT_REGISTER to SLJIT_GP_REGISTER. 52 | 53 | 01.08.2023 - Non-backward compatible 54 | A type argument is added to sljit_get_register_index 55 | and sljit_get_float_register_index is removed. 56 | 57 | 19.07.2023 - Non-backward compatible 58 | SLJIT_MEM_UNALIGNED_16/32 options are renamed 59 | to SLJIT_MEM_ALIGNED_16/32 and a type argument 60 | is added to sljit_get_float_register_index. 61 | 62 | 16.02.2022 - Non-backward compatible 63 | The sljit_emit_cmov operation is replaced 64 | by sljit_emit_select. 65 | 66 | 11.02.2022 - Non-backward compatible 67 | All floating point comparisons are supported, 68 | sljit_cmp_info return value is changed. 69 | 70 | 02.02.2022 - Backward compatible 71 | All SLJIT_SET_* constants are 72 | even numbers. 73 | 74 | 27.01.2022 - Non-backward compatible 75 | The arguments of sljit_emit_shift_into 76 | are changed. 77 | 78 | 17.12.2022 - Non-backward compatible 79 | Replace sljit_emit_fast_enter and 80 | sljit_get_return_address with 81 | sljit_emit_op_dst. 82 | 83 | 13.12.2022 - Non-backward compatible 84 | Replace SLJIT_NOT with SLJIT_XOR. 85 | 86 | 10.11.2022 - Non-backward compatible 87 | Extract the pre/post update operations from 88 | sljit_emit_mem to sljit_emit_mem_update 89 | and sljit_emit_fmem to sljit_emit_fmem_update. 90 | 91 | 04.11.2022 - Non-backward compatible 92 | The SLJIT_32 flag is combined with the type 93 | argument of cmov, not the dst_reg. 94 | 95 | 16.06.2022 - Non-backward compatible 96 | Remove SLJIT_ENTER_CDECL and SLJIT_CALL_CDECL. 97 | The default calling mode is cdecl now. 98 | 99 | 21.04.2022 - Non-backward compatible 100 | Floating point comparison types are renamed. 101 | 102 | 01.03.2022 - Non-backward compatible 103 | Remove SLJIT_NEG. Instead subtraction from 104 | immedate 0 is preferred. 105 | 106 | 31.01.2022 - Non-backward compatible 107 | The SLJIT_CURRENT_FLAGS_ADD_SUB option is 108 | split into SLJIT_CURRENT_FLAGS_ADD and 109 | SLJIT_CURRENT_FLAGS_SUB. 110 | 111 | 27.02.2022 - Non-backward compatible 112 | The SLJIT_F64_ALIGNMENT option is removed. 113 | 114 | 17.02.2022 - Non-backward compatible 115 | Many floating point operations may destroy flags. 116 | 117 | 06.02.2022 - Non-backward compatible 118 | The SLJIT_FUNC_OFFSET macro is renamed to SLJIT_FUNC_ADDR. 119 | Furthermore a new SLJIT_FUNC_UADDR macro is added which 120 | returns with an unsigned address. 121 | 122 | 01.02.2022 - Non-backward compatible 123 | Rework function argument list descriptor macros used by 124 | sljit_emit_enter, sljit_set_context, sljit_emit_call, 125 | and sljit_emit_icall functions. 126 | 127 | 25.01.2022 - Non-backward compatible 128 | Change SLJIT_I32_OP and SLJIT_F32_OP to SLJIT_32. 129 | 130 | 24.01.2022 - Non-backward compatible 131 | The SLJIT_UNUSED value is replaced by sljit_emit_op2u and 132 | sljit_emit_return_void functions. 133 | 134 | 27.05.2021 - Non-backward compatible 135 | The comparison types with the 32 suffix are removed from the 136 | project. The sljit_set_current_flags has a new flag which 137 | must be set when the flags are set by a 32 bit operation. 138 | 139 | 04.05.2021 - Non-backward compatible 140 | The mul overflow comparison type is removed from the project 141 | and the normal overflow type should be used instead. 142 | 143 | 28.04.2021 - Non-backward compatible 144 | The current_flags argument of sljit_set_current_flags must 145 | provide information about the instructions which set the CPU 146 | status flags. 147 | 148 | 16.08.2020 - Non-backward compatible 149 | A second parameter has been added to sljit_create_compiler() 150 | and sljit_free_code() to pass some data to the executable 151 | allocator functions. 152 | 153 | 24.01.2020 - Non-backward compatible 154 | The SLJIT_MOV instructions does not support SLJIT_UNDEFINED 155 | as destination. New prefetch instructions has been added 156 | instead. 157 | 158 | 20.01.2019 - Non-backward compatible 159 | The check_sljit_emit_fast_return function is removed, and 160 | this operation is available through check_sljit_emit_op_src. 161 | 162 | 16.01.2019 - Backward compatible 163 | A new opcode (SLJIT_ENDBR) is added to support 164 | Intel Control-flow Enforcement Technology (CET). 165 | 166 | 08.01.2018 - Non-backward compatible 167 | Fields of sljit_stack are renamed to fit a 168 | top-down stack better. 169 | 170 | 02.01.2018 - Non-backward compatible 171 | Immediate source argument has not been supported 172 | for NOT, NEG, CLZ, and fast_return instructions 173 | anymore. No CPU supports immedate arguments for 174 | these opcodes. 175 | 176 | 26.12.2017 - Non-backward compatible 177 | The MOVU opcodes are removed because the emulation 178 | is inefficient. The sljit_emit_mem() operation is 179 | added instead. 180 | 181 | 18.10.2017 - Non-backward compatible 182 | The SLJIT_CALL0 - SLJIT_CALL3 jump types are 183 | replaced by sljit_emit_call and sljit_emit_icall 184 | function calls. These functions allows declaring 185 | the argument types. 186 | 187 | 06.05.2017 - Non-backward compatible 188 | Src argument is removed from sljit_emit_op_flags. 189 | 190 | 24.04.2017 - Non-backward compatible 191 | The sljit_is_fpu_available function is replaced 192 | by sljit_has_cpu_feature. 193 | 194 | 20.04.2017 - Non-backward compatible 195 | x86 specific cmov is changed to a general function 196 | 197 | 27.03.2017 - Non-backward compatible 198 | JIT stack is changed from bottom-up to top-town. 199 | 200 | 15.01.2017 - Non-backward compatible 201 | Move with update may modifiy flags, the base register 202 | can only be used once and [reg+reg< 0 is not supported anymore. 204 | 205 | 12.01.2017 - Non-backward compatible 206 | Introducing a new flag mechanism which provides better 207 | compatibility with CPUs without flags. Only two flags 208 | remain: zero and variable. The current type of the 209 | variable flag is specified by the arithmetic operator. 210 | The SLJIT_KEEP_FLAGS is removed. 211 | 212 | 29.02.2016 - Non-backward compatible 213 | Several types and instructions are renamed to improve 214 | readability. In general byte, half, and int are renamed 215 | to 8, 16, and 32. Floating point types are also renamed 216 | from d and s to f64 and f32. 217 | 218 | [s|u]b -> [s|u]8 (8 bit values) 219 | [s|u]h -> [s|u]16 (16 bit values) 220 | [s|u]i -> [s|u]32 (32 bit values) 221 | d -> f64 (64 bit floating point value) 222 | s -> f32 (32 bit floating point value) 223 | 224 | 18.05.2015 - Non-backward compatible 225 | SLJIT_[I|]L[U|S]DIV is renamed to SLJIT_[I|][U|S]DIVMOD 226 | 227 | 29.09.2014 - Non-backward compatible 228 | The sljit_create_compiler, sljit_allocate_stack, and 229 | sljit_free_stack functions have an allocator_data 230 | argument now. 231 | 232 | 19.09.2014 - Non-backward compatible 233 | Using I, D, S prefixes in conditional and floating 234 | point operations. And an L prefix to long multiplication 235 | and division (op0 opcodes). 236 | 237 | 11.08.2014 - Non-backward compatible 238 | A currently unused options parameter is added to sljit_emit_enter 239 | and sljit_set_context. 240 | 241 | 06.07.2014 - Non-backward compatible 242 | SCRATCH registers are renamed to Rx and SAVED registers 243 | are renamed to Sx. See the explanation of these registers 244 | in sljitLir.h. 245 | 246 | 31.05.2014 - Non-backward compatible 247 | SLJIT_TEMPORARY_EREGx registers were not renamed to 248 | SLJIT_SCRATCH_EREGx when the change was done on 08.11.2012 249 | 250 | 05.03.2014 - Backward compatible 251 | The sljit_set_target now supports those jumps, which 252 | does not created with SLJIT_REWRITABLE_JUMP flag. 253 | Reason: sljit_emit_ijump does not support conditional 254 | jumps. 255 | 256 | 03.03.2014 - Non-backward compatible 257 | SLJIT_MOV_UI cannot be combined with SLJIT_INT_OP. 258 | Reason: SLJIT_INT_OP flag is not recommended to use 259 | directly, and SLJIT_IMOV has no sign bit. 260 | 261 | 29.01.2014 - Backward compatible 262 | Bits assigned to SLJIT_MEM and SLJIT_IMM flags are changed. 263 | Reason: the most common cases are fits into one byte now, 264 | and more registers can be supported in the future. 265 | 266 | 08.11.2012 - Non-backward compatible 267 | SLJIT_TEMPORARY_REGx registers are renamed to SLJIT_SCRATCH_REGx. 268 | 269 | 07.11.2012 - Non-backward compatible 270 | sljit_emit_cond_value is renamed to sljit_emit_op_flags. An 271 | extra source argument is added which will be used in the future. 272 | 273 | 05.11.2012 - Backward compatible 274 | sljit_emit_cond_value now supports SLJIT_AND and SLJIT_INT_OP 275 | flags, which makes this function complete. 276 | 277 | 01.11.2012 - Non-backward compatible 278 | SLJIT_F* opcodes are renamed to SLJIT_*D to show that 279 | they are double precision operators. Furthermore 280 | SLJIT_*S single precision opcodes are added. 281 | 282 | 01.11.2012 - Non-backward compatible 283 | Register arguments of operations with SLJIT_INT_OP flag 284 | must be computed by another operation with SLJIT_INT_OP flag. 285 | The same way as SLJIT_SINGLE_OP flag works with floating point 286 | numbers. See the description of SLJIT_INT_OP. 287 | 288 | 01.11.2012 - Backward compatible 289 | All operations whose support the SLJIT_INT_OP flag, have an 290 | alternate name now, which includes the SLJIT_INT_OP. These 291 | names starting with I. 292 | 293 | 31.10.2012 - Non-backward compatible 294 | Renaming sljit_w to sljit_sw, sljit_i to sljit_si, sljit_h 295 | to sljit_sh, and sljit_b to sljit_sb. Reason: their sign 296 | bit is part of the type now. 297 | 298 | 20.10.2012 - Non-backward compatible 299 | Renaming SLJIT_C_FLOAT_NAN to SLJIT_C_FLOAT_UNORDERED. 300 | Reason: all architectures call these unordered comparions. 301 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # This script is incomplete and is only meant as an aid for building 2 | # and testing sljit in platforms without GNU make. 3 | # You are better off install GNU make and using that instead. 4 | 5 | cmake_minimum_required(VERSION 3.12) 6 | 7 | project(sljit C) 8 | 9 | # https://gist.github.com/tusharpm/d71dd6cab8a00320ddb48cc82bf7f64c 10 | 11 | if(POLICY CMP0007) 12 | cmake_policy(SET CMP0007 NEW) 13 | endif() 14 | 15 | function(ReadVariables MKFile) 16 | file(READ "${MKFile}" FileContents) 17 | string(REPLACE "\\\n" "" FileContents ${FileContents}) 18 | string(REPLACE "\n" ";" FileLines ${FileContents}) 19 | list(REMOVE_ITEM FileLines "") 20 | foreach(line ${FileLines}) 21 | if(line MATCHES "^[ A-Z]*=") 22 | string(REPLACE "=" ";" line_split ${line}) 23 | list(GET line_split -1 value) 24 | string(STRIP "${value}" value) 25 | separate_arguments(value) 26 | list(REMOVE_AT line_split -1) 27 | foreach(var_name ${line_split}) 28 | string(STRIP ${var_name} var_name) 29 | set(${var_name} ${value} PARENT_SCOPE) 30 | endforeach() 31 | endif() 32 | endforeach() 33 | endfunction() 34 | 35 | ReadVariables(GNUmakefile) 36 | 37 | find_package(Threads REQUIRED) 38 | include_directories(${SRCDIR} ${TESTDIR}) 39 | add_executable(sljit_test ${TESTDIR}/sljitMain.c ${TESTDIR}/sljitTest.c ${SRCDIR}/sljitLir.c) 40 | target_compile_definitions(sljit_test PRIVATE SLJIT_HAVE_CONFIG_PRE) 41 | target_link_libraries(sljit_test Threads::Threads) 42 | if(MSVC) 43 | set_target_properties(sljit_test PROPERTIES LINK_FLAGS "/STACK:0x400000") 44 | else() 45 | set_target_properties(sljit_test PROPERTIES LINK_FLAGS "-Wl,--stack,4194304") 46 | endif() -------------------------------------------------------------------------------- /GNUmakefile: -------------------------------------------------------------------------------- 1 | ifdef CROSS_COMPILER 2 | CC = $(CROSS_COMPILER) 3 | else 4 | ifndef CC 5 | # default compiler 6 | CC = gcc 7 | endif 8 | endif 9 | 10 | ifndef COMPAT_FLAGS 11 | # Should be replaced by proper warning options 12 | #COMPAT_FLAGS = -std=c89 -pedantic -Wpedantic 13 | COMPAT_FLAGS = 14 | endif 15 | 16 | ifndef OPT_FLAGS 17 | OPT_FLAGS = -O2 18 | endif 19 | 20 | ifndef WARN_FLAGS 21 | WARN_FLAGS = -Wall -Wextra -Wconversion -Wsign-compare -Wdeclaration-after-statement -Wunused-function -Wshadow 22 | endif 23 | 24 | ifndef WERROR 25 | WERROR = -Werror 26 | endif 27 | 28 | CPPFLAGS = $(EXTRA_CPPFLAGS) -Isljit_src 29 | CFLAGS += $(COMPAT_FLAGS) $(OPT_FLAGS) $(WARN_FLAGS) $(WERROR) 30 | REGEX_CFLAGS += $(CFLAGS) -fshort-wchar 31 | EXAMPLE_CFLAGS += $(CFLAGS) -Wno-unused-but-set-variable 32 | LDFLAGS = $(EXTRA_LDFLAGS) 33 | 34 | BINDIR = bin 35 | SRCDIR = sljit_src 36 | TESTDIR = test_src 37 | REGEXDIR = regex_src 38 | EXAMPLEDIR = docs/tutorial/sources 39 | 40 | TARGET = $(BINDIR)/sljit_test $(BINDIR)/regex_test 41 | EXAMPLE_TARGET = $(BINDIR)/func_call $(BINDIR)/first_program $(BINDIR)/branch $(BINDIR)/loop $(BINDIR)/array_access $(BINDIR)/func_call $(BINDIR)/struct_access $(BINDIR)/temp_var $(BINDIR)/brainfuck 42 | 43 | SLJIT_HEADERS = $(SRCDIR)/sljitLir.h $(SRCDIR)/sljitConfig.h $(SRCDIR)/sljitConfigInternal.h 44 | 45 | SLJIT_LIR_FILES = $(SRCDIR)/sljitLir.c $(SRCDIR)/sljitUtils.c \ 46 | $(SRCDIR)/allocator_src/sljitExecAllocatorCore.c $(SRCDIR)/allocator_src/sljitExecAllocatorApple.c \ 47 | $(SRCDIR)/allocator_src/sljitExecAllocatorPosix.c $(SRCDIR)/allocator_src/sljitExecAllocatorWindows.c \ 48 | $(SRCDIR)/allocator_src/sljitProtExecAllocatorNetBSD.c $(SRCDIR)/allocator_src/sljitProtExecAllocatorPosix.c \ 49 | $(SRCDIR)/allocator_src/sljitWXExecAllocatorPosix.c $(SRCDIR)/allocator_src/sljitWXExecAllocatorWindows.c \ 50 | $(SRCDIR)/sljitNativeARM_32.c $(SRCDIR)/sljitNativeARM_T2_32.c $(SRCDIR)/sljitNativeARM_64.c \ 51 | $(SRCDIR)/sljitNativeMIPS_common.c $(SRCDIR)/sljitNativeMIPS_32.c $(SRCDIR)/sljitNativeMIPS_64.c \ 52 | $(SRCDIR)/sljitNativePPC_common.c $(SRCDIR)/sljitNativePPC_32.c $(SRCDIR)/sljitNativePPC_64.c \ 53 | $(SRCDIR)/sljitNativeRISCV_common.c $(SRCDIR)/sljitNativeRISCV_32.c $(SRCDIR)/sljitNativeRISCV_64.c \ 54 | $(SRCDIR)/sljitNativeS390X.c $(SRCDIR)/sljitNativeLOONGARCH_64.c \ 55 | $(SRCDIR)/sljitNativeX86_common.c $(SRCDIR)/sljitNativeX86_32.c $(SRCDIR)/sljitNativeX86_64.c 56 | 57 | .PHONY: all clean examples 58 | 59 | all: $(TARGET) 60 | 61 | clean: 62 | -$(RM) $(BINDIR)/*.o $(BINDIR)/sljit_test $(BINDIR)/regex_test $(EXAMPLE_TARGET) 63 | 64 | $(BINDIR)/.keep : 65 | mkdir -p $(BINDIR) 66 | @touch $@ 67 | 68 | $(BINDIR)/sljitLir.o : $(BINDIR)/.keep $(SLJIT_LIR_FILES) $(SLJIT_HEADERS) 69 | $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(SRCDIR)/sljitLir.c 70 | 71 | $(BINDIR)/sljitMain.o : $(TESTDIR)/sljitMain.c $(BINDIR)/.keep $(SLJIT_HEADERS) 72 | $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(TESTDIR)/sljitMain.c 73 | 74 | $(BINDIR)/regexMain.o : $(REGEXDIR)/regexMain.c $(BINDIR)/.keep $(SLJIT_HEADERS) 75 | $(CC) $(CPPFLAGS) $(REGEX_CFLAGS) -c -o $@ $(REGEXDIR)/regexMain.c 76 | 77 | $(BINDIR)/regexJIT.o : $(REGEXDIR)/regexJIT.c $(BINDIR)/.keep $(SLJIT_HEADERS) $(REGEXDIR)/regexJIT.h 78 | $(CC) $(CPPFLAGS) $(REGEX_CFLAGS) -c -o $@ $(REGEXDIR)/regexJIT.c 79 | 80 | $(BINDIR)/sljit_test: $(BINDIR)/.keep $(BINDIR)/sljitMain.o $(TESTDIR)/sljitTest.c $(SRCDIR)/sljitLir.c $(SLJIT_LIR_FILES) $(SLJIT_HEADERS) $(TESTDIR)/sljitConfigPre.h $(TESTDIR)/sljitConfigPost.h $(TESTDIR)/sljitTestBuffers.h $(TESTDIR)/sljitTestCall.h $(TESTDIR)/sljitTestFloat.h $(TESTDIR)/sljitTestSimd.h 81 | $(CC) $(CPPFLAGS) -DSLJIT_HAVE_CONFIG_PRE=1 -I$(TESTDIR) $(CFLAGS) $(LDFLAGS) $(BINDIR)/sljitMain.o $(TESTDIR)/sljitTest.c $(SRCDIR)/sljitLir.c -o $@ -lm -lpthread $(EXTRA_LIBS) 82 | 83 | $(BINDIR)/regex_test: $(BINDIR)/.keep $(BINDIR)/regexMain.o $(BINDIR)/regexJIT.o $(BINDIR)/sljitLir.o 84 | $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(BINDIR)/regexMain.o $(BINDIR)/regexJIT.o $(BINDIR)/sljitLir.o -o $@ -lm -lpthread $(EXTRA_LIBS) 85 | 86 | examples: $(EXAMPLE_TARGET) 87 | 88 | $(BINDIR)/first_program: $(EXAMPLEDIR)/first_program.c $(BINDIR)/.keep $(BINDIR)/sljitLir.o 89 | $(CC) $(CPPFLAGS) $(EXAMPLE_CFLAGS) $(LDFLAGS) $(EXAMPLEDIR)/first_program.c $(BINDIR)/sljitLir.o -o $@ -lm -lpthread $(EXTRA_LIBS) 90 | 91 | $(BINDIR)/branch: $(EXAMPLEDIR)/branch.c $(BINDIR)/.keep $(BINDIR)/sljitLir.o 92 | $(CC) $(CPPFLAGS) $(EXAMPLE_CFLAGS) $(LDFLAGS) $(EXAMPLEDIR)/branch.c $(BINDIR)/sljitLir.o -o $@ -lm -lpthread $(EXTRA_LIBS) 93 | 94 | $(BINDIR)/loop: $(EXAMPLEDIR)/loop.c $(BINDIR)/.keep $(BINDIR)/sljitLir.o 95 | $(CC) $(CPPFLAGS) $(EXAMPLE_CFLAGS) $(LDFLAGS) $(EXAMPLEDIR)/loop.c $(BINDIR)/sljitLir.o -o $@ -lm -lpthread $(EXTRA_LIBS) 96 | 97 | $(BINDIR)/array_access: $(EXAMPLEDIR)/array_access.c $(BINDIR)/.keep $(BINDIR)/sljitLir.o 98 | $(CC) $(CPPFLAGS) $(EXAMPLE_CFLAGS) $(LDFLAGS) $(EXAMPLEDIR)/array_access.c $(BINDIR)/sljitLir.o -o $@ -lm -lpthread $(EXTRA_LIBS) 99 | 100 | $(BINDIR)/func_call: $(EXAMPLEDIR)/func_call.c $(BINDIR)/.keep $(BINDIR)/sljitLir.o 101 | $(CC) $(CPPFLAGS) $(EXAMPLE_CFLAGS) $(LDFLAGS) $(EXAMPLEDIR)/func_call.c $(BINDIR)/sljitLir.o -o $@ -lm -lpthread $(EXTRA_LIBS) 102 | 103 | $(BINDIR)/struct_access: $(EXAMPLEDIR)/struct_access.c $(BINDIR)/.keep $(BINDIR)/sljitLir.o 104 | $(CC) $(CPPFLAGS) $(EXAMPLE_CFLAGS) $(LDFLAGS) $(EXAMPLEDIR)/struct_access.c $(BINDIR)/sljitLir.o -o $@ -lm -lpthread $(EXTRA_LIBS) 105 | 106 | $(BINDIR)/temp_var: $(EXAMPLEDIR)/temp_var.c $(BINDIR)/.keep $(BINDIR)/sljitLir.o 107 | $(CC) $(CPPFLAGS) $(EXAMPLE_CFLAGS) $(LDFLAGS) $(EXAMPLEDIR)/temp_var.c $(BINDIR)/sljitLir.o -o $@ -lm -lpthread $(EXTRA_LIBS) 108 | 109 | $(BINDIR)/brainfuck: $(EXAMPLEDIR)/brainfuck.c $(BINDIR)/.keep $(BINDIR)/sljitLir.o 110 | $(CC) $(CPPFLAGS) $(EXAMPLE_CFLAGS) $(LDFLAGS) $(EXAMPLEDIR)/brainfuck.c $(BINDIR)/sljitLir.o -o $@ -lm -lpthread $(EXTRA_LIBS) 111 | -------------------------------------------------------------------------------- /INTERNAL_CHANGES: -------------------------------------------------------------------------------- 1 | This file is the short summary of the internal changes: 2 | 3 | 18.11.2012 4 | Switching from stdcall to cdecl on x86-32. Fastcall is still the default 5 | on GCC and MSVC. Now Intel C compilers are supported. 6 | 7 | 20.10.2012 8 | Supporting Sparc-32 CPUs. 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | /* 2 | * Stack-less Just-In-Time compiler 3 | * 4 | * Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without modification, are 7 | * permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, this list of 10 | * conditions and the following disclaimer. 11 | * 12 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list 13 | * of conditions and the following disclaimer in the documentation and/or other materials 14 | * provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 19 | * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 22 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | # SLJIT 4 | 5 | Platform-independent low-level JIT compiler 6 | 7 | https://zherczeg.github.io/sljit/ 8 | 9 |
10 | 11 | --- 12 | 13 | ## Purpose 14 | 15 | SLJIT is a low-level, platform-independent JIT compiler, which is very well suited for translating bytecode into machine code. 16 | 17 | ## Features 18 | 19 | - Supports a variety of target architectures: 20 | - `x86` 32 / 64 21 | - `ARM` 32 / 64 22 | - `RISC-V` 32 / 64 23 | - `s390x` 64 24 | - `PowerPC` 32 / 64 25 | - `LoongArch` 64 26 | - `MIPS` 32 / 64 27 | - Supports a large number of operations 28 | - Self-modifying code 29 | - Tail calls 30 | - Fast calls 31 | - Byte order reverse (endianness switching) 32 | - Unaligned memory accesses 33 | - SIMD 34 | - Atomic operations 35 | - Allows direct access to registers (both integer and floating point) 36 | - Supports stack space allocation for function local variables 37 | - Supports all-in-one compilation 38 | - Allows SLJIT's API to be completely hidden from external use 39 | - Allows serializing the compiler into a byte buffer 40 | - Useful for ahead-of-time (AOT) compilation 41 | - Code generation can be resumed after deserialization (partial AOT compilation) 42 | 43 | ## Documentation 44 | 45 | The primary source of documentation is [`sljitLir.h`](./sljit_src/sljitLir.h). 46 | 47 | Additional documentation can be found on [SLJIT's website](https://zherczeg.github.io/sljit/), as well as in the [`docs` folder](./docs/). 48 | 49 | ## Contact 50 | 51 | Either open an [issue](https://github.com/zherczeg/sljit/issues) or write an email to hzmester@freemail.hu. 52 | 53 | ## License 54 | 55 | SLJIT is licensed under the [Simplified BSD License](./LICENSE). 56 | 57 | ## Special Thanks 58 | 59 | - Alexander Nasonov 60 | - Carlo Marcelo Arenas Belón 61 | - Christian Persch 62 | - Daniel Richard G. 63 | - Giuseppe D'Angelo 64 | - H.J. Lu 65 | - James Cowgill 66 | - Jason Hood 67 | - Jiong Wang (*TileGX support*) 68 | - Marc Mutz 69 | - Martin Storsjö 70 | - Michael McConville 71 | - Mingtao Zhou (*LoongArch support*) 72 | - Walter Lee 73 | - Wen Xichang 74 | - YunQiang Su 75 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Documentation 2 | 3 | This folder contains a series of subfolders ([`general`](/docs/general/introduction.md) and [`tutorial`](/docs/tutorial/01-overview.md)) with documentation in [Markdown](https://en.wikipedia.org/wiki/Markdown). 4 | 5 | Additionally, it contains the [sources](/docs/website/) of SLJIT's [website](https://zherczeg.github.io/sljit/). 6 | 7 | > [!NOTE] 8 | > The documentation aims to display nicely when viewed on GitHub, as well as when processed by Docusaurus for the website. 9 | -------------------------------------------------------------------------------- /docs/general/architecture.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 3 3 | description: The inner workings of SLJIT. 4 | --- 5 | 6 | # Architecture 7 | 8 | ## Low-level Intermediate Representation 9 | 10 | Defining a LIR which provides wide range of optimization opportunities and still can be efficiently translated to machine code on all CPUs is the biggest challenge of this project. 11 | Those instruction forms and features which are supported on many (but not necessarily on all) architectures are carefully selected and a LIR is created from them. 12 | These features are also emulated by the remaining architectures with low overhead. 13 | For example, SLJIT supports various memory addressing modes and setting status register bits. 14 | 15 | ## Generic CPU Model 16 | 17 | The CPU has: 18 | - integer registers, which can store either an `int32_t` (4 byte) or `intptr_t` (4 or 8 byte) value 19 | - floating point registers, which can store either a single (4 byte) or double (8 byte) precision value 20 | - boolean status flags 21 | 22 | Some platforms additionally have support for vector registers, which may alias the floating point registers. 23 | 24 | ### Integer Registers 25 | 26 | The most important rule is: when a source operand of an instruction is a register, the data type of the register must match the data type expected by an instruction. 27 | 28 | For example, the following code snippet is a valid instruction sequence: 29 | 30 | ```c 31 | sljit_emit_op1(compiler, SLJIT_MOV32, 32 | SLJIT_R0, 0, SLJIT_MEM1(SLJIT_R1), 0); 33 | // An int32_t value is loaded into SLJIT_R0 34 | sljit_emit_op1(compiler, SLJIT_REV32, 35 | SLJIT_R0, 0, SLJIT_R0, 0); 36 | // the int32_t value in SLJIT_R0 is byte swapped 37 | // and the type of the result is still int32_t 38 | ``` 39 | 40 | The next code snippet is not allowed: 41 | 42 | ```c 43 | sljit_emit_op1(compiler, SLJIT_MOV, 44 | SLJIT_R0, 0, SLJIT_MEM1(SLJIT_R1), 0); 45 | // An intptr_t value is loaded into SLJIT_R0 46 | sljit_emit_op1(compiler, SLJIT_REV32, 47 | SLJIT_R0, 0, SLJIT_R0, 0); 48 | // The result of the instruction is undefined. 49 | // Even crash is possible for some instructions 50 | // (e.g. on MIPS-64). 51 | ``` 52 | 53 | However, it is always allowed to overwrite a register regardless of its previous value: 54 | 55 | ```c 56 | sljit_emit_op1(compiler, SLJIT_MOV, 57 | SLJIT_R0, 0, SLJIT_MEM1(SLJIT_R1), 0); 58 | // An intptr_t value is loaded into SLJIT_R0 59 | sljit_emit_op1(compiler, SLJIT_MOV32, 60 | SLJIT_R0, 0, SLJIT_MEM1(SLJIT_R2), 0); 61 | // From now on SLJIT_R0 contains an int32_t 62 | // value. The previous value is discarded. 63 | ``` 64 | 65 | Type conversion instructions are provided to convert an `int32_t` value to an `intptr_t` value and vice versa. 66 | In certain architectures these conversions are *nops* (no instructions are emitted). 67 | 68 | #### Memory Accessing 69 | 70 | Register arguments of `SLJIT_MEM1` / `SLJIT_MEM2` addressing modes must contain `intptr_t` data. 71 | 72 | #### Signed / Unsigned Values 73 | 74 | Most operations are executed in the same way regardless of if the value is signed or unsigned. 75 | These operations have only one instruction form (e.g. `SLJIT_ADD` / `SLJIT_MUL`). 76 | Instructions where the result depends on the sign have two forms (e.g. integer division, long multiply). 77 | 78 | ### Floating Point Registers 79 | 80 | Floating point registers can either contain a single or double precision value. 81 | Similar to integer registers, the data type of the value stored in a source register must match the data type expected by the instruction. 82 | Otherwise the result is undefined (even a crash is possible). 83 | 84 | #### Rounding 85 | 86 | Similar to standard C, floating point computation results are rounded toward zero. 87 | 88 | ### Boolean Status Flags 89 | 90 | Conditional branches usually depend on the value of CPU status flags. 91 | These status flags are boolean values and can be set by certain instructions. 92 | 93 | For better compatibility with CPUs without flags, SLJIT exposes only two such flags: 94 | - The **zero** (or equal) flag is set if `SLJIT_SET_Z` was specified and the result is zero. 95 | - The **variable** flag's meaning depends on the arithmetic operation that sets it, as well as the type of flag requested. For example, `SLJIT_ADD` supports setting the `Z`, `CARRY` and `OVERFLOW` flags. The latter two will however both map to the variable flag and can thus not be requested at the same time. 96 | 97 | Be aware that different operations give different guarantees on what state the flags will be in afterwards. 98 | Also, not all flags are supported by all operations. 99 | For more details, refer to [`sljitLir.h`](https://github.com/zherczeg/sljit/blob/master/sljit_src/sljitLir.h). 100 | 101 | ## Complex Instructions 102 | 103 | We noticed that introducing complex instructions for common tasks can improve performance. 104 | For example, compare and branch instruction sequences can be optimized if certain conditions apply, but these conditions depend on the target CPU. 105 | SLJIT can do these optimizations, but it needs to understand the "purpose" of the generated code. 106 | Static instruction analysis has a large performance overhead however, so we chose another approach: we introduced complex instruction forms for certain non-atomic tasks. 107 | SLJIT can optimize these instructions more efficiently since their purpose is known to the compiler. 108 | These complex instruction forms can often be assembled from other SLJIT instructions, but we recommended to use them since the compiler can optimize them on certain CPUs. 109 | 110 | ## Generating Functions 111 | 112 | SLJIT is often used for generating function bodies which are 113 | called from C. 114 | SLJIT provides two complex instructions for generating function entry and return: `sljit_emit_enter` and `sljit_emit_return`. 115 | The `sljit_emit_enter` function also initializes the compilation context, which specifies the current register mapping, local space size and other configurations. 116 | The `sljit_set_context` function can also set this context without emitting any machine instructions. 117 | 118 | This context is important since it affects the compiler, so the first instruction after a compiler is created must be either `sljit_emit_enter` or `sljit_set_context`. 119 | The context can be changed by calling `sljit_emit_enter` or `sljit_set_context` again. 120 | 121 | ## Types 122 | 123 | SLJIT defines several types for representing data on the target platform, often times in both a signed and unsigned variant: 124 | - Integers of varying size: `sljit_s8` / `sljit_u8`, `sljit_s16` / `sljit_u16`, `sljit_s32` / `sljit_u32` 125 | - Machine word, capable of holding a pointer: `sljit_sw` / `sljit_uw`, `sljit_sp` / `sljit_up` 126 | - Floating point types: `f32`, `f64` 127 | 128 | It is recommended to use these types instead of the default C types such as `long`, as it improves both the readability and the portability of the code. 129 | -------------------------------------------------------------------------------- /docs/general/contributing.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 5 3 | description: Contributing to SLJIT. 4 | --- 5 | 6 | # Contributing 7 | 8 | SLJIT needs your help! You can contribute by: 9 | - Reporting bugs [here](https://github.com/zherczeg/sljit/issues) 10 | - Submitting patches [here](https://github.com/zherczeg/sljit/pulls) 11 | - Improving SLJIT's documentation 12 | - Testing SLJIT on all sorts of platforms and compilers (especially the not so common ones like MIPS, PowerPC and SPARC) 13 | 14 | Thank you! 15 | -------------------------------------------------------------------------------- /docs/general/getting-started/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Getting Started", 3 | "position": 2, 4 | "link": { 5 | "type": "generated-index", 6 | "description": "Setting up and configuring SLJIT." 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /docs/general/getting-started/configuration.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 2 3 | description: Configuring SLJIT. 4 | --- 5 | 6 | # Configuration 7 | 8 | SLJIT's behavior can be controlled by a series of defines, described in `sljitConfig.h`. 9 | 10 | | Define | Enabled By Default| Description | 11 | | --- | --- | --- | 12 | | `SLJIT_DEBUG` | ✅ | Enable assertions. Should be disabled in release mode. | 13 | | `SLJIT_VERBOSE` | ✅ | When this macro is enabled, the `sljit_compiler_verbose` function can be used to dump SLJIT instructions. Otherwise this function is not available. Should be disabled in release mode. | 14 | | `SLJIT_SINGLE_THREADED` | ❌ | Single threaded programs can define this flag which eliminates the `pthread` dependency. | 15 | -------------------------------------------------------------------------------- /docs/general/getting-started/setup.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | description: Setting up SLJIT. 4 | --- 5 | 6 | # Setup 7 | 8 | ## Prerequisites 9 | 10 | To compile SLJIT, you need a C/C++ compiler with support for the `C99` standard. 11 | 12 | In case you want to build [the tests](#building-the-tests) or [the examples](#building-the-examples), you additionally need [GNU Make](https://www.gnu.org/software/make/). If you are using the MSVC toolchain on Windows (where GNU Make is not available), you can use [CMake](https://cmake.org/) to build the tests instead. 13 | 14 | ## Using SLJIT in Your Project 15 | 16 | Place the contents of the [`sljit_src` folder](https://github.com/zherczeg/sljit/tree/master/sljit_src) in a suitable location in your project's source directory. 17 | 18 | SLJIT can be used in one of two ways: 19 | 20 | ### SLJIT as a Library 21 | 22 | Compile `sljitLir.c` as a separate translation unit. Be sure to add `sljit_src` to the list of include directories, e.g. by specifying `-Ipath/to/sljit` when compiling with GCC / Clang. 23 | 24 | To use SLJIT, include `sljitLir.h` and link against `sljitLir.o`. 25 | 26 | ### SLJIT All-in-one 27 | 28 | In case you want to avoid exposing SLJIT's interface to other translation units, you can also embed SLJIT as a hidden implementation detail. To do so, define `SLJIT_CONFIG_STATIC` before including `sljitLir.c` (yes, the C file): 29 | 30 | ```c title="hidden.c" 31 | #define SLJIT_CONFIG_STATIC 1 32 | #include "sljitLir.c" 33 | 34 | // SLJIT can be used in hidden.c, but not in other translation units 35 | ``` 36 | 37 | This technique can also be used to generate code for multiple target architectures: 38 | 39 | ```c title="x86-32.c" 40 | #define SLJIT_CONFIG_STATIC 1 41 | #define SLJIT_CONFIG_X86_32 1 42 | #include "sljitLir.c" 43 | 44 | // Generate code for x86 32-bit 45 | ``` 46 | 47 | ```c title="x86-64.c" 48 | #define SLJIT_CONFIG_STATIC 1 49 | #define SLJIT_CONFIG_X86_64 1 50 | #include "sljitLir.c" 51 | 52 | // Generate code for x86 64-bit 53 | ``` 54 | 55 | Both `x86-32.c` and `x86-64.c` can be linked together into the same binary / library without running into issues due to clashing symbols. 56 | 57 | ## Building the Tests 58 | 59 | ### Using GNU Make 60 | 61 | Navigate to the root directory of the SLJIT repository and build the default target with GNU Make: 62 | 63 | ```bash 64 | make 65 | ``` 66 | 67 | The test executable `sljit_test` can be found in the `bin` directory. To run the tests, simply execute it. 68 | 69 | ### Using CMake 70 | 71 | > [!NOTE] 72 | > CMake support is currently only intended as a crutch for Windows systems where GNU Make is not available. 73 | 74 | To build the tests on Windows using MSVC and NMake, do the following: 75 | 76 | 1. Open a suitable [developer command prompt](https://learn.microsoft.com/en-us/visualstudio/ide/reference/command-prompt-powershell?view=vs-2022) and navigate into the root directory of the SLJIT repository 77 | 2. Execute the following: 78 | ```bash 79 | cmake -B bin -G "NMake Makefiles" 80 | cmake --build bin 81 | ``` 82 | 83 | The test executable `sljit_test.exe` can be found in the `bin` directory. 84 | 85 | ## Building the Examples 86 | 87 | > [!NOTE] 88 | > You cannot currently build the examples on Windows using MSVC / CMake. 89 | 90 | Build the `examples` target with GNU Make: 91 | 92 | ```bash 93 | make examples 94 | ``` 95 | 96 | The different example executables can be found in the `bin` directory. 97 | -------------------------------------------------------------------------------- /docs/general/introduction.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | description: Introduction to SLJIT. 4 | --- 5 | 6 | # Introduction 7 | 8 | ## Overview 9 | 10 | SLJIT is a stack-less, low-level and platform-independent JIT compiler. 11 | Perhaps *platform-independent assembler* describes it even better. 12 | Its core design principle is that it does not try to be smarter than the developer. 13 | This principle is achieved by providing control over the generated machine code like you would have in other assembly languages. 14 | Unlike other assembly languages however, SLJIT utilizes a *low-level intermediate representation* (LIR) that is platform-independent, which greatly improves portability. 15 | 16 | SLJIT tries to strike a good balance between performance and maintainability. 17 | The LIR code can be compiled to many CPU architectures, and the performance of the generated code is very close to code written in native assembly languages. 18 | Although SLJIT does not support higher level features such as automatic register allocation, it can be a code generation backend for other JIT compiler libraries. 19 | Developing these intermediate libraries on top of SLJIT takes far less time, because they only need to support a single backend. 20 | 21 | If you want to jump right in and see SLJIT in action, take a look at the [Tutorial](../tutorial/01-overview.md). 22 | 23 | 24 | ## Features 25 | 26 | - Supports a variety of [target architectures](#supported-platforms) 27 | - Supports a large number of operations 28 | - Self-modifying code 29 | - Tail calls 30 | - Fast calls (not ABI compatible) 31 | - Byte order reverse (endianness switching) 32 | - Unaligned memory accesses 33 | - SIMD[^1] 34 | - Atomic operations[^1] 35 | - Allows direct access to registers (both integer and floating point) 36 | - Supports stack space allocation for function local variables 37 | - Supports [all-in-one](getting-started/setup.md#sljit-all-in-one) compilation 38 | - Allows SLJIT's API to be completely hidden from external use 39 | - Allows serializing the compiler into a byte buffer 40 | - Useful for ahead-of-time (AOT) compilation 41 | - Code generation can be resumed after deserialization (partial AOT compilation) 42 | 43 | ## Supported Platforms 44 | 45 | | Platform | 64-bit | 32-bit | 46 | | --- | --- | --- | 47 | | `x86` | ✅ | ✅ | 48 | | `ARM` | ✅ | ✅[^2] | 49 | | `RISC-V` | ✅ | ✅ | 50 | | `s390x` | ✅ | ❌ | 51 | | `PowerPC` | ✅ | ✅ | 52 | | `LoongArch` | ✅ | ❌ | 53 | | `MIPS` | ✅[^3] | ✅[^3] | 54 | 55 | [^1]: only on certain platforms 56 | [^2]: ARM-v6, ARM-v7 and Thumb2 instruction sets 57 | [^3]: III, R1 58 | -------------------------------------------------------------------------------- /docs/general/use-cases/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Use Cases", 3 | "position": 4, 4 | "link": { 5 | "type": "generated-index", 6 | "description": "Examples of use cases where SLJIT shines." 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /docs/general/use-cases/bytecode-interpreters.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 2 3 | description: Generating machine code from bytecode with SLJIT. 4 | --- 5 | 6 | # Bytecode Interpreters 7 | 8 | SLJIT's approach is very effective for bytecode interpreters, since their machine-independent bytecode (middle-level representation) typically contains instructions which either can be easly translated to machine code, or which are not worth to translate to machine code in the first place. 9 | 10 | The following table gives a possible mapping for a subset of bytecode instructions targeting a stack machine: 11 | 12 | | Bytecode Instruction | Effect | Mapping to SLJIT | 13 | | --- | --- | --- | 14 | | `pop` | Pop a value from the stack. | ✅ Easy to implement, just decrement the stack pointer. | 15 | | `add` | Pop two values from the stack. Add them and push the result onto the stack. | ✅ Easy to implement if `value` is limited to a single type (e.g. integers). More complex types may require additional checks and dispatching. In those cases, it may be beneficial to just JIT the "fast path" (e.g. the integer case). | 16 | | `resolve` | Pop a value representing the identifier of a variable from the stack. Lookup the variable by its identifier. If found, push its address onto the stack. Otherwise push `NULL` onto the stack. | ❌ Not suitable for JIT compilation. Call a native C/C++ helper instead. | 17 | -------------------------------------------------------------------------------- /docs/general/use-cases/overview.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | description: Determining when to use JIT compilation. 4 | --- 5 | 6 | # Overview 7 | 8 | ## JIT Compilation in General 9 | 10 | Just like any other technique in a programmer's toolbox, just-in-time (JIT) compilation should not be blindly used. It is not a magic wand that performs miracles without drawbacks. In general, JIT compilation can decrease the number of executed instructions, thus speeding up the execution. You can for example embed constants and constant pointers, eliminating certain loads. However, this typically comes with added complexity and memory consumption. On embedded systems, large amounts of JIT-ed code might decrease the efficiency of the instruction cache. 11 | 12 | In the practical experience of SLJIT's author, JIT compilation is similar to code inlining (a static compiler optimization). It basically has the same disadvantages as well. 13 | 14 | As a rule of thumb, you should focus on the most frequently executed parts of your program. When in doubt, profile your application to see where the hotspots are located. Never JIT compile generic (especially complex) algorithms. Their C/C++ counterparts usually perform better. 15 | 16 | ## SLJIT in Particular 17 | 18 | **Advantages:** 19 | - The execution can be continued from any LIR instruction. In other words, jumping into and out of the code is safe. 20 | - The target of (conditional) jump and call instructions can be dynamically modified during the execution of the code. 21 | - Constants can be modified during the execution of the code. 22 | - Support for fast, non-ABI compliant function calls between JIT-ed functions. Requires only a few machine instructions and all registers are keeping their values. 23 | - Move with update instructions, meaning the base register is updated before the actual load or store. 24 | 25 | **Disadvantages:** 26 | - Limited number of arguments (3 machine words) for ABI compatible function calls on all platforms. 27 | -------------------------------------------------------------------------------- /docs/general/use-cases/pattern-matching/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Pattern Matching", 3 | "position": 3, 4 | "link": { 5 | "type": "generated-index", 6 | "description": "Improving pattern matching performance with SLJIT." 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /docs/general/use-cases/pattern-matching/performance-comparison.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 3 3 | description: Comparing the performance of different regex engines. 4 | --- 5 | 6 | # Performance Comparison 7 | 8 | > [!NOTE] 9 | > This page was last updated in 2015. 10 | 11 | Processing text or raw byte-sequences are among the common tasks performed by most software tools. 12 | These tasks usually involve pattern matching algorithms, and the most popular tool for thjs purpose is regular expressions. 13 | Regular expressions have evolved a lot since Kleene defined the regular sets in the 1950's. 14 | Today we have several widely used regular expression engines which have different [features](https://en.wikipedia.org/wiki/Comparison_of_regular_expression_engines). 15 | This makes any performance comparison a difficult task, since a faster engine is not necessarily better. 16 | Depending on the use case it might be enough to know whether a POSIX compatible regular expression matches a given line, without needing the actual position of the match (grep utility). 17 | Other use cases however require the position of capturing brackets, unicode support, conditional and atomic block support, just to name a few. 18 | The former case needs a less sophisticated algorithm, which is likely be much faster than the latter, but again, that does not mean the former is better. 19 | More about these engine types can be found [here](regular-expression-engine-types.md). 20 | 21 | ## Participants 22 | 23 | The following popular engines were chosen: 24 | - PCRE2 10.10 25 | - tre 0.8.0 26 | - Oniguruma 5.9.6 27 | - re2 by Google 28 | - PCRE2 10.10 with SLJIT support 29 | 30 | Before anyone jumps to conclusions, I should note the following: 31 | - The engines were not fine tuned (because of my lack of knowledge about their internal workings). I just compiled them with the default options. I know enabling or disabling some features can heavily affect the results. If you feel that you have a better configuration, just drop me an email and I will update the results (hzmester(at)freemail(dot)hu). 32 | - The regular expression engines are compiled with `-O3` to allow the best performance. 33 | - This comparison page was inspired by the work of John Maddock (see his own regex comparison [here](http://www.boost.org/doc/libs/1_41_0/libs/regex/doc/gcc-performance.html)). The input is also the same he used before: [mtent12.zip](http://www.gutenberg.org/files/3200/old/mtent12.zip). It is a text file (e-book) of roughly 20 MB. 34 | - Only common patterns are selected. They are not pathological cases nor do they use any PERL specific features. The comparison was caseful. 35 | 36 | The testing environment can be downloaded from [here](https://zherczeg.github.io/sljit/regex-test.tgz). Just extract, type `make`. Download the [mtent12.zip](http://www.gutenberg.org/files/3200/old/mtent12.zip), rename the `mtent12.txt` inside to `mark.txt` and run `runtest`. 37 | 38 | ## Results 39 | 40 | ### Linux x86-64 41 | 42 | - **CPU:** Intel Xeon 2.67 GHz 43 | - **Compiler:** GCC 4.8.2 44 | 45 | | Regular Expression | PCRE | PCRE-DFA | TRE | Oniguruma | RE2 | PCRE-JIT | 46 | | --- | --- | --- | --- | --- | --- | --- | 47 | | `Twain` | 5 ms | 20 ms | 486 ms | 16 ms | 3 ms | 16 ms | 48 | | `(?i)Twain` | 79 ms | 124 ms | 598 ms | 160 ms | 73 ms | 16 ms | 49 | | `[a-z]shing` | 564 ms | 997 ms | 724 ms | 15 ms | 113 ms | 14 ms | 50 | | `Huck[a-zA-Z]+\|Saw[a-zA-Z]+` | 30 ms | 32 ms | 711 ms | 43 ms | 59 ms | 3 ms | 51 | | `\b\w+nn\b` | 837 ms | 1453 ms | 1186 ms | 1083 ms | 59 ms | 113 ms | 52 | | `[a-q][^u-z]{13}x` | 746 ms | 2741 ms | 1928 ms | 61 ms | 3512 ms | 2 ms | 53 | | `Tom\|Sawyer\|Huckleberry\|Finn` | 40 ms | 42 ms | 1242 ms | 51 ms | 61 ms | 29 ms | 54 | | `(?i)Tom\|Sawyer\|Huckleberry\|Finn` | 424 ms | 489 ms | 1887 ms | 820 ms | 98 ms | 94 ms | 55 | | `.{0,2}(Tom\|Sawyer\|Huckleberry\|Finn)` | 5164 ms | 5742 ms | 3425 ms | 127 ms | 66 ms | 443 ms | 56 | | `.{2,4}(Tom\|Sawyer\|Huckleberry\|Finn)` | 5298 ms | 7097 ms | 5248 ms | 124 ms | 66 ms | 487 ms | 57 | | `Tom.{10,25}river\|river.{10,25}Tom` | 83 ms | 108 ms | 804 ms | 90 ms | 68 ms | 18 ms | 58 | | `[a-zA-Z]+ing` | 1373 ms | 2224 ms | 954 ms | 1420 ms | 129 ms | 92 ms | 59 | | `\s[a-zA-Z]{0,12}ing\s` | 592 ms | 1007 ms | 1329 ms | 78 ms | 82 ms | 140 ms | 60 | | `([A-Za-z]awyer\|[A-Za-z]inn)\s` | 1112 ms | 1489 ms | 1313 ms | 243 ms | 111 ms | 46 ms | 61 | | `["'][^"']{0,30}[?!\.]["']` | 65 ms | 114 ms | 687 ms | 91 ms | 63 ms | 15 ms | 62 | 63 | ### Linux x86-32 64 | 65 | - **CPU:** Intel Xeon 2.67 GHz 66 | - **Compiler:** GCC 4.8.2 67 | 68 | | Regular Expression | PCRE | PCRE-DFA | TRE | Oniguruma | RE2 | PCRE-JIT | 69 | | --- | --- | --- | --- | --- | --- | --- | 70 | | `Twain` | 5 ms | 20 ms | 548 ms | 17 ms | 4 ms | 18 ms | 71 | | `(?i)Twain` | 97 ms | 144 ms | 683 ms | 139 ms | 74 ms | 16 ms | 72 | | `[a-z]shing` | 594 ms | 996 ms | 766 ms | 15 ms | 107 ms | 14 ms | 73 | | `Huck[a-zA-Z]+\|Saw[a-zA-Z]+` | 26 ms | 27 ms | 822 ms | 49 ms | 60 ms | 3 ms | 74 | | `\b\w+nn\b` | 978 ms | 1494 ms | 1205 ms | 1151 ms | 59 ms | 114 ms | 75 | | `[a-q][^u-z]{13}x` | 770 ms | 3112 ms | 2080 ms | 61 ms | 780 ms | 2 ms | 76 | | `Tom\|Sawyer\|Huckleberry\|Finn` | 38 ms | 37 ms | 1346 ms | 58 ms | 61 ms | 29 ms | 77 | | `(?i)Tom\|Sawyer\|Huckleberry\|Finn` | 464 ms | 481 ms | 1853 ms | 663 ms | 93 ms | 93 ms | 78 | | `.{0,2}(Tom\|Sawyer\|Huckleberry\|Finn)` | 6726 ms | 5636 ms | 3641 ms | 139 ms | 70 ms | 406 ms | 79 | | `.{2,4}(Tom\|Sawyer\|Huckleberry\|Finn)` | 7107 ms | 7252 ms | 5700 ms | 136 ms | 70 ms | 434 ms | 80 | | `Tom.{10,25}river\|river.{10,25}Tom` | 85 ms | 105 ms | 904 ms | 106 ms | 69 ms | 18 ms | 81 | | `[a-zA-Z]+ing` | 1740 ms | 2369 ms | 892 ms | 1387 ms | 144 ms | 90 ms | 82 | | `\s[a-zA-Z]{0,12}ing\s` | 708 ms | 968 ms | 1271 ms | 98 ms | 97 ms | 167 ms | 83 | | `([A-Za-z]awyer\|[A-Za-z]inn)\s` | 1300 ms | 1479 ms | 1583 ms | 255 ms | 104 ms | 45 ms | 84 | | `["'][^"']{0,30}[?!\.]["']` | 73 ms | 118 ms | 765 ms | 100 ms | 65 ms | 14 ms | 85 | 86 | ### Windows x86-64 87 | 88 | - **CPU:** Intel Core i5 3.2 GHz 89 | - **Compiler:** GCC 4.4.7 90 | 91 | | Regular expression | PCRE | PCRE-DFA | TRE | Oniguruma | RE2 | PCRE-JIT | 92 | | --- | --- | --- | --- | --- | --- | --- | 93 | | `Twain` | 7 ms | 12 ms | 315 ms | 20 ms | 8 ms | 16 ms | 94 | | `(?i)Twain` | 47 ms | 90 ms | 414 ms | 110 ms | 131 ms | 16 ms | 95 | | `[a-z]shing` | 330 ms | 704 ms | 485 ms | 19 ms | 131 ms | 15 ms | 96 | | `Huck[a-zA-Z]+\|Saw[a-zA-Z]+` | 20 ms | 22 ms | 518 ms | 38 ms | 130 ms | 2 ms | 97 | | `\b\w+nn\b` | 521 ms | 987 ms | 1109 ms | 782 ms | 131 ms | 85 ms | 98 | | `[a-q][^u-z]{13}x` | 428 ms | 1852 ms | 1168 ms | 43 ms | 3316 ms | 1 ms | 99 | | `Tom\|Sawyer\|Huckleberry\|Finn` | 25 ms | 29 ms | 863 ms | 44 ms | 132 ms | 23 ms | 100 | | `(?i)Tom\|Sawyer\|Huckleberry\|Finn` | 239 ms | 358 ms | 1310 ms | 424 ms | 132 ms | 68 ms | 101 | | `.{0,2}(Tom\|Sawyer\|Huckleberry\|Finn)` | 2970 ms | 3583 ms | 2170 ms | 85 ms | 133 ms | 268 ms | 102 | | `.{2,4}(Tom\|Sawyer\|Huckleberry\|Finn)` | 2965 ms | 4134 ms | 3298 ms | 84 ms | 136 ms | 296 ms | 103 | | `Tom.{10,25}river\|river.{10,25}Tom` | 54 ms | 81 ms | 655 ms | 80 ms | 138 ms | 14 ms | 104 | | `[a-zA-Z]+ing` | 773 ms | 1686 ms | 567 ms | 922 ms | 181 ms | 70 ms | 105 | | `\s[a-zA-Z]{0,12}ing\s` | 338 ms | 685 ms | 864 ms | 76 ms | 167 ms | 96 ms | 106 | | `([A-Za-z]awyer\|[A-Za-z]inn)\s` | 664 ms | 1087 ms | 875 ms | 182 ms | 139 ms | 35 ms | 107 | | `["'][^"']{0,30}[?!\.]["']` | 44 ms | 78 ms | 456 ms | 79 ms | 142 ms | 10 ms | 108 | -------------------------------------------------------------------------------- /docs/general/use-cases/pattern-matching/regular-expression-engine-types.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 2 3 | description: A comparison of regular experssion engine types. 4 | --- 5 | 6 | # Regular Expression Engine Types 7 | 8 | Matching regular expressions is not considered a complex task and many people think that this problem was solved a long time ago. 9 | The reason for this belief is a great deal of misinformation which has been spread across the internet and the education. 10 | On the contrary there is no best solution for matching a pattern at the moment, and choosing the right regular expression engine is as difficult as choosing the right programming language. 11 | The aim of this page is showing the advantages and disadvantages of different engine types. 12 | 13 | In general we distinguish two engine types: 14 | - **Performance-oriented engines:** very fast in general, and very slow in special (called pathological) cases. 15 | - **Balanced engines:** no weaknesses, no strengths. Usually predictable worst case runtime. 16 | 17 | Balanced engines are slower than performance-oriented engines, but adding some pathological patterns to the benchmark set can quickly turn the tide. 18 | 19 | The following sections go into more detail regarding the different engine types from a technical point of view. 20 | A performance comparison of some of the engines can be found [here](performance-comparison.md). 21 | 22 | ## Multiple Choice Engine with Backtracking 23 | 24 | **Type:** Usually performance-oriented engines 25 | 26 | **Advantages:** 27 | - Large feature set (assertions, conditional blocks, executing code blocks, backtracking control) 28 | - Submatch capture 29 | - Lots of optimization opportunities (mostly backtracking elimination) 30 | 31 | **Disadvantages:** 32 | - Large and complex code base 33 | - May use a large amount of stack 34 | - Examples for pathological cases: 35 | - `(a*)*b` 36 | - `(?:a?){N}a{N}` (where `N` is a positive integer number) 37 | 38 | **Execution modes:** Depth-first search algorithm 39 | - Interpreted execution of a Non-deterministic Finite Automaton (NFA); example: [PCRE interpreter](https://www.pcre.org/) 40 | - Generating machine code from an NFA; example: [Irregexp engine](https://blog.chromium.org/2009/02/irregexp-google-chromes-new-regexp.html) 41 | - Generating machine code from an Abstract Syntax Tree (AST); example: [PCRE JIT compiler](https://www.pcre.org/) 42 | 43 | ## Single Choice Engine with Pre-generated State Machine 44 | 45 | **Type:** Usually performance-oriented engines 46 | 47 | **Advantages:** 48 | - Simple and very fast matching algorithm 49 | - Partial matching support is easy 50 | - Multiple patterns can be matched at the same time (on a single core) 51 | 52 | **Disadvantages:** 53 | - Large memory consumption (can be limited at the expense of performance) 54 | - Limited feature set (and this feature set is not fully supported, sometimes necessitating falling back to other processing modes) 55 | - Examples for pathological cases: 56 | - `a[^b]{N}a` (where `N` is a positive integer number) 57 | - `a[^b]{1,N}abcde` (where `N` is a positive integer number) 58 | 59 | **Execution modes:** Linear search time, exponential state machine build time (especially for combining multiple patterns into a single state machine) 60 | - Following the state transitions of a Deterministic Finite Automaton (DFA); example: [RE2 engine](https://github.com/google/re2) 61 | - DFA based multi pattern matching; example: [MPM library](https://github.com/zherczeg/mpm) 62 | 63 | ## Single Choice Engine with State Tracking 64 | 65 | **Type:** Usually balanced engines 66 | 67 | **Advantages:** 68 | - No pathological cases 69 | - Partial matching support is not difficult 70 | 71 | **Disadvantages:** 72 | - Matching speed is generally low due to the complex state update mechanism 73 | - Limited feature set (due to synchronization issues, they have a similar feature set as the engines with pre-generated state machine) 74 | 75 | **Execution modes:** Linear search time 76 | - Interpreted execution of Deterministic Finite Automaton (DFA); example: [PCRE-DFA interpreter](https://www.pcre.org/) 77 | - Parallel matching of NFA; example: [TRE engine](http://laurikari.net/tre/) 78 | -------------------------------------------------------------------------------- /docs/general/use-cases/pattern-matching/speeding-up-pcre2-with-sljit.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | description: Adding JIT compilation via SLJIT to the PCRE2 library. 4 | --- 5 | 6 | # Speeding Up PCRE2 With SLJIT 7 | 8 | [PCRE2](https://www.pcre.org/) is a C library for matching regular expressions. 9 | This library translates patterns into byte code, and this byte code can be executed by its interpreter. 10 | The library also has a just-in-time (JIT) compiler which can produce machine code from the byte code to further improve the matching performance. 11 | Before going into the details of the JIT compiler, the reason of choosing byte code as an internal representation is explained first. 12 | 13 | Regular expressions were originally designed for defining a set of words using special patterns, and engines only needed to decide whether a given word is in the set. 14 | Eventually patterns become a list of commands, and pattern matching engines become script languages. 15 | Today many constructs of structured programming are available in regular expressions (pcre2pattern / perlre) such as loops (called repetitions), if-else selection (called conditional blocks), function calls (called recursions), returns and breaks (called control verbs). 16 | The execution of each command is accurately defined which allows fine control over the entire matching process. 17 | Patterns can also store information in local variables (called capturing blocks and marks) and these variables are often available after the matching is completed. 18 | Byte code is used as an internal representation in many script languages, and modern regular expression engines are no different. 19 | There are several methods to improve the performance of byte code execution (including JIT compiling), but even the fastest script language can do very little to improve the speed of a slow bubble sort. 20 | Hence it is recommended to carefully design patterns to avoid slow matching speed. 21 | 22 | ## Structure of the Generated Code 23 | 24 | Regular expression patterns are a sequence of sub-patterns which are matched in concatenation order. 25 | When a sub-pattern matches successfully, the engine tries to match the next sub-pattern, and when its matching is failed, the engine falls back to the previous sub-pattern. 26 | If the previous sub-pattern has multiple options for matching, and another option does match, the engine will try to match the next sub-pattern again. 27 | This technique is called backtracking. 28 | 29 | The code generated by PCRE2 JIT is specialized for this execution order. 30 | For each sub-pattern the compiler generates two code paths called matching and backtracking path. 31 | The order of matching paths in the generated code is the same as the original concatenation order since the next sub-pattern must be matched after a successful match. 32 | However the backtracking paths are generated in a reversed concatenation order because the engine must fall back to the previous sub-pattern after a failed match. 33 | Control flow is shown in the next figure where green and red arrows show the possible control transfers from matching and backtracking paths respectively. 34 | Due to the code generation order described before, no jump instructions are needed for control transfers represented by horizontal arrows. 35 | 36 | ![figure1](figure1.svg) 37 | 38 | The next figure shows the structure of the machine code generated from the /a(?:\w\d)+d/ pattern: 39 | 40 | ```python 41 | 42 | # Start of matching paths 43 | ENTER 44 | # Matching path of matching the "a" letter 45 | MATCH "a", IF FAILS GOTO L6 46 | # Matching path of (?:)+ 47 | STACK_PUSH NULL 48 | L1: 49 | # Matching path of matching the \w special character 50 | MATCH WORD_CHARACTER, IF FAILS GOTO L5 51 | # Matching path of matching the \d special character 52 | MATCH DIGIT_CHARACTER, IF FAILS GOTO L4 53 | # Continue the matching path of (?:)+ 54 | STACK_PUSH STRING_POINTER 55 | GOTO L1 56 | L2: 57 | # Matching path of matching the "d" letter 58 | MATCH "d", IF FAILS GOTO L3 59 | RETURN SUCCESS 60 | 61 | # Start of backtracking paths 62 | # Backtracking path of matching the "d" letter (empty) 63 | L3: 64 | # Backtracking path of (?:)+ (empty) 65 | # Backtracking path of matching the dot special character (empty) 66 | L4: 67 | # Backtracking path of matching the "b" letter (empty) 68 | L5: 69 | # Continue backtracking path of (?:)+ 70 | STRING_POINTER = STACK_POP 71 | IF STRING_POINTER != NULL GOTO L2 72 | # Backtracking path of matching the "a" letter (empty) 73 | L6: 74 | RETURN FAIL 75 | ``` 76 | 77 | When a matching path has only one alternative (e.g. matching the letter `a`), the backtracking path is often empty, i.e. no instructions are generated at all. 78 | Some constructs may contain the code paths of other sub-patterns. 79 | In our example above, the code paths of `\w\d` sub-pattern is nested into the code paths of `(?:)+`. 80 | Furthermore the current position in the input is stored in the `STRING_POINTER` variable. 81 | This variable must have the correct value when the execution enters into a matching path, but it is undefined for backtracking paths. 82 | Hence the backtracking path must restore (or set) it before jumps to a matching path. 83 | This restoration can be seen in the backtracking path of `(?:)+`. 84 | 85 | More about this method can be found in this [research paper](https://dl.acm.org/doi/abs/10.1145/2544137.2544146). 86 | In the followings some optimizations done by the compiler is shown. 87 | 88 | ## Single Character Repitition Optimizations 89 | 90 | Sometimes multiple letters represent a single character, such as `sh` in English or `sch` in German. 91 | These sequences cannot be broken into smaller parts, so perl calls them atomic blocks. 92 | Another well known example is `\r\n` which represents a single newline. 93 | Although `\r` and `\n` are also newlines, the `x\R{2}y` pattern does not match to `x\r\ny`, because there is only one newline between `x` and `y` letters. 94 | Atomic blocks can speed up matching, since they can eliminate many retries. 95 | For example `a+b` and `a++b` matches to the same strings since no `b` can be present in a sequence of `a`-s. 96 | Hence the engine automatically converts the repetitions to the latter form whenever it has no side effects. 97 | 98 | The JIT compiler can speed up repetitions followed by a single character as well. 99 | An example is `\w+x`, where `\w+` cannot be converted to `\w++` because `x` is included in `\w` character class. 100 | The code generated for `\w+` also records the first and last occurrence of `x` and backtracking is limited to this range. 101 | This optimization has the highest efficiency when at most one `x` is found during the repetition. 102 | 103 | The `(*SKIP)` control verb allows moving forward in the input. 104 | For example, this verb can be used to search identifiers in a source code excluding comments and string literals. 105 | To do that, the pattern should also look for comments and string literals but it skips these blocks instead of returning with a match. 106 | Skip can be used to improve performance as well. 107 | The `\w+!` and `\w+(*SKIP)!` patterns match to the same strings because when `\w+` is matched to a range of characters, but the match is failed afterwards, then any other match attempts within this range must fail as well. 108 | Therefore the search can be resumed from the end of the range which eliminates several match attempts. 109 | Besides adding `(*SKIP)` verbs to the pattern, the JIT compiler can also enhance iterators to remember the range of their last successful match, and any future matching attempts within this range triggers a fail. 110 | 111 | ## Character Class Optimizations 112 | 113 | Checking that a character is in a set of characters (called character classes) is a frequent operation in pattern matching. 114 | When caseless mode is enabled, even a simple pattern character may match to different characters especially when UTF is enabled. 115 | 116 | The most basic optimization is caseless compare with a single compare instruction if there is only one bit difference between the binary representation of the lower and upper case of a character. 117 | For example, ascii `x` and `X` differs only in bit 6, so `(chr|0x20)=='x'` performs a caseless compare, and it is faster than doing two compares. 118 | This can be extended to ranges, so the `[f-xF-X]` range can be checked with this formula: `((chr|0x20)-'f')<('x'-'f')`. 119 | Optimizing these cases is no different from optimizing conditional expressions in static compilers such as GCC. 120 | 121 | The JIT compiler also has some UTF related optimizations. 122 | For example, if a class is limited to characters less than 128 in UTF8 mode, reading only the next byte is enough and it is faster than decoding the UTF8 character. 123 | This optimization is not limited to the previous case, the compiler can generate specialized readers which do not decode characters outside of a given range. 124 | When invalid UTF8 parsing is enabled, the character reader first checks whether the input buffer has at least four remaining bytes. 125 | This is nearly always true, and then the character can be decoded without further boundary checks since four is the size of the longest UTF8 character. 126 | 127 | The JIT compiler generates helper functions for several operations, such as decoding complex UTF cases. 128 | These functions are extremely lightweight: they don't set up a call frame or save any CPU registers, and can even modify the status of the caller. 129 | The effect is quite similar to inlining, except that the function is actually called. 130 | Must CPUs has return address predictors, so calling these functions are cheap operations. 131 | 132 | ## Literal Optimizations 133 | 134 | Literals are fixed character sequences and they are often found in patterns. 135 | Comparing them to the input is a frequent task which normally requires the same number of steps as the length of the literal. 136 | However CPU registers are often large enough to hold multiple characters so the number of comparisons can be reduced as long as the CPU can read a whole register from any starting address. 137 | Such read is called unaligned access and requires hardware support. 138 | 139 | Single Instruction Multiple Data (SIMD) operations can speed up literal searching. 140 | These operations can process the input efficiently since they use large registers which can hold several input characters. 141 | The JIT compiler uses SIMD for searching characters and character pairs. 142 | Searching a pair is based on an observation that the chance of finding a pair is often much lower than finding a single character. 143 | The only condition is that the two characters of a pair must be different since searching two spaces instead of one might not give better results. 144 | The compiler tries to detect the pair with the lowest match probability, so it will choose the `a` and `c` characters from the `a.(?i:b).c` pattern. 145 | 146 | ## Summary 147 | 148 | PCRE2 is among the most feature rich regular expression libraries. 149 | It supports many regular expression constructs and it has many operating modes. 150 | Its JIT compiler tries to optimize many of these features with static compiler optimizations, and this text introduces some of these optimizations. 151 | Besides these optimizations, directed pattern transformations can also help to improve performance, but that is the focus of other projects such as [repan](https://github.com/zherczeg/repan). 152 | -------------------------------------------------------------------------------- /docs/tutorial/01-overview.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | > [!NOTE] 4 | > The original version of this tutorial was provided by Wen Xichang (wenxichang@163.com) in 2015. 5 | 6 | To be able to follow this tutorial, you will need: 7 | - A `C99` compatible C/C++ compiler (somewhat recent versions of GCC / Clang / MSVC are safe choices) 8 | - GNU Make (or CMake, if you are on Windows) 9 | 10 | The examples shown in the tutorial can be built via the `examples` make target. See the [setup guide](../general/getting-started/setup.md) for more details. 11 | 12 | The tutorial assumes you are already familiar with the C programming language. 13 | -------------------------------------------------------------------------------- /docs/tutorial/02-your-first-program.md: -------------------------------------------------------------------------------- 1 | # Your First Program 2 | 3 | To use SLJIT, simply include the `sljitLir.h` header in your code and link against `sljitLir.c`. 4 | Let's jump right into your first program: 5 | 6 | ```c 7 | #include "sljitLir.h" 8 | 9 | #include 10 | #include 11 | 12 | typedef sljit_sw (SLJIT_FUNC *func3_t)(sljit_sw a, sljit_sw b, sljit_sw c); 13 | 14 | static int add3(sljit_sw a, sljit_sw b, sljit_sw c) 15 | { 16 | void *code; 17 | sljit_uw len; 18 | func3_t func; 19 | 20 | /* Create a SLJIT compiler */ 21 | struct sljit_compiler *C = sljit_create_compiler(NULL); 22 | 23 | /* Start a context (function prologue) */ 24 | sljit_emit_enter(C, 25 | 0, /* Options */ 26 | SLJIT_ARGS3(W, W, W, W), /* 1 return value and 3 parameters of type sljit_sw */ 27 | 1, /* 1 scratch register used */ 28 | 3, /* 3 saved registers used */ 29 | 0); /* 0 bytes allocated for function local variables */ 30 | 31 | /* The first argument of a function is stored in register SLJIT_S0, the 2nd in SLJIT_S1, etc. */ 32 | /* R0 = first */ 33 | sljit_emit_op1(C, SLJIT_MOV, SLJIT_R0, 0, SLJIT_S0, 0); 34 | 35 | /* R0 = R0 + second */ 36 | sljit_emit_op2(C, SLJIT_ADD, SLJIT_R0, 0, SLJIT_R0, 0, SLJIT_S1, 0); 37 | 38 | /* R0 = R0 + third */ 39 | sljit_emit_op2(C, SLJIT_ADD, SLJIT_R0, 0, SLJIT_R0, 0, SLJIT_S2, 0); 40 | 41 | /* This statement moves R0 to RETURN REG and returns */ 42 | /* (in fact, R0 is the RETURN REG itself) */ 43 | sljit_emit_return(C, SLJIT_MOV, SLJIT_R0, 0); 44 | 45 | /* Generate machine code */ 46 | code = sljit_generate_code(C, 0, NULL); 47 | len = sljit_get_generated_code_size(C); 48 | 49 | /* Execute code */ 50 | func = (func3_t)code; 51 | printf("func return %ld\n", (long)func(a, b, c)); 52 | 53 | /* dump_code(code, len); */ 54 | 55 | /* Clean up */ 56 | sljit_free_compiler(C); 57 | sljit_free_code(code, NULL); 58 | 59 | return 0; 60 | } 61 | 62 | int main() 63 | { 64 | return add3(4, 5, 6); 65 | } 66 | ``` 67 | 68 | Code generation with SLJIT typically starts with a call to `sljit_emit_enter`, which generates the *function prologue*: certain register are saved to the stack, stack space for function-local variables is allocted if requested and a call frame is established. 69 | 70 | This is necessary as the code generated by SLJIT wants to interoperate nicely with the other parts of your program: it can be called just like a C function pointer and you can [call C functions](04-calling-external-functions.md) from within JIT-ed code with ease. 71 | 72 | The rules for interoperation are also refered to as the *Application Binary Interface*, or ABI for short. These typically vary between different architectures and operating systems. The most common ones are: 73 | - [System V ABI](https://wiki.osdev.org/System_V_ABI) - used by the major Unix operating systems (Linux / BSD / AIX / ...) 74 | - [Windows x64 ABI](https://learn.microsoft.com/en-us/cpp/build/x64-software-conventions?view=msvc-170) - used by (you guessed it) Windows 75 | 76 | Luckily, SLJIT does all the heavy lifting so that you do not have to worry about platform and ABI specific stuff for the most part. If you are interested in how things work under the hood though, take a look at the *calling conventions* sections in the ABI documentation. 77 | 78 | SLJIT supports two types of registers (analoguous to the underlying ABIs): 79 | - **Scratch registers** (also known as *volatile registers*) - may not preserve their value accross function calls 80 | - **Saved registers** (also known as *non-volatile registers*) - preserve their value accross function calls 81 | 82 | We declare the amount of scratch and saved registers our function will use upfront in the call to `sljit_emit_enter`. These registers are then referred to by their names (`SLJIT_R0`, `SLJIT_R1`, `SLJIT_R2`, ... for scratch registers and `SLJIT_S0`, `SLJIT_S1`, `SLJIT_S2`, ... for saved registers). 83 | Additionally, SLJIT supports dedicated floating point and vector registers. These are referred to by `SLJIT_FRN` / `SLJIT_FSN` and `SLJIT_VRN` / `SLJIT_VSN` respectively (where `N` is a number starting from `0`). 84 | 85 | As different architectures have different amounts of registers, the amount of scratch and saved registers available varies accross them. You can query the available amount of registers with the following macros: 86 | - `SLJIT_NUMBER_OF_REGISTERS` (>= 12 on all supported platforms) 87 | - `SLJIT_NUMBER_OF_SCRATCH_REGISTERS` 88 | - `SLJIT_NUMBER_OF_SAVED_REGISTERS` (>= 6 on all supported platforms) 89 | - `SLJIT_NUMBER_OF_FLOAT_REGISTERS` 90 | - `SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS` 91 | - `SLJIT_NUMBER_OF_VECTOR_REGISTERS` 92 | - `SLJIT_NUMBER_OF_SAVED_VECTOR_REGISTERS` 93 | 94 | Note that the different register sets may overlap, i.e. two distinct SLJIT registers may refer to the same physical register. This is especially true between scratch and saved registers of the same kind, as well as between floating point and vector registers. 95 | 96 | A function's signature is defined using one of the `SLJIT_ARGS...` macros. In the example above, the function declares a return type and three parameters of type `W`, i.e. an integer of machine word width. For the other supported types, take a look at the `SLJIT_ARG_TYPE_...` macros in `sljitLir.h`. Parameters are passed by default in registers `SLJIT_S0` - `SLJIT_S3` (for integers) and `SLJIT_FR0` - `SLJIT_FR3` (for floating point numbers) respectively. Analoguos, the return value is passed in `SLJIT_R0` or `SLJIT_FR0`. 97 | 98 | Most generic operations are carried out by invoking one of the `sljit_emit_opN` functions. These typically take one target, as well as `N` source operands. 99 | 100 | | 1st parameter | 2nd parameter | Semantic | Example | 101 | | --- | --- | --- | --- | 102 | | `r` | `0` | The value contained in register `r`, i.e. `*r` | `SLJIT_R0, 0` | 103 | | `SLJIT_IMM` | Value `i` | The value `i` | `SLJIT_IMM, 17` | 104 | | `SLJIT_MEM` / `SLJIT_MEM0` | Address `a` | The value at address `a` | `SLJIT_MEM0, &my_c_func` | 105 | | `SLJIT_MEM1(r)` | Offset `o` | The value at address `*r + o` | `SLJIT_MEM1(SLJIT_R0), 16`
Access the memory at the address in `SLJIT_R0` offset by `16` | 106 | | `SLJIT_MEM2(r1, r2)` | Shift `s` | The value at address `*r1 + (*r2 * (1 << s))`;
`s` must be in `[0, 1, 2, 3]` | `SLJIT_MEM2(SLJIT_R0, SLJIT_R1), 2`
Access index `SLJIT_R1` in an array of items of length `2` byte starting at address `SLJIT_R0` | 107 | 108 | Lastly, control is returned to the caller by invoking `sljit_emit_return`. 109 | -------------------------------------------------------------------------------- /docs/tutorial/03-branching.md: -------------------------------------------------------------------------------- 1 | # Branching 2 | 3 | Branching allows us to divert control flow. This can be useful to implement higher-level constructs such as conditionals and loops. 4 | 5 | Branches, also referred to as *jumps*, come in two flavors: 6 | 7 | - **Conditional:** only taken if a condition is met; otherwise, execution continues at the next instruction 8 | - **Unconditional:** always taken 9 | 10 | Jumps can be emitted via calls to `sljit_emit_cmp` (conditional) and `sljit_emit_jump` (unconditional). Both of these functions return a pointer to `struct sljit_jump`, which needs to be connected to a `struct sljit_label` (the jump's target) later on. 11 | 12 | Labels can be emitted via calls to `sljit_emit_label` and connected to jumps via `sljit_set_label`. The whole mechanism is very similar to labels and gotos in C. 13 | 14 | In order to map higher-level constructs such as conditionals and loops to SLJIT, it helps to think about them in terms of labels and (un)conditional gotos. As an example, take the following simple function body: 15 | 16 | ```c 17 | if ((a & 1) == 0) 18 | return c; 19 | return b; 20 | ``` 21 | 22 | Expressing the implicit control flow with lables and gotos yields: 23 | 24 | 25 | ``` 26 | R0 = a & 1; 27 | if R0 == 0 then goto ret_c; 28 | R0 = b; 29 | goto out; 30 | ret_c: 31 | R0 = c; 32 | out: 33 | return R0; 34 | ``` 35 | 36 | This is also what higher-level language compilers do under the hood. The result can now easily be assembled with SLJIT: 37 | 38 | ```c 39 | #include "sljitLir.h" 40 | 41 | #include 42 | #include 43 | 44 | typedef sljit_sw (SLJIT_FUNC *func3_t)(sljit_sw a, sljit_sw b, sljit_sw c); 45 | 46 | static int branch(sljit_sw a, sljit_sw b, sljit_sw c) 47 | { 48 | void *code; 49 | sljit_uw len; 50 | func3_t func; 51 | 52 | struct sljit_jump *ret_c; 53 | struct sljit_jump *out; 54 | 55 | /* Create a SLJIT compiler */ 56 | struct sljit_compiler *C = sljit_create_compiler(NULL); 57 | 58 | /* 3 arg, 1 temp reg, 3 save reg */ 59 | sljit_emit_enter(C, 0, SLJIT_ARGS3(W, W, W, W), 1, 3, 0); 60 | 61 | /* R0 = a & 1, S0 is argument a */ 62 | sljit_emit_op2(C, SLJIT_AND, SLJIT_R0, 0, SLJIT_S0, 0, SLJIT_IMM, 1); 63 | 64 | /* if R0 == 0 then jump to ret_c, where is ret_c? we assign it later */ 65 | ret_c = sljit_emit_cmp(C, SLJIT_EQUAL, SLJIT_R0, 0, SLJIT_IMM, 0); 66 | 67 | /* R0 = b, S1 is argument b */ 68 | sljit_emit_op1(C, SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_S1, 0); 69 | 70 | /* jump to out */ 71 | out = sljit_emit_jump(C, SLJIT_JUMP); 72 | 73 | /* here is the 'ret_c' should jump, we emit a label and set it to ret_c */ 74 | sljit_set_label(ret_c, sljit_emit_label(C)); 75 | 76 | /* R0 = c, S2 is argument c */ 77 | sljit_emit_op1(C, SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_S2, 0); 78 | 79 | /* here is the 'out' should jump */ 80 | sljit_set_label(out, sljit_emit_label(C)); 81 | 82 | /* end of function */ 83 | sljit_emit_return(C, SLJIT_MOV, SLJIT_RETURN_REG, 0); 84 | 85 | /* Generate machine code */ 86 | code = sljit_generate_code(C, 0, NULL); 87 | len = sljit_get_generated_code_size(C); 88 | 89 | /* Execute code */ 90 | func = (func3_t)code; 91 | printf("func return %ld\n", (long)func(a, b, c)); 92 | 93 | /* dump_code(code, len); */ 94 | 95 | /* Clean up */ 96 | sljit_free_compiler(C); 97 | sljit_free_code(code, NULL); 98 | return 0; 99 | } 100 | 101 | int main() 102 | { 103 | return branch(4, 5, 6); 104 | } 105 | ``` 106 | 107 | *The complete source code of the example can be found [here](sources/branch.c).* 108 | 109 | Building on these basic techniques, you can further use branches to generate a loop. So, given the following function body: 110 | 111 | ```c 112 | i = 0; 113 | ret = 0; 114 | for (i = 0; i < a; ++i) { 115 | ret += b; 116 | } 117 | return ret; 118 | ``` 119 | 120 | You can again make the control flow explicit using labels and gotos: 121 | 122 | 123 | ``` 124 | i = 0; 125 | ret = 0; 126 | loopstart: 127 | if i >= a then goto out; 128 | ret += b 129 | goto loopstart; 130 | out: 131 | return ret; 132 | ``` 133 | 134 | And then use that to assemble the function with SLJIT: 135 | 136 | ```c 137 | #include "sljitLir.h" 138 | 139 | #include 140 | #include 141 | 142 | typedef sljit_sw (SLJIT_FUNC *func2_t)(sljit_sw a, sljit_sw b); 143 | 144 | static int loop(sljit_sw a, sljit_sw b) 145 | { 146 | void *code; 147 | sljit_uw len; 148 | func2_t func; 149 | 150 | struct sljit_label *loopstart; 151 | struct sljit_jump *out; 152 | 153 | /* Create a SLJIT compiler */ 154 | struct sljit_compiler *C = sljit_create_compiler(NULL); 155 | 156 | /* 2 arg, 2 temp reg, 2 saved reg */ 157 | sljit_emit_enter(C, 0, SLJIT_ARGS2(W, W, W), 2, 2, 0); 158 | 159 | /* R0 = 0 */ 160 | sljit_emit_op2(C, SLJIT_XOR, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_R1, 0); 161 | /* RET = 0 */ 162 | sljit_emit_op1(C, SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0); 163 | /* loopstart: */ 164 | loopstart = sljit_emit_label(C); 165 | /* R1 >= a --> jump out */ 166 | out = sljit_emit_cmp(C, SLJIT_GREATER_EQUAL, SLJIT_R1, 0, SLJIT_S0, 0); 167 | /* RET += b */ 168 | sljit_emit_op2(C, SLJIT_ADD, SLJIT_RETURN_REG, 0, SLJIT_RETURN_REG, 0, SLJIT_S1, 0); 169 | /* R1 += 1 */ 170 | sljit_emit_op2(C, SLJIT_ADD, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, 1); 171 | /* jump loopstart */ 172 | sljit_set_label(sljit_emit_jump(C, SLJIT_JUMP), loopstart); 173 | /* out: */ 174 | sljit_set_label(out, sljit_emit_label(C)); 175 | 176 | /* return RET */ 177 | sljit_emit_return(C, SLJIT_MOV, SLJIT_RETURN_REG, 0); 178 | 179 | /* Generate machine code */ 180 | code = sljit_generate_code(C, 0, NULL); 181 | len = sljit_get_generated_code_size(C); 182 | 183 | /* Execute code */ 184 | func = (func2_t)code; 185 | printf("func return %ld\n", (long)func(a, b)); 186 | 187 | /* dump_code(code, len); */ 188 | 189 | /* Clean up */ 190 | sljit_free_compiler(C); 191 | sljit_free_code(code, NULL); 192 | return 0; 193 | } 194 | 195 | int main() 196 | { 197 | return loop(4, 5); 198 | } 199 | ``` 200 | 201 | The other conditionals and loops can be achieved very similarly. 202 | 203 | *The complete source code of the example can be found [here](sources/loop.c).* 204 | -------------------------------------------------------------------------------- /docs/tutorial/04-calling-external-functions.md: -------------------------------------------------------------------------------- 1 | # Calling External Functions 2 | 3 | To call an external function from JIT-ed code, simply invoke `sljit_emit_icall` and specify `SLJIT_CALL`, which represents the platform's default C calling convention. There are other calling conventions available as well for more advanced use cases. 4 | 5 | Similar to `sljit_emit_enter`, `sljit_emit_icall` requires knowledge about the target function's signature. So, to call a function that takes an `sljit_sw` as its sole argument and returns an `sljit_sw`, you would specify its signature with `SLJIT_ARGS1(W, W)`. Integer arguments are passed in registers `R0`, `R1` and `R2` and the result (if present) is returned in `R0`. 6 | 7 | To point SLJIT to the function you want to call, you can use `SLJIT_FUNC_ADDR` to pass its address as an immediate value. 8 | 9 | So, to call a function `sljit_sw print_num(sljit_sw a)`, passing the value in `S2`, you could do the following: 10 | 11 | ```c 12 | /* R0 = S2 */ 13 | sljit_emit_op1(C, SLJIT_MOV, SLJIT_R0, 0, SLJIT_S2, 0); 14 | /* print_num(R0) */ 15 | sljit_emit_icall(C, SLJIT_CALL, SLJIT_ARGS1(W, W), SLJIT_IMM, SLJIT_FUNC_ADDR(print_num)); 16 | ``` 17 | 18 | *The complete source code of the example can be found [here](sources/func_call.c).* 19 | -------------------------------------------------------------------------------- /docs/tutorial/05-accessing-structures.md: -------------------------------------------------------------------------------- 1 | # Accessing Structures 2 | 3 | While SLJIT does not support record types (structs and classes) directly, it is still very easy to work with them. Assuming you have in `S0` the address to a `struct point` defined as follows: 4 | 5 | ```c 6 | struct point_st { 7 | sljit_sw x; 8 | sljit_s32 y; 9 | sljit_s16 z; 10 | sljit_s8 d; 11 | }; 12 | ``` 13 | 14 | To move member `y` into `R0`, you can use the `SLJIT_MEM1` addressing mode, which allows us to specify an offset. To obtain the offset of `y` in `point_st`, you can use the handy `SLJIT_OFFSETOF` macro like so: 15 | 16 | ```c 17 | sljit_emit_op1(C, SLJIT_MOV_S32, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_S0), SLJIT_OFFSETOF(struct point_st, y)); 18 | ``` 19 | 20 | And always keep in mind to use the correctly typed variant of `SLJIT_MOV`! 21 | 22 | *The complete source code of the example can be found [here](sources/struct_access.c).* 23 | -------------------------------------------------------------------------------- /docs/tutorial/06-accessing-arrays.md: -------------------------------------------------------------------------------- 1 | # Accessing Arrays 2 | 3 | Accessing arrays works similar to accessing structures. In case you are dealing with arrays of items of at most 8 bytes, you can utilize the shift of SLJIT's `SLJIT_MEM2` addressing mode. For example, assuming you have the base address of an array of `sljit_sw`s in `S0` and want to access the `S2`-th item: 4 | 5 | ```c 6 | sljit_sw s0[]; 7 | r0 = s0[s2]; 8 | ``` 9 | 10 | You can simply use `SLJIT_WORD_SHIFT` to correctly account for the size of each item: 11 | 12 | ```c 13 | sljit_emit_op1(C, SLJIT_MOV, SLJIT_R0, 0, SLJIT_MEM2(SLJIT_S0, SLJIT_S2), SLJIT_WORD_SHIFT); 14 | ``` 15 | 16 | In case the size of an item cannot be represented with `SLJIT_MEM2`'s shift, you can still fall back to calculating the offset manually and passing it into `SLJIT_MEM1`. This can be combined with structure access as well. Suppose you want to assemble the following: 17 | 18 | ```c 19 | struct point_st { 20 | sljit_sw x; 21 | sljit_s32 y; 22 | sljit_s16 z; 23 | sljit_s8 d; 24 | }; 25 | 26 | point_st s0[]; 27 | r0 = s0[s2].x; 28 | ``` 29 | 30 | As `point_st` is larger than 8 bytes, you need to convert the array index to a byte offset beforehand and store it in a temporary: 31 | 32 | ```c 33 | /* calculate the array index: R2 = S2 * sizeof(point_st) */ 34 | sljit_emit_op2(C, SLJIT_MUL, SLJIT_R1, 0, SLJIT_S2, 0, SLJIT_IMM, sizeof(struct point_st)); 35 | /* access the array item: R0 = S0[R2] */ 36 | sljit_emit_op1(C, SLJIT_MOV, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_S0), SLJIT_R2); 37 | ``` 38 | 39 | Above example relies on the fact that `x` is the first member of `point_st` and thus shares its address with the surrounding struct. In case you want to access a different member, you need to further take its offset into account. 40 | 41 | *The complete source code of the example can be found [here](sources/array_access.c).* 42 | -------------------------------------------------------------------------------- /docs/tutorial/07-local-variables.md: -------------------------------------------------------------------------------- 1 | # Local Variables 2 | 3 | In some cases you are dealing with data that cannot be mapped to registers, either because it needs to be linear in memory (think of structs and arrays) or because it is simply too large to fit into the available ones. 4 | 5 | While you could resort to dynamic memory allocation, e.g. through a call to external function `malloc` and the likes, there is a better way for temporary variables of fixed size: *function local storage*. 6 | 7 | Local storage can be requested via the last parameter of `sljit_emit_enter` in bytes, which in the previous examples was always zero. Under the hood, SLJIT will allocate the requested amount as a contiguous block of memory in the function's stack frame. 8 | 9 | Due to its otherwise stackless API, SLJIT hides most of these implementation details from you. There are two ways to access this local data: 10 | 11 | - Special register `SLJIT_SP` acts as a pointer to the base of the local data. It can *only* be used in the form of `SLJIT_MEM1(SLJIT_SP)` to access local data at an offset. 12 | - If instead you need the actual address, you can use `sljit_get_local_base`. For example, `sljit_get_local_base(C, SLJIT_R0, 0, 0x40)` will load the address of the local data area offset by `0x40` into `R0`. 13 | 14 | *To see local variables in action, take a look at [this](sources/array_access.c) example.* 15 | -------------------------------------------------------------------------------- /docs/tutorial/08-where-to-go-from-here.md: -------------------------------------------------------------------------------- 1 | # Where To Go From Here 2 | 3 | You should now have a basic understanding of how to use SLJIT. In case things are still unclear or you want to know more about a certain topic, take a look at [`sljitLir.h`](https://github.com/zherczeg/sljit/blob/master/sljit_src/sljitLir.h). 4 | 5 | Also, you may have noticed the commented out calls to `dump_code` throughout the sources in this tutorial. If you are interested in what assembly SLJIT actually generates, you can provide your own routine to do so (assuming you are on Linux `x86-32` or `x86-64`): 6 | 7 | ```c 8 | static void dump_code(void *code, sljit_uw len) 9 | { 10 | FILE *fp = fopen("/tmp/sljit_dump", "wb"); 11 | if (!fp) 12 | return; 13 | fwrite(code, len, 1, fp); 14 | fclose(fp); 15 | #if defined(SLJIT_CONFIG_X86_64) 16 | system("objdump -b binary -m l1om -D /tmp/sljit_dump"); 17 | #elif defined(SLJIT_CONFIG_X86_32) 18 | system("objdump -b binary -m i386 -D /tmp/sljit_dump"); 19 | #endif 20 | } 21 | ``` 22 | 23 | And lastly, to see SLJIT used in a more complex scenario, take a look at [this](sources/brainfuck.c) [Brainfuck](https://en.wikipedia.org/wiki/Brainfuck) compiler. 24 | -------------------------------------------------------------------------------- /docs/tutorial/sources/99bottles.bf: -------------------------------------------------------------------------------- 1 | ########################## 2 | ### 3 | ### Severely updated version! 4 | ### (now says "1 bottle" and 5 | ### contains no extra "0" verse) 6 | ### 7 | ########################## 8 | ### 99 Bottles of Beer ### 9 | ### coded in Brainfuck ### 10 | ### with explanations ### 11 | ########################## 12 | # 13 | # This Bottles of Beer program 14 | # was written by Andrew Paczkowski 15 | # Coder Alias: thepacz 16 | # three_halves_plus_one@yahoo.com 17 | ##### 18 | 19 | > 0 in the zeroth cell 20 | +++++++>++++++++++[<+++++>-] 57 in the first cell or "9" 21 | +++++++>++++++++++[<+++++>-] 57 in second cell or "9" 22 | ++++++++++ 10 in third cell 23 | >+++++++++ 9 in fourth cell 24 | 25 | ########################################## 26 | ### create ASCII chars in higher cells ### 27 | ########################################## 28 | 29 | >>++++++++[<++++>-] " " 30 | >++++++++++++++[<+++++++>-] b 31 | +>+++++++++++[<++++++++++>-] o 32 | ++>+++++++++++++++++++[<++++++>-] t 33 | ++>+++++++++++++++++++[<++++++>-] t 34 | >++++++++++++[<+++++++++>-] l 35 | +>++++++++++[<++++++++++>-] e 36 | +>+++++++++++++++++++[<++++++>-] s 37 | >++++++++[<++++>-] " " 38 | +>+++++++++++[<++++++++++>-] o 39 | ++>++++++++++[<++++++++++>-] f 40 | >++++++++[<++++>-] " " 41 | >++++++++++++++[<+++++++>-] b 42 | +>++++++++++[<++++++++++>-] e 43 | +>++++++++++[<++++++++++>-] e 44 | >+++++++++++++++++++[<++++++>-] r 45 | >++++++++[<++++>-] " " 46 | +>+++++++++++[<++++++++++>-] o 47 | >+++++++++++[<++++++++++>-] n 48 | >++++++++[<++++>-] " " 49 | ++>+++++++++++++++++++[<++++++>-] t 50 | ++++>++++++++++[<++++++++++>-] h 51 | +>++++++++++[<++++++++++>-] e 52 | >++++++++[<++++>-] " " 53 | ++>+++++++++++++[<+++++++++>-] w 54 | +>++++++++++++[<++++++++>-] a 55 | >++++++++++++[<+++++++++>-] l 56 | >++++++++++++[<+++++++++>-] l 57 | >+++++[<++>-] LF 58 | ++>+++++++++++++++++++[<++++++>-] t 59 | +>++++++++++++[<++++++++>-] a 60 | +++>+++++++++++++[<++++++++>-] k 61 | +>++++++++++[<++++++++++>-] e 62 | >++++++++[<++++>-] " " 63 | +>+++++++++++[<++++++++++>-] o 64 | >+++++++++++[<++++++++++>-] n 65 | +>++++++++++[<++++++++++>-] e 66 | >++++++++[<++++>-] " " 67 | >++++++++++[<++++++++++>-] d 68 | +>+++++++++++[<++++++++++>-] o 69 | ++>+++++++++++++[<+++++++++>-] w 70 | >+++++++++++[<++++++++++>-] n 71 | >++++++++[<++++>-] " " 72 | +>++++++++++++[<++++++++>-] a 73 | >+++++++++++[<++++++++++>-] n 74 | >++++++++++[<++++++++++>-] d 75 | >++++++++[<++++>-] " " 76 | ++>+++++++++++[<++++++++++>-] p 77 | +>++++++++++++[<++++++++>-] a 78 | +>+++++++++++++++++++[<++++++>-] s 79 | +>+++++++++++++++++++[<++++++>-] s 80 | >++++++++[<++++>-] " " 81 | +>+++++++++++++[<++++++++>-] i 82 | ++>+++++++++++++++++++[<++++++>-] t 83 | >++++++++[<++++>-] " " 84 | +>++++++++++++[<++++++++>-] a 85 | >+++++++++++++++++++[<++++++>-] r 86 | +>+++++++++++[<++++++++++>-] o 87 | >+++++++++++++[<+++++++++>-] u 88 | >+++++++++++[<++++++++++>-] n 89 | >++++++++++[<++++++++++>-] d 90 | >+++++[<++>-] LF 91 | +++++++++++++ CR 92 | 93 | [<]>>>> go back to fourth cell 94 | 95 | ################################# 96 | ### initiate the display loop ### 97 | ################################# 98 | 99 | [ loop 100 | < back to cell 3 101 | [ loop 102 | [>]<< go to last cell and back to LF 103 | .. output 2 newlines 104 | [<]> go to first cell 105 | 106 | ################################### 107 | #### begin display of characters### 108 | ################################### 109 | # 110 | #.>.>>>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.> 111 | #X X b o t t l e s o f b e e r 112 | #.>.>.>.>.>.>.>.>.>.>.>. 113 | #o n t h e w a l l N 114 | #[<]> go to first cell 115 | #.>.>>>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>>>>>>>>>>>>>.> 116 | #X X b o t t l e s o f b e e r N 117 | #.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.> 118 | #t a k e o n e d o w n a n d p a s s 119 | #.>.>.>.>.>.>.>.>.>. 120 | #i t a r o u n d N 121 | ##### 122 | 123 | [<]>> go to cell 2 124 | - subtract 1 from cell 2 125 | < go to cell 1 126 | 127 | ######################## 128 | ### display last line ## 129 | ######################## 130 | # 131 | #.>.>>>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.> 132 | #X X b o t t l e s o f b e e r 133 | #.>.>.>.>.>.>.>.>.>.>. 134 | #o n t h e w a l l 135 | ##### 136 | 137 | [<]>>>- go to cell 3/subtract 1 138 | ] end loop when cell 3 is 0 139 | ++++++++++ add 10 to cell 3 140 | <++++++++++ back to cell 2/add 10 141 | <- back to cell 1/subtract 1 142 | [>]<. go to last line/carriage return 143 | [<]> go to first line 144 | 145 | ######################## 146 | ### correct last line ## 147 | ######################## 148 | # 149 | #.>.>>>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.> 150 | #X X b o t t l e s o f b e e r 151 | #.>.>.>.>.>.>.>.>.>.>. 152 | #o n t h e w a l l 153 | ##### 154 | 155 | [<]>>>>- go to cell 4/subtract 1 156 | ] end loop when cell 4 is 0 157 | 158 | ############################################################## 159 | ### By this point verses 9910 are displayed but to work ### 160 | ### with the lower numbered verses in a more readable way ### 161 | ### we initiate a new loop for verses 9{CODE} that will not ### 162 | ### use the fourth cell at all ### 163 | ############################################################## 164 | 165 | + add 1 to cell four (to keep it nonzero) 166 | <-- back to cell 3/subtract 2 167 | 168 | [ loop 169 | [>]<< go to last cell and back to LF 170 | .. output 2 newlines 171 | [<]> go to first cell 172 | 173 | ################################### 174 | #### begin display of characters### 175 | ################################### 176 | # 177 | #>.>>>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.> 178 | # X b o t t l e s o f b e e r 179 | #.>.>.>.>.>.>.>.>.>.>.>. 180 | #o n t h e w a l l N 181 | #[<]> go to first cell 182 | #>.>>>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>>>>>>>>>>>>>.> 183 | # X b o t t l e s o f b e e r N 184 | #.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.> 185 | #t a k e o n e d o w n a n d p a s s 186 | #.>.>.>.>.>.>.>.>.>. 187 | #i t a r o u n d N 188 | ##### 189 | 190 | [<]>> go to cell 2 191 | - subtract 1 from cell 2 192 | 193 | ######################## 194 | ### display last line ## 195 | ######################## 196 | # 197 | #.>>>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.> 198 | #X b o t t l e s o f b e e r 199 | #.>.>.>.>.>.>.>.>.>.>. 200 | #o n t h e w a l l 201 | ##### 202 | 203 | [<]>>>- go to cell 3/subtract 1 204 | ] end loop when cell 3 is 0 205 | + add 1 to cell 3 to keep it nonzero 206 | 207 | [>]<. go to last line/carriage return 208 | [<]> go to first line 209 | 210 | ######################## 211 | ### correct last line ## 212 | ######################## 213 | # 214 | #>.>>>.>.>.>.>.>.>.>>.>.>.>.>.>.>.>.>.> 215 | # X b o t t l e o f b e e r 216 | #.>.>.>.>.>.>.>.>.>.>.<<<<. 217 | #o n t h e w a l l 218 | ##### 219 | 220 | [>]<< go to last cell and back to LF 221 | .. output 2 newlines 222 | [<]> go to first line 223 | 224 | ######################### 225 | ### the final verse ## 226 | ######################### 227 | # 228 | #>.>>>.>.>.>.>.>.>.>>.>.>.>.>.>.>.>.>.> 229 | # X b o t t l e o f b e e r 230 | #.>.>.>.>.>.>.>.>.>.>.>. 231 | #o n t h e w a l l N 232 | #[<]> go to first cell 233 | #>.>>>.>.>.>.>.>.>.>>.>.>.>.>.>.>.>.>>>>>>>>>>>>>.> 234 | # X b o t t l e o f b e e r N 235 | #.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.> 236 | #t a k e o n e d o w n a n d p a s s 237 | #.>.>.>.>.>.>.>.>.>. 238 | #i t a r o u n d N 239 | #[>]< go to last line 240 | #<<<.<<.<<<. 241 | # n o 242 | #[<]>>>> go to fourth cell 243 | #>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.> 244 | # b o t t l e s o f b e e r 245 | #.>.>.>.>.>.>.>.>.>.>.>. 246 | #o n t h e w a l l N 247 | #####fin## -------------------------------------------------------------------------------- /docs/tutorial/sources/array_access.c: -------------------------------------------------------------------------------- 1 | #include "sljitLir.h" 2 | 3 | #include 4 | #include 5 | 6 | typedef sljit_sw (SLJIT_FUNC *func_arr_t)(sljit_sw *arr, sljit_sw narr); 7 | 8 | static void SLJIT_FUNC print_num(sljit_sw a) 9 | { 10 | printf("num = %ld\n", (long)a); 11 | } 12 | 13 | /* 14 | This example, we generate a function like this: 15 | 16 | sljit_sw func(sljit_sw *array, sljit_sw narray) 17 | { 18 | sljit_sw i; 19 | for (i = 0; i < narray; ++i) 20 | print_num(array[i]); 21 | return narray; 22 | } 23 | 24 | */ 25 | 26 | static int array_access(sljit_sw *arr, sljit_sw narr) 27 | { 28 | void *code; 29 | sljit_uw len; 30 | func_arr_t func; 31 | struct sljit_label *loopstart; 32 | struct sljit_jump *out; 33 | 34 | /* Create a SLJIT compiler */ 35 | struct sljit_compiler *C = sljit_create_compiler(NULL); 36 | 37 | sljit_emit_enter(C, 0, SLJIT_ARGS2(W, P, W), 1, 3, 0); 38 | /* opt arg R S local_size */ 39 | 40 | /* S2 = 0 */ 41 | sljit_emit_op2(C, SLJIT_XOR, SLJIT_S2, 0, SLJIT_S2, 0, SLJIT_S2, 0); 42 | 43 | /* S1 = narr */ 44 | sljit_emit_op1(C, SLJIT_MOV, SLJIT_S1, 0, SLJIT_IMM, narr); 45 | 46 | /* loopstart: */ 47 | loopstart = sljit_emit_label(C); 48 | 49 | /* S2 >= narr --> jumo out */ 50 | out = sljit_emit_cmp(C, SLJIT_GREATER_EQUAL, SLJIT_S2, 0, SLJIT_S1, 0); 51 | 52 | /* R0 = (sljit_sw *)S0[S2]; */ 53 | sljit_emit_op1(C, SLJIT_MOV, SLJIT_R0, 0, SLJIT_MEM2(SLJIT_S0, SLJIT_S2), SLJIT_WORD_SHIFT); 54 | 55 | /* print_num(R0) */ 56 | sljit_emit_icall(C, SLJIT_CALL, SLJIT_ARGS1V(W), SLJIT_IMM, SLJIT_FUNC_ADDR(print_num)); 57 | 58 | /* S2 += 1 */ 59 | sljit_emit_op2(C, SLJIT_ADD, SLJIT_S2, 0, SLJIT_S2, 0, SLJIT_IMM, 1); 60 | 61 | /* jump loopstart */ 62 | sljit_set_label(sljit_emit_jump(C, SLJIT_JUMP), loopstart); 63 | 64 | /* out: */ 65 | sljit_set_label(out, sljit_emit_label(C)); 66 | 67 | /* return S1 */ 68 | sljit_emit_return(C, SLJIT_MOV, SLJIT_S1, 0); 69 | 70 | /* Generate machine code */ 71 | code = sljit_generate_code(C, 0, NULL); 72 | len = sljit_get_generated_code_size(C); 73 | 74 | /* Execute code */ 75 | func = (func_arr_t)code; 76 | printf("func return %ld\n", (long)func(arr, narr)); 77 | 78 | /* dump_code(code, len); */ 79 | 80 | /* Clean up */ 81 | sljit_free_compiler(C); 82 | sljit_free_code(code, NULL); 83 | return 0; 84 | } 85 | 86 | int main(void) 87 | { 88 | sljit_sw arr[8] = { 3, -10, 4, 6, 8, 12, 2000, 0 }; 89 | return array_access(arr, 8); 90 | } 91 | -------------------------------------------------------------------------------- /docs/tutorial/sources/brainfuck.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Brainfuck interpreter with SLJIT 3 | * 4 | * Copyright 2015 Wen Xichang (wenxichang@163.com). All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without modification, are 7 | * permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, this list of 10 | * conditions and the following disclaimer. 11 | * 12 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list 13 | * of conditions and the following disclaimer in the documentation and/or other materials 14 | * provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 19 | * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 22 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #include "sljitLir.h" 28 | 29 | #include 30 | #include 31 | 32 | #define BF_CELL_SIZE 3000 33 | #define BF_LOOP_LEVEL 256 34 | 35 | static int readvalid(FILE *src) 36 | { 37 | int chr; 38 | 39 | while ((chr = fgetc(src)) != EOF) { 40 | switch (chr) { 41 | case '+': 42 | case '-': 43 | case '>': 44 | case '<': 45 | case '.': 46 | case ',': 47 | case '[': 48 | case ']': 49 | return chr; 50 | } 51 | } 52 | 53 | return chr; 54 | } 55 | 56 | /* reading same instruction, and count, for optimization */ 57 | /* ++++ -> '+', 4 */ 58 | static int gettoken(FILE *src, int *ntok) 59 | { 60 | int chr = readvalid(src); 61 | int chr2; 62 | int cnt = 1; 63 | 64 | if (chr == EOF) 65 | return EOF; 66 | 67 | if (chr == '.' || chr == ',' || chr == '[' || chr == ']') { 68 | *ntok = 1; 69 | return chr; 70 | } 71 | 72 | while ((chr2 = readvalid(src)) == chr) 73 | cnt++; 74 | 75 | if (chr2 != EOF) 76 | ungetc(chr2, src); 77 | 78 | *ntok = cnt; 79 | return chr; 80 | } 81 | 82 | /* maintaining loop matched [] */ 83 | struct loop_node_st { 84 | struct sljit_label *loop_start; 85 | struct sljit_jump *loop_end; 86 | }; 87 | 88 | /* stack of loops */ 89 | static struct loop_node_st loop_stack[BF_LOOP_LEVEL]; 90 | static int loop_sp; 91 | 92 | static int loop_push(struct sljit_label *loop_start, struct sljit_jump *loop_end) 93 | { 94 | if (loop_sp >= BF_LOOP_LEVEL) 95 | return -1; 96 | 97 | loop_stack[loop_sp].loop_start = loop_start; 98 | loop_stack[loop_sp].loop_end = loop_end; 99 | loop_sp++; 100 | return 0; 101 | } 102 | 103 | static int loop_pop(struct sljit_label **loop_start, struct sljit_jump **loop_end) 104 | { 105 | if (loop_sp <= 0) 106 | return -1; 107 | 108 | loop_sp--; 109 | *loop_start = loop_stack[loop_sp].loop_start; 110 | *loop_end = loop_stack[loop_sp].loop_end; 111 | return 0; 112 | } 113 | 114 | static void *SLJIT_FUNC my_alloc(size_t size, size_t n) 115 | { 116 | return calloc(size, n); 117 | } 118 | 119 | static void SLJIT_FUNC my_putchar(sljit_sw c) 120 | { 121 | putchar((int)c); 122 | } 123 | 124 | static sljit_sw SLJIT_FUNC my_getchar(void) 125 | { 126 | return getchar(); 127 | } 128 | 129 | static void SLJIT_FUNC my_free(void *mem) 130 | { 131 | free(mem); 132 | } 133 | 134 | #define loop_empty() (loop_sp == 0) 135 | 136 | /* compile bf source to a void func() */ 137 | static void *compile(FILE *src, sljit_uw *lcode) 138 | { 139 | void *code = NULL; 140 | int chr; 141 | int nchr; 142 | 143 | struct sljit_compiler *C = sljit_create_compiler(NULL); 144 | struct sljit_jump *end; 145 | struct sljit_label *loop_start; 146 | struct sljit_jump *loop_end; 147 | 148 | int SP = SLJIT_S0; /* bf SP */ 149 | int CELLS = SLJIT_S1; /* bf array */ 150 | 151 | sljit_emit_enter(C, 0, SLJIT_ARGS2V(W, W), 2, 2, 0); 152 | /* opt arg R S local_size */ 153 | 154 | /* SP = 0 */ 155 | sljit_emit_op2(C, SLJIT_XOR, SP, 0, SP, 0, SP, 0); 156 | 157 | sljit_emit_op1(C, SLJIT_MOV, SLJIT_R0, 0, SLJIT_IMM, BF_CELL_SIZE); 158 | sljit_emit_op1(C, SLJIT_MOV, SLJIT_R1, 0, SLJIT_IMM, 1); 159 | sljit_emit_icall(C, SLJIT_CALL, SLJIT_ARGS2(P, W, W), SLJIT_IMM, SLJIT_FUNC_ADDR(my_alloc));/* calloc(BF_CELL_SIZE, 1) => R0 */ 160 | 161 | end = sljit_emit_cmp(C, SLJIT_EQUAL, SLJIT_R0, 0, SLJIT_IMM, 0); /* R0 == 0 --> jump end */ 162 | 163 | sljit_emit_op1(C, SLJIT_MOV, CELLS, 0, SLJIT_R0, 0); /* CELLS = R0 */ 164 | 165 | while ((chr = gettoken(src, &nchr)) != EOF) { 166 | switch (chr) { 167 | case '+': 168 | case '-': 169 | sljit_emit_op1(C, SLJIT_MOV_U8, SLJIT_R0, 0, SLJIT_MEM2(CELLS, SP), 0); /* R0 = CELLS[SP] */ 170 | sljit_emit_op2(C, chr == '+' ? SLJIT_ADD : SLJIT_SUB, 171 | SLJIT_R0, 0, SLJIT_R0, 0, SLJIT_IMM, nchr); /* R0 ?= nchr */ 172 | sljit_emit_op1(C, SLJIT_MOV_U8, SLJIT_MEM2(CELLS, SP), 0, SLJIT_R0, 0); /* CELLS[SP] = R0 */ 173 | break; 174 | case '>': 175 | case '<': 176 | sljit_emit_op2(C, chr == '>' ? SLJIT_ADD : SLJIT_SUB, 177 | SP, 0, SP, 0, SLJIT_IMM, nchr); /* SP ?= nchr */ 178 | break; 179 | case '.': 180 | sljit_emit_op1(C, SLJIT_MOV_U8, SLJIT_R0, 0, SLJIT_MEM2(CELLS, SP), 0); /* R0 = CELLS[SP] */ 181 | sljit_emit_icall(C, SLJIT_CALL, SLJIT_ARGS1(W, W), SLJIT_IMM, SLJIT_FUNC_ADDR(my_putchar)); /* putchar(R0) */ 182 | break; 183 | case ',': 184 | sljit_emit_icall(C, SLJIT_CALL, SLJIT_ARGS0(W), SLJIT_IMM, SLJIT_FUNC_ADDR(my_getchar)); /* R0 = getchar() */ 185 | sljit_emit_op1(C, SLJIT_MOV_U8, SLJIT_MEM2(CELLS, SP), 0, SLJIT_R0, 0); /* CELLS[SP] = R0 */ 186 | break; 187 | case '[': 188 | loop_start = sljit_emit_label(C); /* loop_start: */ 189 | sljit_emit_op1(C, SLJIT_MOV_U8, SLJIT_R0, 0, SLJIT_MEM2(CELLS, SP), 0); /* R0 = CELLS[SP] */ 190 | loop_end = sljit_emit_cmp(C, SLJIT_EQUAL, SLJIT_R0, 0, SLJIT_IMM, 0); /* IF R0 == 0 goto loop_end */ 191 | 192 | if (loop_push(loop_start, loop_end)) { 193 | fprintf(stderr, "Too many loop level\n"); 194 | goto compile_failed; 195 | } 196 | break; 197 | case ']': 198 | if (loop_pop(&loop_start, &loop_end)) { 199 | fprintf(stderr, "Unmatch loop ]\n"); 200 | goto compile_failed; 201 | } 202 | 203 | sljit_set_label(sljit_emit_jump(C, SLJIT_JUMP), loop_start); /* goto loop_start */ 204 | sljit_set_label(loop_end, sljit_emit_label(C)); /* loop_end: */ 205 | break; 206 | } 207 | } 208 | 209 | if (!loop_empty()) { 210 | fprintf(stderr, "Unmatch loop [\n"); 211 | goto compile_failed; 212 | } 213 | 214 | sljit_emit_op1(C, SLJIT_MOV, SLJIT_R0, 0, CELLS, 0); 215 | sljit_emit_icall(C, SLJIT_CALL, SLJIT_ARGS1(P, P), SLJIT_IMM, SLJIT_FUNC_ADDR(my_free)); /* free(CELLS) */ 216 | 217 | sljit_set_label(end, sljit_emit_label(C)); 218 | sljit_emit_return_void(C); 219 | 220 | code = sljit_generate_code(C, 0, NULL); 221 | if (lcode) 222 | *lcode = sljit_get_generated_code_size(C); 223 | 224 | compile_failed: 225 | sljit_free_compiler(C); 226 | return code; 227 | } 228 | 229 | /* function prototype of bf compiled code */ 230 | typedef void (*bf_entry_t)(void); 231 | 232 | int main(int argc, char **argv) 233 | { 234 | void *code; 235 | bf_entry_t entry; 236 | FILE *fp; 237 | 238 | if (argc < 2) { 239 | fprintf(stderr, "Usage: %s \n", argv[0]); 240 | return -1; 241 | } 242 | 243 | fp = fopen(argv[1], "rb"); 244 | if (!fp) { 245 | perror("open"); 246 | return -1; 247 | } 248 | 249 | code = compile(fp, NULL); 250 | fclose(fp); 251 | 252 | if (!code) { 253 | fprintf(stderr, "[Fatal]: Compile failed\n"); 254 | return -1; 255 | } 256 | 257 | entry = (bf_entry_t)code; 258 | entry(); 259 | 260 | sljit_free_code(code, NULL); 261 | return 0; 262 | } 263 | -------------------------------------------------------------------------------- /docs/tutorial/sources/branch.c: -------------------------------------------------------------------------------- 1 | #include "sljitLir.h" 2 | 3 | #include 4 | #include 5 | 6 | typedef sljit_sw (SLJIT_FUNC *func3_t)(sljit_sw a, sljit_sw b, sljit_sw c); 7 | 8 | /* 9 | This example, we generate a function like this: 10 | 11 | sljit_sw func(sljit_sw a, sljit_sw b, sljit_sw c) 12 | { 13 | if ((a & 1) == 0) 14 | return c; 15 | return b; 16 | } 17 | 18 | */ 19 | static int branch(sljit_sw a, sljit_sw b, sljit_sw c) 20 | { 21 | void *code; 22 | sljit_uw len; 23 | func3_t func; 24 | 25 | struct sljit_jump *ret_c; 26 | struct sljit_jump *out; 27 | 28 | /* Create a SLJIT compiler */ 29 | struct sljit_compiler *C = sljit_create_compiler(NULL); 30 | 31 | /* 3 arg, 1 temp reg, 3 save reg */ 32 | sljit_emit_enter(C, 0, SLJIT_ARGS3(W, W, W, W), 1, 3, 0); 33 | 34 | /* R0 = a & 1, S0 is argument a */ 35 | sljit_emit_op2(C, SLJIT_AND, SLJIT_R0, 0, SLJIT_S0, 0, SLJIT_IMM, 1); 36 | 37 | /* if R0 == 0 then jump to ret_c, where is ret_c? we assign it later */ 38 | ret_c = sljit_emit_cmp(C, SLJIT_EQUAL, SLJIT_R0, 0, SLJIT_IMM, 0); 39 | 40 | /* R0 = b, S1 is argument b */ 41 | sljit_emit_op1(C, SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_S1, 0); 42 | 43 | /* jump to out */ 44 | out = sljit_emit_jump(C, SLJIT_JUMP); 45 | 46 | /* here is the 'ret_c' should jump, we emit a label and set it to ret_c */ 47 | sljit_set_label(ret_c, sljit_emit_label(C)); 48 | 49 | /* R0 = c, S2 is argument c */ 50 | sljit_emit_op1(C, SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_S2, 0); 51 | 52 | /* here is the 'out' should jump */ 53 | sljit_set_label(out, sljit_emit_label(C)); 54 | 55 | /* end of function */ 56 | sljit_emit_return(C, SLJIT_MOV, SLJIT_RETURN_REG, 0); 57 | 58 | /* Generate machine code */ 59 | code = sljit_generate_code(C, 0, NULL); 60 | len = sljit_get_generated_code_size(C); 61 | 62 | /* Execute code */ 63 | func = (func3_t)code; 64 | printf("func return %ld\n", (long)func(a, b, c)); 65 | 66 | /* dump_code(code, len); */ 67 | 68 | /* Clean up */ 69 | sljit_free_compiler(C); 70 | sljit_free_code(code, NULL); 71 | return 0; 72 | } 73 | 74 | int main() 75 | { 76 | return branch(4, 5, 6); 77 | } 78 | -------------------------------------------------------------------------------- /docs/tutorial/sources/first_program.c: -------------------------------------------------------------------------------- 1 | #include "sljitLir.h" 2 | 3 | #include 4 | #include 5 | 6 | typedef sljit_sw (SLJIT_FUNC *func3_t)(sljit_sw a, sljit_sw b, sljit_sw c); 7 | 8 | static int add3(sljit_sw a, sljit_sw b, sljit_sw c) 9 | { 10 | void *code; 11 | sljit_uw len; 12 | func3_t func; 13 | 14 | /* Create a SLJIT compiler */ 15 | struct sljit_compiler *C = sljit_create_compiler(NULL); 16 | 17 | /* Start a context (function prologue) */ 18 | sljit_emit_enter(C, 19 | 0, /* Options */ 20 | SLJIT_ARGS3(W, W, W, W), /* 1 return value and 3 parameters of type sljit_sw */ 21 | 1, /* 1 scratch register used */ 22 | 3, /* 3 saved registers used */ 23 | 0); /* 0 bytes allocated for function local variables */ 24 | 25 | /* The first argument of a function is stored in register SLJIT_S0, the 2nd in SLJIT_S1, etc. */ 26 | /* R0 = first */ 27 | sljit_emit_op1(C, SLJIT_MOV, SLJIT_R0, 0, SLJIT_S0, 0); 28 | 29 | /* R0 = R0 + second */ 30 | sljit_emit_op2(C, SLJIT_ADD, SLJIT_R0, 0, SLJIT_R0, 0, SLJIT_S1, 0); 31 | 32 | /* R0 = R0 + third */ 33 | sljit_emit_op2(C, SLJIT_ADD, SLJIT_R0, 0, SLJIT_R0, 0, SLJIT_S2, 0); 34 | 35 | /* This statement moves R0 to RETURN REG and returns */ 36 | /* (in fact, R0 is the RETURN REG itself) */ 37 | sljit_emit_return(C, SLJIT_MOV, SLJIT_R0, 0); 38 | 39 | /* Generate machine code */ 40 | code = sljit_generate_code(C, 0, NULL); 41 | len = sljit_get_generated_code_size(C); 42 | 43 | /* Execute code */ 44 | func = (func3_t)code; 45 | printf("func return %ld\n", (long)func(a, b, c)); 46 | 47 | /* dump_code(code, len); */ 48 | 49 | /* Clean up */ 50 | sljit_free_compiler(C); 51 | sljit_free_code(code, NULL); 52 | 53 | return 0; 54 | } 55 | 56 | int main() 57 | { 58 | return add3(4, 5, 6); 59 | } 60 | -------------------------------------------------------------------------------- /docs/tutorial/sources/func_call.c: -------------------------------------------------------------------------------- 1 | #include "sljitLir.h" 2 | 3 | #include 4 | #include 5 | 6 | typedef sljit_sw (SLJIT_FUNC *func3_t)(sljit_sw a, sljit_sw b, sljit_sw c); 7 | 8 | static sljit_sw SLJIT_FUNC print_num(sljit_sw a) 9 | { 10 | printf("a = %ld\n", (long)a); 11 | return a + 1; 12 | } 13 | 14 | /* 15 | This example, we generate a function like this: 16 | 17 | sljit_sw func(sljit_sw a, sljit_sw b, sljit_sw c) 18 | { 19 | if ((a & 1) == 0) 20 | return print_num(c); 21 | return print_num(b); 22 | } 23 | */ 24 | 25 | static int func_call(sljit_sw a, sljit_sw b, sljit_sw c) 26 | { 27 | void *code; 28 | sljit_uw len; 29 | func3_t func; 30 | 31 | struct sljit_jump *out; 32 | struct sljit_jump *print_c; 33 | 34 | /* Create a SLJIT compiler */ 35 | struct sljit_compiler *C = sljit_create_compiler(NULL); 36 | 37 | sljit_emit_enter(C, 0, SLJIT_ARGS3(W, W, W, W), 3, 3, 0); 38 | 39 | /* a & 1 --> R0 */ 40 | sljit_emit_op2(C, SLJIT_AND, SLJIT_R0, 0, SLJIT_S0, 0, SLJIT_IMM, 1); 41 | /* R0 == 0 --> jump print_c */ 42 | print_c = sljit_emit_cmp(C, SLJIT_EQUAL, SLJIT_R0, 0, SLJIT_IMM, 0); 43 | 44 | /* R0 = S1; print_num(R0) */ 45 | sljit_emit_op1(C, SLJIT_MOV, SLJIT_R0, 0, SLJIT_S1, 0); 46 | sljit_emit_icall(C, SLJIT_CALL, SLJIT_ARGS1(W, W), SLJIT_IMM, SLJIT_FUNC_ADDR(print_num)); 47 | 48 | /* jump out */ 49 | out = sljit_emit_jump(C, SLJIT_JUMP); 50 | /* print_c: */ 51 | sljit_set_label(print_c, sljit_emit_label(C)); 52 | 53 | /* R0 = c; print_num(R0); */ 54 | sljit_emit_op1(C, SLJIT_MOV, SLJIT_R0, 0, SLJIT_S2, 0); 55 | sljit_emit_icall(C, SLJIT_CALL, SLJIT_ARGS1(W, W), SLJIT_IMM, SLJIT_FUNC_ADDR(print_num)); 56 | 57 | /* out: */ 58 | sljit_set_label(out, sljit_emit_label(C)); 59 | sljit_emit_return(C, SLJIT_MOV, SLJIT_R0, 0); 60 | 61 | /* Generate machine code */ 62 | code = sljit_generate_code(C, 0, NULL); 63 | len = sljit_get_generated_code_size(C); 64 | 65 | /* Execute code */ 66 | func = (func3_t)code; 67 | printf("func return %ld\n", (long)func(a, b, c)); 68 | 69 | /* dump_code(code, len); */ 70 | 71 | /* Clean up */ 72 | sljit_free_compiler(C); 73 | sljit_free_code(code, NULL); 74 | return 0; 75 | } 76 | 77 | int main() 78 | { 79 | return func_call(4, 5, 6); 80 | } 81 | -------------------------------------------------------------------------------- /docs/tutorial/sources/hello.bf: -------------------------------------------------------------------------------- 1 | +++++ +++++ initialize counter (cell #0) to 10\ 2 | [ use loop to set the next four cells to 70/100/30/10\ 3 | > +++++ ++ add 7 to cell #1\ 4 | > +++++ +++++ add 10 to cell #2 \ 5 | > +++ add 3 to cell #3\ 6 | > + add 1 to cell #4\ 7 | <<<< - decrement counter (cell #0)\ 8 | ]\ 9 | > ++ . print 'H'\ 10 | > + . print 'e'\ 11 | +++++ ++ . print 'l'\ 12 | . print 'l'\ 13 | +++ . print 'o'\ 14 | > ++ . print ' '\ 15 | << +++++ +++++ +++++ . print 'W'\ 16 | > . print 'o'\ 17 | +++ . print 'r'\ 18 | ----- - . print 'l'\ 19 | ----- --- . print 'd'\ 20 | > + . print '!'\ 21 | > . print '\n'\ -------------------------------------------------------------------------------- /docs/tutorial/sources/loop.c: -------------------------------------------------------------------------------- 1 | #include "sljitLir.h" 2 | 3 | #include 4 | #include 5 | 6 | typedef sljit_sw (SLJIT_FUNC *func2_t)(sljit_sw a, sljit_sw b); 7 | 8 | /* 9 | This example, we generate a function like this: 10 | 11 | sljit_sw func(sljit_sw a, sljit_sw b) 12 | { 13 | sljit_sw i; 14 | sljit_sw ret = 0; 15 | for (i = 0; i < a; ++i) { 16 | ret += b; 17 | } 18 | return ret; 19 | } 20 | */ 21 | 22 | static int loop(sljit_sw a, sljit_sw b) 23 | { 24 | void *code; 25 | sljit_uw len; 26 | func2_t func; 27 | 28 | struct sljit_label *loopstart; 29 | struct sljit_jump *out; 30 | 31 | /* Create a SLJIT compiler */ 32 | struct sljit_compiler *C = sljit_create_compiler(NULL); 33 | 34 | /* 2 arg, 2 temp reg, 2 saved reg */ 35 | sljit_emit_enter(C, 0, SLJIT_ARGS2(W, W, W), 2, 2, 0); 36 | 37 | /* R0 = 0 */ 38 | sljit_emit_op2(C, SLJIT_XOR, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_R1, 0); 39 | /* RET = 0 */ 40 | sljit_emit_op1(C, SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0); 41 | /* loopstart: */ 42 | loopstart = sljit_emit_label(C); 43 | /* R1 >= a --> jump out */ 44 | out = sljit_emit_cmp(C, SLJIT_GREATER_EQUAL, SLJIT_R1, 0, SLJIT_S0, 0); 45 | /* RET += b */ 46 | sljit_emit_op2(C, SLJIT_ADD, SLJIT_RETURN_REG, 0, SLJIT_RETURN_REG, 0, SLJIT_S1, 0); 47 | /* R1 += 1 */ 48 | sljit_emit_op2(C, SLJIT_ADD, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, 1); 49 | /* jump loopstart */ 50 | sljit_set_label(sljit_emit_jump(C, SLJIT_JUMP), loopstart); 51 | /* out: */ 52 | sljit_set_label(out, sljit_emit_label(C)); 53 | 54 | /* return RET */ 55 | sljit_emit_return(C, SLJIT_MOV, SLJIT_RETURN_REG, 0); 56 | 57 | /* Generate machine code */ 58 | code = sljit_generate_code(C, 0, NULL); 59 | len = sljit_get_generated_code_size(C); 60 | 61 | /* Execute code */ 62 | func = (func2_t)code; 63 | printf("func return %ld\n", (long)func(a, b)); 64 | 65 | /* dump_code(code, len); */ 66 | 67 | /* Clean up */ 68 | sljit_free_compiler(C); 69 | sljit_free_code(code, NULL); 70 | return 0; 71 | } 72 | 73 | int main() 74 | { 75 | return loop(4, 5); 76 | } 77 | -------------------------------------------------------------------------------- /docs/tutorial/sources/struct_access.c: -------------------------------------------------------------------------------- 1 | #include "sljitLir.h" 2 | 3 | #include 4 | #include 5 | 6 | struct point_st { 7 | sljit_sw x; 8 | sljit_s32 y; 9 | sljit_s16 z; 10 | sljit_s8 d; 11 | }; 12 | 13 | typedef sljit_sw (SLJIT_FUNC *point_func_t)(struct point_st *point); 14 | 15 | static sljit_sw SLJIT_FUNC print_num(sljit_sw a) 16 | { 17 | printf("a = %ld\n", (long)a); 18 | return a + 1; 19 | } 20 | 21 | /* 22 | This example, we generate a function like this: 23 | 24 | sljit_sw func(struct point_st *point) 25 | { 26 | print_num(point->x); 27 | print_num(point->y); 28 | print_num(point->z); 29 | print_num(point->d); 30 | return point->x; 31 | } 32 | */ 33 | 34 | static int struct_access() 35 | { 36 | void *code; 37 | sljit_uw len; 38 | point_func_t func; 39 | 40 | struct point_st point = { 41 | -5, -20, 5, 'a' 42 | }; 43 | 44 | /* Create a SLJIT compiler */ 45 | struct sljit_compiler *C = sljit_create_compiler(NULL); 46 | 47 | sljit_emit_enter(C, 0, SLJIT_ARGS1(W, W), 1, 1, 0); 48 | /* opt arg R S local_size */ 49 | 50 | /* S0->x --> R0; print_num(R0) */ 51 | sljit_emit_op1(C, SLJIT_MOV, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_S0), SLJIT_OFFSETOF(struct point_st, x)); 52 | sljit_emit_icall(C, SLJIT_CALL, SLJIT_ARGS1(W, P), SLJIT_IMM, SLJIT_FUNC_ADDR(print_num)); 53 | 54 | /* S0->y --> R0; print_num(R0) */ 55 | sljit_emit_op1(C, SLJIT_MOV_S32, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_S0), SLJIT_OFFSETOF(struct point_st, y)); 56 | sljit_emit_icall(C, SLJIT_CALL, SLJIT_ARGS1(W, P), SLJIT_IMM, SLJIT_FUNC_ADDR(print_num)); 57 | 58 | /* S0->z --> R0; print_num(R0) */ 59 | sljit_emit_op1(C, SLJIT_MOV_S16, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_S0), SLJIT_OFFSETOF(struct point_st, z)); 60 | sljit_emit_icall(C, SLJIT_CALL, SLJIT_ARGS1(W, P), SLJIT_IMM, SLJIT_FUNC_ADDR(print_num)); 61 | 62 | /* S0->d --> R0; print_num(R0) */ 63 | sljit_emit_op1(C, SLJIT_MOV_S8, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_S0), SLJIT_OFFSETOF(struct point_st, d)); 64 | sljit_emit_icall(C, SLJIT_CALL, SLJIT_ARGS1(W, P), SLJIT_IMM, SLJIT_FUNC_ADDR(print_num)); 65 | 66 | /* return S0->x */ 67 | sljit_emit_return(C, SLJIT_MOV, SLJIT_MEM1(SLJIT_S0), SLJIT_OFFSETOF(struct point_st, x)); 68 | 69 | /* Generate machine code */ 70 | code = sljit_generate_code(C, 0, NULL); 71 | len = sljit_get_generated_code_size(C); 72 | 73 | /* Execute code */ 74 | func = (point_func_t)code; 75 | printf("func return %ld\n", (long)func(&point)); 76 | 77 | /* dump_code(code, len); */ 78 | 79 | /* Clean up */ 80 | sljit_free_compiler(C); 81 | sljit_free_code(code, NULL); 82 | return 0; 83 | } 84 | 85 | int main() 86 | { 87 | return struct_access(); 88 | } 89 | -------------------------------------------------------------------------------- /docs/tutorial/sources/temp_var.c: -------------------------------------------------------------------------------- 1 | #include "sljitLir.h" 2 | 3 | #include 4 | #include 5 | 6 | typedef sljit_sw (SLJIT_FUNC *func3_t)(sljit_sw a, sljit_sw b, sljit_sw c); 7 | 8 | static sljit_sw SLJIT_FUNC print_arr(sljit_sw *a, sljit_sw n) 9 | { 10 | sljit_sw i; 11 | sljit_sw sum = 0; 12 | for (i = 0; i < n; ++i) { 13 | sum += a[i]; 14 | printf("arr[%ld] = %ld\n", (long)i, (long)a[i]); 15 | } 16 | return sum; 17 | } 18 | 19 | /* 20 | This example, we generate a function like this: 21 | 22 | sljit_sw func(sljit_sw a, sljit_sw b, sljit_sw c) 23 | { 24 | sljit_sw arr[3] = { a, b, c }; 25 | return print_arr(arr, 3); 26 | } 27 | */ 28 | 29 | static int temp_var(sljit_sw a, sljit_sw b, sljit_sw c) 30 | { 31 | void *code; 32 | sljit_uw len; 33 | func3_t func; 34 | 35 | /* Create a SLJIT compiler */ 36 | struct sljit_compiler *C = sljit_create_compiler(NULL); 37 | 38 | /* reserved space in stack for sljit_sw arr[3] */ 39 | sljit_emit_enter(C, 0, SLJIT_ARGS3(W, W, W, W), 2, 3, 3 * sizeof(sljit_sw)); 40 | /* opt arg R S local_size */ 41 | 42 | /* arr[0] = S0, SLJIT_SP is the init address of local var */ 43 | sljit_emit_op1(C, SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), 0, SLJIT_S0, 0); 44 | /* arr[1] = S1 */ 45 | sljit_emit_op1(C, SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), 1 * sizeof(sljit_sw), SLJIT_S1, 0); 46 | /* arr[2] = S2 */ 47 | sljit_emit_op1(C, SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), 2 * sizeof(sljit_sw), SLJIT_S2, 0); 48 | 49 | /* R0 = arr; in fact SLJIT_SP is the address of arr, but can't do so in SLJIT */ 50 | sljit_get_local_base(C, SLJIT_R0, 0, 0); /* get the address of local variables */ 51 | sljit_emit_op1(C, SLJIT_MOV, SLJIT_R1, 0, SLJIT_IMM, 3); /* R1 = 3; */ 52 | sljit_emit_icall(C, SLJIT_CALL, SLJIT_ARGS2(W, P, W), SLJIT_IMM, SLJIT_FUNC_ADDR(print_arr)); 53 | sljit_emit_return(C, SLJIT_MOV, SLJIT_R0, 0); 54 | 55 | /* Generate machine code */ 56 | code = sljit_generate_code(C, 0, NULL); 57 | len = sljit_get_generated_code_size(C); 58 | 59 | /* Execute code */ 60 | func = (func3_t)code; 61 | printf("func return %ld\n", (long)func(a, b, c)); 62 | 63 | /* dump_code(code, len); */ 64 | 65 | /* Clean up */ 66 | sljit_free_compiler(C); 67 | sljit_free_code(code, NULL); 68 | return 0; 69 | } 70 | 71 | int main() 72 | { 73 | return temp_var(7, 8, 9); 74 | } 75 | -------------------------------------------------------------------------------- /docs/website/.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | /node_modules 3 | 4 | # Production 5 | /build 6 | 7 | # Generated files 8 | .docusaurus 9 | .cache-loader 10 | 11 | # Misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | -------------------------------------------------------------------------------- /docs/website/README.md: -------------------------------------------------------------------------------- 1 | # Website 2 | 3 | This website is built using [Docusaurus](https://docusaurus.io/). 4 | 5 | ## Structure 6 | 7 | - `src` contains the home page 8 | - `static` contains static assets (images, ...); **NOTE:** the `.nojekyll` file is important, see [here](https://docusaurus.io/docs/deployment#docusaurusconfigjs-settings) 9 | - `docusaurus.config.js` contains the Docusaurus related configuration 10 | - `sidebar.js` contains the sidebar configuration 11 | 12 | ## Local Development 13 | 14 | In order to preview changes to the website locally on your machine, you need the following: 15 | - [Node.js](https://nodejs.org) >= 18.0 16 | - npm (comes with Node.js on Windows / MacOS; separate package on Linux) 17 | 18 | Install the dependencies: 19 | 20 | ```bash 21 | cd docs/website 22 | npm install 23 | ``` 24 | 25 | Above step needs to be done only once initially, or after dependencies have changed. 26 | 27 | To start the development server, run the following: 28 | 29 | ```bash 30 | npm run start 31 | ``` 32 | 33 | A browser window should open automatically (it may take some time to load initially as the website is processed). If it does not, take a look at the output of above command for more details. 34 | 35 | ## Adding Documentation 36 | 37 | To add or change documentation, simply create or edit the corresponding Markdown file. No JavaScript or React knowledge needed. 38 | 39 | Docusaurus has been configured to take the `general` and `tutorial` folders into account. If you want to add another section, create the corresponding folder structure and extend [`docusaurus.config.js`](./docusaurus.config.js) and [`sidebar.js`](./sidebars.js) accordingly. 40 | 41 | ## Changing the Homepage 42 | 43 | The homepage is based on React and written in JavaScript. Its main entry point is the [`src/pages/index.js`](./src/pages/index.js) file. 44 | 45 | ## Upgrading Docusaurus 46 | 47 | Docusaurus will let you know if a new version is available when you [start the development server](#local-development). See also [here](https://docusaurus.io/docs/migration). 48 | -------------------------------------------------------------------------------- /docs/website/docusaurus.config.js: -------------------------------------------------------------------------------- 1 | import { themes as prismThemes } from 'prism-react-renderer'; 2 | import remarkGithubAdmonitionsToDirectives from "remark-github-admonitions-to-directives"; 3 | import RemarkLinkRewrite from 'remark-link-rewrite'; 4 | 5 | // This runs in Node.js - Don't use client-side code here (browser APIs, JSX...) 6 | 7 | // Base path for links to source files 8 | const GITHUB_BLOB_URL = 'https://github.com/zherczeg/sljit/blob/'; 9 | 10 | // Revision to use when linking to source files. 11 | // Defaults to master, but could be injected via an environment variable to 12 | // support versioned docs 13 | const REVISION = process.env.SLJIT_DOCS_SOURCE_REVISION 14 | ? process.env.SLJIT_DOCS_SOURCE_REVISION 15 | : 'master'; 16 | 17 | const config = { 18 | title: 'SLJIT', 19 | tagline: 'Platform-independent low-level JIT compiler', 20 | 21 | url: 'https://zherczeg.github.io', 22 | baseUrl: '/sljit/', 23 | 24 | organizationName: 'zherczeg', 25 | projectName: 'sljit', 26 | 27 | onBrokenLinks: 'throw', 28 | onBrokenMarkdownLinks: 'throw', 29 | 30 | i18n: { 31 | defaultLocale: 'en', 32 | locales: ['en'], 33 | }, 34 | 35 | presets: [ 36 | [ 37 | 'classic', 38 | ({ 39 | docs: { 40 | path: '..', // '.' would be the website folder itself 41 | include: [ 42 | 'general/**/*.{md,mdx}', 43 | 'tutorial/**/*.{md,mdx}' 44 | ], 45 | sidebarPath: './sidebars.js', 46 | editUrl: 'https://github.com/zherczeg/sljit/docs/docs/', 47 | // Some Markdown fixups to display nicely both on GitHub and via Docusaurus 48 | beforeDefaultRemarkPlugins: [ 49 | // 1. Convert GitHub-style admonitions to Docusaurus directives 50 | remarkGithubAdmonitionsToDirectives, 51 | // 2. Convert relative links to source files to absolute links to the files on GitHub 52 | [ 53 | RemarkLinkRewrite, { 54 | replacer: (url) => { 55 | if (url.startsWith('sources/')) { 56 | return GITHUB_BLOB_URL + REVISION + '/docs/tutorial/' + url; 57 | } 58 | return url 59 | } 60 | } 61 | ] 62 | ] 63 | }, 64 | blog: false, 65 | theme: { 66 | customCss: './src/css/custom.css', 67 | }, 68 | }), 69 | ], 70 | ], 71 | 72 | themeConfig: 73 | ({ 74 | navbar: { 75 | title: 'SLJIT', 76 | items: [ 77 | { 78 | type: 'docSidebar', 79 | sidebarId: 'generalSidebar', 80 | position: 'left', 81 | label: 'Docs', 82 | }, 83 | { 84 | type: 'docSidebar', 85 | sidebarId: 'tutorialSidebar', 86 | position: 'left', 87 | label: 'Tutorial', 88 | }, 89 | { 90 | 'aria-label': 'GitHub', 91 | className: 'navbar--github-link', 92 | href: 'https://github.com/zherczeg/sljit', 93 | position: 'right', 94 | }, 95 | ], 96 | }, 97 | docs: { 98 | sidebar: { 99 | hideable: true, 100 | }, 101 | }, 102 | footer: { 103 | style: 'light', 104 | links: [ 105 | { 106 | title: 'Content', 107 | items: [ 108 | { 109 | label: 'Docs', 110 | to: '/docs/general/introduction', 111 | }, 112 | { 113 | label: 'Tutorial', 114 | to: '/docs/tutorial/overview', 115 | }, 116 | ], 117 | }, 118 | { 119 | title: 'More', 120 | items: [ 121 | { 122 | label: 'GitHub', 123 | href: 'https://github.com/zherczeg/sljit', 124 | }, 125 | ], 126 | }, 127 | { 128 | title: 'Attribution', 129 | items: [ 130 | { 131 | html: ` 132 | 133 | 134 | Solar Icon Set 135 | 136 | by 137 | 138 | 480 Design 139 | 140 | and 141 | 142 | R4IN80W 143 | 144 | | 145 | 146 | CC BY 4.0 147 | 148 | 149 | ` 150 | } 151 | ] 152 | } 153 | ], 154 | copyright: `Copyright © ${new Date().getFullYear()} SLJIT contributors. Built with Docusaurus.`, 155 | }, 156 | prism: { 157 | theme: prismThemes.github, 158 | darkTheme: prismThemes.dracula, 159 | }, 160 | }), 161 | }; 162 | 163 | export default config; 164 | -------------------------------------------------------------------------------- /docs/website/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "website", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "docusaurus": "docusaurus", 7 | "start": "docusaurus start", 8 | "build": "docusaurus build", 9 | "swizzle": "docusaurus swizzle", 10 | "deploy": "docusaurus deploy", 11 | "clear": "docusaurus clear", 12 | "serve": "docusaurus serve", 13 | "write-translations": "docusaurus write-translations", 14 | "write-heading-ids": "docusaurus write-heading-ids" 15 | }, 16 | "dependencies": { 17 | "@docusaurus/core": "^3.7.0", 18 | "@docusaurus/preset-classic": "^3.7.0", 19 | "@iconify/react": "^5.2.0", 20 | "@mdx-js/react": "^3.0.0", 21 | "clsx": "^2.0.0", 22 | "prism-react-renderer": "^2.3.0", 23 | "raw-loader": "^4.0.2", 24 | "react": "^18.0.0", 25 | "react-dom": "^18.0.0", 26 | "remark-github-admonitions-to-directives": "^2.1.0", 27 | "remark-link-rewrite": "^1.0.7" 28 | }, 29 | "devDependencies": { 30 | "@docusaurus/module-type-aliases": "^3.7.0", 31 | "@docusaurus/types": "^3.7.0" 32 | }, 33 | "browserslist": { 34 | "production": [ 35 | ">0.5%", 36 | "not dead", 37 | "not op_mini all" 38 | ], 39 | "development": [ 40 | "last 3 chrome version", 41 | "last 3 firefox version", 42 | "last 5 safari version" 43 | ] 44 | }, 45 | "engines": { 46 | "node": ">=18.0" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /docs/website/sidebars.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | // This runs in Node.js - Don't use client-side code here (browser APIs, JSX...) 4 | 5 | /** 6 | @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} 7 | */ 8 | const sidebars = { 9 | generalSidebar: [{type: 'autogenerated', dirName: 'general'}], 10 | tutorialSidebar: [{type: 'autogenerated', dirName: 'tutorial'}] 11 | }; 12 | 13 | export default sidebars; 14 | -------------------------------------------------------------------------------- /docs/website/src/components/HomepageFeatures/index.js: -------------------------------------------------------------------------------- 1 | import clsx from 'clsx'; 2 | import Heading from '@theme/Heading'; 3 | import { Icon } from '@iconify/react'; 4 | import styles from './styles.module.css'; 5 | 6 | const FeatureList = [ 7 | { 8 | title: 'Versatile', 9 | icon: 'solar:cpu-linear', 10 | description: ( 11 | <> 12 | SLJIT can generate code for a variety of architectures, including 13 | x86, ARM and RISC-V. 14 | 15 | ), 16 | }, 17 | { 18 | title: 'Powerful', 19 | icon: 'solar:bolt-linear', 20 | description: ( 21 | <> 22 | SLJIT supports a large number of operations, from basic integer math 23 | to tail calls and SIMD. 24 | 25 | ), 26 | }, 27 | { 28 | title: 'Permissive', 29 | icon: 'solar:chat-square-like-linear', 30 | description: ( 31 | <> 32 | Published under a Simplified BSD License, SLJIT can be used with 33 | minimal restrictions. 34 | 35 | ), 36 | }, 37 | ]; 38 | 39 | function Feature({icon, title, description}) { 40 | return ( 41 |
42 |
43 | 44 |
45 |
46 | {title} 47 |

{description}

48 |
49 |
50 | ); 51 | } 52 | 53 | export default function HomepageFeatures() { 54 | return ( 55 |
56 |
57 |
58 | {FeatureList.map((props, idx) => ( 59 | 60 | ))} 61 |
62 |
63 |
64 | ); 65 | } 66 | -------------------------------------------------------------------------------- /docs/website/src/components/HomepageFeatures/styles.module.css: -------------------------------------------------------------------------------- 1 | .features { 2 | display: flex; 3 | align-items: center; 4 | padding: 2rem 0; 5 | width: 100%; 6 | } 7 | 8 | .featureIcon { 9 | margin-bottom: 1rem; 10 | } 11 | -------------------------------------------------------------------------------- /docs/website/src/css/custom.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --ifm-color-primary: #3d3846; 3 | --ifm-color-primary-dark: #37323f; 4 | --ifm-color-primary-darker: #34303c; 5 | --ifm-color-primary-darkest: #2b2731; 6 | --ifm-color-primary-light: #433e4d; 7 | --ifm-color-primary-lighter: #464051; 8 | --ifm-color-primary-lightest: #4f495b; 9 | --ifm-link-color: rgb(17, 15, 192); 10 | --ifm-footer-background-color: var(--ifm-navbar-background-color); 11 | } 12 | 13 | [data-theme='dark'] { 14 | --ifm-color-primary: #c0bfbc; 15 | --ifm-color-primary-dark: #aeaca8; 16 | --ifm-color-primary-darker: #a4a39f; 17 | --ifm-color-primary-darkest: #898781; 18 | --ifm-color-primary-light: #d2d2d0; 19 | --ifm-color-primary-lighter: #dcdbd9; 20 | --ifm-color-primary-lightest: #f7f7f7; 21 | --ifm-link-color: rgb(140, 140, 255); 22 | } 23 | 24 | .navbar--github-link { 25 | width: 32px; 26 | height: 32px; 27 | padding: 6px; 28 | border-radius: 50%; 29 | transition: background var(--ifm-transition-fast); 30 | } 31 | 32 | .navbar--github-link:hover { 33 | background: var(--ifm-color-emphasis-200); 34 | } 35 | 36 | .navbar--github-link:before { 37 | content: ''; 38 | height: 100%; 39 | display: block; 40 | background: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E") no-repeat; 41 | } 42 | 43 | html[data-theme='dark'] .navbar--github-link:before { 44 | background: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='white' d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E") no-repeat; 45 | } 46 | -------------------------------------------------------------------------------- /docs/website/src/pages/index.js: -------------------------------------------------------------------------------- 1 | import clsx from 'clsx'; 2 | import Link from '@docusaurus/Link'; 3 | import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; 4 | import Layout from '@theme/Layout'; 5 | import HomepageFeatures from '@site/src/components/HomepageFeatures'; 6 | 7 | import Heading from '@theme/Heading'; 8 | import styles from './index.module.css'; 9 | 10 | function HomepageHeader() { 11 | const {siteConfig} = useDocusaurusContext(); 12 | return ( 13 |
14 |
15 | 16 | {siteConfig.title} 17 | 18 |

{siteConfig.tagline}

19 |
20 | 23 | Get Started 24 | 25 |
26 |
27 |
28 | ); 29 | } 30 | 31 | export default function Home() { 32 | const {siteConfig} = useDocusaurusContext(); 33 | return ( 34 | 37 | 38 |
39 | 40 |
41 |
42 | ); 43 | } 44 | -------------------------------------------------------------------------------- /docs/website/src/pages/index.module.css: -------------------------------------------------------------------------------- 1 | .heroBanner { 2 | padding: 4rem 0; 3 | text-align: center; 4 | position: relative; 5 | overflow: hidden; 6 | } 7 | 8 | @media screen and (max-width: 996px) { 9 | .heroBanner { 10 | padding: 2rem; 11 | } 12 | } 13 | 14 | .buttons { 15 | display: flex; 16 | align-items: center; 17 | justify-content: center; 18 | } 19 | -------------------------------------------------------------------------------- /docs/website/static/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zherczeg/sljit/7779da89dc7e00a540712fcb859b762d4eca2a26/docs/website/static/.nojekyll -------------------------------------------------------------------------------- /docs/website/static/assets/regex-test.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zherczeg/sljit/7779da89dc7e00a540712fcb859b762d4eca2a26/docs/website/static/assets/regex-test.tgz -------------------------------------------------------------------------------- /regex_src/regexJIT.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Stack-less Just-In-Time compiler 3 | * 4 | * Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without modification, are 7 | * permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, this list of 10 | * conditions and the following disclaimer. 11 | * 12 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list 13 | * of conditions and the following disclaimer in the documentation and/or other materials 14 | * provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 19 | * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 22 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef _REGEX_JIT_H_ 28 | #define _REGEX_JIT_H_ 29 | 30 | #ifdef __cplusplus 31 | extern "C" { 32 | #endif 33 | 34 | /* Character type config. */ 35 | #define REGEX_USE_8BIT_CHARS 36 | 37 | #ifdef REGEX_USE_8BIT_CHARS 38 | typedef char regex_char_t; 39 | #else 40 | typedef wchar_t regex_char_t; 41 | #endif 42 | 43 | /* Error codes. */ 44 | #define REGEX_NO_ERROR 0 45 | #define REGEX_MEMORY_ERROR 1 46 | #define REGEX_INVALID_REGEX 2 47 | 48 | /* Note: large, nested {a,b} iterations can blow up the memory consumption 49 | a{n,m} is replaced by aa...aaa?a?a?a?a? (n >= 0, m > 0) 50 | \__n__/\____m___/ 51 | a{n,} is replaced by aa...aaa+ (n > 0) 52 | \_n-1_/ 53 | */ 54 | 55 | /* The value returned by regex_compile. Can be used for multiple matching. */ 56 | struct regex_machine; 57 | 58 | /* A matching state. */ 59 | struct regex_match; 60 | 61 | /* Note: REGEX_MATCH_BEGIN and REGEX_MATCH_END does not change the parsing 62 | (Hence ^ and $ are parsed normally). 63 | Force matching to start from begining of the string (same as ^). */ 64 | #define REGEX_MATCH_BEGIN 0x01 65 | /* Force matching to continue until the last character (same as $). */ 66 | #define REGEX_MATCH_END 0x02 67 | /* Changes . to [^\r\n] 68 | Note: [...] and [^...] are NOT affected at all (as other regex engines do). */ 69 | #define REGEX_NEWLINE 0x04 70 | /* Non greedy matching. In case of Thompson (non-recursive) algorithm, 71 | it (usually) does not have a significant speed gain. */ 72 | #define REGEX_MATCH_NON_GREEDY 0x08 73 | /* Verbose. This define can be commented out, which disables all verbose features. */ 74 | #define REGEX_MATCH_VERBOSE 0x10 75 | 76 | /* If error occures the function returns NULL, and the error code returned in error variable. 77 | You can pass NULL to error if you don't care about the error code. 78 | The re_flags argument contains the default REGEX_MATCH flags. See above. */ 79 | struct regex_machine* regex_compile(const regex_char_t *regex_string, int length, int re_flags, int *error); 80 | void regex_free_machine(struct regex_machine *machine); 81 | 82 | /* Create and init match structure for a given machine. */ 83 | struct regex_match* regex_begin_match(struct regex_machine *machine); 84 | void regex_reset_match(struct regex_match *match); 85 | void regex_free_match(struct regex_match *match); 86 | 87 | /* Pattern matching. 88 | regex_continue_match does not support REGEX_MATCH_VERBOSE flag. */ 89 | void regex_continue_match(struct regex_match *match, const regex_char_t *input_string, int length); 90 | int regex_get_result(struct regex_match *match, int *end, int *id); 91 | /* Returns true, if the best match has already found. */ 92 | int regex_is_match_finished(struct regex_match *match); 93 | 94 | /* Only exists if VERBOSE is defined in regexJIT.c 95 | Do both sanity check and verbose. 96 | (The latter only if REGEX_MATCH_VERBOSE was passed to regex_compile) */ 97 | void regex_continue_match_debug(struct regex_match *match, const regex_char_t *input_string, int length); 98 | 99 | /* Misc. */ 100 | const char* regex_get_platform_name(void); 101 | 102 | #ifdef __cplusplus 103 | } /* extern "C" */ 104 | #endif 105 | 106 | #endif 107 | -------------------------------------------------------------------------------- /regex_src/regexMain.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Stack-less Just-In-Time compiler 3 | * 4 | * Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without modification, are 7 | * permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, this list of 10 | * conditions and the following disclaimer. 11 | * 12 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list 13 | * of conditions and the following disclaimer in the documentation and/or other materials 14 | * provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 19 | * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 22 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | /* Must be the first one. Must not depend on any other include. */ 28 | #include "sljitLir.h" 29 | #include "regexJIT.h" 30 | 31 | #include 32 | 33 | #if defined _WIN32 || defined _WIN64 34 | #define COLOR_RED 35 | #define COLOR_GREEN 36 | #define COLOR_ARCH 37 | #define COLOR_DEFAULT 38 | #else 39 | #define COLOR_RED "\33[31m" 40 | #define COLOR_GREEN "\33[32m" 41 | #define COLOR_ARCH "\33[33m" 42 | #define COLOR_DEFAULT "\33[0m" 43 | #endif 44 | 45 | #ifdef REGEX_USE_8BIT_CHARS 46 | #define S(str) str 47 | #else 48 | #define S(str) L##str 49 | #endif 50 | 51 | #ifdef REGEX_MATCH_VERBOSE 52 | void verbose_test(regex_char_t *pattern, regex_char_t *string) 53 | { 54 | int error; 55 | regex_char_t *ptr; 56 | struct regex_machine* machine; 57 | struct regex_match* match; 58 | int begin, end, id; 59 | 60 | ptr = pattern; 61 | while (*ptr) 62 | ptr++; 63 | 64 | printf("Start test '%s' matches to '%s'\n", pattern, string); 65 | machine = regex_compile(pattern, (int)(ptr - pattern), REGEX_MATCH_VERBOSE | REGEX_NEWLINE, &error); 66 | 67 | if (error) { 68 | printf("WARNING: Error %d\n", error); 69 | return; 70 | } 71 | if (!machine) { 72 | printf("ERROR: machine must be exists. Report this bug, please\n"); 73 | return; 74 | } 75 | 76 | match = regex_begin_match(machine); 77 | if (!match) { 78 | printf("WARNING: Not enough memory for matching\n"); 79 | regex_free_machine(machine); 80 | return; 81 | } 82 | 83 | ptr = string; 84 | while (*ptr) 85 | ptr++; 86 | 87 | regex_continue_match_debug(match, string, (int)(ptr - string)); 88 | 89 | begin = regex_get_result(match, &end, &id); 90 | printf("Math returns: %3d->%3d [%3d]\n", begin, end, id); 91 | 92 | regex_free_match(match); 93 | regex_free_machine(machine); 94 | } 95 | #endif 96 | 97 | struct test_case { 98 | int begin; /* Expected begin. */ 99 | int end; /* Expected end. */ 100 | int id; /* Expected id. */ 101 | int finished; /* -1 : don't care, 0 : false, 1 : true. */ 102 | int flags; /* REGEX_MATCH_* */ 103 | const regex_char_t *pattern; /* NULL : use the previous pattern. */ 104 | const regex_char_t *string; /* NULL : end of tests. */ 105 | }; 106 | 107 | static void run_tests(struct test_case* test, int verbose, int silent) 108 | { 109 | int error; 110 | const regex_char_t *ptr; 111 | struct regex_machine* machine = NULL; 112 | struct regex_match* match; 113 | int begin, end, id, finished; 114 | int success = 0, fail = 0; 115 | 116 | if (!verbose && !silent) 117 | printf("Pass -v to enable verbose, -s to disable this hint.\n\n"); 118 | 119 | for ( ; test->string ; test++) { 120 | if (verbose) 121 | printf("test: '%s' '%s': ", test->pattern ? test->pattern : "[[REUSE]]", test->string); 122 | fail++; 123 | 124 | if (test->pattern) { 125 | if (machine) 126 | regex_free_machine(machine); 127 | 128 | ptr = test->pattern; 129 | while (*ptr) 130 | ptr++; 131 | 132 | machine = regex_compile(test->pattern, (int)(ptr - test->pattern), test->flags, &error); 133 | 134 | if (error) { 135 | if (!verbose) 136 | printf("test: '%s' '%s': ", test->pattern ? test->pattern : "[[REUSE]]", test->string); 137 | printf("ABORT: Error %d\n", error); 138 | return; 139 | } 140 | if (!machine) { 141 | if (!verbose) 142 | printf("test: '%s' '%s': ", test->pattern ? test->pattern : "[[REUSE]]", test->string); 143 | printf("ABORT: machine must be exists. Report this bug, please\n"); 144 | return; 145 | } 146 | } 147 | else if (test->flags != 0) { 148 | if (!verbose) 149 | printf("test: '%s' '%s': ", test->pattern ? test->pattern : "[[REUSE]]", test->string); 150 | printf("ABORT: flag must be 0 if no pattern\n"); 151 | return; 152 | } 153 | 154 | ptr = test->string; 155 | while (*ptr) 156 | ptr++; 157 | 158 | match = regex_begin_match(machine); 159 | #ifdef REGEX_MATCH_VERBOSE 160 | if (!match) { 161 | if (!verbose) 162 | printf("test: '%s' '%s': ", test->pattern ? test->pattern : "[[REUSE]]", test->string); 163 | printf("ABORT: Not enough memory for matching\n"); 164 | regex_free_machine(machine); 165 | return; 166 | } 167 | regex_continue_match_debug(match, test->string, (int)(ptr - test->string)); 168 | begin = regex_get_result(match, &end, &id); 169 | finished = regex_is_match_finished(match); 170 | 171 | if (begin != test->begin || end != test->end || id != test->id) { 172 | if (!verbose) 173 | printf("test: '%s' '%s': ", test->pattern ? test->pattern : "[[REUSE]]", test->string); 174 | printf("FAIL A: begin: %d != %d || end: %d != %d || id: %d != %d\n", test->begin, begin, test->end, end, test->id, id); 175 | continue; 176 | } 177 | if (test->finished != -1 && test->finished != !!finished) { 178 | if (!verbose) 179 | printf("test: '%s' '%s': ", test->pattern ? test->pattern : "[[REUSE]]", test->string); 180 | printf("FAIL A: finish check\n"); 181 | continue; 182 | } 183 | #endif 184 | 185 | regex_reset_match(match); 186 | regex_continue_match(match, test->string, (int)(ptr - test->string)); 187 | begin = regex_get_result(match, &end, &id); 188 | finished = regex_is_match_finished(match); 189 | regex_free_match(match); 190 | 191 | if (begin != test->begin || end != test->end || id != test->id) { 192 | if (!verbose) 193 | printf("test: '%s' '%s': ", test->pattern ? test->pattern : "[[REUSE]]", test->string); 194 | printf("FAIL B: begin: %d != %d || end: %d != %d || id: %d != %d\n", test->begin, begin, test->end, end, test->id, id); 195 | continue; 196 | } 197 | if (test->finished != -1 && test->finished != !!finished) { 198 | if (!verbose) 199 | printf("test: '%s' '%s': ", test->pattern ? test->pattern : "[[REUSE]]", test->string); 200 | printf("FAIL B: finish check\n"); 201 | continue; 202 | } 203 | 204 | if (verbose) 205 | printf("SUCCESS\n"); 206 | fail--; 207 | success++; 208 | } 209 | if (machine) 210 | regex_free_machine(machine); 211 | 212 | printf("REGEX tests: "); 213 | if (fail == 0) 214 | printf("all tests " COLOR_GREEN "PASSED" COLOR_DEFAULT " "); 215 | else 216 | printf(COLOR_RED "%d" COLOR_DEFAULT " (" COLOR_RED "%d%%" COLOR_DEFAULT ") tests failed ", fail, fail * 100 / (success + fail)); 217 | printf("on " COLOR_ARCH "%s" COLOR_DEFAULT "\n", regex_get_platform_name()); 218 | } 219 | 220 | /* Testing. */ 221 | 222 | static struct test_case tests[] = { 223 | { 3, 7, 0, -1, 0, 224 | S("text"), S("is textile") }, 225 | { 0, 10, 0, -1, 0, 226 | S("^(ab|c)*?d+(es)?"), S("abccabddeses") }, 227 | { -1, 0, 0, 1, 0, 228 | S("^a+"), S("saaaa") }, 229 | { 3, 6, 0, 0, 0, 230 | S("(a+|b+)$"), S("saabbb") }, 231 | { 1, 6, 0, 0, 0, 232 | S("(a+|b+){,2}$"), S("saabbb") }, 233 | { 1, 6, 0, 1, 0, 234 | S("(abcde|bc)(a+*|(b|c){2}+){0}"), S("babcdeaaaaaaaa") }, 235 | { 1, 6, 0, 1, 0, 236 | S("(abc(aa)?|(cab+){2})"), S("cabcaa") }, 237 | { -1, 0, 0, 1, 0, 238 | S("^(abc(aa)?|(cab+){2})$"), S("cabcaa") }, 239 | { 0, 3, 1, -1, 0, 240 | S("^(ab{001!})?c"), S("abcde") }, 241 | { 1, 15, 2, -1, 0, 242 | S("(c?(a|bb{2!}){2,3}()+d){2,3}"), S("ccabbadbbadcaadcaad") }, 243 | { 2, 9, 0, -1, 0, 244 | NULL, S("cacaadaadaa") }, 245 | { -1, 0, 0, -1, REGEX_MATCH_BEGIN, 246 | S("(((ab?c|d{1})))"), S("ad") }, 247 | { 0, 9, 3, -1, REGEX_MATCH_BEGIN, 248 | S("^((a{1!}|b{2!}|c{3!}){3,6}d)+"), S("cabadbacddaa") }, 249 | { 1, 6, 0, 0, REGEX_MATCH_END, 250 | S("(a+(bb|cc?)?){4,}"), S("maaaac") }, 251 | { 3, 12, 1, 0, REGEX_MATCH_END, 252 | S("(x+x+{02,03}(x+|{1!})){03,06}$"), S("aaaxxxxxxxxx") }, 253 | { 1, 2, 3, -1, 0, 254 | S("((c{1!})?|x+{2!}|{3!})(a|c)"), S("scs") }, 255 | { 1, 4, 2, 1, 0, 256 | NULL, S("sxxaxxxaccacca") }, 257 | { 0, 2, 1, 1, 0, 258 | NULL, S("ccdcdcdddddcdccccd") }, 259 | { 0, 3, 0, -1, REGEX_MATCH_NON_GREEDY, 260 | S("^a+a+a+"), S("aaaaaa") }, 261 | { 2, 5, 0, -1, REGEX_MATCH_NON_GREEDY, 262 | S("a+a+a+"), S("bbaaaaaa") }, 263 | { 1, 4, 0, 1, 0, 264 | S("baa|a+"), S("sbaaaaaa") }, 265 | { 0, 6, 0, 1, 0, 266 | S("baaa|baa|sbaaaa"), S("sbaaaaa") }, 267 | { 1, 4, 0, 1, REGEX_MATCH_NON_GREEDY, 268 | S("baaa|baa"), S("xbaaa") }, 269 | { 0, 0, 3, 1, 0, 270 | S("{3!}"), S("xx") }, 271 | { 0, 0, 1, 1, 0, 272 | S("{1!}(a{2!})*"), S("xx") }, 273 | { 0, 2, 2, 0, 0, 274 | NULL, S("aa") }, 275 | { 0, 0, 1, 1, REGEX_MATCH_NON_GREEDY, 276 | S("{1!}(a{2!})*"), S("aaxx") }, 277 | { 4, 12, 0, 1, 0, 278 | S("(.[]-]){3}[^]-]{2}"), S("ax-xs-[][]lmn") }, 279 | { 3, 7, 1, 1, 0, 280 | S("([ABC]|[abc]{1!}){3,5}"), S("AbSAabbx") }, 281 | { 0, 8, 3, 0, 0, 282 | S("^[x\\-y[\\]]+([[\\]]{3!})*$"), S("x-y[-][]") }, 283 | { 0, 9, 0, 0, 0, 284 | NULL, S("x-y[-][]x") }, 285 | { 2, 8, 0, 1, 0, 286 | S("<(/{1!})?[^>]+>"), S(" ") }, 287 | { 2, 9, 1, 1, 0, 288 | NULL, S(" ") }, 289 | { 2, 9, 0, 1, 0, 290 | S("[A-Z0-9a-z]+"), S("[(Iden9aA)]") }, 291 | { 1, 4, 0, 1, 0, 292 | S("[^x-y]+[a-c_]{2,3}"), S("x_a_y") }, 293 | { 4, 11, 0, 0, 0, 294 | NULL, S("ssaymmaa_ccl") }, 295 | { 3, 6, 0, 1, REGEX_NEWLINE, 296 | S(".a[^k]"), S("\na\nxa\ns") }, 297 | { 0, 2, 0, 1, REGEX_NEWLINE, 298 | S("^a+"), S("aa\n") }, 299 | { 1, 4, 0, 1, 0 /* =REGEX_NEWLINE */, 300 | NULL, S("\naaa\n") }, 301 | { 2, 3, 0, 1, 0 /* =REGEX_NEWLINE */, 302 | NULL, S("\n\na\n") }, 303 | { 0, 2, 0, 1, REGEX_NEWLINE, 304 | S("a+$"), S("aa\n") }, 305 | { 0, 3, 0, 0, 0 /* =REGEX_NEWLINE */, 306 | NULL, S("aaa") }, 307 | { 2, 4, 1, 1, REGEX_NEWLINE, 308 | S("^a(a{1!})*$"), S("\n\naa\n\n") }, 309 | { 0, 1, 0, 0, 0 /* REGEX_NEWLINE */, 310 | NULL, S("a") }, 311 | { -1, 0, 0, -1, 0 /* REGEX_NEWLINE */, 312 | NULL, S("ab\nba") }, 313 | { -1, 0, 0, 0, 0, 314 | NULL, NULL } 315 | }; 316 | 317 | int main(int argc, char* argv[]) 318 | { 319 | int has_arg = (argc >= 2 && argv[1][0] == '-' && argv[1][2] == '\0'); 320 | 321 | /* verbose_test("a((b)((c|d))|)c|"); */ 322 | /* verbose_test("Xa{009,0010}Xb{,7}Xc{5,}Xd{,}Xe{1,}Xf{,1}X"); */ 323 | /* verbose_test("{3!}({3})({0!}){,"); */ 324 | /* verbose_test("(s(ab){2,4}t){2,}*S(a*(b)(c()|)d+){3,4}{0,0}*M"); */ 325 | /* verbose_test("^a({2!})*b+(a|{1!}b)+d$"); */ 326 | /* verbose_test("((a|b|c)*(xy)+)+", "asbcxyxy"); */ 327 | 328 | run_tests(tests, has_arg && argv[1][1] == 'v', has_arg && argv[1][1] == 's'); 329 | 330 | #if !(defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED) 331 | sljit_free_unused_memory_exec(); 332 | #endif /* !SLJIT_CONFIG_UNSUPPORTED */ 333 | 334 | return 0; 335 | } 336 | -------------------------------------------------------------------------------- /sljit_src/allocator_src/sljitExecAllocatorApple.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Stack-less Just-In-Time compiler 3 | * 4 | * Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without modification, are 7 | * permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, this list of 10 | * conditions and the following disclaimer. 11 | * 12 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list 13 | * of conditions and the following disclaimer in the documentation and/or other materials 14 | * provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 19 | * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 22 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #include 28 | #include 29 | /* 30 | On macOS systems, returns MAP_JIT if it is defined _and_ we're running on a 31 | version where it's OK to have more than one JIT block or where MAP_JIT is 32 | required. 33 | On non-macOS systems, returns MAP_JIT if it is defined. 34 | */ 35 | #include 36 | 37 | #if (defined(TARGET_OS_OSX) && TARGET_OS_OSX) || (TARGET_OS_MAC && !TARGET_OS_IPHONE) 38 | 39 | #if defined(SLJIT_CONFIG_X86) && SLJIT_CONFIG_X86 40 | 41 | #include 42 | #include 43 | 44 | #define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec) 45 | 46 | #ifdef MAP_JIT 47 | #define SLJIT_MAP_JIT (get_map_jit_flag()) 48 | static SLJIT_INLINE int get_map_jit_flag(void) 49 | { 50 | size_t page_size; 51 | void *ptr; 52 | struct utsname name; 53 | static int map_jit_flag = -1; 54 | 55 | if (map_jit_flag < 0) { 56 | map_jit_flag = 0; 57 | uname(&name); 58 | 59 | /* Kernel version for 10.14.0 (Mojave) or later */ 60 | if (atoi(name.release) >= 18) { 61 | page_size = get_page_alignment() + 1; 62 | /* Only use MAP_JIT if a hardened runtime is used */ 63 | ptr = mmap(NULL, page_size, PROT_WRITE | PROT_EXEC, 64 | MAP_PRIVATE | MAP_ANON, -1, 0); 65 | 66 | if (ptr != MAP_FAILED) 67 | munmap(ptr, page_size); 68 | else 69 | map_jit_flag = MAP_JIT; 70 | } 71 | } 72 | return map_jit_flag; 73 | } 74 | #else /* !defined(MAP_JIT) */ 75 | #define SLJIT_MAP_JIT (0) 76 | #endif 77 | 78 | #elif defined(SLJIT_CONFIG_ARM) && SLJIT_CONFIG_ARM 79 | 80 | #include 81 | #include 82 | 83 | #define SLJIT_MAP_JIT (MAP_JIT) 84 | #define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec) \ 85 | apple_update_wx_flags(enable_exec) 86 | 87 | static SLJIT_INLINE void apple_update_wx_flags(sljit_s32 enable_exec) 88 | { 89 | #if MAC_OS_X_VERSION_MIN_REQUIRED < 110000 90 | if (__builtin_available(macos 11, *)) 91 | #endif /* BigSur */ 92 | pthread_jit_write_protect_np(enable_exec); 93 | } 94 | 95 | #elif defined(SLJIT_CONFIG_PPC) && SLJIT_CONFIG_PPC 96 | 97 | #define SLJIT_MAP_JIT (0) 98 | #define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec) 99 | 100 | #else 101 | #error "Unsupported architecture" 102 | #endif /* SLJIT_CONFIG */ 103 | 104 | #else /* !TARGET_OS_OSX */ 105 | 106 | #ifdef MAP_JIT 107 | #define SLJIT_MAP_JIT (MAP_JIT) 108 | #else 109 | #define SLJIT_MAP_JIT (0) 110 | #endif 111 | 112 | #endif /* TARGET_OS_OSX */ 113 | 114 | static SLJIT_INLINE void* alloc_chunk(sljit_uw size) 115 | { 116 | void *retval; 117 | int prot = PROT_READ | PROT_WRITE | PROT_EXEC; 118 | int flags = MAP_PRIVATE; 119 | int fd = -1; 120 | 121 | flags |= MAP_ANON | SLJIT_MAP_JIT; 122 | 123 | retval = mmap(NULL, size, prot, flags, fd, 0); 124 | if (retval == MAP_FAILED) 125 | return NULL; 126 | 127 | SLJIT_UPDATE_WX_FLAGS(retval, (uint8_t *)retval + size, 0); 128 | 129 | return retval; 130 | } 131 | 132 | static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size) 133 | { 134 | munmap(chunk, size); 135 | } 136 | 137 | #include "sljitExecAllocatorCore.c" 138 | -------------------------------------------------------------------------------- /sljit_src/allocator_src/sljitExecAllocatorFreeBSD.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Stack-less Just-In-Time compiler 3 | * 4 | * Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without modification, are 7 | * permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, this list of 10 | * conditions and the following disclaimer. 11 | * 12 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list 13 | * of conditions and the following disclaimer in the documentation and/or other materials 14 | * provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 19 | * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 22 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #include 28 | #include 29 | 30 | #ifdef PROC_WXMAP_CTL 31 | static SLJIT_INLINE int sljit_is_wx_block(void) 32 | { 33 | static int wx_block = -1; 34 | if (wx_block < 0) { 35 | int sljit_wx_enable = PROC_WX_MAPPINGS_PERMIT; 36 | wx_block = !!procctl(P_PID, 0, PROC_WXMAP_CTL, &sljit_wx_enable); 37 | } 38 | return wx_block; 39 | } 40 | 41 | #define SLJIT_IS_WX_BLOCK sljit_is_wx_block() 42 | #else /* !PROC_WXMAP_CTL */ 43 | #define SLJIT_IS_WX_BLOCK (1) 44 | #endif /* PROC_WXMAP_CTL */ 45 | 46 | static SLJIT_INLINE void* alloc_chunk(sljit_uw size) 47 | { 48 | void *retval; 49 | int prot = PROT_READ | PROT_WRITE | PROT_EXEC; 50 | int flags = MAP_PRIVATE; 51 | int fd = -1; 52 | 53 | #ifdef PROT_MAX 54 | prot |= PROT_MAX(prot); 55 | #endif 56 | 57 | #ifdef MAP_ANON 58 | flags |= MAP_ANON; 59 | #else /* !MAP_ANON */ 60 | if (SLJIT_UNLIKELY((dev_zero < 0) && open_dev_zero())) 61 | return NULL; 62 | 63 | fd = dev_zero; 64 | #endif /* MAP_ANON */ 65 | 66 | retry: 67 | retval = mmap(NULL, size, prot, flags, fd, 0); 68 | if (retval == MAP_FAILED) { 69 | if (!SLJIT_IS_WX_BLOCK) 70 | goto retry; 71 | 72 | return NULL; 73 | } 74 | 75 | /* HardenedBSD's mmap lies, so check permissions again. */ 76 | if (mprotect(retval, size, PROT_READ | PROT_WRITE | PROT_EXEC) < 0) { 77 | munmap(retval, size); 78 | return NULL; 79 | } 80 | 81 | return retval; 82 | } 83 | 84 | static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size) 85 | { 86 | munmap(chunk, size); 87 | } 88 | 89 | #include "sljitExecAllocatorCore.c" 90 | -------------------------------------------------------------------------------- /sljit_src/allocator_src/sljitExecAllocatorPosix.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Stack-less Just-In-Time compiler 3 | * 4 | * Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without modification, are 7 | * permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, this list of 10 | * conditions and the following disclaimer. 11 | * 12 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list 13 | * of conditions and the following disclaimer in the documentation and/or other materials 14 | * provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 19 | * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 22 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #include 28 | #include 29 | 30 | static SLJIT_INLINE void* alloc_chunk(sljit_uw size) 31 | { 32 | void *retval; 33 | int prot = PROT_READ | PROT_WRITE | PROT_EXEC; 34 | int flags = MAP_PRIVATE; 35 | int fd = -1; 36 | 37 | #ifdef PROT_MAX 38 | prot |= PROT_MAX(prot); 39 | #endif 40 | 41 | #ifdef MAP_ANON 42 | flags |= MAP_ANON; 43 | #else /* !MAP_ANON */ 44 | if (SLJIT_UNLIKELY((dev_zero < 0) && open_dev_zero())) 45 | return NULL; 46 | 47 | fd = dev_zero; 48 | #endif /* MAP_ANON */ 49 | 50 | retval = mmap(NULL, size, prot, flags, fd, 0); 51 | if (retval == MAP_FAILED) 52 | return NULL; 53 | 54 | return retval; 55 | } 56 | 57 | static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size) 58 | { 59 | munmap(chunk, size); 60 | } 61 | 62 | #include "sljitExecAllocatorCore.c" 63 | -------------------------------------------------------------------------------- /sljit_src/allocator_src/sljitExecAllocatorWindows.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Stack-less Just-In-Time compiler 3 | * 4 | * Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without modification, are 7 | * permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, this list of 10 | * conditions and the following disclaimer. 11 | * 12 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list 13 | * of conditions and the following disclaimer in the documentation and/or other materials 14 | * provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 19 | * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 22 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec) 28 | 29 | static SLJIT_INLINE void* alloc_chunk(sljit_uw size) 30 | { 31 | return VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 32 | } 33 | 34 | static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size) 35 | { 36 | SLJIT_UNUSED_ARG(size); 37 | VirtualFree(chunk, 0, MEM_RELEASE); 38 | } 39 | 40 | #include "sljitExecAllocatorCore.c" 41 | -------------------------------------------------------------------------------- /sljit_src/allocator_src/sljitProtExecAllocatorNetBSD.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Stack-less Just-In-Time compiler 3 | * 4 | * Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without modification, are 7 | * permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, this list of 10 | * conditions and the following disclaimer. 11 | * 12 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list 13 | * of conditions and the following disclaimer in the documentation and/or other materials 14 | * provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 19 | * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 22 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #define SLJIT_HAS_CHUNK_HEADER 28 | #define SLJIT_HAS_EXECUTABLE_OFFSET 29 | 30 | struct sljit_chunk_header { 31 | void *executable; 32 | }; 33 | 34 | /* 35 | * MAP_REMAPDUP is a NetBSD extension available sinde 8.0, make sure to 36 | * adjust your feature macros (ex: -D_NETBSD_SOURCE) as needed 37 | */ 38 | static SLJIT_INLINE struct sljit_chunk_header* alloc_chunk(sljit_uw size) 39 | { 40 | struct sljit_chunk_header *retval; 41 | 42 | retval = (struct sljit_chunk_header *)mmap(NULL, size, 43 | PROT_READ | PROT_WRITE | PROT_MPROTECT(PROT_EXEC), 44 | MAP_ANON | MAP_SHARED, -1, 0); 45 | 46 | if (retval == MAP_FAILED) 47 | return NULL; 48 | 49 | retval->executable = mremap(retval, size, NULL, size, MAP_REMAPDUP); 50 | if (retval->executable == MAP_FAILED) { 51 | munmap((void *)retval, size); 52 | return NULL; 53 | } 54 | 55 | if (mprotect(retval->executable, size, PROT_READ | PROT_EXEC) == -1) { 56 | munmap(retval->executable, size); 57 | munmap((void *)retval, size); 58 | return NULL; 59 | } 60 | 61 | return retval; 62 | } 63 | 64 | static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size) 65 | { 66 | struct sljit_chunk_header *header = ((struct sljit_chunk_header *)chunk) - 1; 67 | 68 | munmap(header->executable, size); 69 | munmap((void *)header, size); 70 | } 71 | 72 | #include "sljitExecAllocatorCore.c" 73 | -------------------------------------------------------------------------------- /sljit_src/allocator_src/sljitProtExecAllocatorPosix.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Stack-less Just-In-Time compiler 3 | * 4 | * Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without modification, are 7 | * permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, this list of 10 | * conditions and the following disclaimer. 11 | * 12 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list 13 | * of conditions and the following disclaimer in the documentation and/or other materials 14 | * provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 19 | * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 22 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #define SLJIT_HAS_CHUNK_HEADER 28 | #define SLJIT_HAS_EXECUTABLE_OFFSET 29 | 30 | struct sljit_chunk_header { 31 | void *executable; 32 | }; 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #ifndef O_NOATIME 40 | #define O_NOATIME 0 41 | #endif 42 | 43 | /* this is a linux extension available since kernel 3.11 */ 44 | #ifndef O_TMPFILE 45 | #define O_TMPFILE 0x404000 46 | #endif 47 | 48 | #ifndef _GNU_SOURCE 49 | char *secure_getenv(const char *name); 50 | int mkostemp(char *template, int flags); 51 | #endif 52 | 53 | static SLJIT_INLINE int create_tempfile(void) 54 | { 55 | int fd; 56 | char tmp_name[256]; 57 | size_t tmp_name_len = 0; 58 | char *dir; 59 | struct stat st; 60 | #if defined(SLJIT_SINGLE_THREADED) && SLJIT_SINGLE_THREADED 61 | mode_t mode; 62 | #endif 63 | 64 | #ifdef HAVE_MEMFD_CREATE 65 | /* this is a GNU extension, make sure to use -D_GNU_SOURCE */ 66 | fd = memfd_create("sljit", MFD_CLOEXEC); 67 | if (fd != -1) { 68 | fchmod(fd, 0); 69 | return fd; 70 | } 71 | #endif 72 | 73 | dir = secure_getenv("TMPDIR"); 74 | 75 | if (dir) { 76 | size_t len = strlen(dir); 77 | if (len > 0 && len < sizeof(tmp_name)) { 78 | if ((stat(dir, &st) == 0) && S_ISDIR(st.st_mode)) { 79 | memcpy(tmp_name, dir, len + 1); 80 | tmp_name_len = len; 81 | } 82 | } 83 | } 84 | 85 | #ifdef P_tmpdir 86 | if (!tmp_name_len) { 87 | tmp_name_len = strlen(P_tmpdir); 88 | if (tmp_name_len > 0 && tmp_name_len < sizeof(tmp_name)) 89 | strcpy(tmp_name, P_tmpdir); 90 | } 91 | #endif 92 | if (!tmp_name_len) { 93 | strcpy(tmp_name, "/tmp"); 94 | tmp_name_len = 4; 95 | } 96 | 97 | SLJIT_ASSERT(tmp_name_len > 0 && tmp_name_len < sizeof(tmp_name)); 98 | 99 | if (tmp_name_len > 1 && tmp_name[tmp_name_len - 1] == '/') 100 | tmp_name[--tmp_name_len] = '\0'; 101 | 102 | fd = open(tmp_name, O_TMPFILE | O_EXCL | O_RDWR | O_NOATIME | O_CLOEXEC, 0); 103 | if (fd != -1) 104 | return fd; 105 | 106 | if (tmp_name_len >= sizeof(tmp_name) - 7) 107 | return -1; 108 | 109 | strcpy(tmp_name + tmp_name_len, "/XXXXXX"); 110 | #if defined(SLJIT_SINGLE_THREADED) && SLJIT_SINGLE_THREADED 111 | mode = umask(0777); 112 | #endif 113 | fd = mkostemp(tmp_name, O_CLOEXEC | O_NOATIME); 114 | #if defined(SLJIT_SINGLE_THREADED) && SLJIT_SINGLE_THREADED 115 | umask(mode); 116 | #else 117 | fchmod(fd, 0); 118 | #endif 119 | 120 | if (fd == -1) 121 | return -1; 122 | 123 | if (unlink(tmp_name)) { 124 | close(fd); 125 | return -1; 126 | } 127 | 128 | return fd; 129 | } 130 | 131 | static SLJIT_INLINE struct sljit_chunk_header* alloc_chunk(sljit_uw size) 132 | { 133 | struct sljit_chunk_header *retval; 134 | int fd; 135 | 136 | fd = create_tempfile(); 137 | if (fd == -1) 138 | return NULL; 139 | 140 | if (ftruncate(fd, (off_t)size)) { 141 | close(fd); 142 | return NULL; 143 | } 144 | 145 | retval = (struct sljit_chunk_header *)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 146 | 147 | if (retval == MAP_FAILED) { 148 | close(fd); 149 | return NULL; 150 | } 151 | 152 | retval->executable = mmap(NULL, size, PROT_READ | PROT_EXEC, MAP_SHARED, fd, 0); 153 | 154 | if (retval->executable == MAP_FAILED) { 155 | munmap((void *)retval, size); 156 | close(fd); 157 | return NULL; 158 | } 159 | 160 | close(fd); 161 | return retval; 162 | } 163 | 164 | static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size) 165 | { 166 | struct sljit_chunk_header *header = ((struct sljit_chunk_header *)chunk) - 1; 167 | 168 | munmap(header->executable, size); 169 | munmap((void *)header, size); 170 | } 171 | 172 | #include "sljitExecAllocatorCore.c" 173 | -------------------------------------------------------------------------------- /sljit_src/allocator_src/sljitWXExecAllocatorPosix.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Stack-less Just-In-Time compiler 3 | * 4 | * Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without modification, are 7 | * permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, this list of 10 | * conditions and the following disclaimer. 11 | * 12 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list 13 | * of conditions and the following disclaimer in the documentation and/or other materials 14 | * provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 19 | * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 22 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | /* 28 | This file contains a simple W^X executable memory allocator 29 | 30 | In *NIX, MAP_ANON is required (that is considered a feature) so make 31 | sure to set the right availability macros for your system or the code 32 | will fail to build. 33 | 34 | If your system doesn't support mapping of anonymous pages (ex: IRIX) it 35 | is also likely that it doesn't need this allocator and should be using 36 | the standard one instead. 37 | 38 | It allocates a separate map for each code block and may waste a lot of 39 | memory, because whatever was requested, will be rounded up to the page 40 | size (minimum 4KB, but could be even bigger). 41 | 42 | It changes the page permissions (RW <-> RX) as needed and therefore, if you 43 | will be updating the code after it has been generated, need to make sure to 44 | block any concurrent execution, or could result in a SIGBUS, that could 45 | even manifest itself at a different address than the one that was being 46 | modified. 47 | 48 | Only use if you are unable to use the regular allocator because of security 49 | restrictions and adding exceptions to your application or the system are 50 | not possible. 51 | */ 52 | 53 | #include 54 | #include 55 | 56 | #define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec) \ 57 | sljit_update_wx_flags((from), (to), (enable_exec)) 58 | 59 | #if !(defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED) 60 | #include 61 | #define SLJIT_SE_LOCK() pthread_mutex_lock(&se_lock) 62 | #define SLJIT_SE_UNLOCK() pthread_mutex_unlock(&se_lock) 63 | #else 64 | #define SLJIT_SE_LOCK() 65 | #define SLJIT_SE_UNLOCK() 66 | #endif /* !SLJIT_SINGLE_THREADED */ 67 | 68 | #define SLJIT_WX_IS_BLOCK(ptr, size) generic_check_is_wx_block(ptr, size) 69 | 70 | static SLJIT_INLINE int generic_check_is_wx_block(void *ptr, sljit_uw size) 71 | { 72 | if (SLJIT_LIKELY(!mprotect(ptr, size, PROT_EXEC))) 73 | return !!mprotect(ptr, size, PROT_READ | PROT_WRITE); 74 | 75 | return 1; 76 | } 77 | 78 | SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size) 79 | { 80 | #if !(defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED) 81 | static pthread_mutex_t se_lock = PTHREAD_MUTEX_INITIALIZER; 82 | #endif 83 | static int wx_block = -1; 84 | int prot = PROT_READ | PROT_WRITE; 85 | sljit_uw* ptr; 86 | 87 | if (SLJIT_UNLIKELY(wx_block > 0)) 88 | return NULL; 89 | 90 | #ifdef PROT_MAX 91 | prot |= PROT_MAX(PROT_READ | PROT_WRITE | PROT_EXEC); 92 | #endif 93 | 94 | size += sizeof(sljit_uw); 95 | ptr = (sljit_uw*)mmap(NULL, size, prot, MAP_PRIVATE | MAP_ANON, -1, 0); 96 | 97 | if (ptr == MAP_FAILED) 98 | return NULL; 99 | 100 | if (SLJIT_UNLIKELY(wx_block < 0)) { 101 | SLJIT_SE_LOCK(); 102 | wx_block = SLJIT_WX_IS_BLOCK(ptr, size); 103 | SLJIT_SE_UNLOCK(); 104 | if (SLJIT_UNLIKELY(wx_block)) { 105 | munmap((void *)ptr, size); 106 | return NULL; 107 | } 108 | } 109 | 110 | *ptr++ = size; 111 | return ptr; 112 | } 113 | 114 | #undef SLJIT_SE_UNLOCK 115 | #undef SLJIT_SE_LOCK 116 | 117 | SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr) 118 | { 119 | sljit_uw *start_ptr = ((sljit_uw*)ptr) - 1; 120 | munmap((void*)start_ptr, *start_ptr); 121 | } 122 | 123 | static void sljit_update_wx_flags(void *from, void *to, int enable_exec) 124 | { 125 | sljit_uw page_mask = (sljit_uw)get_page_alignment(); 126 | sljit_uw start = (sljit_uw)from; 127 | sljit_uw end = (sljit_uw)to; 128 | int prot = PROT_READ | (enable_exec ? PROT_EXEC : PROT_WRITE); 129 | 130 | SLJIT_ASSERT(start < end); 131 | 132 | start &= ~page_mask; 133 | end = (end + page_mask) & ~page_mask; 134 | 135 | mprotect((void*)start, end - start, prot); 136 | } 137 | 138 | SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void) 139 | { 140 | /* This allocator does not keep unused memory for future allocations. */ 141 | } 142 | -------------------------------------------------------------------------------- /sljit_src/allocator_src/sljitWXExecAllocatorWindows.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Stack-less Just-In-Time compiler 3 | * 4 | * Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without modification, are 7 | * permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, this list of 10 | * conditions and the following disclaimer. 11 | * 12 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list 13 | * of conditions and the following disclaimer in the documentation and/or other materials 14 | * provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 19 | * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 22 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | /* 28 | This file contains a simple W^X executable memory allocator 29 | 30 | In *NIX, MAP_ANON is required (that is considered a feature) so make 31 | sure to set the right availability macros for your system or the code 32 | will fail to build. 33 | 34 | If your system doesn't support mapping of anonymous pages (ex: IRIX) it 35 | is also likely that it doesn't need this allocator and should be using 36 | the standard one instead. 37 | 38 | It allocates a separate map for each code block and may waste a lot of 39 | memory, because whatever was requested, will be rounded up to the page 40 | size (minimum 4KB, but could be even bigger). 41 | 42 | It changes the page permissions (RW <-> RX) as needed and therefore, if you 43 | will be updating the code after it has been generated, need to make sure to 44 | block any concurrent execution, or could result in a SIGBUS, that could 45 | even manifest itself at a different address than the one that was being 46 | modified. 47 | 48 | Only use if you are unable to use the regular allocator because of security 49 | restrictions and adding exceptions to your application or the system are 50 | not possible. 51 | */ 52 | 53 | #define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec) \ 54 | sljit_update_wx_flags((from), (to), (enable_exec)) 55 | 56 | SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size) 57 | { 58 | sljit_uw *ptr; 59 | 60 | size += sizeof(sljit_uw); 61 | ptr = (sljit_uw*)VirtualAlloc(NULL, size, 62 | MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 63 | 64 | if (!ptr) 65 | return NULL; 66 | 67 | *ptr++ = size; 68 | 69 | return ptr; 70 | } 71 | 72 | SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr) 73 | { 74 | sljit_uw start = (sljit_uw)ptr - sizeof(sljit_uw); 75 | #if defined(SLJIT_DEBUG) && SLJIT_DEBUG 76 | sljit_uw page_mask = (sljit_uw)get_page_alignment(); 77 | 78 | SLJIT_ASSERT(!(start & page_mask)); 79 | #endif 80 | VirtualFree((void*)start, 0, MEM_RELEASE); 81 | } 82 | 83 | static void sljit_update_wx_flags(void *from, void *to, sljit_s32 enable_exec) 84 | { 85 | DWORD oldprot; 86 | sljit_uw page_mask = (sljit_uw)get_page_alignment(); 87 | sljit_uw start = (sljit_uw)from; 88 | sljit_uw end = (sljit_uw)to; 89 | DWORD prot = enable_exec ? PAGE_EXECUTE : PAGE_READWRITE; 90 | 91 | SLJIT_ASSERT(start < end); 92 | 93 | start &= ~page_mask; 94 | end = (end + page_mask) & ~page_mask; 95 | 96 | VirtualProtect((void*)start, end - start, prot, &oldprot); 97 | } 98 | 99 | SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void) 100 | { 101 | /* This allocator does not keep unused memory for future allocations. */ 102 | } 103 | -------------------------------------------------------------------------------- /sljit_src/sljitConfig.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Stack-less Just-In-Time compiler 3 | * 4 | * Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without modification, are 7 | * permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, this list of 10 | * conditions and the following disclaimer. 11 | * 12 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list 13 | * of conditions and the following disclaimer in the documentation and/or other materials 14 | * provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 19 | * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 22 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef SLJIT_CONFIG_H_ 28 | #define SLJIT_CONFIG_H_ 29 | 30 | #ifdef __cplusplus 31 | extern "C" { 32 | #endif /* __cplusplus */ 33 | 34 | /* 35 | This file contains the basic configuration options for the SLJIT compiler 36 | and their default values. These options can be overridden in the 37 | sljitConfigPre.h header file when SLJIT_HAVE_CONFIG_PRE is set to a 38 | non-zero value. 39 | */ 40 | 41 | /* --------------------------------------------------------------------- */ 42 | /* Utilities */ 43 | /* --------------------------------------------------------------------- */ 44 | 45 | /* Implements a stack like data structure (by using mmap / VirtualAlloc */ 46 | /* or a custom allocator). */ 47 | #ifndef SLJIT_UTIL_STACK 48 | /* Enabled by default */ 49 | #define SLJIT_UTIL_STACK 1 50 | #endif /* SLJIT_UTIL_STACK */ 51 | 52 | /* Uses user provided allocator to allocate the stack (see SLJIT_UTIL_STACK) */ 53 | #ifndef SLJIT_UTIL_SIMPLE_STACK_ALLOCATION 54 | /* Disabled by default */ 55 | #define SLJIT_UTIL_SIMPLE_STACK_ALLOCATION 0 56 | #endif /* SLJIT_UTIL_SIMPLE_STACK_ALLOCATION */ 57 | 58 | /* Single threaded application. Does not require any locks. */ 59 | #ifndef SLJIT_SINGLE_THREADED 60 | /* Disabled by default. */ 61 | #define SLJIT_SINGLE_THREADED 0 62 | #endif /* SLJIT_SINGLE_THREADED */ 63 | 64 | /* --------------------------------------------------------------------- */ 65 | /* Configuration */ 66 | /* --------------------------------------------------------------------- */ 67 | 68 | /* If SLJIT_STD_MACROS_DEFINED is not defined, the application should 69 | define SLJIT_MALLOC, SLJIT_FREE, SLJIT_MEMCPY, and NULL. */ 70 | #ifndef SLJIT_STD_MACROS_DEFINED 71 | /* Disabled by default. */ 72 | #define SLJIT_STD_MACROS_DEFINED 0 73 | #endif /* SLJIT_STD_MACROS_DEFINED */ 74 | 75 | /* Executable code allocation: 76 | If SLJIT_EXECUTABLE_ALLOCATOR is not defined, the application should 77 | define SLJIT_MALLOC_EXEC and SLJIT_FREE_EXEC. 78 | Optionally, depending on the implementation used for the allocator, 79 | SLJIT_EXEC_OFFSET and SLJIT_UPDATE_WX_FLAGS might also be needed. */ 80 | #ifndef SLJIT_EXECUTABLE_ALLOCATOR 81 | /* Enabled by default. */ 82 | #define SLJIT_EXECUTABLE_ALLOCATOR 1 83 | 84 | /* When SLJIT_PROT_EXECUTABLE_ALLOCATOR is enabled SLJIT uses 85 | an allocator which does not set writable and executable 86 | permission flags at the same time. 87 | Instead, it creates a shared memory segment (usually backed by a file) 88 | and maps it twice, with different permissions, depending on the use 89 | case. 90 | The trade-off is increased use of virtual memory, incompatibility with 91 | fork(), and some possible additional security risks by the use of 92 | publicly accessible files for the generated code. */ 93 | #ifndef SLJIT_PROT_EXECUTABLE_ALLOCATOR 94 | /* Disabled by default. */ 95 | #define SLJIT_PROT_EXECUTABLE_ALLOCATOR 0 96 | #endif /* SLJIT_PROT_EXECUTABLE_ALLOCATOR */ 97 | 98 | /* When SLJIT_WX_EXECUTABLE_ALLOCATOR is enabled SLJIT uses an 99 | allocator which does not set writable and executable permission 100 | flags at the same time. 101 | Instead, it creates a new independent map on each invocation and 102 | switches permissions at the underlying pages as needed. 103 | The trade-off is increased memory use and degraded performance. */ 104 | #ifndef SLJIT_WX_EXECUTABLE_ALLOCATOR 105 | /* Disabled by default. */ 106 | #define SLJIT_WX_EXECUTABLE_ALLOCATOR 0 107 | #endif /* SLJIT_WX_EXECUTABLE_ALLOCATOR */ 108 | 109 | #endif /* !SLJIT_EXECUTABLE_ALLOCATOR */ 110 | 111 | /* Return with error when an invalid argument is passed. */ 112 | #ifndef SLJIT_ARGUMENT_CHECKS 113 | /* Disabled by default */ 114 | #define SLJIT_ARGUMENT_CHECKS 0 115 | #endif /* SLJIT_ARGUMENT_CHECKS */ 116 | 117 | /* Debug checks (assertions, etc.). */ 118 | #ifndef SLJIT_DEBUG 119 | /* Enabled by default */ 120 | #define SLJIT_DEBUG 1 121 | #endif /* SLJIT_DEBUG */ 122 | 123 | /* Verbose operations. */ 124 | #ifndef SLJIT_VERBOSE 125 | /* Enabled by default */ 126 | #define SLJIT_VERBOSE 1 127 | #endif /* SLJIT_VERBOSE */ 128 | 129 | /* 130 | SLJIT_IS_FPU_AVAILABLE 131 | The availability of the FPU can be controlled by SLJIT_IS_FPU_AVAILABLE. 132 | zero value - FPU is NOT present. 133 | nonzero value - FPU is present. 134 | */ 135 | 136 | /* For further configurations, see the beginning of sljitConfigInternal.h */ 137 | 138 | #ifdef __cplusplus 139 | } /* extern "C" */ 140 | #endif /* __cplusplus */ 141 | 142 | #endif /* SLJIT_CONFIG_H_ */ 143 | -------------------------------------------------------------------------------- /sljit_src/sljitConfigCPU.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Stack-less Just-In-Time compiler 3 | * 4 | * Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without modification, are 7 | * permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, this list of 10 | * conditions and the following disclaimer. 11 | * 12 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list 13 | * of conditions and the following disclaimer in the documentation and/or other materials 14 | * provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 19 | * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 22 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef SLJIT_CONFIG_CPU_H_ 28 | #define SLJIT_CONFIG_CPU_H_ 29 | 30 | /* --------------------------------------------------------------------- */ 31 | /* Architecture */ 32 | /* --------------------------------------------------------------------- */ 33 | 34 | /* Architecture selection. */ 35 | /* #define SLJIT_CONFIG_X86_32 1 */ 36 | /* #define SLJIT_CONFIG_X86_64 1 */ 37 | /* #define SLJIT_CONFIG_ARM_V6 1 */ 38 | /* #define SLJIT_CONFIG_ARM_V7 1 */ 39 | /* #define SLJIT_CONFIG_ARM_THUMB2 1 */ 40 | /* #define SLJIT_CONFIG_ARM_64 1 */ 41 | /* #define SLJIT_CONFIG_PPC_32 1 */ 42 | /* #define SLJIT_CONFIG_PPC_64 1 */ 43 | /* #define SLJIT_CONFIG_MIPS_32 1 */ 44 | /* #define SLJIT_CONFIG_MIPS_64 1 */ 45 | /* #define SLJIT_CONFIG_RISCV_32 1 */ 46 | /* #define SLJIT_CONFIG_RISCV_64 1 */ 47 | /* #define SLJIT_CONFIG_S390X 1 */ 48 | /* #define SLJIT_CONFIG_LOONGARCH_64 */ 49 | 50 | /* #define SLJIT_CONFIG_AUTO 1 */ 51 | /* #define SLJIT_CONFIG_UNSUPPORTED 1 */ 52 | 53 | /*****************/ 54 | /* Sanity check. */ 55 | /*****************/ 56 | 57 | #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) \ 58 | + (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) \ 59 | + (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) \ 60 | + (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \ 61 | + (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) \ 62 | + (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \ 63 | + (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) \ 64 | + (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) \ 65 | + (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) \ 66 | + (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) \ 67 | + (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) \ 68 | + (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) \ 69 | + (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) \ 70 | + (defined SLJIT_CONFIG_LOONGARCH_64 && SLJIT_CONFIG_LOONGARCH_64) \ 71 | + (defined SLJIT_CONFIG_AUTO && SLJIT_CONFIG_AUTO) \ 72 | + (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED) >= 2 73 | #error "Multiple architectures are selected" 74 | #endif 75 | 76 | #if !(defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) \ 77 | && !(defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) \ 78 | && !(defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) \ 79 | && !(defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \ 80 | && !(defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) \ 81 | && !(defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \ 82 | && !(defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) \ 83 | && !(defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) \ 84 | && !(defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) \ 85 | && !(defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) \ 86 | && !(defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) \ 87 | && !(defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) \ 88 | && !(defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) \ 89 | && !(defined SLJIT_CONFIG_LOONGARCH_64 && SLJIT_CONFIG_LOONGARCH_64) \ 90 | && !(defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED) \ 91 | && !(defined SLJIT_CONFIG_AUTO && SLJIT_CONFIG_AUTO) 92 | #if defined SLJIT_CONFIG_AUTO && !SLJIT_CONFIG_AUTO 93 | #error "An architecture must be selected" 94 | #else /* SLJIT_CONFIG_AUTO */ 95 | #define SLJIT_CONFIG_AUTO 1 96 | #endif /* !SLJIT_CONFIG_AUTO */ 97 | #endif /* !SLJIT_CONFIG */ 98 | 99 | /********************************************************/ 100 | /* Automatic CPU detection (requires compiler support). */ 101 | /********************************************************/ 102 | 103 | #if (defined SLJIT_CONFIG_AUTO && SLJIT_CONFIG_AUTO) 104 | #ifndef _WIN32 105 | 106 | #if defined(__i386__) || defined(__i386) 107 | #define SLJIT_CONFIG_X86_32 1 108 | #elif defined(__x86_64__) 109 | #define SLJIT_CONFIG_X86_64 1 110 | #elif defined(__aarch64__) 111 | #define SLJIT_CONFIG_ARM_64 1 112 | #elif defined(__thumb2__) 113 | #define SLJIT_CONFIG_ARM_THUMB2 1 114 | #elif (defined(__ARM_ARCH) && __ARM_ARCH >= 7) || \ 115 | ((defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7S__)) \ 116 | || (defined(__ARM_ARCH_8A__) || defined(__ARM_ARCH_8R__)) \ 117 | || (defined(__ARM_ARCH_9A__))) 118 | #define SLJIT_CONFIG_ARM_V7 1 119 | #elif defined(__arm__) || defined (__ARM__) 120 | #define SLJIT_CONFIG_ARM_V6 1 121 | #elif defined(__ppc64__) || defined(__powerpc64__) || (defined(_ARCH_PPC64) && defined(__64BIT__)) || (defined(_POWER) && defined(__64BIT__)) 122 | #define SLJIT_CONFIG_PPC_64 1 123 | #elif defined(__ppc__) || defined(__powerpc__) || defined(_ARCH_PPC) || defined(_ARCH_PWR) || defined(_ARCH_PWR2) || defined(_POWER) 124 | #define SLJIT_CONFIG_PPC_32 1 125 | #elif defined(__mips__) && !defined(_LP64) 126 | #define SLJIT_CONFIG_MIPS_32 1 127 | #elif defined(__mips64) 128 | #define SLJIT_CONFIG_MIPS_64 1 129 | #elif defined (__riscv_xlen) && (__riscv_xlen == 32) 130 | #define SLJIT_CONFIG_RISCV_32 1 131 | #elif defined (__riscv_xlen) && (__riscv_xlen == 64) 132 | #define SLJIT_CONFIG_RISCV_64 1 133 | #elif defined (__loongarch_lp64) 134 | #define SLJIT_CONFIG_LOONGARCH_64 1 135 | #elif defined(__s390x__) 136 | #define SLJIT_CONFIG_S390X 1 137 | #else 138 | /* Unsupported architecture */ 139 | #define SLJIT_CONFIG_UNSUPPORTED 1 140 | #endif 141 | 142 | #else /* _WIN32 */ 143 | 144 | #if defined(_M_X64) || defined(__x86_64__) 145 | #define SLJIT_CONFIG_X86_64 1 146 | #elif (defined(_M_ARM) && _M_ARM >= 7 && defined(_M_ARMT)) || defined(__thumb2__) 147 | #define SLJIT_CONFIG_ARM_THUMB2 1 148 | #elif (defined(_M_ARM) && _M_ARM >= 7) 149 | #define SLJIT_CONFIG_ARM_V7 1 150 | #elif defined(_ARM_) 151 | #define SLJIT_CONFIG_ARM_V6 1 152 | #elif defined(_M_ARM64) || defined(__aarch64__) 153 | #define SLJIT_CONFIG_ARM_64 1 154 | #else 155 | #define SLJIT_CONFIG_X86_32 1 156 | #endif 157 | 158 | #endif /* !_WIN32 */ 159 | #endif /* SLJIT_CONFIG_AUTO */ 160 | 161 | #if (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED) 162 | #undef SLJIT_EXECUTABLE_ALLOCATOR 163 | #endif /* SLJIT_CONFIG_UNSUPPORTED */ 164 | 165 | /******************************/ 166 | /* CPU family type detection. */ 167 | /******************************/ 168 | 169 | #if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \ 170 | || (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) 171 | #define SLJIT_CONFIG_ARM_32 1 172 | #endif /* SLJIT_CONFIG_ARM_V6 || SLJIT_CONFIG_ARM_V7 || SLJIT_CONFIG_ARM_THUMB2 */ 173 | 174 | #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) || (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) 175 | #define SLJIT_CONFIG_X86 1 176 | #elif (defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32) || (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) 177 | #define SLJIT_CONFIG_ARM 1 178 | #elif (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) || (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) 179 | #define SLJIT_CONFIG_PPC 1 180 | #elif (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) || (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) 181 | #define SLJIT_CONFIG_MIPS 1 182 | #elif (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) || (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) 183 | #define SLJIT_CONFIG_RISCV 1 184 | #elif (defined SLJIT_CONFIG_LOONGARCH_64 && SLJIT_CONFIG_LOONGARCH_64) 185 | #define SLJIT_CONFIG_LOONGARCH 1 186 | #endif 187 | 188 | #endif /* SLJIT_CONFIG_CPU_H_ */ 189 | -------------------------------------------------------------------------------- /sljit_src/sljitNativeRISCV_32.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Stack-less Just-In-Time compiler 3 | * 4 | * Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without modification, are 7 | * permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, this list of 10 | * conditions and the following disclaimer. 11 | * 12 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list 13 | * of conditions and the following disclaimer in the documentation and/or other materials 14 | * provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 19 | * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 22 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_r, sljit_sw imm, sljit_s32 tmp_r) 28 | { 29 | SLJIT_UNUSED_ARG(tmp_r); 30 | 31 | if (RISCV_HAS_COMPRESSED(200) && imm <= SIMM16_MAX && imm >= SIMM16_MIN) 32 | return push_inst16(compiler, C_LI | C_RD(dst_r) | C_IMM_I(imm)); 33 | 34 | if (imm <= SIMM_MAX && imm >= SIMM_MIN) 35 | return push_inst(compiler, ADDI | RD(dst_r) | RS1(TMP_ZERO) | IMM_I(imm)); 36 | 37 | if (imm & 0x800) 38 | imm += 0x1000; 39 | 40 | if (RISCV_HAS_COMPRESSED(200) && imm <= 0x1ffff && imm >= -0x20000) 41 | FAIL_IF(push_inst16(compiler, C_LUI | C_RD(dst_r) | ((sljit_u16)(((imm) & 0x1f000) >> 10) | ((imm) & 0x20000) >> 5))); 42 | else 43 | FAIL_IF(push_inst(compiler, LUI | RD(dst_r) | (sljit_ins)(imm & ~(sljit_sw)0xfff))); 44 | 45 | imm &= 0xfff; 46 | 47 | if (imm == 0) 48 | return SLJIT_SUCCESS; 49 | 50 | if (RISCV_HAS_COMPRESSED(200) && (imm <= 0x1f || imm >= 0xfe0)) 51 | return push_inst16(compiler, C_ADDI | C_RD(dst_r) | C_IMM_I(imm)); 52 | 53 | return push_inst(compiler, ADDI | RD(dst_r) | RS1(dst_r) | IMM_I(imm)); 54 | } 55 | 56 | SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *compiler, 57 | sljit_s32 freg, sljit_f64 value) 58 | { 59 | union { 60 | sljit_s32 imm[2]; 61 | sljit_f64 value; 62 | } u; 63 | 64 | CHECK_ERROR(); 65 | CHECK(check_sljit_emit_fset64(compiler, freg, value)); 66 | 67 | u.value = value; 68 | 69 | if (u.imm[0] != 0) 70 | FAIL_IF(load_immediate(compiler, TMP_REG1, u.imm[0], TMP_REG3)); 71 | if (u.imm[1] != 0) 72 | FAIL_IF(load_immediate(compiler, TMP_REG2, u.imm[1], TMP_REG3)); 73 | 74 | FAIL_IF(push_inst(compiler, ADDI | RD(SLJIT_SP) | RS1(SLJIT_SP) | IMM_I(-16))); 75 | FAIL_IF(push_inst(compiler, SW | RS1(SLJIT_SP) | RS2(u.imm[0] != 0 ? TMP_REG1 : TMP_ZERO) | (8 << 7))); 76 | FAIL_IF(push_inst(compiler, SW | RS1(SLJIT_SP) | RS2(u.imm[1] != 0 ? TMP_REG2 : TMP_ZERO) | (12 << 7))); 77 | FAIL_IF(push_inst(compiler, FLD | FRD(freg) | RS1(SLJIT_SP) | IMM_I(8))); 78 | return push_inst(compiler, ADDI | RD(SLJIT_SP) | RS1(SLJIT_SP) | IMM_I(16)); 79 | } 80 | 81 | SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fcopy(struct sljit_compiler *compiler, sljit_s32 op, 82 | sljit_s32 freg, sljit_s32 reg) 83 | { 84 | sljit_ins inst; 85 | sljit_s32 reg2 = 0; 86 | 87 | CHECK_ERROR(); 88 | CHECK(check_sljit_emit_fcopy(compiler, op, freg, reg)); 89 | 90 | if (op & SLJIT_32) { 91 | if (op == SLJIT_COPY32_TO_F32) 92 | inst = FMV_W_X | RS1(reg) | FRD(freg); 93 | else 94 | inst = FMV_X_W | FRS1(freg) | RD(reg); 95 | 96 | return push_inst(compiler, inst); 97 | } 98 | 99 | FAIL_IF(push_inst(compiler, ADDI | RD(SLJIT_SP) | RS1(SLJIT_SP) | IMM_I(-16))); 100 | 101 | if (reg & REG_PAIR_MASK) { 102 | reg2 = REG_PAIR_SECOND(reg); 103 | reg = REG_PAIR_FIRST(reg); 104 | } 105 | 106 | if (op == SLJIT_COPY_TO_F64) { 107 | if (reg2 != 0) 108 | FAIL_IF(push_inst(compiler, SW | RS1(SLJIT_SP) | RS2(reg2) | (8 << 7))); 109 | else 110 | FAIL_IF(push_inst(compiler, FSW | RS1(SLJIT_SP) | FRS2(freg) | (8 << 7))); 111 | 112 | FAIL_IF(push_inst(compiler, SW | RS1(SLJIT_SP) | RS2(reg) | (12 << 7))); 113 | FAIL_IF(push_inst(compiler, FLD | FRD(freg) | RS1(SLJIT_SP) | IMM_I(8))); 114 | } else { 115 | FAIL_IF(push_inst(compiler, FSD | RS1(SLJIT_SP) | FRS2(freg) | (8 << 7))); 116 | 117 | if (reg2 != 0) 118 | FAIL_IF(push_inst(compiler, FMV_X_W | FRS1(freg) | RD(reg2))); 119 | 120 | FAIL_IF(push_inst(compiler, LW | RD(reg) | RS1(SLJIT_SP) | IMM_I(12))); 121 | } 122 | 123 | return push_inst(compiler, ADDI | RD(SLJIT_SP) | RS1(SLJIT_SP) | IMM_I(16)); 124 | } 125 | 126 | static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw init_value, sljit_ins last_ins) 127 | { 128 | if ((init_value & 0x800) != 0) 129 | init_value += 0x1000; 130 | 131 | FAIL_IF(push_inst(compiler, LUI | RD(dst) | (sljit_ins)(init_value & ~0xfff))); 132 | return push_inst(compiler, last_ins | RS1(dst) | IMM_I(init_value)); 133 | } 134 | 135 | SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset) 136 | { 137 | sljit_u16 *inst = (sljit_u16*)addr; 138 | SLJIT_UNUSED_ARG(executable_offset); 139 | 140 | if ((new_target & 0x800) != 0) 141 | new_target += 0x1000; 142 | 143 | SLJIT_UPDATE_WX_FLAGS(inst, inst + 4, 0); 144 | 145 | SLJIT_ASSERT((inst[0] & 0x7f) == LUI); 146 | inst[0] = (sljit_u16)((inst[0] & 0xfff) | (new_target & 0xf000)); 147 | inst[1] = (sljit_u16)(new_target >> 16); 148 | SLJIT_ASSERT((inst[2] & 0x707f) == ADDI || (inst[2] & 0x707f) == JALR); 149 | inst[3] = (sljit_u16)((inst[3] & 0xf) | (new_target << 4)); 150 | 151 | SLJIT_UPDATE_WX_FLAGS(inst, inst + 4, 1); 152 | inst = (sljit_u16 *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset); 153 | SLJIT_CACHE_FLUSH(inst, inst + 4); 154 | } 155 | -------------------------------------------------------------------------------- /sljit_src/sljitNativeRISCV_64.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Stack-less Just-In-Time compiler 3 | * 4 | * Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without modification, are 7 | * permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, this list of 10 | * conditions and the following disclaimer. 11 | * 12 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list 13 | * of conditions and the following disclaimer in the documentation and/or other materials 14 | * provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 19 | * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 22 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | static sljit_s32 load_immediate32(struct sljit_compiler *compiler, sljit_s32 dst_r, sljit_sw imm) 28 | { 29 | SLJIT_ASSERT((imm <= 0x7fffffffl && imm > SIMM_MAX) || (imm >= S32_MIN && imm < SIMM_MIN)); 30 | 31 | if (imm > S32_MAX) { 32 | SLJIT_ASSERT((imm & 0x800) != 0); 33 | FAIL_IF(push_inst(compiler, LUI | RD(dst_r) | (sljit_ins)0x80000000u)); 34 | return push_inst(compiler, XORI | RD(dst_r) | RS1(dst_r) | IMM_I(imm)); 35 | } 36 | 37 | if (RISCV_HAS_COMPRESSED(200) && imm <= 0x1ffff && imm >= -0x20000) { 38 | if (imm > 0x1f7ff) { 39 | SLJIT_ASSERT((imm & 0x800) != 0); 40 | FAIL_IF(push_inst16(compiler, C_LUI | C_RD(dst_r) | (sljit_u16)0x1000)); 41 | return push_inst(compiler, XORI | RD(dst_r) | RS1(dst_r) | IMM_I(imm)); 42 | } 43 | 44 | if ((imm & 0x800) != 0) 45 | imm += 0x1000; 46 | 47 | FAIL_IF(push_inst16(compiler, C_LUI | C_RD(dst_r) | ((sljit_u16)(((imm) & 0x1f000) >> 10) | ((imm) & 0x20000) >> 5))); 48 | } else { 49 | if ((imm & 0x800) != 0) 50 | imm += 0x1000; 51 | 52 | FAIL_IF(push_inst(compiler, LUI | RD(dst_r) | (sljit_ins)(imm & ~(sljit_sw)0xfff))); 53 | } 54 | 55 | imm &= 0xfff; 56 | 57 | if (imm == 0) 58 | return SLJIT_SUCCESS; 59 | 60 | if (RISCV_HAS_COMPRESSED(200) && (imm <= 0x1f || imm >= 0xfe0)) 61 | return push_inst16(compiler, C_ADDI | C_RD(dst_r) | C_IMM_I(imm)); 62 | 63 | return push_inst(compiler, ADDI | RD(dst_r) | RS1(dst_r) | IMM_I(imm)); 64 | } 65 | 66 | static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_r, sljit_sw imm, sljit_s32 tmp_r) 67 | { 68 | sljit_sw high, shift; 69 | 70 | if (RISCV_HAS_COMPRESSED(200) && imm <= SIMM16_MAX && imm >= SIMM16_MIN) 71 | return push_inst16(compiler, C_LI | C_RD(dst_r) | C_IMM_I(imm)); 72 | 73 | if (imm <= SIMM_MAX && imm >= SIMM_MIN) 74 | return push_inst(compiler, ADDI | RD(dst_r) | RS1(TMP_ZERO) | IMM_I(imm)); 75 | 76 | if (imm <= 0x7fffffffl && imm >= S32_MIN) 77 | return load_immediate32(compiler, dst_r, imm); 78 | 79 | /* Shifted small immediates. */ 80 | 81 | high = imm; 82 | shift = 0; 83 | while ((high & 0xff) == 0) { 84 | high >>= 8; 85 | shift += 8; 86 | } 87 | 88 | if ((high & 0xf) == 0) { 89 | high >>= 4; 90 | shift += 4; 91 | } 92 | 93 | if ((high & 0x3) == 0) { 94 | high >>= 2; 95 | shift += 2; 96 | } 97 | 98 | if ((high & 0x1) == 0) { 99 | high >>= 1; 100 | shift += 1; 101 | } 102 | 103 | if (high <= 0x7fffffffl && high >= S32_MIN) { 104 | load_immediate(compiler, dst_r, high, tmp_r); 105 | 106 | if (RISCV_HAS_COMPRESSED(200)) 107 | return push_inst16(compiler, C_SLLI | C_RD(dst_r) | C_IMM_I(shift)); 108 | return push_inst(compiler, SLLI | RD(dst_r) | RS1(dst_r) | IMM_I(shift)); 109 | } 110 | 111 | /* Trailing zeroes could be used to produce shifted immediates. */ 112 | 113 | if (imm <= 0x7ffffffffffl && imm >= -0x80000000000l) { 114 | high = imm >> 12; 115 | 116 | if (imm & 0x800) 117 | high = ~high; 118 | 119 | FAIL_IF(load_immediate32(compiler, dst_r, high)); 120 | 121 | if (RISCV_HAS_COMPRESSED(200)) 122 | FAIL_IF(push_inst16(compiler, C_SLLI | C_RD(dst_r) | (sljit_u16)(12 << 2))); 123 | else 124 | FAIL_IF(push_inst(compiler, SLLI | RD(dst_r) | RS1(dst_r) | IMM_I(12))); 125 | 126 | SLJIT_ASSERT((imm & 0xfff) != 0); 127 | return push_inst(compiler, XORI | RD(dst_r) | RS1(dst_r) | IMM_I(imm)); 128 | } 129 | 130 | SLJIT_ASSERT(dst_r != tmp_r); 131 | 132 | high = imm >> 32; 133 | imm = (sljit_s32)imm; 134 | 135 | if ((imm & 0x80000000l) != 0) 136 | high = ~high; 137 | 138 | if (high <= 0x7ffff && high >= -0x80000) { 139 | FAIL_IF(push_inst(compiler, LUI | RD(tmp_r) | (sljit_ins)(high << 12))); 140 | high = 0x1000; 141 | } else { 142 | if ((high & 0x800) != 0) 143 | high += 0x1000; 144 | 145 | FAIL_IF(push_inst(compiler, LUI | RD(tmp_r) | (sljit_ins)(high & ~0xfff))); 146 | high &= 0xfff; 147 | } 148 | 149 | if (imm <= SIMM_MAX && imm >= SIMM_MIN) { 150 | if (RISCV_HAS_COMPRESSED(200) && imm <= 0x1f && imm >= -0x20) 151 | FAIL_IF(push_inst16(compiler, C_LI | C_RD(dst_r) | C_IMM_I(imm))); 152 | else 153 | FAIL_IF(push_inst(compiler, ADDI | RD(dst_r) | RS1(TMP_ZERO) | IMM_I(imm))); 154 | imm = 0; 155 | } else if (imm > S32_MAX) { 156 | SLJIT_ASSERT((imm & 0x800) != 0); 157 | 158 | FAIL_IF(push_inst(compiler, LUI | RD(dst_r) | (sljit_ins)0x80000000u)); 159 | imm = 0x1000 | (imm & 0xfff); 160 | } else { 161 | if ((imm & 0x800) != 0) 162 | imm += 0x1000; 163 | 164 | if (RISCV_HAS_COMPRESSED(200) && imm <= 0x1ffff && imm >= -0x20000) 165 | FAIL_IF(push_inst16(compiler, C_LUI | C_RD(dst_r) | ((sljit_u16)(((imm) & 0x1f000) >> 10) | ((imm) & 0x20000) >> 5))); 166 | else 167 | FAIL_IF(push_inst(compiler, LUI | RD(dst_r) | (sljit_ins)(imm & ~0xfff))); 168 | imm &= 0xfff; 169 | } 170 | 171 | if ((high & 0xfff) != 0) { 172 | SLJIT_ASSERT(high <= 0xfff); 173 | if (RISCV_HAS_COMPRESSED(200) && (high <= 0x1f || high >= 0xfe0)) 174 | FAIL_IF(push_inst16(compiler, C_ADDI | C_RD(tmp_r) | C_IMM_I(high))); 175 | else 176 | FAIL_IF(push_inst(compiler, ADDI | RD(tmp_r) | RS1(tmp_r) | IMM_I(high))); 177 | } 178 | 179 | if (imm & 0x1000) 180 | FAIL_IF(push_inst(compiler, XORI | RD(dst_r) | RS1(dst_r) | IMM_I(imm))); 181 | else if (imm != 0) { 182 | SLJIT_ASSERT(imm <= 0xfff); 183 | if (RISCV_HAS_COMPRESSED(200) && (imm <= 0x1f || imm >= 0xfe0)) 184 | FAIL_IF(push_inst16(compiler, C_ADDI | C_RD(dst_r) | C_IMM_I(imm))); 185 | else 186 | FAIL_IF(push_inst(compiler, ADDI | RD(dst_r) | RS1(dst_r) | IMM_I(imm))); 187 | } 188 | 189 | if (RISCV_HAS_COMPRESSED(200)) 190 | FAIL_IF(push_inst16(compiler, C_SLLI | C_RD(tmp_r) | (sljit_u16)((high & 0x1000) ? (20 << 2) : (1 << 12)))); 191 | else 192 | FAIL_IF(push_inst(compiler, SLLI | RD(tmp_r) | RS1(tmp_r) | IMM_I((high & 0x1000) ? 20 : 32))); 193 | return push_inst(compiler, XOR | RD(dst_r) | RS1(dst_r) | RS2(tmp_r)); 194 | } 195 | 196 | SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *compiler, 197 | sljit_s32 freg, sljit_f64 value) 198 | { 199 | union { 200 | sljit_sw imm; 201 | sljit_f64 value; 202 | } u; 203 | 204 | CHECK_ERROR(); 205 | CHECK(check_sljit_emit_fset64(compiler, freg, value)); 206 | 207 | u.value = value; 208 | 209 | if (u.imm == 0) 210 | return push_inst(compiler, FMV_W_X | (1 << 25) | RS1(TMP_ZERO) | FRD(freg)); 211 | 212 | FAIL_IF(load_immediate(compiler, TMP_REG1, u.imm, TMP_REG3)); 213 | return push_inst(compiler, FMV_W_X | (1 << 25) | RS1(TMP_REG1) | FRD(freg)); 214 | } 215 | 216 | SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fcopy(struct sljit_compiler *compiler, sljit_s32 op, 217 | sljit_s32 freg, sljit_s32 reg) 218 | { 219 | sljit_ins inst; 220 | 221 | CHECK_ERROR(); 222 | CHECK(check_sljit_emit_fcopy(compiler, op, freg, reg)); 223 | 224 | if (GET_OPCODE(op) == SLJIT_COPY_TO_F64) 225 | inst = FMV_W_X | RS1(reg) | FRD(freg); 226 | else 227 | inst = FMV_X_W | FRS1(freg) | RD(reg); 228 | 229 | if (!(op & SLJIT_32)) 230 | inst |= (sljit_ins)1 << 25; 231 | 232 | return push_inst(compiler, inst); 233 | } 234 | 235 | static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw init_value, sljit_ins last_ins) 236 | { 237 | sljit_sw high; 238 | 239 | if ((init_value & 0x800) != 0) 240 | init_value += 0x1000; 241 | 242 | high = init_value >> 32; 243 | 244 | if ((init_value & 0x80000000l) != 0) 245 | high = ~high; 246 | 247 | if ((high & 0x800) != 0) 248 | high += 0x1000; 249 | 250 | FAIL_IF(push_inst(compiler, LUI | RD(TMP_REG3) | (sljit_ins)(high & ~0xfff))); 251 | FAIL_IF(push_inst(compiler, ADDI | RD(TMP_REG3) | RS1(TMP_REG3) | IMM_I(high))); 252 | FAIL_IF(push_inst(compiler, LUI | RD(dst) | (sljit_ins)(init_value & ~0xfff))); 253 | FAIL_IF(push_inst(compiler, SLLI | RD(TMP_REG3) | RS1(TMP_REG3) | IMM_I(32))); 254 | FAIL_IF(push_inst(compiler, XOR | RD(dst) | RS1(dst) | RS2(TMP_REG3))); 255 | return push_inst(compiler, last_ins | RS1(dst) | IMM_I(init_value)); 256 | } 257 | 258 | SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset) 259 | { 260 | sljit_u16 *inst = (sljit_u16*)addr; 261 | sljit_sw high; 262 | SLJIT_UNUSED_ARG(executable_offset); 263 | 264 | if ((new_target & 0x800) != 0) 265 | new_target += 0x1000; 266 | 267 | high = (sljit_sw)new_target >> 32; 268 | 269 | if ((new_target & 0x80000000l) != 0) 270 | high = ~high; 271 | 272 | if ((high & 0x800) != 0) 273 | high += 0x1000; 274 | 275 | SLJIT_UPDATE_WX_FLAGS(inst, inst + 12, 0); 276 | 277 | SLJIT_ASSERT((inst[0] & 0x7f) == LUI); 278 | inst[0] = (sljit_u16)((inst[0] & 0xfff) | (high & 0xf000)); 279 | inst[1] = (sljit_u16)(high >> 16); 280 | SLJIT_ASSERT((inst[2] & 0x707f) == ADDI); 281 | inst[3] = (sljit_u16)((inst[3] & 0xf) | (high << 4)); 282 | SLJIT_ASSERT((inst[4] & 0x7f) == LUI); 283 | inst[4] = (sljit_u16)((inst[4] & 0xfff) | (new_target & 0xf000)); 284 | inst[5] = (sljit_u16)(new_target >> 16); 285 | SLJIT_ASSERT((inst[10] & 0x707f) == ADDI || (inst[10] & 0x707f) == JALR); 286 | inst[11] = (sljit_u16)((inst[11] & 0xf) | (new_target << 4)); 287 | SLJIT_UPDATE_WX_FLAGS(inst, inst + 12, 1); 288 | 289 | inst = (sljit_u16 *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset); 290 | SLJIT_CACHE_FLUSH(inst, inst + 12); 291 | } 292 | -------------------------------------------------------------------------------- /test_src/sljitConfigPost.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Stack-less Just-In-Time compiler 3 | * 4 | * Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without modification, are 7 | * permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, this list of 10 | * conditions and the following disclaimer. 11 | * 12 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list 13 | * of conditions and the following disclaimer in the documentation and/or other materials 14 | * provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 19 | * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 22 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef SLJIT_CONFIG_POST_H_ 28 | #define SLJIT_CONFIG_POST_H_ 29 | 30 | void *sljit_test_malloc_exec(sljit_uw size, void *exec_allocator_data); 31 | void sljit_test_free_code(void* code, void *exec_allocator_data); 32 | 33 | #endif /* SLJIT_CONFIG_POST_H_ */ 34 | -------------------------------------------------------------------------------- /test_src/sljitConfigPre.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Stack-less Just-In-Time compiler 3 | * 4 | * Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without modification, are 7 | * permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, this list of 10 | * conditions and the following disclaimer. 11 | * 12 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list 13 | * of conditions and the following disclaimer in the documentation and/or other materials 14 | * provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 19 | * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 22 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef SLJIT_CONFIG_PRE_H_ 28 | #define SLJIT_CONFIG_PRE_H_ 29 | 30 | #define SLJIT_HAVE_CONFIG_POST 1 31 | 32 | #define SLJIT_MALLOC_EXEC(size, exec_allocator_data) sljit_test_malloc_exec((size), (exec_allocator_data)) 33 | #define SLJIT_FREE_EXEC(ptr, exec_allocator_data) sljit_test_free_code((ptr), (exec_allocator_data)) 34 | 35 | #endif /* SLJIT_CONFIG_PRE_H_ */ 36 | -------------------------------------------------------------------------------- /test_src/sljitMain.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Stack-less Just-In-Time compiler 3 | * 4 | * Copyright 2009-2010 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without modification, are 7 | * permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, this list of 10 | * conditions and the following disclaimer. 11 | * 12 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list 13 | * of conditions and the following disclaimer in the documentation and/or other materials 14 | * provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 19 | * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 22 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #include "sljitLir.h" 28 | 29 | #include 30 | #include 31 | 32 | int sljit_test(int argc, char* argv[]); 33 | 34 | union executable_code { 35 | void* code; 36 | sljit_sw (SLJIT_FUNC *func)(sljit_sw* a); 37 | }; 38 | typedef union executable_code executable_code; 39 | 40 | static void error(const char* str) 41 | { 42 | printf("An error occured: %s\n", str); 43 | exit(-1); 44 | } 45 | 46 | void devel(void) 47 | { 48 | executable_code code; 49 | 50 | struct sljit_compiler *compiler = sljit_create_compiler(NULL); 51 | sljit_sw buf[4]; 52 | 53 | if (!compiler) 54 | error("Not enough of memory"); 55 | buf[0] = 5; 56 | buf[1] = 12; 57 | buf[2] = 0; 58 | buf[3] = 0; 59 | 60 | #if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) 61 | sljit_compiler_verbose(compiler, stdout); 62 | #endif 63 | sljit_emit_enter(compiler, 0, SLJIT_ARGS1(W, P), 4 | SLJIT_ENTER_FLOAT(4), 5, 2 * sizeof(sljit_sw)); 64 | 65 | sljit_emit_return(compiler, SLJIT_MOV, SLJIT_RETURN_REG, 0); 66 | 67 | code.code = sljit_generate_code(compiler, 0, NULL); 68 | sljit_free_compiler(compiler); 69 | 70 | printf("Code at: %p\n", (void*)SLJIT_FUNC_ADDR(code.code)); 71 | 72 | printf("Function returned with %ld\n", (long)code.func((sljit_sw*)buf)); 73 | printf("buf[0] = %ld\n", (long)buf[0]); 74 | printf("buf[1] = %ld\n", (long)buf[1]); 75 | printf("buf[2] = %ld\n", (long)buf[2]); 76 | printf("buf[3] = %ld\n", (long)buf[3]); 77 | sljit_free_code(code.code, NULL); 78 | } 79 | 80 | int main(int argc, char* argv[]) 81 | { 82 | /* devel(); */ 83 | return sljit_test(argc, argv); 84 | } 85 | --------------------------------------------------------------------------------