├── .gitignore ├── CMakeLists.txt ├── README.md ├── deps └── pull_deps.py ├── include ├── pwart.h └── pwart_syslib.h ├── makescript └── sljit_make_config.mk ├── pwart ├── def.h ├── extfunc.c ├── hostdef.c ├── make_config.mk ├── modparser.c ├── namespace.c ├── opgen_ctl.c ├── opgen_mem.c ├── opgen_misc.c ├── opgen_num.c ├── opgen_utils.c ├── pwart.c ├── util.c └── wagen.c ├── pwart_syslib ├── libffi.c ├── libuv.c ├── libwasi.c ├── pwart_syslib.c ├── util.c └── wasiexec.c ├── sljit ├── .gitignore ├── API_CHANGES ├── CMakeLists.txt ├── GNUmakefile ├── INTERNAL_CHANGES ├── LICENSE ├── README.md ├── docs │ ├── README.md │ ├── general │ │ ├── architecture.md │ │ ├── contributing.md │ │ ├── getting-started │ │ │ ├── configuration.md │ │ │ └── setup.md │ │ ├── introduction.md │ │ └── use-cases │ │ │ ├── bytecode-interpreters.md │ │ │ ├── overview.md │ │ │ └── pattern-matching │ │ │ ├── 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 ├── 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 └── tests ├── .gitignore ├── Makefile ├── benchsort.c ├── benchsort.wat ├── binary.wat ├── compare.wat ├── control.wat ├── convert.wat ├── extension1.wat ├── ffitestdll.c ├── syslibtest1.c ├── syslibtest1.wat ├── test1.wat ├── testexe3.c ├── testmain.c ├── testmain2.c └── unary.wat /.gitignore: -------------------------------------------------------------------------------- 1 | /.vscode 2 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | cmake_minimum_required(VERSION 3.15) 3 | 4 | if(COMMAND cmake_policy) 5 | cmake_policy(SET CMP0003 NEW) 6 | endif() 7 | 8 | set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) 9 | 10 | project(pwart) 11 | 12 | 13 | option(PWART_SYSLIB_ENABLED "compile pwart_syslib, require uv_a and libffi_a defined" OFF) 14 | 15 | if("${DEPS_SOURCE_DIRS}" STREQUAL "") 16 | if(NOT ("$ENV{DEPS_SOURCE_DIRS}" STREQUAL "")) 17 | set(DEPS_SOURCE_DIRS $ENV{DEPS_SOURCE_DIRS}) 18 | else() 19 | get_filename_component(DEPS_SOURCE_DIRS ../deps ABSOLUTE) 20 | endif() 21 | endif() 22 | 23 | option(BUILD_TESTING "enable test" OFF) 24 | 25 | 26 | if(BUILD_TESTING) 27 | add_compile_options(-ggdb3 -Wall) 28 | add_definitions(-DDEBUG_BUILD=1) 29 | endif() 30 | 31 | add_library(pwart STATIC pwart/pwart.c sljit/sljit_src/sljitLir.c) 32 | target_link_libraries(pwart m) 33 | target_include_directories(pwart PUBLIC include sljit/sljit_src) 34 | 35 | 36 | if (PWART_SYSLIB_ENABLED) 37 | add_library(pwart_syslib STATIC pwart_syslib/pwart_syslib.c) 38 | add_executable(pwart_wasiexec pwart_syslib/wasiexec.c) 39 | if (NOT DEPS_SOURCE_DIRS) 40 | get_filename_component(DEPS_SOURCE_DIRS .. ABSOLUTE) 41 | endif() 42 | 43 | if (NOT TARGET ffi_static AND EXISTS ${DEPS_SOURCE_DIRS}/libffi) 44 | add_subdirectory("${DEPS_SOURCE_DIRS}/libffi" ./build-libffi EXCLUDE_FROM_ALL) 45 | endif() 46 | if(NOT TARGET uv_a) 47 | add_subdirectory("${DEPS_SOURCE_DIRS}/libuv" ./build-libuv EXCLUDE_FROM_ALL) 48 | endif() 49 | if(NOT TARGET uvwasi_a) 50 | add_subdirectory("${DEPS_SOURCE_DIRS}/uvwasi" ./build-uvwasi EXCLUDE_FROM_ALL) 51 | endif() 52 | # uvwasi mark the header as PRIVATE(Strange), So we need include it manually. 53 | target_include_directories(pwart_syslib PUBLIC "${DEPS_SOURCE_DIRS}/uvwasi/include") 54 | target_include_directories(pwart_wasiexec PUBLIC "${DEPS_SOURCE_DIRS}/uvwasi/include") 55 | 56 | 57 | if (TARGET ffi_static) 58 | message("libffi found, libffi binding is enabled.") 59 | target_compile_definitions(pwart_syslib PRIVATE -DPWART_SYSLIB_LIBFFI_ENABLED) 60 | target_link_libraries(pwart_syslib PUBLIC pwart uvwasi_a uv_a ffi_static) 61 | else() 62 | message("libffi not found, libffi binding is disabled.") 63 | target_link_libraries(pwart_syslib PUBLIC pwart uvwasi_a uv_a) 64 | endif() 65 | 66 | 67 | target_link_libraries(pwart_wasiexec pwart_syslib) 68 | endif(PWART_SYSLIB_ENABLED) 69 | 70 | set(WAT2WASM $ENV{WAT2WASM}) 71 | 72 | if (NOT WAT2WASM) 73 | find_program(WAT2WASM wat2wasm) 74 | endif() 75 | 76 | 77 | 78 | if (BUILD_TESTING) 79 | enable_testing() 80 | execute_process(COMMAND ${WAT2WASM} "--enable-multi-memory" "--enable-extended-const" "--enable-tail-call" "test1.wat" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/tests" COMMAND_ECHO STDOUT) 81 | execute_process(COMMAND ${WAT2WASM} "--enable-multi-memory" "extension1.wat" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/tests" COMMAND_ECHO STDOUT) 82 | execute_process(COMMAND ${WAT2WASM} "unary.wat" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/tests" COMMAND_ECHO STDOUT) 83 | execute_process(COMMAND ${WAT2WASM} "benchsort.wat" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/tests" COMMAND_ECHO STDOUT) 84 | execute_process(COMMAND ${WAT2WASM} "binary.wat" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/tests" COMMAND_ECHO STDOUT) 85 | execute_process(COMMAND ${WAT2WASM} "control.wat" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/tests" COMMAND_ECHO STDOUT) 86 | execute_process(COMMAND ${WAT2WASM} "convert.wat" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/tests" COMMAND_ECHO STDOUT) 87 | execute_process(COMMAND ${WAT2WASM} "compare.wat" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/tests" COMMAND_ECHO STDOUT) 88 | add_executable(pwarttest tests/testmain.c) 89 | add_executable(pwarttest2 tests/testmain2.c) 90 | target_link_libraries(pwarttest pwart) 91 | target_link_libraries(pwarttest2 pwart) 92 | add_test(NAME test1 COMMAND pwarttest WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/tests") 93 | add_test(NAME test2 COMMAND pwarttest2 WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/tests") 94 | 95 | if(PWART_SYSLIB_ENABLED) 96 | execute_process(COMMAND ${WAT2WASM} "--enable-multi-memory" "syslibtest1.wat" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/tests" COMMAND_ECHO STDOUT) 97 | add_library(ffitestdll SHARED tests/ffitestdll.c) 98 | add_executable(syslibtest1 tests/syslibtest1.c) 99 | target_link_libraries(syslibtest1 pwart pwart_syslib) 100 | add_test(NAME syslibtest1 COMMAND syslibtest1 $ WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/tests") 101 | endif() 102 | 103 | endif() -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PWART 2 | 3 | ## 4 | **PWART** is a light-weight JIT runtime for WebAssembly. 5 | 6 | PWART use sljit to generate native code, no other dependency. All code is writen in C, include sljit. 7 | 8 | PWART support 32bit and 64bit architecture, test only on x86_64, i686 ,aarch64 and armv7l, but should also work on risc-v etc. thanks to sljit. 9 | 10 | Currently, PWART still need more test to improve and verify the stablity. 11 | 12 | 13 | about sljit: https://github.com/zherczeg/sljit 14 | 15 | ## Usage 16 | 17 | Currently only support GCC-like toolchain, consider use MinGW on Windows please. 18 | 19 | ### CMake mode 20 | ```shell 21 | cmake -S . -B build 22 | ``` 23 | 24 | ```shell 25 | python deps/pull_deps.py 26 | cmake -S . -B build -DPWART_SYSLIB_ENABLED=ON 27 | ``` 28 | 29 | ### Makefile mode 30 | 31 | (*Makefile mode do not support to build pwart_syslib component yet.*) 32 | 33 | 1. Set environment variable PWART_SOURCE_DIR to the project directory. 34 | 35 | 2. In your Makefile, write 36 | ```shell 37 | include $(PWART_SOURCE_DIR)/pwart/make_config.mk 38 | ``` 39 | 40 | 3. Put flags to build your target. 41 | ```shell 42 | your_target:build_pwart 43 | $(CC) $(PWART_CFLAGS) $(CFLAGS) -o your_output your_source.c $(PWART_LDFLAGS) $(LDFLAGS) 44 | ``` 45 | 46 | 4. In your source, include "pwart.h". A simple demo show below. 47 | 48 | ```C 49 | void *stackbase = pwart_allocate_stack(64 * 1024); 50 | pwart_module_state ctx=pwart_load_module(data,len,&err); 51 | if(ctx==NULL){printf("load module failed:%s\n",err);return 0;}; 52 | pwart_wasmfunction test1 = pwart_get_export_function(ctx, "test1"); 53 | pwart_call_wasm_function(test1,stackbase); 54 | ... 55 | ``` 56 | 57 | See [include/pwart.h](include/pwart.h) , [tests/testmain.c](tests/testmain.c) [tests/testmain2.c](tests/testmain2.c) 58 | and [tests/Makefile](tests/Makefile) for detail usage. 59 | 60 | ## SYSLIB and WASI Support 61 | 62 | There are experimental Runtime Core Library(SYSLIB) and WASI Support, can be enabled by `-DPWART_SYSLIB_ENABLED=ON` in CMake. And you need to pull the dependencies ([libuv](https://github.com/libuv/libuv), [libffi with cmake(optional)](https://github.com/partic2/libffi), [uvwasi](https://github.com/nodejs/uvwasi)) by using `python deps/pull_deps`.py* 63 | 64 | The `pwart_wasiexec` can be used to execute a WASI module, and you can also use `libpwart_syslib.a` to embed the library. See also [include/pwart_syslib.h](include/pwart_syslib.h) 65 | 66 | 67 | ## Test 68 | 69 | To run the test, you need WAT2WASM to compile wat file. You can get it by compile [wabt](https://github.com/WebAssembly/wabt),Then 70 | ``` 71 | export PWART_SOURCE_DIR= 72 | export WAT2WASM= 73 | cd $PWART_SOURCE_DIR/tests 74 | make 75 | ``` 76 | or , If you use cmake 77 | ``` 78 | cmake -S . -B build -DBUILD_TESTING=ON -DPWART_SYSLIB_ENABLED=ON 79 | cd build 80 | make test 81 | ``` 82 | 83 | ## Implemented 84 | 85 | WebAssembly MVP 86 | 87 | Import/Export of Mutable Globals 88 | 89 | Sign-extension operators 90 | 91 | Multi-value 92 | 93 | Non-trapping Float-to-int Conversions (For performance, the behavior depend on the host.) 94 | 95 | Bulk Memory Operations(Conditional Segment Initialization is not supported yet.) 96 | 97 | Memory64(support i64 index, offset and align are still 32bit.) 98 | 99 | Reference types 100 | 101 | Multiple memories 102 | 103 | Extended Constant Expressions 104 | 105 | Tail Call 106 | 107 | Simple namespace support 108 | 109 | ## NOT Implemented 110 | 111 | Fixed-width SIMD. 112 | 113 | 114 | ## Benchmarks 115 | 116 | The source code are here [tests/benchsort.c](tests/benchsort.c). 117 | 118 | Until May 18, 2023 119 | 120 | Time Consumed 121 | 122 | | | GCC (-O2) | PWART (fixed memory) | PWART (dynamic memory) | PWART (native memory) | TinyCC | V8(Chrome v113) | 123 | | ---- | ----: | ----: | ----: | ----: | ----: | ----: | 124 | | Windows10 x86_64 | 2823ms | 3622ms | 2720ms | Not test yet | 6330ms | 2618ms | 125 | | Linux aarch64 | 1561ms | 1997ms | 2079ms | Not test yet | 7681ms | 1465ms | 126 | 127 | **fixed memory** mean wasm module use memory with maximum limit size (expected to be faster). **native memory** mean memory is mapped to host memory directly, This feature is not supported by any toolchain, So we need write .wat by hand before testing. 128 | 129 | See [include/pwart.h](include/pwart.h) for detail. 130 | 131 | 132 | ## Roadmap 133 | 134 | 1. More test , and fix. 135 | 136 | 2. Performance optimization. 137 | 138 | 3. More libuv and libffi binding. 139 | -------------------------------------------------------------------------------- /deps/pull_deps.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import os 3 | 4 | def url_replacer(url): 5 | return url 6 | 7 | git='git' 8 | 9 | if os.environ.get('DEPS_SOURCE_DIRS','')=='': 10 | os.environ['DEPS_SOURCE_DIRS']=os.path.join(os.path.dirname(os.path.abspath(__file__))) 11 | 12 | deps_dir=os.environ.get('DEPS_SOURCE_DIRS') 13 | 14 | 15 | def pull(dep_name, repo_url, branch="main"): 16 | """ 17 | Pull remote repository dependency to local 18 | Args: 19 | dep_name (str): Dependency name (will be used as directory name) 20 | repo_url (str): Repository URL (can be replace by url_replacer, if needed) 21 | branch (str): Repository branch, defaults to main 22 | """ 23 | 24 | repo_url = url_replacer(repo_url) 25 | 26 | base_dir = deps_dir 27 | target_dir = os.path.join(base_dir, dep_name) 28 | 29 | if os.path.exists(target_dir): 30 | try: 31 | # Execute git clone command 32 | cmd = [ 33 | git, 'pull', 34 | '--rebase' 35 | ] 36 | print(f'[INFO] Update {target_dir}') 37 | subprocess.run(cmd, check=True,cwd=target_dir) 38 | print(f"[OK] Successfully pulled {dep_name} @{branch}") 39 | 40 | except subprocess.CalledProcessError as e: 41 | print(f"[ERROR] Failed to pull {dep_name}: {str(e)}") 42 | except Exception as e: 43 | print(f"[ERROR] Unexpected error: {str(e)}") 44 | else: 45 | try: 46 | # Execute git clone command 47 | cmd = [ 48 | git, 'clone', 49 | '-b', branch, 50 | '--depth', '1', 51 | repo_url, 52 | target_dir 53 | ] 54 | print(f'[INFO] Clone into {target_dir}') 55 | subprocess.run(cmd, check=True) 56 | print(f"[OK] Successfully pulled {dep_name} @{branch}") 57 | 58 | except subprocess.CalledProcessError as e: 59 | print(f"[ERROR] Failed to pull {dep_name}: {str(e)}") 60 | except Exception as e: 61 | print(f"[ERROR] Unexpected error: {str(e)}") 62 | return target_dir 63 | 64 | 65 | def main(): 66 | pull('libffi','https://gitee.com/partic/libffi','main') 67 | pull('libuv','https://gitee.com/partic/libuv-patched','v1.x') 68 | pull('uvwasi','https://gitee.com/partic/uvwasi','main') 69 | 70 | if __name__=='__main__': 71 | main() 72 | -------------------------------------------------------------------------------- /include/pwart_syslib.h: -------------------------------------------------------------------------------- 1 | #ifndef _PWART_SYSLIB_H 2 | #define _PWART_SYSLIB_H 3 | 4 | #include 5 | 6 | 7 | extern char **pwart_syslib_get_enabled_list(); 8 | /* wasi module require extra initialize before invoking exports. see pwart_wasi_module_init */ 9 | extern char *pwart_syslib_load(pwart_namespace ns); 10 | extern char *pwart_syslib_unload(pwart_namespace ns); 11 | 12 | /* 13 | libffi is optional. 14 | There is also "ffi_is_enabled" function in this module. 15 | If libffi isn't enabled, all function in this module just do nothing except "ffi_is_enabled". 16 | */ 17 | extern int pwart_libffi_module_ffi_is_enabled(); 18 | extern char *pwart_libffi_module_delete(struct pwart_host_module *mod); 19 | extern struct pwart_host_module *pwart_libffi_module_new(); 20 | 21 | extern struct pwart_host_module *pwart_libuv_module_new(); 22 | extern char *pwart_libuv_module_delete(struct pwart_host_module *mod); 23 | 24 | /* module wasi_snapshot_preview1 */ 25 | extern void pwart_wasi_module_set_wasimemory(struct pwart_wasm_memory *m); 26 | extern void pwart_wasi_module_set_wasiargs(uint32_t argc,char **argv); 27 | /* Initialize wasi environment, the wasi 'memory' and 'args' should be set properly */ 28 | extern char *pwart_wasi_module_init(); 29 | /* Currently we only support to create and initialize ONE wasi module in one PROCESS in same time, 30 | If you want another one, delete the previous one.*/ 31 | extern struct pwart_host_module *pwart_wasi_module_new(); 32 | extern char *pwart_wasi_module_delete(struct pwart_host_module *mod); 33 | 34 | 35 | #endif -------------------------------------------------------------------------------- /makescript/sljit_make_config.mk: -------------------------------------------------------------------------------- 1 | 2 | 3 | SLJIT_SOURCE_ROOT=$(PWART_SOURCE_DIR)/sljit 4 | 5 | SLJIT_CFLAGS= 6 | 7 | # Allow empty PTHREAD_LDFLAGS ? 8 | ifndef PTHREAD_LDFLAGS 9 | PTHREAD_LDFLAGS=-lpthread 10 | endif 11 | 12 | SLJIT_LDFLAGS=sljitLir.o -lm $(PTHREAD_LDFLAGS) 13 | 14 | build_sljit: 15 | $(CC) $(SLJIT_CFLAGS) $(CFLAGS) -c $(SLJIT_SOURCE_ROOT)/sljit_src/sljitLir.c -------------------------------------------------------------------------------- /pwart/hostdef.c: -------------------------------------------------------------------------------- 1 | #ifndef _PWART_HOSTDEF_C 2 | #define _PWART_HOSTDEF_C 3 | 4 | #include 5 | 6 | #define __tostrInternal(s) #s 7 | #define tostr(s) __tostrInternal(s) 8 | static char *host_definition[]={ 9 | #ifdef __linux__ 10 | "__linux__", 11 | #endif 12 | #ifdef _WIN32 13 | "_WIN32", 14 | #endif 15 | #ifdef _WIN64 16 | "_WIN64", 17 | #endif 18 | #ifdef __x86__ 19 | "__x86__", 20 | #endif 21 | #ifdef __x86_64__ 22 | "__x86_64__", 23 | #endif 24 | #ifdef __ARM_ARCH 25 | "__ARM_ARCH="tostr(__ARM_ARCH), 26 | #endif 27 | #ifdef __riscv_xlen 28 | "__riscv_xlen="tostr(__riscv_xlen), 29 | #endif 30 | #ifdef __arm__ 31 | "__arm__", 32 | #endif 33 | #ifdef __aarch64__ 34 | "__aarch64__", 35 | #endif 36 | #ifdef __ANDROID__ 37 | "__ANDROID__", 38 | #endif 39 | #ifdef __ANDROID_API__ 40 | "__ANDROID_API__="tostr(__ANDROID_API__), 41 | #endif 42 | #ifdef __SOFTFP__ 43 | "__SOFTFP__", 44 | #endif 45 | #ifdef __LITTLE_ENDIAN__ 46 | "__LITTLE_ENDIAN__", 47 | #endif 48 | #ifdef __MIPSEL__ 49 | "__MIPSEL__", 50 | #endif 51 | #ifdef __NetBSD__ 52 | "__NetBSD__", 53 | #endif 54 | #ifdef __APPLE__ 55 | "__APPLE__", 56 | #endif 57 | NULL 58 | }; 59 | 60 | #undef tostr 61 | 62 | #endif -------------------------------------------------------------------------------- /pwart/make_config.mk: -------------------------------------------------------------------------------- 1 | include $(PWART_SOURCE_DIR)/makescript/sljit_make_config.mk 2 | 3 | PWART_CFLAGS=$(SLJIT_CFLAGS) -I$(PWART_SOURCE_DIR)/include 4 | 5 | PWART_LDFLAGS=pwart.o $(SLJIT_LDFLAGS) -lm 6 | 7 | build_pwart:build_sljit 8 | $(CC) $(PWART_CFLAGS) $(CFLAGS) -c $(PWART_SOURCE_DIR)/pwart/pwart.c 9 | 10 | clean: 11 | - rm $(PWART_SOURCE_DIR)/pwart/pwart.o 12 | 13 | -------------------------------------------------------------------------------- /pwart/namespace.c: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _PWART_NAMESPACE_C 3 | #define _PWART_NAMESPACE_C 4 | 5 | #include 6 | 7 | #include "def.h" 8 | 9 | #include "util.c" 10 | 11 | static Namespace *namespace_GetNamespaceFormResolver(struct pwart_symbol_resolver *_this){ 12 | return (Namespace *)_this; 13 | } 14 | 15 | extern struct pwart_symbol_resolver *pwart_namespace_resolver(pwart_namespace ns){ 16 | return &((Namespace *)ns)->resolver; 17 | } 18 | 19 | static void namespace_SymbolResolve(struct pwart_symbol_resolver *_this,struct pwart_symbol_resolve_request *req){ 20 | Namespace *n=namespace_GetNamespaceFormResolver(_this); 21 | struct pwart_named_module *m=pwart_namespace_find_module(n,req->import_module); 22 | req->result=NULL; 23 | if(m==NULL){ 24 | return; 25 | } 26 | switch(m->type){ 27 | case PWART_MODULE_TYPE_HOST_MODULE: 28 | m->val.host->resolve(m->val.host,req); 29 | break; 30 | case PWART_MODULE_TYPE_WASM_MODULE: 31 | switch(req->kind){ 32 | case PWART_KIND_FUNCTION: 33 | req->result=pwart_get_export_function(m->val.wasm,req->import_field); 34 | break; 35 | case PWART_KIND_GLOBAL: 36 | req->result=pwart_get_export_global(m->val.wasm,req->import_field); 37 | break; 38 | case PWART_KIND_TABLE: 39 | req->result=pwart_get_export_table(m->val.wasm,req->import_field); 40 | break; 41 | case PWART_KIND_MEMORY: 42 | req->result=pwart_get_export_memory(m->val.wasm,req->import_field); 43 | break; 44 | } 45 | break; 46 | } 47 | return; 48 | } 49 | 50 | extern pwart_namespace pwart_namespace_new(){ 51 | Namespace *ns=(Namespace *)wa_calloc(sizeof(Namespace)); 52 | dynarr_init(&ns->mods,sizeof(struct pwart_named_module)); 53 | ns->resolver.resolve=&namespace_SymbolResolve; 54 | return ns; 55 | } 56 | 57 | extern char *pwart_namespace_delete(pwart_namespace ns){ 58 | Namespace *n=(Namespace *)ns; 59 | int i=0; 60 | for(i=0;imods->len;i++){ 61 | struct pwart_named_module *m=dynarr_get(n->mods,struct pwart_named_module,i); 62 | switch(m->type){ 63 | case PWART_MODULE_TYPE_HOST_MODULE: 64 | if(m->val.host->on_detached!=NULL){ 65 | m->val.host->on_detached(m->val.host); 66 | } 67 | break; 68 | case PWART_MODULE_TYPE_WASM_MODULE: 69 | ReturnIfErr(pwart_free_module_state(m->val.wasm)); 70 | break; 71 | } 72 | } 73 | wa_free(n); 74 | return NULL; 75 | } 76 | 77 | extern struct pwart_named_module *pwart_namespace_find_module(pwart_namespace ns,const char *name){ 78 | Namespace *n=(Namespace *)ns; 79 | int i=0; 80 | for(i=0;imods->len;i++){ 81 | struct pwart_named_module *m=dynarr_get(n->mods,struct pwart_named_module,i); 82 | if(strcmp(m->name,name)==0){ 83 | return m; 84 | } 85 | } 86 | return NULL; 87 | } 88 | 89 | extern char *pwart_namespace_remove_module(pwart_namespace ns,const char *name){ 90 | struct pwart_named_module *m=pwart_namespace_find_module(ns,name); 91 | if(m!=NULL){ 92 | switch(m->type){ 93 | case PWART_MODULE_TYPE_HOST_MODULE: 94 | if(m->val.host->on_detached!=NULL){ 95 | m->val.host->on_detached(m->val.host); 96 | } 97 | break; 98 | case PWART_MODULE_TYPE_WASM_MODULE: 99 | ReturnIfErr(pwart_free_module_state(m->val.wasm)); 100 | break; 101 | } 102 | m->type=PWART_MODULE_TYPE_NULL; 103 | } 104 | return NULL; 105 | } 106 | 107 | 108 | extern char *pwart_namespace_define_module(pwart_namespace ns,struct pwart_named_module *mod){ 109 | Namespace *n=(Namespace *)ns; 110 | struct pwart_named_module *m; 111 | m=pwart_namespace_find_module(ns,mod->name); 112 | if(m!=NULL){ 113 | pwart_namespace_remove_module(ns,m->name); 114 | }else{ 115 | m=dynarr_push_type(&n->mods,struct pwart_named_module); 116 | } 117 | memmove(m,mod,sizeof(struct pwart_named_module)); 118 | switch(m->type){ 119 | case PWART_MODULE_TYPE_HOST_MODULE: 120 | m->val.host->namespace2=ns; 121 | if(m->val.host->on_attached!=NULL){ 122 | m->val.host->on_attached(m->val.host); 123 | } 124 | break; 125 | case PWART_MODULE_TYPE_WASM_MODULE: 126 | pwart_set_state_symbol_resolver(m->val.wasm,&n->resolver); 127 | ((RuntimeContext *)m->val.wasm)->is_in_namespace=1; 128 | break; 129 | } 130 | return NULL; 131 | } 132 | 133 | extern pwart_module_state *pwart_namespace_define_wasm_module(pwart_namespace ns,const char *name,const char *wasm_bytes,int length,char **err_msg){ 134 | Namespace *n=(Namespace *)ns; 135 | struct pwart_named_module mod; 136 | char *err=NULL; 137 | pwart_module_state state=NULL; 138 | pwart_module_compiler m=pwart_new_module_compiler(); 139 | pwart_set_symbol_resolver(m,&n->resolver); 140 | err=pwart_compile(m,wasm_bytes,length); 141 | if(err==NULL){ 142 | state=pwart_get_module_state(m); 143 | }else{ 144 | if(err_msg!=NULL)*err_msg=err; 145 | return NULL; 146 | } 147 | pwart_free_module_compiler(m); 148 | mod.name=name; 149 | mod.type=PWART_MODULE_TYPE_WASM_MODULE; 150 | mod.val.wasm=state; 151 | pwart_namespace_define_module(ns,&mod); 152 | return state; 153 | } 154 | 155 | struct InternalHostModule{ 156 | struct pwart_host_module base; 157 | char **names; 158 | void **symbols; 159 | int length; 160 | }; 161 | 162 | static void namespace_InternalHostModuleSymbolResolver(struct pwart_host_module *_this2,struct pwart_symbol_resolve_request *req){ 163 | struct InternalHostModule *_this=(struct InternalHostModule *)_this2; 164 | int i=0; 165 | req->result=NULL; 166 | for(i=0;i<_this->length;i++){ 167 | if(strcmp(_this->names[i],req->import_field)==0){ 168 | req->result=_this->symbols[i]; 169 | break; 170 | } 171 | } 172 | } 173 | 174 | extern struct pwart_host_module *pwart_namespace_new_host_module(char **names,pwart_host_function_c *funcs,int length){ 175 | struct InternalHostModule *hostmod=wa_calloc(sizeof(struct InternalHostModule)); 176 | hostmod->length=length; 177 | hostmod->names=names; 178 | /*XXX: Once pwart_wasm_function changed, Fix here by using pwart_wrap_host_function_c. */ 179 | hostmod->symbols=(void *)funcs; 180 | hostmod->base.resolve=&namespace_InternalHostModuleSymbolResolver; 181 | return (struct pwart_host_module *)hostmod; 182 | } 183 | 184 | extern struct pwart_host_module *pwart_namespace_new_host_module2(char **names,void **symbols,int length){ 185 | struct InternalHostModule *hostmod=wa_calloc(sizeof(struct InternalHostModule)); 186 | hostmod->length=length; 187 | hostmod->names=names; 188 | hostmod->symbols=symbols; 189 | hostmod->base.resolve=&namespace_InternalHostModuleSymbolResolver; 190 | return (struct pwart_host_module *)hostmod; 191 | } 192 | 193 | extern void pwart_namespace_delete_host_module(struct pwart_host_module *hostmod){ 194 | wa_free(hostmod); 195 | } 196 | 197 | 198 | #endif -------------------------------------------------------------------------------- /pwart/opgen_misc.c: -------------------------------------------------------------------------------- 1 | #ifndef _PWART_OPGEN_MISC_C 2 | #define _PWART_OPGEN_MISC_C 3 | 4 | #include "def.h" 5 | #include "extfunc.c" 6 | #include "opgen_num.c" 7 | #include "opgen_mem.c" 8 | #include "opgen_utils.c" 9 | 10 | static void opgen_GenRefNull(ModuleCompiler *m, int32_t typeidx) { 11 | StackValue *sv = stackvalue_Push(m, WVT_REF); 12 | sv->jit_type = SVT_GENERAL; 13 | sv->val.op = SLJIT_IMM; 14 | sv->val.opw = 0; 15 | } 16 | static void opgen_GenIsNull(ModuleCompiler *m) { 17 | StackValue *sv = &m->stack[m->sp]; 18 | if (sv->wasm_type == WVT_REF || sv->wasm_type == WVT_FUNC) { 19 | sljit_emit_op2u(m->jitc, SLJIT_SUB | SLJIT_SET_Z, sv->val.op, sv->val.opw, 20 | SLJIT_IMM, 0); 21 | m->sp--; 22 | stackvalue_Push(m,WVT_I32); 23 | sv->jit_type = SVT_CMP; 24 | sv->val.cmp.flag = SLJIT_EQUAL; 25 | } else { 26 | m->sp--; 27 | stackvalue_Push(m,WVT_I32); 28 | sv->jit_type = SVT_GENERAL; 29 | sv->val.opw = 0; 30 | sv->val.op = SLJIT_IMM; 31 | } 32 | } 33 | 34 | static void opgen_GenRefFunc(ModuleCompiler *m, int32_t fidx) { 35 | int32_t a; 36 | StackValue *sv; 37 | a = pwart_GetFreeReg(m, RT_INTEGER, 0); 38 | sljit_emit_op1(m->jitc, SLJIT_MOV, a, 0, SLJIT_IMM,(sljit_uw)(m->context->funcentries+fidx)); 39 | sv = stackvalue_Push(m, WVT_FUNC); 40 | sv->jit_type = SVT_GENERAL; 41 | sv->val.op = SLJIT_MEM1(a); 42 | sv->val.opw = 0; 43 | } 44 | 45 | static void opgen_GenTableSize(ModuleCompiler *m,int tabidx){ 46 | int32_t r; 47 | StackValue *sv=NULL; 48 | r = pwart_GetFreeReg(m, RT_INTEGER, 0); 49 | Table *tab=*dynarr_get(m->context->tables,Table *,tabidx); 50 | sljit_emit_op1(m->jitc,SLJIT_MOV,r,0,SLJIT_IMM,(sljit_sw)&tab->size); 51 | sv = stackvalue_Push(m, WVT_I32); 52 | sv->jit_type = SVT_GENERAL; 53 | sv->val.op = SLJIT_MEM1(r); 54 | sv->val.opw = 0; 55 | } 56 | 57 | static char *opgen_GenMiscOp_FC(ModuleCompiler *m,int opcode){ 58 | StackValue *sv; 59 | int a,b; 60 | #if DEBUG_BUILD 61 | switch(opcode){ 62 | case 0x0: case 0x1: case 0x2: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7: 63 | wa_debug("op fc %x:%s\n", m->pc, "ixx.trunc_sat_fxx_s|u"); 64 | break; 65 | case 0x0a: 66 | wa_debug("op fc %x:%s\n", m->pc, "memory.copy"); 67 | break; 68 | case 0x0b: 69 | wa_debug("op fc %x:%s\n", m->pc, "memory.fill"); 70 | break; 71 | } 72 | #endif 73 | switch(opcode){ 74 | //Non-trapping Float-to-int Conversions 75 | //the behavior when convert is overflow is depend on sljit implementation. 76 | case 0x00: //i32.trunc_sat_f32_s 77 | opgen_GenNumOp(m,0xa8); 78 | break; 79 | case 0x01: //i32.trunc_sat_f32_u 80 | opgen_GenNumOp(m,0xa9); 81 | break; 82 | case 0x02: //i32.trunc_sat_f64_s 83 | opgen_GenNumOp(m,0xaa); 84 | break; 85 | case 0x03: //i32.trunc_sat_f64_u 86 | opgen_GenNumOp(m,0xab); 87 | break; 88 | case 0x04: //i64.trunc_sat_f32_s 89 | opgen_GenNumOp(m,0xae); 90 | break; 91 | case 0x05: //i64.trunc_sat_f32_u 92 | opgen_GenNumOp(m,0xaf); 93 | break; 94 | case 0x06: //i64.trunc_sat_f64_s 95 | opgen_GenNumOp(m,0xb0); 96 | break; 97 | case 0x07: //i64.trunc_sat_f64_u 98 | opgen_GenNumOp(m,0xb1); 99 | break; 100 | case 0x0a: //memory.copy 101 | a=read_LEB_signed(m->bytes,&m->pc,32); //destination memory index 102 | b=read_LEB_signed(m->bytes,&m->pc,32); //source memory index 103 | opgen_GenMemoryCopy(m,a,b); 104 | break; 105 | case 0x0b: //memory.fill 106 | a=read_LEB_signed(m->bytes,&m->pc,32); //destination memory index 107 | opgen_GenMemoryFill(m,a); 108 | break; 109 | case 0x0e: //table.copy 110 | { 111 | int32_t dtab=read_LEB_signed(m->bytes,&m->pc,32); //destination table index 112 | int32_t stab=read_LEB_signed(m->bytes,&m->pc,32); //source table index 113 | opgen_GenTableCopy(m,dtab,stab); 114 | } 115 | break; 116 | case 0x0f: //table.grow 117 | //table are not allowed to grow 118 | read_LEB_signed(m->bytes,&m->pc,32); //table index 119 | m->sp-=2; 120 | sv=stackvalue_Push(m,WVT_I32); 121 | sv->val.op=SLJIT_IMM; 122 | sv->val.opw=-1; 123 | break; 124 | case 0x10: //table.size 125 | { 126 | uint32_t tabidx=read_LEB_signed(m->bytes,&m->pc,32); 127 | opgen_GenTableSize(m,tabidx); 128 | } 129 | break; 130 | case 0x11: //table.fill 131 | { 132 | uint32_t tabidx=read_LEB_signed(m->bytes,&m->pc,32); 133 | opgen_GenTableFill(m,tabidx); 134 | } 135 | break; 136 | default: 137 | wa_debug("unrecognized misc opcode 0xfc 0x%x at %d", opcode, m->pc); 138 | return "unrecognized opcode"; 139 | } 140 | return NULL; 141 | } 142 | 143 | static char *opgen_GenMiscOp(ModuleCompiler *m, int opcode) { 144 | int32_t tidx,fidx,opcode2; 145 | uint8_t *bytes = m->bytes; 146 | switch (opcode) { 147 | case 0xd0: // ref.null 148 | tidx = read_LEB_signed(bytes, &m->pc, 32); // ref type 149 | opgen_GenRefNull(m, tidx); 150 | break; 151 | case 0xd1: // ref.isnull 152 | opgen_GenIsNull(m); 153 | break; 154 | case 0xd2: // ref.func 155 | fidx = read_LEB(bytes, &m->pc, 32); 156 | opgen_GenRefFunc(m, fidx); 157 | break; 158 | case 0xfc: // misc prefix 159 | opcode2=m->bytes[m->pc]; 160 | m->pc++; 161 | ReturnIfErr(opgen_GenMiscOp_FC(m,opcode2)); 162 | break; 163 | default: 164 | wa_debug("unrecognized opcode 0x%x at %d", opcode, m->pc); 165 | return "unrecognized opcode"; 166 | } 167 | return NULL; 168 | } 169 | 170 | 171 | //if fn is stub/inline function, generate native code and return 1, else return 0. 172 | static int pwart_CheckAndGenStubFunction(ModuleCompiler *m,WasmFunctionEntry fn){ 173 | int i1; 174 | pwart_get_builtin_symbols(&i1); 175 | if(fn==pwart_InlineFuncList.get_self_runtime_context){ 176 | opgen_GenRefConst(m,m->context); 177 | return 1; 178 | }else if(fn==pwart_InlineFuncList.ref_from_i64){ 179 | if(m->target_ptr_size==32){ 180 | opgen_GenConvertOp(m,WASMOPC_i32_wrap_i64); 181 | } 182 | m->stack[m->sp].wasm_type=WVT_REF; 183 | return 1; 184 | }else if(fn==pwart_InlineFuncList.i64_from_ref){ 185 | if(m->target_ptr_size==32){ 186 | m->stack[m->sp].wasm_type=WVT_I32; 187 | opgen_GenConvertOp(m,WASMOPC_i64_extend_i32_u); 188 | } 189 | m->stack[m->sp].wasm_type=WVT_I64; 190 | return 1; 191 | }else if(fn==pwart_InlineFuncList.ref_from_index){ 192 | StackValue *sv=m->stack+m->sp-1; 193 | SLJIT_ASSERT((sv->jit_type==SVT_GENERAL) && (sv->val.op==SLJIT_IMM)); 194 | opgen_GenBaseAddressReg(m,sv->val.opw); 195 | stackvalue_EmitSwapTopTwoValue(m); 196 | m->sp--; 197 | return 1; 198 | } 199 | return 0; 200 | } 201 | #endif -------------------------------------------------------------------------------- /pwart/util.c: -------------------------------------------------------------------------------- 1 | #ifndef _PWART_UTIL_C 2 | 3 | #define _PWART_UTIL_C 4 | 5 | #ifndef DEBUG_BUILD 6 | #define DEBUG_BUILD 0 7 | #endif 8 | 9 | #define PWART_DEBUG_RUNTIME_PROBE 0 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | #include 19 | 20 | #include "../sljit/sljit_src/sljitLir.h" 21 | 22 | 23 | #define ReturnIfErr(expr) {char *err=expr;if(err!=NULL){wa_debug("error occure:%s\n",err);return err;}} 24 | 25 | 26 | 27 | static void *wa_malloc(size_t size) { 28 | void *res = malloc(size); 29 | return res; 30 | } 31 | 32 | static void *wa_realloc(void *p,size_t nsize){ 33 | void *res=realloc(p,nsize); 34 | return res; 35 | } 36 | 37 | static void wa_free(void *p){ 38 | free(p); 39 | } 40 | 41 | static void *wa_calloc(size_t size){ 42 | return calloc(size,1); 43 | } 44 | 45 | 46 | static void wa_debug(char *fmt,...){ 47 | #if DEBUG_BUILD 48 | va_list args; 49 | va_start(args,fmt); 50 | vprintf(fmt,args); 51 | va_end(args); 52 | fflush(stdout); 53 | #endif 54 | } 55 | 56 | static void wa_abort(){ 57 | printf("aborted...\n"); 58 | exit(1); 59 | } 60 | 61 | static void wa_assert(int cond,char *failInfo){ 62 | if(!cond){ 63 | wa_debug("assert fail due to %s\n",failInfo); 64 | wa_abort(); 65 | } 66 | } 67 | 68 | // type readers 69 | 70 | static uint64_t read_LEB_(uint8_t *bytes, uint32_t *pos, uint32_t maxbits, int sign) { 71 | uint64_t result = 0; 72 | uint32_t shift = 0; 73 | uint32_t bcnt = 0; 74 | uint32_t startpos = *pos; 75 | uint64_t byte; 76 | 77 | while (1) { 78 | byte = bytes[*pos]; 79 | *pos += 1; 80 | result |= ((byte & 0x7f)< (maxbits + 7 - 1) / 7) { 87 | wa_debug("Unsigned LEB at byte %d overflow", startpos); 88 | } 89 | } 90 | if (sign && (shift < maxbits) && (byte & 0x40)) { 91 | // Sign extend 92 | result |= - (1 << shift); 93 | } 94 | return result; 95 | } 96 | 97 | static uint64_t read_LEB(uint8_t *bytes, uint32_t *pos, uint32_t maxbits) { 98 | return read_LEB_(bytes, pos, maxbits, 0); 99 | } 100 | 101 | static uint64_t read_LEB_signed(uint8_t *bytes, uint32_t *pos, uint32_t maxbits) { 102 | return read_LEB_(bytes, pos, maxbits, 1); 103 | } 104 | 105 | static uint32_t read_uint32(uint8_t *bytes, uint32_t *pos) { 106 | *pos += 4; 107 | return ((uint32_t *) (bytes+*pos-4))[0]; 108 | } 109 | 110 | 111 | struct dynarr{ 112 | uint32_t len; 113 | uint32_t cap; 114 | uint32_t elemSize; 115 | uint8_t data[1]; 116 | }; 117 | 118 | static void dynarr_init(struct dynarr **arr,uint32_t elemSize){ 119 | if(*arr!=NULL){ 120 | wa_free(*arr); 121 | } 122 | *arr=wa_malloc(sizeof(struct dynarr)+elemSize); 123 | (*arr)->cap=1; 124 | (*arr)->len=0; 125 | (*arr)->elemSize=elemSize; 126 | } 127 | static void *dynarr_push(struct dynarr **buf,int count){ 128 | struct dynarr *arr=*buf; 129 | uint32_t cap=arr->cap; 130 | uint32_t elemSize=arr->elemSize; 131 | void *newelem=NULL; 132 | while(cap<=arr->len+count){ 133 | cap=cap*2; 134 | } 135 | if(arr->cap!=cap){ 136 | arr=wa_realloc(*buf,sizeof(struct dynarr)+elemSize*cap); 137 | *buf=arr; 138 | arr->cap=cap; 139 | } 140 | newelem=&arr->data[arr->len*elemSize]; 141 | memset(newelem,0,elemSize*count); 142 | arr->len+=count; 143 | return newelem; 144 | } 145 | #if DEBUG_BUILD 146 | 147 | static void *dynarr_push_sizecheck(struct dynarr **buf,int count,int size){ 148 | struct dynarr *arr=*buf; 149 | if(arr->elemSize!=size){ 150 | wa_debug("size check failed."); 151 | wa_abort(1); 152 | } 153 | return dynarr_push(buf,count); 154 | } 155 | #define dynarr_push_type(dynarr,typename) (typename *)dynarr_push_sizecheck(dynarr,1,sizeof(typename)) 156 | #else 157 | #define dynarr_push_type(dynarr,typename) (typename *)dynarr_push(dynarr,1) 158 | #endif 159 | 160 | static void *dynarr_pop(struct dynarr **buf,int count){ 161 | struct dynarr *arr=*buf; 162 | uint32_t elemSize=arr->elemSize; 163 | arr->len-=count; 164 | return arr->data+arr->len*elemSize; 165 | } 166 | #define dynarr_pop_type(dynarr,typename) (typename *)dynarr_pop(dynarr,1) 167 | 168 | #if DEBUG_BUILD 169 | static void *dynarr_get_boundcheck(struct dynarr *dynarr,int index){ 170 | if(index>dynarr->len || index<0){ 171 | wa_debug("bound check failed."); 172 | wa_abort(1); 173 | } 174 | return dynarr->data+index*dynarr->elemSize; 175 | } 176 | #define dynarr_get(dynarr,typename,index) ((typename *)dynarr_get_boundcheck(dynarr,index)) 177 | #else 178 | #define dynarr_get(dynarr,typename,index) (((typename *)dynarr->data)+index) 179 | #endif 180 | 181 | 182 | static void dynarr_free(struct dynarr **arr){ 183 | if(*arr!=NULL){ 184 | wa_free(*arr); 185 | } 186 | *arr=NULL; 187 | } 188 | 189 | //pool can allocate small memory many times and free all in one call. 190 | struct pool{ 191 | struct dynarr *chunks; // chunks ,type (char *) 192 | int cur; 193 | int used; 194 | int chunk_size; 195 | }; 196 | 197 | static void pool_init(struct pool *p,int chunk_size){ 198 | dynarr_init(&p->chunks,sizeof(char *)); 199 | *dynarr_push_type(&p->chunks,char *)=wa_calloc(chunk_size); 200 | p->cur=0; 201 | p->used=0; 202 | p->chunk_size=chunk_size; 203 | } 204 | 205 | //alloc size must less than chunk_size 206 | static char *pool_alloc(struct pool *p,int size){ 207 | wa_assert(size<=p->chunk_size,"pool_alloc require sizeused+size<=p->chunk_size){ 210 | r=*dynarr_get(p->chunks,char *,p->cur)+p->used; 211 | p->used+=size; 212 | }else{ 213 | r=wa_calloc(p->chunk_size); 214 | *dynarr_push_type(&p->chunks,char *)=r; 215 | p->cur=p->chunks->len-1; 216 | p->used=size; 217 | } 218 | return r; 219 | } 220 | 221 | static void pool_free(struct pool *p){ 222 | for(int i=0;ichunks->len;i++){ 223 | wa_free(*dynarr_get(p->chunks,char *,i)); 224 | } 225 | dynarr_free(&p->chunks); 226 | } 227 | 228 | 229 | 230 | 231 | #endif -------------------------------------------------------------------------------- /pwart_syslib/libuv.c: -------------------------------------------------------------------------------- 1 | #ifndef _PWART_SYSLIB_LIBUV_C 2 | #define _PWART_SYSLIB_LIBUV_C 3 | 4 | 5 | #include 6 | #include 7 | 8 | #include "./util.c" 9 | 10 | 11 | static void wasm__uv_version(void *fp){ 12 | void *sp=fp; 13 | pwart_rstack_put_i32(&sp,uv_version()); 14 | } 15 | 16 | static void wasm__uv_dlopen(void *fp){ 17 | void *sp=fp; 18 | _wargref(filename) 19 | sp=fp; 20 | void *lib=wa_malloc(sizeof(uv_lib_t)); 21 | int result=uv_dlopen(filename,lib); 22 | pwart_rstack_put_ref(&sp,lib); 23 | pwart_rstack_put_i32(&sp,result); 24 | } 25 | 26 | static void wasm__uv_dlsym(void *fp){ 27 | void *sp=fp; 28 | _wargref(lib) 29 | _wargref(name) 30 | sp=fp; 31 | void *ptr=NULL; 32 | int result=uv_dlsym(lib,name,&ptr); 33 | pwart_rstack_put_ref(&sp,ptr); 34 | pwart_rstack_put_i32(&sp,result); 35 | } 36 | 37 | static void wasm__uv_dlclose(void *fp){ 38 | void *sp=fp; 39 | _wargref(lib) 40 | sp=fp; 41 | uv_dlclose(lib); 42 | wa_free(lib); 43 | } 44 | 45 | struct libuv_wasmthread{ 46 | uv_thread_t uvt; 47 | pwart_wasm_function wasmentry; 48 | uint64_t arg; 49 | void *stack; 50 | }; 51 | static void wasm__uv_wasmthreadentry(void *awt){ 52 | struct libuv_wasmthread *wt=awt; 53 | wt->stack=pwart_allocate_stack(64*1024); 54 | void *sp=wt->stack; 55 | pwart_rstack_put_i64(&sp,wt->arg); 56 | pwart_call_wasm_function(wt->wasmentry,wt); 57 | pwart_free_stack(wt->stack); 58 | wa_free(wt); 59 | } 60 | static void wasm__uv_thread_create(void *fp){ 61 | void *sp=fp; 62 | _wargref(entry) 63 | _wargi64(arg) 64 | struct libuv_wasmthread *info=wa_malloc(sizeof(struct libuv_wasmthread)); 65 | info->wasmentry=entry; 66 | info->arg=arg; 67 | uv_thread_create(&info->uvt,wasm__uv_wasmthreadentry,info); 68 | sp=fp; 69 | pwart_rstack_put_ref(&sp,info); 70 | } 71 | 72 | 73 | static void wasm__uv_mutex_init(void *fp){ 74 | void *sp=fp; 75 | void *mut=wa_malloc(sizeof(uv_mutex_t)); 76 | uv_mutex_init(mut); 77 | pwart_rstack_put_ref(&sp,mut); 78 | } 79 | 80 | static void wasm__uv_mutex_destroy(void *fp){ 81 | void *sp=fp; 82 | _wargref(mut) 83 | uv_mutex_destroy(mut); 84 | wa_free(mut); 85 | } 86 | 87 | static void wasm__uv_mutex_lock(void *fp){ 88 | void *sp=fp; 89 | _wargref(mut) 90 | uv_mutex_lock(mut); 91 | } 92 | 93 | static void wasm__uv_mutex_trylock(void *fp){ 94 | void *sp=fp; 95 | _wargref(mut) 96 | int err=uv_mutex_trylock(mut); 97 | pwart_rstack_put_i32(&sp,err); 98 | } 99 | 100 | static void wasm__uv_mutex_unlock(void *fp){ 101 | void *sp=fp; 102 | _wargref(mut) 103 | uv_mutex_unlock(mut); 104 | } 105 | 106 | 107 | static void wasm__uv_cond_init(void *fp){ 108 | void *sp=fp; 109 | void *cond=wa_malloc(sizeof(uv_cond_t)); 110 | uv_cond_init(cond); 111 | pwart_rstack_put_ref(&sp,cond); 112 | } 113 | 114 | static void wasm__uv_cond_destroy(void *fp){ 115 | void *sp=fp; 116 | _wargref(cond) 117 | uv_cond_destroy(cond); 118 | wa_free(cond); 119 | } 120 | 121 | static void wasm__uv_cond_signal(void *fp){ 122 | void *sp=fp; 123 | _wargref(cond) 124 | uv_cond_signal(cond); 125 | } 126 | 127 | static void wasm__uv_cond_wait(void *fp){ 128 | void *sp=fp; 129 | _wargref(cond) 130 | _wargref(mut) 131 | uv_cond_wait(cond,mut); 132 | } 133 | 134 | 135 | static void wasm__uv_cond_timedwait(void *fp){ 136 | void *sp=fp; 137 | _wargref(cond) 138 | _wargref(mut) 139 | _wargi64(timeout) 140 | int r=uv_cond_timedwait(cond,mut,timeout); 141 | pwart_rstack_put_i32(&sp,r); 142 | } 143 | 144 | static struct dynarr *uvsyms=NULL; //type pwart_named_symbol 145 | 146 | static char *libuv_funcname_list[]={ 147 | "uv_version","uv_dlopen","uv_dlsym","uv_dlclose","uv_thread_create", 148 | "uv_mutex_init","uv_mutex_destroy","uv_mutex_lock","uv_mutex_unlock","uv_mutex_trylock", 149 | "uv_cond_init","uv_cond_destroy","uv_cond_signal","uv_cond_wait" 150 | }; 151 | static pwart_host_function_c libuv_funcsymbols_list[]={ 152 | &wasm__uv_version,&wasm__uv_dlopen,&wasm__uv_dlsym,&wasm__uv_dlclose,&wasm__uv_thread_create, 153 | &wasm__uv_mutex_init,&wasm__uv_mutex_destroy,&wasm__uv_mutex_lock,&wasm__uv_mutex_unlock,&wasm__uv_mutex_trylock, 154 | &wasm__uv_cond_init,&wasm__uv_cond_destroy,&wasm__uv_cond_signal,&wasm__uv_cond_wait 155 | }; 156 | 157 | 158 | extern struct pwart_host_module *pwart_libuv_module_new(){ 159 | return pwart_namespace_new_host_module(libuv_funcname_list,libuv_funcsymbols_list,14); 160 | } 161 | 162 | extern char *pwart_libuv_module_delete(struct pwart_host_module *mod){ 163 | wa_free(mod); 164 | return NULL; 165 | } 166 | 167 | #endif -------------------------------------------------------------------------------- /pwart_syslib/pwart_syslib.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | #include "./libffi.c" 9 | #include "./libuv.c" 10 | #include "./libwasi.c" 11 | 12 | 13 | static char *enabled_module[]={ 14 | "libuv", 15 | "libffi", 16 | NULL 17 | }; 18 | 19 | extern char **pwart_syslib_get_enabled_list(){ 20 | return enabled_module; 21 | } 22 | 23 | extern char *pwart_syslib_load(pwart_namespace ns){ 24 | struct pwart_named_module mod; 25 | mod.name="libuv"; 26 | mod.type=PWART_MODULE_TYPE_HOST_MODULE; 27 | mod.val.host=pwart_libuv_module_new(); 28 | char *err=pwart_namespace_define_module(ns,&mod); 29 | if(err!=NULL)return err; 30 | mod.name="libffi"; 31 | mod.val.host=pwart_libffi_module_new(); 32 | err=pwart_namespace_define_module(ns,&mod); 33 | if(err!=NULL)return err; 34 | if(uvwcinited){ 35 | mod.name="wasi_snapshot_preview1"; 36 | mod.val.host=pwart_wasi_module_new(); 37 | err=pwart_namespace_define_module(ns,&mod); 38 | if(err!=NULL)return err; 39 | } 40 | return NULL; 41 | } 42 | 43 | extern char *pwart_syslib_unload(pwart_namespace ns){ 44 | pwart_libuv_module_delete(pwart_namespace_find_module(ns,"libuv")->val.host); 45 | pwart_libffi_module_delete(pwart_namespace_find_module(ns,"libffi")->val.host); 46 | pwart_wasi_module_delete(pwart_namespace_find_module(ns,"wasi_snapshot_preview1")->val.host); 47 | return NULL; 48 | } -------------------------------------------------------------------------------- /pwart_syslib/util.c: -------------------------------------------------------------------------------- 1 | #ifndef _PWART_SYSLIB_UTILS_C 2 | #define _PWART_SYSLIB_UTILS_C 3 | 4 | #define _wargref(vname) void *vname=pwart_rstack_get_ref(&sp); 5 | #define _wargi32(vname) uint32_t vname=pwart_rstack_get_i32(&sp); 6 | #define _wargi64(vname) uint64_t vname=pwart_rstack_get_i64(&sp); 7 | 8 | //XXX: Can we use pwart internal code? 9 | #include "../pwart/util.c" 10 | 11 | 12 | #endif -------------------------------------------------------------------------------- /pwart_syslib/wasiexec.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main(int argc,char **argv){ 9 | pwart_wasi_module_set_wasiargs(argc-1,argv+1); 10 | if(argc>=2){ 11 | char *modpath=argv[1]; 12 | void *stackbase = pwart_allocate_stack(64 * 1024); 13 | char *err=NULL; 14 | void *sp; 15 | long filesize; 16 | FILE *f; 17 | int len; 18 | int returncode; 19 | 20 | f = fopen(modpath, "rb"); 21 | 22 | fseek(f,0,SEEK_END); 23 | filesize=ftell(f); 24 | 25 | if(filesize>1024*1024*1024){ 26 | printf(".wasm file too large(>1GB)\n"); 27 | return 1; 28 | } 29 | fseek(f,0,SEEK_SET); 30 | 31 | uint8_t *data = malloc(filesize); 32 | 33 | pwart_namespace *ns=pwart_namespace_new(); 34 | 35 | err=pwart_wasi_module_init(); 36 | if(err!=NULL){ 37 | printf("warning:%s uvwasi will not load",err); 38 | } 39 | pwart_syslib_load(ns); 40 | len = fread(data, 1, filesize, f); 41 | fclose(f); 42 | pwart_module_state stat=pwart_namespace_define_wasm_module(ns,"__main__",data,len,&err); 43 | free(data); 44 | if(err!=NULL){ 45 | printf("error occur:%s\n",err); 46 | return 1; 47 | } 48 | struct pwart_wasm_memory *mem=pwart_get_export_memory(stat,"memory"); 49 | pwart_wasi_module_set_wasimemory(mem); 50 | pwart_wasm_function fn=pwart_get_start_function(stat); 51 | if(fn!=NULL){ 52 | pwart_call_wasm_function(fn,stackbase); 53 | } 54 | fn=pwart_get_export_function(stat,"_start"); 55 | if(fn!=NULL){ 56 | pwart_call_wasm_function(fn,stackbase); 57 | }else{ 58 | printf("%s\n","'_start' function not found. "); 59 | } 60 | pwart_free_stack(stackbase); 61 | return 0; 62 | }else{ 63 | printf("No input .wasm file.\n"); 64 | return 1; 65 | } 66 | } -------------------------------------------------------------------------------- /sljit/.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | taring 3 | -------------------------------------------------------------------------------- /sljit/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() -------------------------------------------------------------------------------- /sljit/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 | -------------------------------------------------------------------------------- /sljit/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 | -------------------------------------------------------------------------------- /sljit/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 | -------------------------------------------------------------------------------- /sljit/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 | -------------------------------------------------------------------------------- /sljit/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 | -------------------------------------------------------------------------------- /sljit/docs/general/architecture.md: -------------------------------------------------------------------------------- 1 | # Architecture 2 | 3 | ## Low-level Intermediate Representation 4 | 5 | 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. 6 | 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. 7 | These features are also emulated by the remaining architectures with low overhead. 8 | For example, SLJIT supports various memory addressing modes and setting status register bits. 9 | 10 | ## Generic CPU Model 11 | 12 | The CPU has: 13 | - integer registers, which can store either an `int32_t` (4 byte) or `intptr_t` (4 or 8 byte) value 14 | - floating point registers, which can store either a single (4 byte) or double (8 byte) precision value 15 | - boolean status flags 16 | 17 | Some platforms additionally have support for vector registers, which may alias the floating point registers. 18 | 19 | ### Integer Registers 20 | 21 | 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. 22 | 23 | For example, the following code snippet is a valid instruction sequence: 24 | 25 | ```c 26 | sljit_emit_op1(compiler, SLJIT_MOV32, 27 | SLJIT_R0, 0, SLJIT_MEM1(SLJIT_R1), 0); 28 | // An int32_t value is loaded into SLJIT_R0 29 | sljit_emit_op1(compiler, SLJIT_REV32, 30 | SLJIT_R0, 0, SLJIT_R0, 0); 31 | // the int32_t value in SLJIT_R0 is byte swapped 32 | // and the type of the result is still int32_t 33 | ``` 34 | 35 | The next code snippet is not allowed: 36 | 37 | ```c 38 | sljit_emit_op1(compiler, SLJIT_MOV, 39 | SLJIT_R0, 0, SLJIT_MEM1(SLJIT_R1), 0); 40 | // An intptr_t value is loaded into SLJIT_R0 41 | sljit_emit_op1(compiler, SLJIT_REV32, 42 | SLJIT_R0, 0, SLJIT_R0, 0); 43 | // The result of the instruction is undefined. 44 | // Even crash is possible for some instructions 45 | // (e.g. on MIPS-64). 46 | ``` 47 | 48 | However, it is always allowed to overwrite a register regardless of its previous value: 49 | 50 | ```c 51 | sljit_emit_op1(compiler, SLJIT_MOV, 52 | SLJIT_R0, 0, SLJIT_MEM1(SLJIT_R1), 0); 53 | // An intptr_t value is loaded into SLJIT_R0 54 | sljit_emit_op1(compiler, SLJIT_MOV32, 55 | SLJIT_R0, 0, SLJIT_MEM1(SLJIT_R2), 0); 56 | // From now on SLJIT_R0 contains an int32_t 57 | // value. The previous value is discarded. 58 | ``` 59 | 60 | Type conversion instructions are provided to convert an `int32_t` value to an `intptr_t` value and vice versa. 61 | In certain architectures these conversions are *nops* (no instructions are emitted). 62 | 63 | #### Memory Accessing 64 | 65 | Register arguments of `SLJIT_MEM1` / `SLJIT_MEM2` addressing modes must contain `intptr_t` data. 66 | 67 | #### Signed / Unsigned Values 68 | 69 | Most operations are executed in the same way regardless of if the value is signed or unsigned. 70 | These operations have only one instruction form (e.g. `SLJIT_ADD` / `SLJIT_MUL`). 71 | Instructions where the result depends on the sign have two forms (e.g. integer division, long multiply). 72 | 73 | ### Floating Point Registers 74 | 75 | Floating point registers can either contain a single or double precision value. 76 | Similar to integer registers, the data type of the value stored in a source register must match the data type expected by the instruction. 77 | Otherwise the result is undefined (even a crash is possible). 78 | 79 | #### Rounding 80 | 81 | Similar to standard C, floating point computation results are rounded toward zero. 82 | 83 | ### Boolean Status Flags 84 | 85 | Conditional branches usually depend on the value of CPU status flags. 86 | These status flags are boolean values and can be set by certain instructions. 87 | 88 | For better compatibility with CPUs without flags, SLJIT exposes only two such flags: 89 | - The **zero** (or equal) flag is set if `SLJIT_SET_Z` was specified and the result is zero. 90 | - 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. 91 | 92 | Be aware that different operations give different guarantees on what state the flags will be in afterwards. 93 | Also, not all flags are supported by all operations. 94 | For more details, refer to [`sljitLir.h`](/sljit_src/sljitLir.h). 95 | 96 | ## Complex Instructions 97 | 98 | We noticed that introducing complex instructions for common tasks can improve performance. 99 | For example, compare and branch instruction sequences can be optimized if certain conditions apply, but these conditions depend on the target CPU. 100 | SLJIT can do these optimizations, but it needs to understand the "purpose" of the generated code. 101 | Static instruction analysis has a large performance overhead however, so we chose another approach: we introduced complex instruction forms for certain non-atomic tasks. 102 | SLJIT can optimize these instructions more efficiently since their purpose is known to the compiler. 103 | 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. 104 | 105 | ## Generating Functions 106 | 107 | SLJIT is often used for generating function bodies which are 108 | called from C. 109 | SLJIT provides two complex instructions for generating function entry and return: `sljit_emit_enter` and `sljit_emit_return`. 110 | The `sljit_emit_enter` function also initializes the compilation context, which specifies the current register mapping, local space size and other configurations. 111 | The `sljit_set_context` function can also set this context without emitting any machine instructions. 112 | 113 | 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`. 114 | The context can be changed by calling `sljit_emit_enter` or `sljit_set_context` again. 115 | 116 | ## Types 117 | 118 | SLJIT defines several types for representing data on the target platform, often times in both a signed and unsigned variant: 119 | - Integers of varying size: `sljit_s8` / `sljit_u8`, `sljit_s16` / `sljit_u16`, `sljit_s32` / `sljit_u32` 120 | - Machine word, capable of holding a pointer: `sljit_sw` / `sljit_uw`, `sljit_sp` / `sljit_up` 121 | - Floating point types: `f32`, `f64` 122 | 123 | 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. 124 | -------------------------------------------------------------------------------- /sljit/docs/general/contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | SLJIT needs your help! You can contribute by: 4 | - Reporting bugs [here](https://github.com/zherczeg/sljit/issues) 5 | - Submitting patches [here](https://github.com/zherczeg/sljit/pulls) 6 | - Improving SLJIT's documentation 7 | - Testing SLJIT on all sorts of platforms and compilers (especially the not so common ones like MIPS, PowerPC and SPARC) 8 | 9 | Thank you! 10 | -------------------------------------------------------------------------------- /sljit/docs/general/getting-started/configuration.md: -------------------------------------------------------------------------------- 1 | # Configuration 2 | 3 | SLJIT's behavior can be controlled by a series of defines, described in `sljitConfig.h`. 4 | 5 | | Define | Enabled By Default| Description | 6 | | --- | --- | --- | 7 | | `SLJIT_DEBUG` | ✅ | Enable assertions. Should be disabled in release mode. | 8 | | `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. | 9 | | `SLJIT_SINGLE_THREADED` | ❌ | Single threaded programs can define this flag which eliminates the `pthread` dependency. | 10 | -------------------------------------------------------------------------------- /sljit/docs/general/getting-started/setup.md: -------------------------------------------------------------------------------- 1 | # Setup 2 | 3 | ## Prerequisites 4 | 5 | To compile SLJIT, you need a C/C++ compiler with support for the `C99` standard. 6 | 7 | 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. 8 | 9 | ## Using SLJIT in Your Project 10 | 11 | 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. 12 | 13 | SLJIT can be used in one of two ways: 14 | 15 | ### SLJIT as a Library 16 | 17 | 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. 18 | 19 | To use SLJIT, include `sljitLir.h` and link against `sljitLir.o`. 20 | 21 | ### SLJIT All-in-one 22 | 23 | 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): 24 | 25 | ```c title="hidden.c" 26 | #define SLJIT_CONFIG_STATIC 1 27 | #include "sljitLir.c" 28 | 29 | // SLJIT can be used in hidden.c, but not in other translation units 30 | ``` 31 | 32 | This technique can also be used to generate code for multiple target architectures: 33 | 34 | ```c title="x86-32.c" 35 | #define SLJIT_CONFIG_STATIC 1 36 | #define SLJIT_CONFIG_X86_32 1 37 | #include "sljitLir.c" 38 | 39 | // Generate code for x86 32-bit 40 | ``` 41 | 42 | ```c title="x86-64.c" 43 | #define SLJIT_CONFIG_STATIC 1 44 | #define SLJIT_CONFIG_X86_64 1 45 | #include "sljitLir.c" 46 | 47 | // Generate code for x86 64-bit 48 | ``` 49 | 50 | 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. 51 | 52 | ## Building the Tests 53 | 54 | ### Using GNU Make 55 | 56 | Navigate to the root directory of the SLJIT repository and build the default target with GNU Make: 57 | 58 | ```bash 59 | make 60 | ``` 61 | 62 | The test executable `sljit_test` can be found in the `bin` directory. To run the tests, simply execute it. 63 | 64 | ### Using CMake 65 | 66 | > [!NOTE] 67 | > CMake support is currently only intended as a crutch for Windows systems where GNU Make is not available. 68 | 69 | To build the tests on Windows using MSVC and NMake, do the following: 70 | 71 | 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 72 | 2. Execute the following: 73 | ```bash 74 | cmake -B bin -G "NMake Makefiles" 75 | cmake --build bin 76 | ``` 77 | 78 | The test executable `sljit_test.exe` can be found in the `bin` directory. 79 | 80 | ## Building the Examples 81 | 82 | > [!NOTE] 83 | > You cannot currently build the examples on Windows using MSVC / CMake. 84 | 85 | Build the `examples` target with GNU Make: 86 | 87 | ```bash 88 | make examples 89 | ``` 90 | 91 | The different example executables can be found in the `bin` directory. 92 | -------------------------------------------------------------------------------- /sljit/docs/general/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | ## Overview 4 | 5 | SLJIT is a stack-less, low-level and platform-independent JIT compiler. 6 | Perhaps *platform-independent assembler* describes it even better. 7 | Its core design principle is that it does not try to be smarter than the developer. 8 | This principle is achieved by providing control over the generated machine code like you would have in other assembly languages. 9 | Unlike other assembly languages however, SLJIT utilizes a *low-level intermediate representation* (LIR) that is platform-independent, which greatly improves portability. 10 | 11 | SLJIT tries to strike a good balance between performance and maintainability. 12 | 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. 13 | 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. 14 | Developing these intermediate libraries on top of SLJIT takes far less time, because they only need to support a single backend. 15 | 16 | If you want to jump right in and see SLJIT in action, take a look at the [Tutorial](/docs/tutorial/01-overview.md). 17 | 18 | 19 | ## Features 20 | 21 | - Supports a variety of [target architectures](#supported-platforms) 22 | - Supports a large number of operations 23 | - Self-modifying code 24 | - Tail calls 25 | - Fast calls (not ABI compatible) 26 | - Byte order reverse (endianness switching) 27 | - Unaligned memory accesses 28 | - SIMD[^1] 29 | - Atomic operations[^1] 30 | - Allows direct access to registers (both integer and floating point) 31 | - Supports stack space allocation for function local variables 32 | - Supports [all-in-one](/docs/general/getting-started/setup.md#sljit-all-in-one) compilation 33 | - Allows SLJIT's API to be completely hidden from external use 34 | - Allows serializing the compiler into a byte buffer 35 | - Useful for ahead-of-time (AOT) compilation 36 | - Code generation can be resumed after deserialization (partial AOT compilation) 37 | 38 | ## Supported Platforms 39 | 40 | | Platform | 64-bit | 32-bit | 41 | | --- | --- | --- | 42 | | `x86` | ✅ | ✅ | 43 | | `ARM` | ✅ | ✅[^2] | 44 | | `RISC-V` | ✅ | ✅ | 45 | | `s390x` | ✅ | ❌ | 46 | | `PowerPC` | ✅ | ✅ | 47 | | `LoongArch` | ✅ | ❌ | 48 | | `MIPS` | ✅[^3] | ✅[^3] | 49 | 50 | [^1]: only on certain platforms 51 | [^2]: ARM-v6, ARM-v7 and Thumb2 instruction sets 52 | [^3]: III, R1 53 | -------------------------------------------------------------------------------- /sljit/docs/general/use-cases/bytecode-interpreters.md: -------------------------------------------------------------------------------- 1 | # Bytecode Interpreters 2 | 3 | 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. 4 | 5 | The following table gives a possible mapping for a subset of bytecode instructions targeting a stack machine: 6 | 7 | | Bytecode Instruction | Effect | Mapping to SLJIT | 8 | | --- | --- | --- | 9 | | `pop` | Pop a value from the stack. | ✅ Easy to implement, just decrement the stack pointer. | 10 | | `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). | 11 | | `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. | 12 | -------------------------------------------------------------------------------- /sljit/docs/general/use-cases/overview.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | ## JIT Compilation in General 4 | 5 | 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. 6 | 7 | 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. 8 | 9 | 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. 10 | 11 | ## SLJIT in Particular 12 | 13 | **Advantages:** 14 | - The execution can be continued from any LIR instruction. In other words, jumping into and out of the code is safe. 15 | - The target of (conditional) jump and call instructions can be dynamically modified during the execution of the code. 16 | - Constants can be modified during the execution of the code. 17 | - 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. 18 | - Move with update instructions, meaning the base register is updated before the actual load or store. 19 | 20 | **Disadvantages:** 21 | - Limited number of arguments (3 machine words) for ABI compatible function calls on all platforms. 22 | -------------------------------------------------------------------------------- /sljit/docs/general/use-cases/pattern-matching/regular-expression-engine-types.md: -------------------------------------------------------------------------------- 1 | # Regular Expression Engine Types 2 | 3 | Matching regular expressions is not considered a complex task and many people think that this problem was solved a long time ago. 4 | The reason for this belief is a great deal of misinformation which has been spread across the internet and the education. 5 | 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. 6 | The aim of this page is showing the advantages and disadvantages of different engine types. 7 | 8 | In general we distinguish two engine types: 9 | - **Performance-oriented engines:** very fast in general, and very slow in special (called pathological) cases. 10 | - **Balanced engines:** no weaknesses, no strengths. Usually predictable worst case runtime. 11 | 12 | Balanced engines are slower than performance-oriented engines, but adding some pathological patterns to the benchmark set can quickly turn the tide. 13 | 14 | The following sections go into more detail regarding the different engine types from a technical point of view. 15 | A performance comparison of some of the engines can be found [here](./performance-comparison.md). 16 | 17 | ## Multiple Choice Engine with Backtracking 18 | 19 | **Type:** Usually performance-oriented engines 20 | 21 | **Advantages:** 22 | - Large feature set (assertions, conditional blocks, executing code blocks, backtracking control) 23 | - Submatch capture 24 | - Lots of optimization opportunities (mostly backtracking elimination) 25 | 26 | **Disadvantages:** 27 | - Large and complex code base 28 | - May use a large amount of stack 29 | - Examples for pathological cases: 30 | - `(a*)*b` 31 | - `(?:a?){N}a{N}` (where `N` is a positive integer number) 32 | 33 | **Execution modes:** Depth-first search algorithm 34 | - Interpreted execution of a Non-deterministic Finite Automaton (NFA); example: [PCRE interpreter](https://www.pcre.org/) 35 | - Generating machine code from an NFA; example: [Irregexp engine](https://blog.chromium.org/2009/02/irregexp-google-chromes-new-regexp.html) 36 | - Generating machine code from an Abstract Syntax Tree (AST); example: [PCRE JIT compiler](https://www.pcre.org/) 37 | 38 | ## Single Choice Engine with Pre-generated State Machine 39 | 40 | **Type:** Usually performance-oriented engines 41 | 42 | **Advantages:** 43 | - Simple and very fast matching algorithm 44 | - Partial matching support is easy 45 | - Multiple patterns can be matched at the same time (on a single core) 46 | 47 | **Disadvantages:** 48 | - Large memory consumption (can be limited at the expense of performance) 49 | - Limited feature set (and this feature set is not fully supported, sometimes necessitating falling back to other processing modes) 50 | - Examples for pathological cases: 51 | - `a[^b]{N}a` (where `N` is a positive integer number) 52 | - `a[^b]{1,N}abcde` (where `N` is a positive integer number) 53 | 54 | **Execution modes:** Linear search time, exponential state machine build time (especially for combining multiple patterns into a single state machine) 55 | - Following the state transitions of a Deterministic Finite Automaton (DFA); example: [RE2 engine](https://github.com/google/re2) 56 | - DFA based multi pattern matching; example: [MPM library](https://github.com/zherczeg/mpm) 57 | 58 | ## Single Choice Engine with State Tracking 59 | 60 | **Type:** Usually balanced engines 61 | 62 | **Advantages:** 63 | - No pathological cases 64 | - Partial matching support is not difficult 65 | 66 | **Disadvantages:** 67 | - Matching speed is generally low due to the complex state update mechanism 68 | - Limited feature set (due to synchronization issues, they have a similar feature set as the engines with pre-generated state machine) 69 | 70 | **Execution modes:** Linear search time 71 | - Interpreted execution of Deterministic Finite Automaton (DFA); example: [PCRE-DFA interpreter](https://www.pcre.org/) 72 | - Parallel matching of NFA; example: [TRE engine](http://laurikari.net/tre/) 73 | -------------------------------------------------------------------------------- /sljit/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](/docs/general/getting-started/setup) for more details. 11 | 12 | The tutorial assumes you are already familiar with the C programming language. 13 | -------------------------------------------------------------------------------- /sljit/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](./calling-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 | -------------------------------------------------------------------------------- /sljit/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](/docs/tutorial/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](/docs/tutorial/sources/loop.c).* 204 | -------------------------------------------------------------------------------- /sljit/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](/docs/tutorial/sources/func_call.c).* 19 | -------------------------------------------------------------------------------- /sljit/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](/docs/tutorial/sources/struct_access.c).* 23 | -------------------------------------------------------------------------------- /sljit/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](/docs/tutorial/sources/array_access.c).* 42 | -------------------------------------------------------------------------------- /sljit/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](/docs/tutorial/sources/array_access.c) example.* 15 | -------------------------------------------------------------------------------- /sljit/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`](/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](/docs/tutorial/sources/brainfuck.c) [Brainfuck](https://en.wikipedia.org/wiki/Brainfuck) compiler. 24 | -------------------------------------------------------------------------------- /sljit/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 | -------------------------------------------------------------------------------- /sljit/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 | -------------------------------------------------------------------------------- /sljit/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 | -------------------------------------------------------------------------------- /sljit/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 | -------------------------------------------------------------------------------- /sljit/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'\ -------------------------------------------------------------------------------- /sljit/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 | -------------------------------------------------------------------------------- /sljit/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 | -------------------------------------------------------------------------------- /sljit/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 | -------------------------------------------------------------------------------- /sljit/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 | -------------------------------------------------------------------------------- /sljit/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/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/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/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/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/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/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/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/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/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/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 | -------------------------------------------------------------------------------- /sljit/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 | -------------------------------------------------------------------------------- /sljit/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 | -------------------------------------------------------------------------------- /tests/.gitignore: -------------------------------------------------------------------------------- 1 | /testexe 2 | /testexe.exe 3 | /testexe2 4 | /testexe2.exe 5 | /*.o 6 | /*.wasm -------------------------------------------------------------------------------- /tests/Makefile: -------------------------------------------------------------------------------- 1 | 2 | 3 | # CFLAGS+= -ggdb3 -DDEBUG_BUILD=1 4 | 5 | all:test test2 6 | 7 | include $(PWART_SOURCE_DIR)/pwart/make_config.mk 8 | 9 | 10 | test:build_pwart 11 | - rm testexe || rm testexe.exe 12 | $(CC) $(PWART_CFLAGS) $(CFLAGS) -o testexe testmain.c $(PWART_LDFLAGS) $(LDFLAGS) 13 | $(WAT2WASM) --enable-multi-memory --enable-extended-const --enable-tail-call test1.wat 14 | $(WAT2WASM) unary.wat 15 | $(WAT2WASM) binary.wat 16 | $(WAT2WASM) control.wat 17 | $(WAT2WASM) convert.wat 18 | $(WAT2WASM) compare.wat 19 | ./testexe 20 | 21 | test2:build_pwart 22 | $(CC) $(PWART_CFLAGS) $(CFLAGS) -o testexe2 testmain2.c $(PWART_LDFLAGS) $(LDFLAGS) 23 | $(WAT2WASM) --enable-multi-memory extension1.wat 24 | $(WAT2WASM) benchsort.wat 25 | ./testexe2 26 | 27 | # WIP... 28 | test3:build_pwart 29 | $(CC) $(PWART_CFLAGS) $(CFLAGS) -o testexe3 testexe3.c $(PWART_LDFLAGS) $(LDFLAGS) 30 | $(WAT2WASM) --enable-multi-memory extension1.wat 31 | $(WAT2WASM) benchsort.wat 32 | ./testexe3 -------------------------------------------------------------------------------- /tests/benchsort.c: -------------------------------------------------------------------------------- 1 | 2 | /* https://github.com/cave7/sort/blob/master/quicksort.c */ 3 | 4 | #ifndef EM_PORT_API 5 | # if defined(__EMSCRIPTEN__) 6 | # include 7 | # if defined(__cplusplus) 8 | # define EM_PORT_API(rettype) extern "C" rettype EMSCRIPTEN_KEEPALIVE 9 | # else 10 | # define EM_PORT_API(rettype) rettype EMSCRIPTEN_KEEPALIVE 11 | # endif 12 | # else 13 | # if defined(__cplusplus) 14 | # define EM_PORT_API(rettype) extern "C" rettype 15 | # else 16 | # define EM_PORT_API(rettype) rettype 17 | # endif 18 | # endif 19 | #endif 20 | 21 | int quicksort_r(int* a,int start,int end){ 22 | if (start>=end) { 23 | return 0; 24 | } 25 | int pivot=a[end]; 26 | int swp; 27 | //set a pointer to divide array into two parts 28 | //one part is smaller than pivot and another larger 29 | int pointer=start; 30 | int i; 31 | for (i=start; i 75 | #include 76 | #endif 77 | 78 | #if !defined(__PWART__) 79 | int main(){ 80 | clock_t c=clock(); 81 | mainloop(); 82 | printf("time consumed:%d ms\n",(int)((clock()-c)/(CLOCKS_PER_SEC/1000))); 83 | return 0; 84 | } 85 | #endif -------------------------------------------------------------------------------- /tests/binary.wat: -------------------------------------------------------------------------------- 1 | (module 2 | ;; i32 3 | (func (export "i32_add") (result i32) 4 | i32.const 1 5 | i32.const 2 6 | i32.add) 7 | (func (export "i32_sub") (result i32) 8 | i32.const 20 9 | i32.const 4 10 | i32.sub) 11 | (func (export "i32_mul") (result i32) 12 | i32.const 3 13 | i32.const 7 14 | i32.mul) 15 | (func (export "i32_div_s") (result i32) 16 | i32.const -4 17 | i32.const 2 18 | i32.div_s) 19 | (func (export "i32_div_u") (result i32) 20 | i32.const -4 21 | i32.const 2 22 | i32.div_u) 23 | (func (export "i32_rem_s") (result i32) 24 | i32.const -5 25 | i32.const 2 26 | i32.rem_s) 27 | (func (export "i32_rem_u") (result i32) 28 | i32.const -5 29 | i32.const 2 30 | i32.rem_u) 31 | (func (export "i32_and") (result i32) 32 | i32.const 11 33 | i32.const 5 34 | i32.and) 35 | (func (export "i32_or") (result i32) 36 | i32.const 11 37 | i32.const 5 38 | i32.or) 39 | (func (export "i32_xor") (result i32) 40 | i32.const 11 41 | i32.const 5 42 | i32.xor) 43 | (func (export "i32_shl") (result i32) 44 | i32.const -100 45 | i32.const 3 46 | i32.shl) 47 | (func (export "i32_shr_u") (result i32) 48 | i32.const -100 49 | i32.const 3 50 | i32.shr_u) 51 | (func (export "i32_shr_s") (result i32) 52 | i32.const -100 53 | i32.const 3 54 | i32.shr_s) 55 | (func (export "i32_rotl") (result i32) 56 | i32.const -100 57 | i32.const 3 58 | i32.rotl) 59 | (func (export "i32_rotr") (result i32) 60 | i32.const -100 61 | i32.const 3 62 | i32.rotr) 63 | 64 | ;; i64 65 | (func (export "i64_add") (result i64) 66 | i64.const 1 67 | i64.const 2 68 | i64.add) 69 | (func (export "i64_sub") (result i64) 70 | i64.const 20 71 | i64.const 4 72 | i64.sub) 73 | (func (export "i64_mul") (result i64) 74 | i64.const 3 75 | i64.const 7 76 | i64.mul) 77 | (func (export "i64_div_s") (result i64) 78 | i64.const -4 79 | i64.const 2 80 | i64.div_s) 81 | (func (export "i64_div_u") (result i64) 82 | i64.const -4 83 | i64.const 2 84 | i64.div_u) 85 | (func (export "i64_rem_s") (result i64) 86 | i64.const -5 87 | i64.const 2 88 | i64.rem_s) 89 | (func (export "i64_rem_u") (result i64) 90 | i64.const -5 91 | i64.const 2 92 | i64.rem_u) 93 | (func (export "i64_and") (result i64) 94 | i64.const 11 95 | i64.const 5 96 | i64.and) 97 | (func (export "i64_or") (result i64) 98 | i64.const 11 99 | i64.const 5 100 | i64.or) 101 | (func (export "i64_xor") (result i64) 102 | i64.const 11 103 | i64.const 5 104 | i64.xor) 105 | (func (export "i64_shl") (result i64) 106 | i64.const -100 107 | i64.const 3 108 | i64.shl) 109 | (func (export "i64_shr_u") (result i64) 110 | i64.const -100 111 | i64.const 3 112 | i64.shr_u) 113 | (func (export "i64_shr_s") (result i64) 114 | i64.const -100 115 | i64.const 3 116 | i64.shr_s) 117 | (func (export "i64_rotl") (result i64) 118 | i64.const -100 119 | i64.const 3 120 | i64.rotl) 121 | (func (export "i64_rotr") (result i64) 122 | i64.const -100 123 | i64.const 3 124 | i64.rotr) 125 | 126 | ;; f32 127 | (func (export "f32_add") (result f32) 128 | f32.const 1.25 129 | f32.const 3.75 130 | f32.add) 131 | (func (export "f32_sub") (result f32) 132 | f32.const 4.5 133 | f32.const 1e4 134 | f32.sub) 135 | (func (export "f32_mul") (result f32) 136 | f32.const 1234.5 137 | f32.const -6.875 138 | f32.mul) 139 | (func (export "f32_div") (result f32) 140 | f32.const 1e14 141 | f32.const -2e5 142 | f32.div) 143 | (func (export "f32_min") (result f32) 144 | f32.const 0 145 | f32.const 0 146 | f32.min) 147 | (func (export "f32_max") (result f32) 148 | f32.const 0 149 | f32.const 0 150 | f32.max) 151 | (func (export "f32_copysign") (result f32) 152 | f32.const 0 153 | f32.const 0 154 | f32.copysign) 155 | 156 | ;; f64 157 | (func (export "f64_add") (result f64) 158 | f64.const 987654321 159 | f64.const 123456789 160 | f64.add) 161 | (func (export "f64_sub") (result f64) 162 | f64.const 1234e56 163 | f64.const 5.5e23 164 | f64.sub) 165 | (func (export "f64_mul") (result f64) 166 | f64.const -123e4 167 | f64.const 12341234 168 | f64.mul) 169 | (func (export "f64_div") (result f64) 170 | f64.const 1e200 171 | f64.const 1e50 172 | f64.div) 173 | (func (export "f64_min") (result f64) 174 | f64.const 0 175 | f64.const 0 176 | f64.min) 177 | (func (export "f64_max") (result f64) 178 | f64.const 0 179 | f64.const 0 180 | f64.max) 181 | (func (export "f64_copysign") (result f64) 182 | f64.const 0 183 | f64.const 0 184 | f64.copysign) 185 | ) -------------------------------------------------------------------------------- /tests/control.wat: -------------------------------------------------------------------------------- 1 | (module 2 | (func $brif0 (param i32) (result i32) 3 | (block $exit (result i32) 4 | (i32.sub 5 | (br_if $exit (i32.const 42) (local.get 0)) 6 | (i32.const 13)))) 7 | 8 | (func (export "brif1") (result i32) 9 | (call $brif0 (i32.const 0))) 10 | 11 | (func (export "brif2") (result i32) 12 | (call $brif0 (i32.const 1))) 13 | 14 | 15 | (func $loop0 (param i32) (result i32) 16 | (local i32) 17 | i32.const 0 18 | local.set 1 19 | loop $cont 20 | block $nest1 21 | local.get 1 22 | i32.const 1 23 | i32.add 24 | local.set 1 25 | block $nest2 26 | local.get 1 27 | local.get 0 28 | i32.lt_s 29 | br_if $cont 30 | br $nest2 31 | end 32 | end 33 | end 34 | local.get 1 35 | return) 36 | 37 | (func (export "loop1") (result i32) 38 | i32.const 3 39 | call $loop0) 40 | 41 | (func (export "loop2") (result i32) 42 | i32.const 10 43 | call $loop0) 44 | 45 | (func (export "if1") (result i32) (local i32) 46 | i32.const 0 47 | local.set 0 48 | i32.const 1 49 | if 50 | local.get 0 51 | i32.const 1 52 | i32.add 53 | local.set 0 54 | end 55 | i32.const 0 56 | if 57 | local.get 0 58 | i32.const 1 59 | i32.add 60 | local.set 0 61 | end 62 | local.get 0 63 | return) 64 | 65 | (func (export "if2") (result i32) (local i32 i32) 66 | 67 | i32.const 1 68 | if 69 | i32.const 1 70 | local.set 0 71 | else 72 | i32.const 2 73 | local.set 0 74 | end 75 | i32.const 0 76 | if 77 | i32.const 4 78 | local.set 1 79 | else 80 | i32.const 8 81 | local.set 1 82 | end 83 | local.get 0 84 | local.get 1 85 | i32.add 86 | return) 87 | 88 | (func $brtable0 (param i32) (result i32) 89 | block $default 90 | block $2 91 | block $1 92 | block $0 93 | local.get 0 94 | br_table $0 $1 $2 $default 95 | end 96 | ;; 0 97 | i32.const 0 98 | return 99 | end 100 | ;; 1 101 | i32.const 1 102 | return 103 | end 104 | end 105 | ;; 2, fallthrough 106 | 107 | ;; default 108 | i32.const 2 109 | return) 110 | 111 | (func (export "brtable1") (result i32) 112 | i32.const 0 113 | call $brtable0) 114 | (func (export "brtable2") (result i32) 115 | i32.const 1 116 | call $brtable0) 117 | (func (export "brtable3") (result i32) 118 | i32.const 2 119 | call $brtable0) 120 | 121 | (func (export "expr_block") (result i32) 122 | block (result i32) 123 | i32.const 10 124 | drop 125 | i32.const 1 126 | end 127 | ) 128 | (func (export "expr_brif") (param i32) (result i32) 129 | (block $exit (result i32) 130 | (i32.sub 131 | (br_if $exit (i32.const 42) (local.get 0)) 132 | (i32.const 13)))) 133 | 134 | ) -------------------------------------------------------------------------------- /tests/convert.wat: -------------------------------------------------------------------------------- 1 | (module 2 | ;; i32 3 | (func (export "i32_wrap_i64") (result i32) 4 | i64.const -1 5 | i32.wrap_i64) 6 | (func (export "i32_trunc_s_f32") (result i32) 7 | f32.const -100.12345 8 | i32.trunc_f32_s) 9 | (func (export "i32_trunc_u_f32") (result i32) 10 | f32.const 3e9 11 | i32.trunc_f32_u) 12 | (func (export "i32_trunc_s_f64") (result i32) 13 | f64.const -100.12345 14 | i32.trunc_f64_s) 15 | (func (export "i32_trunc_u_f64") (result i32) 16 | f64.const 3e9 17 | i32.trunc_f64_u) 18 | 19 | ;; i64 20 | (func (export "i64_extend_u_i32") (result i64) 21 | i32.const -1 22 | i64.extend_i32_u) 23 | (func (export "i64_extend_s_i32") (result i64) 24 | i32.const -1 25 | i64.extend_i32_s) 26 | 27 | (func (export "i64_trunc_s_f32") (result i32) 28 | f32.const -100.12345 29 | i64.trunc_f32_s 30 | i64.const -100 31 | i64.eq) 32 | (func (export "i64_trunc_u_f32") (result i32) 33 | f32.const 3e9 34 | i64.trunc_f32_u 35 | i64.const 3000000000 36 | i64.eq) 37 | (func (export "i64_trunc_s_f64") (result i32) 38 | f64.const -100.12345 39 | i64.trunc_f64_s 40 | i64.const -100 41 | i64.eq) 42 | (func (export "i64_trunc_u_f64") (result i32) 43 | f64.const 3e9 44 | i64.trunc_f64_u 45 | i64.const 3000000000 46 | i64.eq) 47 | 48 | ;; f32 49 | (func (export "f32_convert_s_i32") (result f32) 50 | i32.const -1 51 | f32.convert_i32_s) 52 | (func (export "f32_convert_u_i32") (result f32) 53 | i32.const -1 54 | f32.convert_i32_u) 55 | (func (export "f32_demote_f64") (result f32) 56 | f64.const 12345678.9 57 | f32.demote_f64) 58 | (func (export "f32_convert_s_i64") (result f32) 59 | i64.const 0 60 | f32.convert_i64_s) 61 | (func (export "f32_convert_u_i64") (result f32) 62 | i64.const 0 63 | f32.convert_i64_u) 64 | 65 | ;; f64 66 | (func (export "f64_convert_s_i32") (result f64) 67 | i32.const -1 68 | f64.convert_i32_s) 69 | (func (export "f64_convert_u_i32") (result f64) 70 | i32.const -1 71 | f64.convert_i32_u) 72 | (func (export "f64_demote_f32") (result f64) 73 | f32.const 12345678.9 74 | f64.promote_f32) 75 | (func (export "f64_convert_s_i64") (result f64) 76 | i64.const 0 77 | f64.convert_i64_s) 78 | (func (export "f64_convert_u_i64") (result f64) 79 | i64.const 0 80 | f64.convert_i64_u) 81 | 82 | (func (export "f32_reinterpret_i32") (result f32) 83 | i32.const 0x40900000 84 | f32.reinterpret_i32) 85 | 86 | (func (export "i32_reinterpret_f32") (result i32) 87 | f32.const -3.5 88 | i32.reinterpret_f32) 89 | 90 | (func (export "f64_reinterpret_i64") (result f64) 91 | i64.const 0x405f480000000000 92 | f64.reinterpret_i64) 93 | 94 | (func (export "i64_reinterpret_f64") (result i64) 95 | f64.const 1.375e10 96 | i64.reinterpret_f64) 97 | 98 | (func (export "i64_extend_i8_s") (result i64) 99 | i64.const 0xff 100 | i64.extend8_s 101 | ) 102 | 103 | (func (export "i64_extend_i16_s") (result i64) 104 | i64.const 0xfff0 105 | i64.extend16_s 106 | ) 107 | 108 | (func (export "i32_extend_i8_s") (result i32) 109 | i32.const 0xff 110 | i32.extend8_s 111 | ) 112 | 113 | (func (export "i32_extend_i16_s") (result i32) 114 | i32.const 0xfffe 115 | i32.extend16_s 116 | ) 117 | 118 | ) -------------------------------------------------------------------------------- /tests/extension1.wat: -------------------------------------------------------------------------------- 1 | (module 2 | (type $typeAddTwo (func (param i64 i64) (result i64))) 3 | (import "pwart_builtin" "version" (func $getPwartVersion (result i32) )) 4 | (import "pwart_builtin" "native_index_size" (func $native_index_size (result i32) )) 5 | (;; we use funcref to replace anyref ;;) 6 | (import "pwart_builtin" "get_self_runtime_context" (func $thismodule (result funcref) )) 7 | (import "pwart_builtin" "ref_from_index" (func $ref_from_index (param i32 i32) (result funcref) )) 8 | (import "pwart_builtin" "ref_from_i64" (func $ref_from_i64 (param i64) (result funcref) )) 9 | (import "pwart_builtin" "i64_from_ref" (func $i64_from_ref (param funcref) (result i64) )) 10 | (import "pwart_builtin" "ref_string_length" (func $ref_string_length (param funcref) (result i32) )) 11 | (import "pwart_builtin" "memory_alloc" (func $malloc (param i32) (result i64) )) 12 | (import "pwart_builtin" "memory_free" (func $mfree (param i64))) 13 | (import "pwart_builtin" "native_memory" (memory $mem1 i64 16384)) 14 | (import "pwart_builtin" "ref_copy_bytes" (func $refmcopy (param funcref funcref i32))) 15 | (import "pwart_builtin" "import" (func $dimport (param funcref funcref funcref i32)(result funcref))) 16 | (import "test1" "addTwo" (func $addTwo (param i64 i64) (result i64))) 17 | (import "pwart_builtin" "stdio" (func $stdio (result funcref funcref funcref))) 18 | (import "pwart_builtin" "fwrite" (func $fwrite (param funcref i32 i32 funcref))) 19 | (import "pwart_builtin" "host_definition" (func $host_definition (param i32)(result funcref))) 20 | 21 | 22 | (memory $mem2 1 1) 23 | (data (memory $mem2) (i32.const 0) "fwrite test ok!\n\00\n\\0") 24 | (data (memory $mem2) (i32.const 32) "test1\00addTwo\00") 25 | 26 | (global $mbase (mut i64) (i64.const 0)) 27 | (table $stdiols 3 funcref) 28 | 29 | 30 | (func $test1 (result i64) (local $mem2 i64)(local $stdout funcref)(local $impAddTwo funcref) 31 | (local.set $mem2 (call $malloc (i32.const 128))) 32 | (i64.store $mem1 (local.get $mem2) (call $addTwo (i64.const 123000) (i64.const 456)) ) 33 | i32.const 1 34 | 35 | 36 | (call $dimport (call $thismodule) (call $ref_from_index (i32.const 1)(i32.const 32)) (call $ref_from_index (i32.const 1)(i32.const 38)) (i32.const 0)) 37 | table.set $stdiols 38 | 39 | (i64.add (i64.const 8) (local.get $mem2)) 40 | (i64.const 456000)(i64.const 789) 41 | (call_indirect $stdiols (type $typeAddTwo) (i32.const 1)) 42 | i64.store $mem1 43 | 44 | 45 | (global.set $mbase (local.get $mem2)) 46 | 47 | (call $stdio) 48 | drop 49 | (local.set $stdout) 50 | (table.set $stdiols (i32.const 0) (local.get $stdout)) 51 | drop 52 | 53 | (call $ref_from_i64 (i64.add (local.get $mem2) (i64.const 24))) 54 | (call $ref_from_index (i32.const 1) (i32.const 0)) 55 | i32.const 16 56 | call $refmcopy 57 | 58 | (call $ref_from_i64 (i64.add (local.get $mem2) (i64.const 24))) 59 | i32.const 16 60 | i32.const 1 61 | local.get $stdout 62 | call $fwrite 63 | 64 | global.get $mbase 65 | ) 66 | (func $printstring (param $str funcref) 67 | (call $fwrite 68 | (local.get $str) 69 | (call $ref_string_length (local.get $str)) 70 | (i32.const 1) 71 | (table.get $stdiols (i32.const 0)) 72 | ) 73 | (call $fwrite 74 | (call $ref_from_index (i32.const 1) (i32.const 17)) 75 | (i32.const 1) 76 | (i32.const 1) 77 | (table.get $stdiols (i32.const 0)) 78 | ) 79 | ) 80 | (func $test2 (local $index i32)(local $defstr funcref) 81 | (local.set $index (i32.const 0)) 82 | loop $break1 83 | (local.set $defstr (call $host_definition (local.get $index))) 84 | (i32.eqz (ref.is_null (local.get $defstr))) 85 | if 86 | (call $printstring (local.get $defstr)) 87 | (local.set $index (i32.add (local.get $index)(i32.const 1))) 88 | br $break1 89 | end 90 | end 91 | (call $printstring (call $ref_from_index (i32.const 1) (i32.const 0))) 92 | (call $mfree (global.get $mbase)) 93 | ) 94 | (export "test1" (func $test1)) 95 | (export "test2" (func $test2)) 96 | (export "mem2" (memory $mem2)) 97 | (export "mbase" (global $mbase)) 98 | ) -------------------------------------------------------------------------------- /tests/ffitestdll.c: -------------------------------------------------------------------------------- 1 | 2 | typedef int (*adder2)(int a,int b ,void *p); 3 | 4 | extern int add(int a,int b,adder2 adder){ 5 | if(adder==0){ 6 | return a+b; 7 | }else{ 8 | return adder(a,b,0); 9 | } 10 | } -------------------------------------------------------------------------------- /tests/syslibtest1.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define puti32 pwart_rstack_put_i32 12 | #define puti64 pwart_rstack_put_i64 13 | #define putf32 pwart_rstack_put_f32 14 | #define putf64 pwart_rstack_put_f64 15 | #define putref pwart_rstack_put_ref 16 | 17 | #define geti32 pwart_rstack_get_i32 18 | #define geti64 pwart_rstack_get_i64 19 | #define getf32 pwart_rstack_get_f32 20 | #define getf64 pwart_rstack_get_f64 21 | #define getref pwart_rstack_get_ref 22 | 23 | 24 | 25 | static void test_printf64(void *fp) { 26 | void *sp = fp; 27 | printf("testaid:%lf\n", getf64(&sp)); 28 | sp = fp; 29 | printf("testaid:%lld\n", geti64(&sp)); 30 | } 31 | 32 | static void test_printi64(void *fp) { 33 | void *sp = fp; 34 | printf("testaid:%lld\n", geti64(&sp)); 35 | } 36 | 37 | static void do_resolve(struct pwart_host_module *_this,struct pwart_symbol_resolve_request *req) { 38 | char *mod=req->import_module; 39 | char *name=req->import_field; 40 | void **val=&req->result; 41 | if (!strcmp("testaid", mod)) { 42 | if (!strcmp("printi64", name)) { 43 | *val = pwart_wrap_host_function_c(test_printi64); 44 | } else if (!strcmp("printf64", name)) { 45 | *val = pwart_wrap_host_function_c(test_printf64); 46 | } 47 | } 48 | } 49 | 50 | struct pwart_host_module testaid={.resolve=&do_resolve,.on_attached=NULL,.on_detached=NULL}; 51 | 52 | 53 | int syslib_test(char *ffitestdll){ 54 | 55 | struct pwart_global_compile_config gcfg; 56 | void *stackbase = pwart_allocate_stack(64 * 1024); 57 | char *err=NULL; 58 | void *sp; 59 | FILE *f; 60 | int len; 61 | // 8MB buffer; 62 | uint8_t *data = malloc(1024 * 1024 * 8); 63 | 64 | pwart_get_global_compile_config(&gcfg); 65 | pwart_namespace *ns=pwart_namespace_new(); 66 | 67 | pwart_syslib_load(ns); 68 | struct pwart_named_module nmod; 69 | nmod.name="testaid"; 70 | nmod.type=PWART_MODULE_TYPE_HOST_MODULE; 71 | nmod.val.host=&testaid; 72 | pwart_namespace_define_module(ns,&nmod); 73 | 74 | f = fopen("syslibtest1.wasm", "rb"); 75 | len = fread(data, 1, 1024 * 1024 * 8, f); 76 | fclose(f); 77 | pwart_namespace_define_wasm_module(ns,"syslibtest1",data,len,&err); 78 | if(err!=NULL){ 79 | printf("error occur:%s\n",err); 80 | return 0; 81 | } 82 | struct pwart_symbol_resolve_request req; 83 | req.import_module="syslibtest1"; 84 | 85 | req.import_field="mem0"; 86 | req.kind=PWART_KIND_MEMORY; 87 | req.result=NULL; 88 | pwart_namespace_resolver(ns)->resolve(pwart_namespace_resolver(ns),&req); 89 | if(req.result==NULL){ 90 | printf("error occur:%s\n","import syslibtest1.mem0 failed"); 91 | return 0; 92 | } 93 | struct pwart_wasm_memory *mem0=req.result; 94 | 95 | strcpy(mem0->bytes+64,ffitestdll); 96 | *(int *)(mem0->bytes+428)=0; 97 | *(int *)(mem0->bytes+432)=0; 98 | 99 | req.import_field="fficalltest"; 100 | req.kind=PWART_KIND_FUNCTION; 101 | req.result=NULL; 102 | pwart_namespace_resolver(ns)->resolve(pwart_namespace_resolver(ns),&req); 103 | if(req.result==NULL){ 104 | printf("error occur:%s\n","import syslibtest1.fficalltest failed"); 105 | return 0; 106 | } 107 | pwart_wasm_function test1=(pwart_wasm_function)req.result; 108 | pwart_call_wasm_function(test1,stackbase); 109 | sp=stackbase; 110 | if(pwart_libffi_module_ffi_is_enabled()){ 111 | printf("ffi test result:%d,%d, expect %d,%d...",*(int *)(mem0->bytes+428),*(int *)(mem0->bytes+432),7,7); 112 | if(*(int *)(mem0->bytes+428)==7 && *(int *)(mem0->bytes+432)==7){ 113 | printf("pass\n"); 114 | }else{ 115 | return 0; 116 | } 117 | }else{ 118 | printf("ffi test result(ffi is disabled):%d,%d, expect %d,%d...",*(int *)(mem0->bytes+428),*(int *)(mem0->bytes+432),0,0); 119 | if(*(int *)(mem0->bytes+428)==0 && *(int *)(mem0->bytes+432)==0){ 120 | printf("pass\n"); 121 | }else{ 122 | return 0; 123 | } 124 | } 125 | return 1; 126 | } 127 | 128 | int main(int argc, char *argv[]) { 129 | if (syslib_test(argv[1])) { 130 | printf("syslib_test pass\n"); 131 | } else { 132 | printf("syslib_test failed\n"); 133 | return 1; 134 | } 135 | printf("all test pass.\n"); 136 | return 0; 137 | } -------------------------------------------------------------------------------- /tests/syslibtest1.wat: -------------------------------------------------------------------------------- 1 | (module 2 | (import "pwart_builtin" "version" (func $getPwartVersion (result i32) )) 3 | (import "pwart_builtin" "native_index_size" (func $native_index_size (result i32) )) 4 | (;; we use funcref to replace anyref ;;) 5 | (import "pwart_builtin" "get_self_runtime_context" (func $get_self_runtime_context (result funcref) )) 6 | (import "pwart_builtin" "ref_from_index" (func $ref_from_index (param i32 i32) (result funcref) )) 7 | (import "pwart_builtin" "ref_from_i64" (func $ref_from_i64 (param i64) (result funcref) )) 8 | (import "pwart_builtin" "i64_from_ref" (func $i64_from_ref (param funcref) (result i64) )) 9 | (import "pwart_builtin" "ref_string_length" (func $ref_string_length (param funcref) (result i32) )) 10 | (import "libuv" "uv_thread_create" (func $uv_thread_create(param i64)(result funcref))) 11 | (import "libuv" "uv_mutex_init" (func $uv_mutex_init (result funcref))) 12 | (import "libuv" "uv_mutex_destroy" (func $uv_mutex_destroy (result funcref))) 13 | (import "libuv" "uv_dlopen" (func $uv_dlopen (param funcref)(result funcref i32))) 14 | (import "libuv" "uv_dlsym" (func $uv_dlsym (param funcref funcref)(result funcref))) 15 | (import "libuv" "uv_dlclose" (func $uv_dlcose (param funcref))) 16 | (import "libffi" "ffi_is_enabled" (func $ffi_is_enabled (result i32))) 17 | (import "libffi" "ffix_new_cif" (func $ffix_new_cif (param funcref)(result funcref i32))) 18 | (import "libffi" "ffi_call" (func $ffi_call (param funcref funcref funcref funcref)(result i32))) 19 | (import "libffi" "ffix_call" (func $ffix_call (param funcref funcref funcref funcref)(result i32))) 20 | (import "libffi" "ffix_new_c_callback" (func $ffix_new_c_callback (param funcref funcref funcref)(result funcref funcref))) 21 | (import "pwart_builtin" "native_memory" (memory i64 10000)) 22 | 23 | (import "testaid" "printi64" (func $printi64 (param i64) (result i64) )) 24 | (table $tb0 16 funcref) 25 | (elem $tb0 (i32.const 0) $cbadd) 26 | 27 | (global $crt:sp$ (mut i32) (i32.const 65528)) 28 | (global $crt:fp$ (mut i32) (i32.const 65528)) 29 | (memory $mem0 1 1) 30 | (data (memory $mem0) (i32.const 0) "!\n\00\n\\0") 31 | (data (memory $mem0) (i32.const 64) "ffitest.dll\00") 32 | (data (memory $mem0) (i32.const 288) "add\00") 33 | (data (memory $mem0) (i32.const 296) "iip>i\00") 34 | (data (memory $mem0) (i32.const 312) "\03\00\00\00\00\00\00\00\04\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00") 35 | (data (memory $mem0) (i32.const 428) "\00\00\00\00") 36 | 37 | (func $cbadd (param $cif funcref)(param $ret funcref)(param $args funcref)(param $userdata funcref) 38 | (local $argsbase i64) (local $result i32) 39 | (drop (call $printi64 (i64.const 700))) 40 | (local.set $argsbase (call $i64_from_ref (local.get $args))) 41 | (drop (call $printi64 (i64.const 800))) 42 | (i32.load (local.get $argsbase)) 43 | 44 | (drop (call $printi64 (local.get $argsbase))) 45 | (drop (call $printi64 (i64.add (local.get $argsbase) (i64.const 8)))) 46 | (i32.load (i64.add (local.get $argsbase) (i64.const 8))) 47 | (drop (call $printi64 (i64.const 1000))) 48 | i32.add 49 | local.set $result 50 | (drop (call $printi64 (i64.const 1100))) 51 | (i32.store (call $i64_from_ref (local.get $ret))(local.get $result)) 52 | (drop (call $printi64 (i64.const 1200))) 53 | ) 54 | 55 | (func $fficalltest (export "fficalltest") 56 | (result i32) 57 | (local $dll funcref) (local $fn funcref) (local $cif funcref) (local $ccb funcref) 58 | (local $bp$ i32) (local $fp$ i32) (local $i1$ i32) 59 | 60 | call $ffi_is_enabled 61 | i32.eqz 62 | if 63 | i32.const 0 64 | return 65 | end 66 | 67 | global.get $crt:sp$ 68 | local.set $bp$ 69 | global.get $crt:sp$ 70 | i32.const 16 71 | i32.sub 72 | global.set $crt:sp$ 73 | global.get $crt:sp$ 74 | local.set $fp$ 75 | i32.const 1 76 | i32.const 64 77 | call $ref_from_index 78 | 79 | (drop (call $printi64 (i64.const 100))) 80 | 81 | call $uv_dlopen 82 | drop 83 | local.tee $dll 84 | i32.const 1 85 | i32.const 288 86 | call $ref_from_index 87 | (drop (call $printi64 (i64.const 200))) 88 | call $uv_dlsym 89 | local.set $fn 90 | i32.const 1 91 | i32.const 296 92 | call $ref_from_index 93 | (drop (call $printi64 (i64.const 300))) 94 | call $ffix_new_cif 95 | drop 96 | local.set $cif 97 | 98 | 99 | local.get $cif 100 | local.get $fn 101 | (call $ref_from_index (i32.const 1)(i32.const 428)) 102 | (call $ref_from_index (i32.const 1)(i32.const 312)) 103 | (drop (call $printi64 (i64.const 500))) 104 | call $ffix_call 105 | drop 106 | 107 | (call $ffix_new_c_callback (local.get $cif)(ref.func $cbadd) (ref.null func)) 108 | local.set $ccb 109 | drop 110 | (i64.store $mem0 (i32.const 328)(call $i64_from_ref (local.get $ccb))) 111 | local.get $cif 112 | local.get $fn 113 | (call $ref_from_index (i32.const 1)(i32.const 432)) 114 | (call $ref_from_index (i32.const 1)(i32.const 312)) 115 | (drop (call $printi64 (i64.const 600))) 116 | call $ffix_call 117 | drop 118 | 119 | i32.const 0 120 | return 121 | ) 122 | (export "mem0" (memory $mem0)) 123 | ) -------------------------------------------------------------------------------- /tests/test1.wat: -------------------------------------------------------------------------------- 1 | (module 2 | (import "pwart_builtin" "version" (func $getPwartVersion (result i32) )) 3 | (import "pwart_builtin" "native_index_size" (func $native_index_size (result i32) )) 4 | (;; we use funcref to replace anyref ;;) 5 | (import "pwart_builtin" "get_self_runtime_context" (func $get_self_runtime_context (result funcref) )) 6 | (import "pwart_builtin" "ref_from_index" (func $ref_from_index (param i32 i32) (result funcref) )) 7 | (import "pwart_builtin" "ref_from_i64" (func $ref_from_i64 (param i64) (result funcref) )) 8 | (import "pwart_builtin" "i64_from_ref" (func $i64_from_ref (param funcref) (result i64) )) 9 | (import "pwart_builtin" "ref_string_length" (func $ref_string_length (param funcref) (result i32) )) 10 | (import "testaid" "printi64" (func $printi64 (param i64) (result i64) )) 11 | (memory 4) 12 | (memory $mem1 i64 4 4) 13 | (type $typeAddTwo (func (param i64 i64) (result i64))) 14 | (type $longtype (func (param f64 f64 i32 i32 f32 f32 i64 i64) (result i64))) 15 | 16 | (table 16 funcref ) 17 | (table 16 funcref ) 18 | (elem 0 (i32.const 0) $addTwo ) 19 | (global $one i32 (i32.const 1)) 20 | (global $two i32 (i32.const 2)) 21 | (global $three (mut i32) (i32.add (i32.const 1)(i32.const 2))) 22 | 23 | ;; function 0 24 | (func $nop 25 | ) 26 | 27 | ;; function 1 28 | (func $addTwo (param i64 i64) (result i64) 29 | i64.const 10000 30 | call $printi64 31 | drop 32 | (i64.store $mem1 offset=0 (i64.const 200) (local.get 0) ) 33 | (i64.load $mem1 (i64.const 200)) 34 | local.get 1 35 | i64.add 36 | ) 37 | 38 | ;; function 2 39 | (func $addTwoF (param i32 f64 f64) (result i32 f64) 40 | local.get 0 41 | local.get 1 42 | local.get 2 43 | f64.add 44 | ) 45 | 46 | ;; function 3 47 | (func $test1 (param i32 i32) (result i32) (local i32 i64) 48 | i32.const 2 49 | i32.const 1 50 | i32.const 0 51 | table.get 0 52 | table.set 0 53 | ref.func $addTwo 54 | table.set 0 55 | 56 | i32.const 1 57 | i32.const 0x48 58 | i32.store8 59 | i32.const 2 60 | i32.const 0x6c65 61 | i32.store16 62 | i32.const 4 63 | i32.const 0x6f6c 64 | i32.store 65 | 66 | i64.const 300 67 | call $printi64 68 | drop 69 | 70 | i32.const 6 71 | i32.const 1 72 | i32.const 5 73 | memory.copy 74 | 75 | i64.const 400 76 | call $printi64 77 | drop 78 | 79 | i32.const 11 80 | i32.const 33 81 | i32.const 4 82 | memory.fill 83 | 84 | i64.const 500 85 | call $printi64 86 | drop 87 | 88 | i32.const 15 89 | i32.const 0 90 | i32.store8 91 | 92 | i64.const 600 93 | call $printi64 94 | drop 95 | 96 | block $exit (result i32) 97 | i32.const 1 98 | local.get 0 99 | local.get 1 100 | i32.add 101 | local.tee 2 102 | i32.const 100 103 | i32.ge_u 104 | br_if $exit 105 | local.get 2 106 | global.get $two 107 | i32.mul 108 | local.set 2 109 | end 110 | drop 111 | local.get 2 112 | ) 113 | 114 | ;; function 4 115 | (func $test2 (param i64 i64) (result i64) 116 | i64.const 100 117 | call $printi64 118 | drop 119 | i32.const 100 120 | local.get 0 121 | i64.store 122 | i32.const 100 123 | i64.load 124 | local.get 1 125 | 126 | i32.const 2 127 | i32.const 1 128 | table.get 0 129 | table.set 1 130 | 131 | i64.const 300 132 | call $printi64 133 | drop 134 | 135 | i32.const 3 136 | i32.const 2 137 | table.get 1 138 | i32.const 3 139 | table.fill 1 140 | 141 | 142 | i64.const 400 143 | call $printi64 144 | drop 145 | 146 | i32.const 2 147 | call_indirect 1 (type $typeAddTwo) 148 | 149 | i64.const 500 150 | call $printi64 151 | drop 152 | 153 | i64.const 140 154 | return_call $addTwo 155 | ) 156 | 157 | ;; function 5 158 | (func $test3 (param i32 f64 f64) (result i32 i64) (local i32) 159 | i64.const 100 160 | call $printi64 161 | drop 162 | 163 | i32.const 1 164 | local.get 0 165 | i32.const 160 166 | local.get 1 167 | f64.store 168 | i32.const 160 169 | f64.load 170 | local.get 2 171 | call $addTwoF 172 | local.set 2 173 | local.set 3 174 | drop 175 | 176 | i64.const 200 177 | call $printi64 178 | drop 179 | 180 | local.get 3 181 | local.get 2 182 | i64.trunc_sat_f64_s 183 | ) 184 | 185 | ;; function 6 186 | (func $fib:fib 187 | (param $n i32) (result i32) 188 | local.get $n 189 | i32.const 2 190 | i32.lt_u 191 | if 192 | local.get $n 193 | return 194 | end 195 | local.get $n 196 | i32.const 1 197 | i32.sub 198 | call $fib:fib 199 | local.get $n 200 | i32.const 2 201 | i32.sub 202 | call $fib:fib 203 | i32.add 204 | return 205 | ) 206 | 207 | ;; function 7 208 | (func $fib:parseInt 209 | (param $str i32) (result i32) 210 | (local $res i32) (local $i i32) 211 | i32.const 0 212 | local.set $res 213 | block $2$ 214 | i32.const 0 215 | local.set $i 216 | loop $1$ 217 | local.get $str 218 | local.get $i 219 | i32.add 220 | i32.load8_s offset=0 align=1 221 | i32.const 0 222 | i32.ne 223 | i32.eqz 224 | br_if $2$ 225 | block $3$ 226 | local.get $res 227 | i32.const 10 228 | i32.mul 229 | local.get $str 230 | local.get $i 231 | i32.add 232 | i32.load8_s offset=0 align=1 233 | i32.add 234 | i32.const 48 235 | i32.sub 236 | local.set $res 237 | end $3$ 238 | local.get $i 239 | i32.const 1 240 | i32.add 241 | local.set $i 242 | br $1$ 243 | end $1$ 244 | end $2$ 245 | local.get $res 246 | return 247 | ) 248 | 249 | ;; function 8 250 | (func $fib:main (export "fib_main") 251 | (param $args i32) (param $argv i32) (result i32) 252 | (local $n i32) 253 | local.get $argv 254 | i32.load offset=4 align=4 255 | call $fib:parseInt 256 | local.tee $n 257 | call $fib:fib 258 | return 259 | ) 260 | 261 | ;; function 9 262 | (func $builtinFuncTest (result i32 i32 funcref i32) 263 | call $getPwartVersion 264 | call $native_index_size 265 | call $get_self_runtime_context 266 | i32.const 0 267 | i32.const 1 268 | call $ref_from_index 269 | call $i64_from_ref 270 | call $ref_from_i64 271 | call $ref_string_length 272 | ) 273 | 274 | ;; function 10 expect 4 275 | (func $miscTest1 (result i32) 276 | global.get $three 277 | i32.const 1 278 | i32.add 279 | global.set $three 280 | global.get $three 281 | ) 282 | 283 | (export "addTwo" (func $addTwo)) 284 | (export "test1" (func $test1)) 285 | (export "test2" (func $test2)) 286 | (export "test3" (func $test3)) 287 | (export "builtinFuncTest" (func $builtinFuncTest)) 288 | (export "miscTest1" (func $miscTest1)) 289 | ) -------------------------------------------------------------------------------- /tests/testexe3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | 11 | #define puti32 pwart_rstack_put_i32 12 | #define puti64 pwart_rstack_put_i64 13 | #define putf32 pwart_rstack_put_f32 14 | #define putf64 pwart_rstack_put_f64 15 | #define putref pwart_rstack_put_ref 16 | 17 | #define geti32 pwart_rstack_get_i32 18 | #define geti64 pwart_rstack_get_i64 19 | #define getf32 pwart_rstack_get_f32 20 | #define getf64 pwart_rstack_get_f64 21 | #define getref pwart_rstack_get_ref 22 | 23 | 24 | FILE *cmdf=NULL; 25 | char word[255]; 26 | pwart_module_state wmod=NULL; 27 | void *stackbase = NULL; 28 | pwart_wasm_function wfn=NULL; 29 | void *sp; 30 | int assertFail=0; 31 | int shifted=0; 32 | 33 | int next(){ 34 | if(shifted){ 35 | shifted=0; 36 | return 1; 37 | } 38 | if(feof(cmdf)){ 39 | return 0; 40 | }else{ 41 | fscanf(cmdf,"%s",word); 42 | return 1; 43 | } 44 | } 45 | int ifcmd(char *expect){ 46 | return strcmp(expect,word)==0; 47 | } 48 | 49 | void cmdarg(){ 50 | sp=stackbase; 51 | while(next()){ 52 | if(ifcmd("i32")){ 53 | next(); 54 | puti32(&sp,atoi(word)); 55 | }else if(ifcmd("i64")){ 56 | next(); 57 | puti64(&sp,atoll(word)); 58 | }else if(ifcmd("f32")){ 59 | next(); 60 | putf32(&sp,strtof(word,NULL)); 61 | }else if(ifcmd("f64")){ 62 | next(); 63 | putf64(&sp,strtod(word,NULL)); 64 | }else if(ifcmd("end")){ 65 | break; 66 | }else{ 67 | printf("Not support type %s\n",word); 68 | abort(); 69 | } 70 | } 71 | } 72 | void cmdresult(){ 73 | sp=stackbase; 74 | printf("invoking..."); 75 | pwart_call_wasm_function(wfn,sp); 76 | sp=stackbase; 77 | while(next()){ 78 | if(ifcmd("i32")){ 79 | next(); 80 | int t=geti32(&sp); 81 | if(t!=atoi(word)){ 82 | assertFail=1; 83 | printf("expect %s, got %d\n",word,t); 84 | } 85 | }else if(ifcmd("i64")){ 86 | next(); 87 | long long t=geti64(&sp); 88 | if(t!=atoll(word)){ 89 | assertFail=1; 90 | printf("expect %s, got %lld\n",word,t); 91 | } 92 | }else if(ifcmd("f32")){ 93 | next(); 94 | int t=geti32(&sp); 95 | if(t!=atoi(word)){ 96 | assertFail=1; 97 | printf("expect %s, got %d\n",word,t); 98 | } 99 | }else if(ifcmd("f64")){ 100 | next(); 101 | long long t=geti64(&sp); 102 | if(t!=atoll(word)){ 103 | assertFail=1; 104 | printf("expect %s, got %lld\n",word,t); 105 | } 106 | }else if(ifcmd("end")){ 107 | break; 108 | }else{ 109 | printf("Not support type %s\n",word); 110 | abort(); 111 | } 112 | } 113 | } 114 | 115 | char *cmdinvoke(){ 116 | next(); 117 | printf("function %s :",word); 118 | wfn=pwart_get_export_function(wmod,word); 119 | if(wfn==NULL){ 120 | printf("function not found...\n"); 121 | return "err"; 122 | } 123 | sp=stackbase; 124 | assertFail=0; 125 | while(next()){ 126 | if(ifcmd("arg")){ 127 | cmdarg(); 128 | }else if(ifcmd("result")){ 129 | cmdresult(); 130 | break; 131 | }else{ 132 | shifted=1; 133 | break; 134 | } 135 | } 136 | if(assertFail){ 137 | printf("failed...\n"); 138 | }else{ 139 | printf("pass...\n"); 140 | } 141 | } 142 | 143 | char *cmdfile(){ 144 | char filename[256]="test3/"; 145 | next(); 146 | strcat(filename,word); 147 | next(); 148 | if(ifcmd("file")){ 149 | printf("empty test, skip...\n"); 150 | shifted=1; 151 | return NULL; 152 | }else{ 153 | shifted=1; 154 | } 155 | printf("open %s ...\n",filename); 156 | FILE *f = fopen(filename, "rb"); 157 | if(f==NULL){ 158 | printf("file open failed.\n"); 159 | return "err"; 160 | } 161 | 162 | fseek(f,0,SEEK_END); 163 | int filesize=ftell(f); 164 | 165 | if(filesize>1024*1024*1024){ 166 | printf(".wasm file too large(>1GB)\n"); 167 | return "err"; 168 | } 169 | fseek(f,0,SEEK_SET); 170 | 171 | uint8_t *data = malloc(filesize); 172 | 173 | pwart_namespace *ns=pwart_namespace_new(); 174 | 175 | int len = fread(data, 1, filesize, f); 176 | fclose(f); 177 | char *err=NULL; 178 | pwart_module_state stat=pwart_namespace_define_wasm_module(ns,"__main__",data,len,&err); 179 | free(data); 180 | wmod=stat; 181 | if(err!=NULL){ 182 | printf("error occur:%s\n",err); 183 | return "err"; 184 | } 185 | if(err!=NULL){ 186 | return err; 187 | } 188 | 189 | pwart_wasm_function fn=pwart_get_start_function(stat); 190 | if(fn!=NULL){ 191 | pwart_call_wasm_function(fn,stackbase); 192 | } 193 | while(next()){ 194 | if(ifcmd("invoke")){ 195 | cmdinvoke(); 196 | }else{ 197 | shifted=1; 198 | break; 199 | } 200 | } 201 | pwart_namespace_delete(ns); 202 | return NULL; 203 | } 204 | 205 | 206 | char *parseCommandFile(){ 207 | while(next()){ 208 | if(ifcmd("file")){ 209 | cmdfile(); 210 | } 211 | } 212 | return NULL; 213 | } 214 | 215 | int main(int argc, char *argv[]) { 216 | 217 | stackbase=pwart_allocate_stack(64 * 1024); 218 | cmdf=fopen("test3/testcommand.txt","rb"); 219 | parseCommandFile(); 220 | pwart_free_stack(stackbase); 221 | fclose(cmdf); 222 | return 0; 223 | } -------------------------------------------------------------------------------- /tests/testmain2.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define puti32 pwart_rstack_put_i32 12 | #define puti64 pwart_rstack_put_i64 13 | #define putf32 pwart_rstack_put_f32 14 | #define putf64 pwart_rstack_put_f64 15 | #define putref pwart_rstack_put_ref 16 | 17 | #define geti32 pwart_rstack_get_i32 18 | #define geti64 pwart_rstack_get_i64 19 | #define getf32 pwart_rstack_get_f32 20 | #define getf64 pwart_rstack_get_f64 21 | #define getref pwart_rstack_get_ref 22 | 23 | 24 | 25 | static void test_printf64(void *fp) { 26 | void *sp = fp; 27 | printf("testaid:%lf\n", getf64(&sp)); 28 | sp = fp; 29 | printf("testaid:%lld\n", geti64(&sp)); 30 | } 31 | 32 | static void test_printi64(void *fp) { 33 | void *sp = fp; 34 | printf("testaid:%lld\n", geti64(&sp)); 35 | } 36 | 37 | static void do_resolve(struct pwart_host_module *_this,struct pwart_symbol_resolve_request *req) { 38 | char *mod=req->import_module; 39 | char *name=req->import_field; 40 | void **val=&req->result; 41 | if (!strcmp("testaid", mod)) { 42 | if (!strcmp("printi64", name)) { 43 | *val = pwart_wrap_host_function_c(test_printi64); 44 | } else if (!strcmp("printf64", name)) { 45 | *val = pwart_wrap_host_function_c(test_printf64); 46 | } 47 | } 48 | } 49 | 50 | struct pwart_host_module testaid={.resolve=&do_resolve,.on_attached=NULL,.on_detached=NULL}; 51 | 52 | 53 | int namespace_test(){ 54 | struct pwart_global_compile_config gcfg; 55 | void *stackbase = pwart_allocate_stack(64 * 1024); 56 | char *err=NULL; 57 | void *sp; 58 | FILE *f; 59 | int len; 60 | // 8MB buffer; 61 | uint8_t *data = malloc(1024 * 1024 * 8); 62 | 63 | pwart_get_global_compile_config(&gcfg); 64 | pwart_namespace *ns=pwart_namespace_new(); 65 | 66 | struct pwart_named_module nmod; 67 | nmod.name="testaid"; 68 | nmod.type=PWART_MODULE_TYPE_HOST_MODULE; 69 | nmod.val.host=&testaid; 70 | pwart_namespace_define_module(ns,&nmod); 71 | 72 | f = fopen("test1.wasm", "rb"); 73 | len = fread(data, 1, 1024 * 1024 * 8, f); 74 | fclose(f); 75 | pwart_namespace_define_wasm_module(ns,"test1",data,len,&err); 76 | if(err!=NULL){ 77 | printf("error occur:%s\n",err); 78 | return 0; 79 | } 80 | 81 | f = fopen("extension1.wasm", "rb"); 82 | len = fread(data, 1, 1024 * 1024 * 8, f); 83 | fclose(f); 84 | pwart_namespace_define_wasm_module(ns,"extension1",data,len,&err); 85 | if(err!=NULL){ 86 | printf("error occur:%s\n",err); 87 | return 0; 88 | } 89 | struct pwart_symbol_resolve_request req; 90 | req.import_field="test1"; 91 | req.import_module="extension1"; 92 | req.kind=PWART_KIND_FUNCTION; 93 | req.result=NULL; 94 | pwart_namespace_resolver(ns)->resolve(pwart_namespace_resolver(ns),&req); 95 | if(req.result==NULL){ 96 | printf("error occur:%s\n","import extension1.test1 failed"); 97 | return 0; 98 | } 99 | pwart_wasm_function test1=(pwart_wasm_function)req.result; 100 | pwart_call_wasm_function(test1,stackbase); 101 | sp=stackbase; 102 | uint64_t *pmem=(uint64_t *)(size_t)geti64(&sp); 103 | printf("allocated memory at %p, write value %"PRIu64",%"PRIu64", expect %llu,%llu...",pmem,*pmem,*(pmem+1), 104 | 123456ull,456789ull); 105 | if(*pmem!=(uint64_t)123456ull || *(pmem+1)!=(uint64_t)456789ull){ 106 | return 0; 107 | } 108 | printf("pass\n"); 109 | 110 | req.import_field="mbase"; 111 | req.kind=PWART_KIND_GLOBAL; 112 | req.result=NULL; 113 | pwart_namespace_resolver(ns)->resolve(pwart_namespace_resolver(ns),&req); 114 | if(req.result==NULL){ 115 | printf("error occur:%s\n","import extension1.mbase failed"); 116 | return 0; 117 | } 118 | printf("global mbase:%p, expect %p...",*(void **)req.result,pmem); 119 | if(*(void **)req.result!=pmem){ 120 | return 0; 121 | } 122 | printf("pass\n"); 123 | 124 | req.import_field="test2"; 125 | req.kind=PWART_KIND_FUNCTION; 126 | req.result=NULL; 127 | pwart_namespace_resolver(ns)->resolve(pwart_namespace_resolver(ns),&req); 128 | if(req.result==NULL){ 129 | printf("error occur:%s\n","import extension1.test2 failed"); 130 | return 0; 131 | } 132 | pwart_wasm_function test2=(pwart_wasm_function)req.result; 133 | pwart_call_wasm_function(test2,stackbase); 134 | return 1; 135 | } 136 | 137 | 138 | int benchmark_test(){ 139 | struct pwart_global_compile_config gcfg; 140 | void *stackbase = pwart_allocate_stack(64 * 1024); 141 | char *err=NULL; 142 | void *sp; 143 | FILE *f; 144 | int len; 145 | // 8MB buffer; 146 | uint8_t *data = malloc(1024 * 1024 * 8); 147 | 148 | printf("benchmark testing...\n"); 149 | 150 | pwart_get_global_compile_config(&gcfg); 151 | pwart_namespace *ns=pwart_namespace_new(); 152 | 153 | struct pwart_named_module nmod; 154 | nmod.name="testaid"; 155 | nmod.type=PWART_MODULE_TYPE_HOST_MODULE; 156 | nmod.val.host=&testaid; 157 | pwart_namespace_define_module(ns,&nmod); 158 | 159 | f = fopen("benchsort.wasm", "rb"); 160 | len = fread(data, 1, 1024 * 1024 * 8, f); 161 | fclose(f); 162 | pwart_namespace_define_wasm_module(ns,"benchsort",data,len,&err); 163 | if(err!=NULL){ 164 | printf("error occur:%s\n",err); 165 | return 0; 166 | } 167 | 168 | struct pwart_symbol_resolve_request req; 169 | req.import_module="benchsort"; 170 | req.import_field="mainloop"; 171 | req.kind=PWART_KIND_FUNCTION; 172 | req.result=NULL; 173 | pwart_namespace_resolver(ns)->resolve(pwart_namespace_resolver(ns),&req); 174 | if(req.result==NULL){ 175 | printf("error occur:%s\n","import benchsort.mainloop failed"); 176 | return 0; 177 | } 178 | pwart_wasm_function test1=(pwart_wasm_function)req.result; 179 | clock_t beg=clock(); 180 | pwart_call_wasm_function(test1,stackbase); 181 | clock_t end=clock(); 182 | sp=stackbase; 183 | 184 | req.import_field="memory"; 185 | req.kind=PWART_KIND_MEMORY; 186 | req.result=NULL; 187 | pwart_namespace_resolver(ns)->resolve(pwart_namespace_resolver(ns),&req); 188 | struct pwart_wasm_memory *mem=req.result; 189 | uint32_t *target=(uint32_t *)(mem->bytes+5024); 190 | for(int i1=1;i1<1000;i1++){ 191 | if(*(target+i1)<*(target+i1-1)){ 192 | printf("benchmark test get wrong result, faled."); 193 | return 0; 194 | } 195 | } 196 | printf("benchmark test consume %d ms\n",(int)((end-beg)/(CLOCKS_PER_SEC/1000))); 197 | return 1; 198 | } 199 | 200 | int main(int argc, char *argv[]) { 201 | 202 | if (namespace_test()) { 203 | printf("namespace_test pass\n"); 204 | } else { 205 | printf("namespace_test failed\n"); 206 | return 1; 207 | } 208 | if(benchmark_test()){ 209 | printf("benchmark_test pass\n"); 210 | } else { 211 | printf("benchmark_test failed\n"); 212 | return 1; 213 | } 214 | 215 | printf("all test pass.\n"); 216 | return 0; 217 | } -------------------------------------------------------------------------------- /tests/unary.wat: -------------------------------------------------------------------------------- 1 | (module 2 | (func $f32_is_nan (param f32) (result i32) 3 | local.get 0 4 | local.get 0 5 | f32.ne) 6 | (func $f64_is_nan (param f64) (result i32) 7 | local.get 0 8 | local.get 0 9 | f64.ne) 10 | ;; i32 11 | (func (export "i32_eqz_100") (result i32) 12 | i32.const 100 13 | i32.eqz) 14 | (func (export "i32_eqz_0") (result i32) 15 | i32.const 0 16 | i32.eqz) 17 | (func (export "i32_clz") (result i32) 18 | i32.const 128 19 | i32.clz) 20 | (func (export "i32_ctz") (result i32) 21 | i32.const 128 22 | i32.ctz) 23 | (func (export "i32_popcnt") (result i32) 24 | i32.const 128 25 | i32.popcnt) 26 | 27 | ;; i64 28 | (func (export "i64_eqz_100") (result i32) 29 | i64.const 100 30 | i64.eqz) 31 | (func (export "i64_eqz_0") (result i32) 32 | i64.const 0 33 | i64.eqz) 34 | (func (export "i64_clz") (result i64) 35 | i64.const 128 36 | i64.clz) 37 | (func (export "i64_ctz") (result i64) 38 | i64.const 128 39 | i64.ctz) 40 | (func (export "i64_popcnt") (result i64) 41 | i64.const 128 42 | i64.popcnt) 43 | 44 | ;; f32 45 | (func (export "f32_neg") (result f32) 46 | f32.const 100 47 | f32.neg) 48 | (func (export "f32_abs") (result f32) 49 | f32.const -100 50 | f32.abs) 51 | (func (export "f32_sqrt_neg_is_nan") (result i32) 52 | f32.const -100 53 | f32.sqrt 54 | call $f32_is_nan) 55 | (func (export "f32_sqrt_100") (result f32) 56 | f32.const 100 57 | f32.sqrt) 58 | (func (export "f32_ceil") (result f32) 59 | f32.const -0.75 60 | f32.ceil) 61 | (func (export "f32_floor") (result f32) 62 | f32.const -0.75 63 | f32.floor) 64 | (func (export "f32_trunc") (result f32) 65 | f32.const -0.75 66 | f32.trunc) 67 | (func (export "f32_nearest_lo") (result f32) 68 | f32.const 1.25 69 | f32.nearest) 70 | (func (export "f32_nearest_hi") (result f32) 71 | f32.const 1.75 72 | f32.nearest) 73 | 74 | ;; f64 75 | (func (export "f64_neg") (result f64) 76 | f64.const 100 77 | f64.neg) 78 | (func (export "f64_abs") (result f64) 79 | f64.const -100 80 | f64.abs) 81 | (func (export "f64_sqrt_neg_is_nan") (result i32) 82 | f64.const -100 83 | f64.sqrt 84 | call $f64_is_nan) 85 | (func (export "f64_sqrt_100") (result f64) 86 | f64.const 100 87 | f64.sqrt) 88 | (func (export "f64_ceil") (result f64) 89 | f64.const -0.75 90 | f64.ceil) 91 | (func (export "f64_floor") (result f64) 92 | f64.const -0.75 93 | f64.floor) 94 | (func (export "f64_trunc") (result f64) 95 | f64.const -0.75 96 | f64.trunc) 97 | (func (export "f64_nearest_lo") (result f64) 98 | f64.const 1.25 99 | f64.nearest) 100 | (func (export "f64_nearest_hi") (result f64) 101 | f64.const 1.75 102 | f64.nearest) 103 | ) 104 | 105 | (;; STDOUT ;;; 106 | i32_eqz_100() => i32:0 107 | i32_eqz_0() => i32:1 108 | i32_clz() => i32:24 109 | i32_ctz() => i32:7 110 | i32_popcnt() => i32:1 111 | i64_eqz_100() => i32:0 112 | i64_eqz_0() => i32:1 113 | i64_clz() => i64:56 114 | i64_ctz() => i64:7 115 | i64_popcnt() => i64:1 116 | f32_neg() => f32:-100.000000 117 | f32_abs() => f32:100.000000 118 | f32_sqrt_neg_is_nan() => i32:1 119 | f32_sqrt_100() => f32:10.000000 120 | f32_ceil() => f32:-0.000000 121 | f32_floor() => f32:-1.000000 122 | f32_trunc() => f32:-0.000000 123 | f32_nearest_lo() => f32:1.000000 124 | f32_nearest_hi() => f32:2.000000 125 | f64_neg() => f64:-100.000000 126 | f64_abs() => f64:100.000000 127 | f64_sqrt_neg_is_nan() => i32:1 128 | f64_sqrt_100() => f64:10.000000 129 | f64_ceil() => f64:-0.000000 130 | f64_floor() => f64:-1.000000 131 | f64_trunc() => f64:-0.000000 132 | f64_nearest_lo() => f64:1.000000 133 | f64_nearest_hi() => f64:2.000000 134 | ;;; STDOUT ;;) 135 | --------------------------------------------------------------------------------